[squeak-dev] Duffing broken for Inbox [was: The Inbox: Compiler-ct.480.mcz]
karl ramberg
karlramberg at gmail.com
Tue Sep 13 16:25:22 UTC 2022
I have seen the same issue for Etoys in the inbox. Diff is wrong and all
classes are added to a commit.
Best,
Karl
On Tue, Sep 13, 2022 at 4:34 PM Eliot Miranda <eliot.miranda at gmail.com>
wrote:
> The below shows that code diffing is broken for Inbox. Instead of showing
> the difference in the commit the below appears to list the entire Compiler
> package starting with AssignmentNode.
>
> _,,,^..^,,,_ (phone)
>
> > On Sep 9, 2022, at 5:48 AM, commits at source.squeak.org wrote:
> >
> > A new version of Compiler was added to project The Inbox:
> > http://source.squeak.org/inbox/Compiler-ct.480.mcz
> >
> > ==================== Summary ====================
> >
> > Name: Compiler-ct.480
> > Author: ct
> > Time: 9 September 2022, 2:48:27.444614 pm
> > UUID: 03d9ed0c-8807-be4a-89bf-891d9f639f09
> > Ancestors: Compiler-eem.479
> >
> > Attempts to fix a GC issue while creating an Undeclared variable. Hold a
> strong reference on the newly created association until it has been stored
> as a global.
> >
> > Note: This change makes the assumption that undeclared is not a
> SystemDictionary, which overrides #at:put:. However, I cannot explain why
> AttemptToWriteReadOnlyGlobal is handled in this place, no idea how this
> code could touch any ClassBindings ...
> >
> > Please review.
> >
> > =============== Diff against Compiler-eem.479 ===============
> >
> > Item was added:
> > + (PackageInfo named: 'Compiler') preamble: '"Make sure closures are
> initialized before starting to use them"
> > + Utilities initializeClosures.
> > + '!
> >
> > Item was added:
> > + SystemOrganization addCategory: #'Compiler-Exceptions'!
> > + SystemOrganization addCategory: #'Compiler-Kernel'!
> > + SystemOrganization addCategory: #'Compiler-ParseNodes'!
> > + SystemOrganization addCategory: #'Compiler-Support'!
> > + SystemOrganization addCategory: #'Compiler-Syntax'!
> >
> > Item was added:
> > + ParserNotification subclass: #AmbiguousSelector
> > + instanceVariableNames: 'interval'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Exceptions'!
> > +
> > + !AmbiguousSelector commentStamp: 'nice 2/23/2010 15:40' prior: 0!
> > + An AmbiguousSelector is a notification produced by the
> Scanner/Parser/Compiler when encountering this ambiguous construct:
> > +
> > + 1 at -2
> > +
> > + Upper expression can be interpreted both
> > + 1 @ -2 (regular st-80 and former Squeak syntax, the minus is attached
> to the literal number)
> > + 1 @- 2 (extended binary selector, the minus sign is allowed at any
> position and thus part of the binary selector)
> > + !
> >
> > Item was added:
> > + ----- Method: AmbiguousSelector class>>signalName:inRange: (in
> category 'instance creation') -----
> > + signalName: aString inRange: anInterval
> > + ^ (self new setName: aString range: anInterval) signal!
> >
> > Item was added:
> > + ----- Method: AmbiguousSelector>>openMenuIn: (in category 'handling')
> -----
> > + openMenuIn: aBlock
> > + "Ask the user which selector to choose.
> > + Answer the choosen selector or nil if cancellation is requested."
> > +
> > + | labels actions lines caption choice |
> > + labels := {
> > + ('selector is {1} and argument is negative' translated format:
> {name copyFrom: 1 to: name size - 1}).
> > + ('selector is {1} and argument is positive' translated format:
> {name}).
> > + 'cancel' translated}.
> > + actions := {
> > + name copyReplaceFrom: name size to: name size - 1 with: ' '.
> > + name copyReplaceFrom: name size + 1 to: name size with: ' '.
> > + nil.
> > + }.
> > + lines := {2}.
> > + caption := 'Ambiguous selector: {1} please correct, or cancel:'
> translated format: {name}.
> > + choice := aBlock value: labels value: lines value: caption.
> > + self resume: (actions at: choice ifAbsent: [nil])!
> >
> > Item was added:
> > + ----- Method: AmbiguousSelector>>setName:range: (in category
> 'initialization') -----
> > + setName: aString range: anInterval
> > + name := aString.
> > + interval := anInterval!
> >
> > Item was added:
> > + ParseNode subclass: #AssignmentNode
> > + instanceVariableNames: 'variable value'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !AssignmentNode commentStamp: '<historical>' prior: 0!
> > + AssignmentNode comment: 'I represent a (var_expr) construct.'!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitAssignmentNode: self!
> >
> > Item was added:
> > + ----- Method:
> AssignmentNode>>analyseTempsWithin:rootNode:assignmentPools: (in category
> 'closure analysis') -----
> > + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode
> "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + "N.B. since assigment happens _after_ the value is evaluated the
> value is sent the message _first_."
> > + value analyseTempsWithin: scopeBlock rootNode: rootNode
> assignmentPools: assignmentPools.
> > + variable beingAssignedToAnalyseTempsWithin: scopeBlock rootNode:
> rootNode assignmentPools: assignmentPools!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>emitCodeForEffect:encoder: (in category
> 'code generation') -----
> > + emitCodeForEffect: stack encoder: encoder
> > +
> > + variable emitCodeForLoad: stack forValue: false encoder: encoder.
> > + value emitCodeForValue: stack encoder: encoder.
> > + pc := encoder nextPC. "debug pc is first byte of the store, i.e.
> the next byte".
> > + variable emitCodeForStorePop: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>emitCodeForValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > +
> > + variable emitCodeForLoad: stack forValue: true encoder: encoder.
> > + value emitCodeForValue: stack encoder: encoder.
> > + pc := encoder nextPC. "debug pc is first byte of the store, i.e.
> the next byte".
> > + variable emitCodeForStore: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>ifNilTemporary (in category 'private')
> -----
> > + ifNilTemporary
> > + "(temp := object) == nil ifTrue: [...] ifFalse: [...]"
> > +
> > + ^ self variable!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>ifNilValue (in category 'private') -----
> > + ifNilValue
> > + "(temp := object) == nil ifTrue: [...] ifFalse: [...]"
> > +
> > + ^ self value!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>isAssignmentNode (in category 'testing')
> -----
> > + isAssignmentNode
> > + ^true!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>printOn:indent: (in category 'printing')
> -----
> > + printOn: aStream indent: level
> > + variable printOn: aStream indent: level.
> > + aStream nextPutAll: ' := '.
> > + value printOn: aStream indent: level + 2!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>printOn:indent:precedence: (in category
> 'printing') -----
> > + printOn: aStream indent: level precedence: p
> > +
> > + aStream nextPut: $(.
> > + self printOn: aStream indent: level.
> > + aStream nextPut: $)!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level
> > + variable printWithClosureAnalysisOn: aStream indent: level.
> > + aStream nextPutAll: ' := '.
> > + value printWithClosureAnalysisOn: aStream indent: level + 2!
> >
> > Item was added:
> > + ----- Method:
> AssignmentNode>>printWithClosureAnalysisOn:indent:precedence: (in category
> 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level precedence: p
> > +
> > + aStream nextPut: $(.
> > + self printWithClosureAnalysisOn: aStream indent: level.
> > + aStream nextPut: $)!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>sizeCodeForEffect: (in category 'code
> generation') -----
> > + sizeCodeForEffect: encoder
> > +
> > + ^(variable sizeCodeForLoad: encoder forValue: false)
> > + + (value sizeCodeForValue: encoder)
> > + + (variable sizeCodeForStorePop: encoder)!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > +
> > + ^(variable sizeCodeForLoad: encoder forValue: true)
> > + + (value sizeCodeForValue: encoder)
> > + + (variable sizeCodeForStore: encoder)!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>toDoIncrement: (in category
> 'initialize-release') -----
> > + toDoIncrement: var
> > + ^(var = variable
> > + and: [value isMessageNode]) ifTrue:
> > + [value toDoIncrement: var]!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>value (in category 'initialize-release')
> -----
> > + value
> > + ^ value!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>variable (in category 'equation
> translation') -----
> > + variable
> > + ^variable!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>variable:value: (in category
> 'initialize-release') -----
> > + variable: aVariable value: expression
> > +
> > + variable := aVariable.
> > + value := expression!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>variable:value:from: (in category
> 'initialize-release') -----
> > + variable: aVariable value: expression from: encoder
> > +
> > + (aVariable isMemberOf: MessageAsTempNode)
> > + ifTrue: ["Case of remote temp vars"
> > + ^ aVariable store: expression from: encoder].
> > + variable := aVariable.
> > + value := expression!
> >
> > Item was added:
> > + ----- Method: AssignmentNode>>variable:value:from:sourceRange: (in
> category 'initialize-release') -----
> > + variable: aVariable value: expression from: encoder sourceRange: range
> > +
> > + encoder noteSourceRange: range forNode: self.
> > + ^self
> > + variable: aVariable
> > + value: expression
> > + from: encoder!
> >
> > Item was added:
> > + ParseNode subclass: #BlockArgsNode
> > + instanceVariableNames: 'temporaries'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Syntax'!
> >
> > Item was added:
> > + ParseNode subclass: #BlockNode
> > + instanceVariableNames: 'arguments statements returns nArgsNode size
> temporaries optimized optimizedMessageNode actualScopeIfOptimized
> blockExtent remoteTempNode copiedValues closureCreationNode
> startOfLastStatement tempsMark'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !BlockNode commentStamp: 'ct 1/17/2020 13:05' prior: 0!
> > + I represent a bracketed block with 0 or more arguments and 1 or more
> statements. If I am initialized with no statements, I create one. I have a
> flag to tell whether my last statement returns a value from the enclosing
> method. I can emit for value in the usual way, in which case I create a
> BlockClosure to be evaluated by sending it value: at run time. Or I can
> emit code to be evaluated in line; this only happens at the top level of a
> method and in certain optimized control structures (see MessageNode
> class>>initialize MacroSelectors).
> > +
> > + Instance Variables
> > + actualScopeIfOptimized: <nil | BlockNode>
> > + arguments: <SequencableCollection of:
> TempVariableNode>
> > + blockExtent: <nil | Interval>
> > + closureCreationNode: <LeafNode>
> > + copiedValues: <nil | (SequencableCollection of:
> TempVariableNode)>
> > + nArgsNode: <nil | Integer>
> > + optimized: <Boolean>
> > + optimizedMessageNode: <nil | MessageNode>
> > + remoteTempNode: <nil | RemoteTempVectorNode>
> > + returns: <Boolean>
> > + size: <nil | Integer>
> > + startOfLastStatement: <nil | Integer>
> > + statements: <SequencableCollection of: ParseNode>
> > + temporaries: <SequencableCollection of:
> TempVariableNode>
> > + tempsMark: <nil | Integer>
> > +
> > + actualScopeIfOptimized
> > + - if the receiver has been inlined this is the non-optimized
> BlockNode the receiver is inlined into.
> > +
> > + arguments
> > + - the sequence of arguments to the block (or method if a top-level
> block)
> > +
> > + blockExtent
> > + - the interval defining the range of block scopes the receiver
> comprises, which is itself and any blocks it may contain. See
> #analyseArguments:temporaries:rootNode:
> > +
> > + closureCreationNode
> > + - a place-holder representing the body of the block.
> > +
> > + copiedValues
> > + - blocks do not reference the temporary variables of their outer
> context they close over directly; instead, temporary variables which won't
> change value are collected and copied into the block, and temporary
> variables that are modified either within the block or after it has closed
> over the variables are allocated in a remote temp vector that again becomes
> one of the block's copied values. In this way, a block refers to the outer
> temporaries it closes over only through copiedValues. copiedValues is the
> sequence of these TempVariableNodes.
> > +
> > + nArgsNode
> > + - a place holder for the encoder to allow it to number block
> temporaries
> > +
> > + optimized
> > + - true if the receiver is inlined, false if a true block
> > +
> > + optimizedMessageNode
> > + - the MessageNode in which the receiver is optimized, if it is
> optimized.
> > +
> > + remoteTempNode
> > + - if any of the blocks nested into the receiver either modify a
> temp or access a temp that is modified after the block is created, then
> this temp is allocated remotely in a remote temp vector that allows the
> temp's location to be shared between blocks. This is the node that creates
> the remote temp vector.
> > +
> > + returns
> > + - true if the receiver contains a method return.
> > +
> > + size
> > + - the size of the block's bytecodes if it is generated by
> embedding its bytecodes within an enclosing CompiledMethod.
> > +
> > + startOfLastStatement
> > + - the index in the source of the start of the last statement in
> the block.
> > +
> > + statements
> > + - the sequence of statements comprising the receiver
> > +
> > + temporaries
> > + - the sequence of temporaries (including the remoteTempNode if
> any) of block-local temporaries
> > +
> > + tempsMark
> > + - the index in the source of the last block-local temporary, used
> to auto-insert temps declared during compilation!
> >
> > Item was added:
> > + ----- Method: BlockNode class>>statements:returns: (in category
> 'instance creation') -----
> > + statements: statements returns: returns
> > + ^ self new statements: statements returns: returns!
> >
> > Item was added:
> > + ----- Method: BlockNode class>>withJust: (in category 'instance
> creation') -----
> > + withJust: aNode
> > + ^ self new statements: (Array with: aNode) returns: false!
> >
> > Item was added:
> > + ----- Method: BlockNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitBlockNode: self!
> >
> > Item was added:
> > + ----- Method: BlockNode>>actualScope (in category 'closure analysis')
> -----
> > + actualScope
> > + "Answer the actual scope for the receiver. If this is an
> unoptimized block then it is its
> > + actual scope, but if this is an optimized block then the actual
> scope is some outer block."
> > + ^actualScopeIfOptimized ifNil: [self]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>addArgument: (in category 'accessing') -----
> > + addArgument: aTempVariableNode
> > + temporaries := temporaries copyWith: aTempVariableNode!
> >
> > Item was added:
> > + ----- Method: BlockNode>>addHoistedTemps: (in category 'closure
> analysis') -----
> > + addHoistedTemps: additionalTemporaries "<SequenceableCollection>"
> > + | tempsToBeMerged additionalTempsToAdd |
> > + additionalTemporaries do:
> > + [:temp|
> > + temp definingScope ifNil:
> > + [temp definingScope: self]].
> > + (temporaries isNil or: [temporaries isEmpty]) ifTrue:
> > + [temporaries := additionalTemporaries copy.
> > + ^self].
> > + tempsToBeMerged := additionalTemporaries select:
> > + [:t|
> > + t isBlockArg
> > + and: [temporaries anySatisfy: [:existing|
> existing isBlockArg and: [existing key = t key]]]].
> > + additionalTempsToAdd := tempsToBeMerged isEmpty
> > + ifTrue: [additionalTemporaries copy]
> > + ifFalse: [additionalTemporaries
> reject: [:temp| tempsToBeMerged identityIncludes: temp]].
> > + temporaries := (temporaries isNil or: [temporaries isEmpty])
> > + ifTrue: [additionalTempsToAdd]
> > + ifFalse:
> > + [temporaries last isIndirectTempVector
> > + ifTrue: [temporaries allButLast,
> additionalTempsToAdd, { temporaries last }]
> > + ifFalse: [temporaries,
> additionalTempsToAdd]].
> > + tempsToBeMerged do:
> > + [:t| | merge |
> > + merge := temporaries detect: [:existing| existing isBlockArg
> and: [existing key = t key]].
> > + merge absorbHoistedTemp: t]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>addRemoteTemp:rootNode: (in category 'closure
> analysis') -----
> > + addRemoteTemp: aTempVariableNode rootNode: rootNode "<MethodNode>"
> > + "Add aTempVariableNode to my actualScope's sequence of
> > + remote temps. If I am an optimized block then the actual
> > + scope is my actualScopeIfOptimized, otherwise it is myself."
> > + remoteTempNode == nil ifTrue:
> > + [remoteTempNode := RemoteTempVectorNode new
> > + name: self remoteTempNodeName
> > + index: arguments size + temporaries size
> > + type: LdTempType
> > + scope: 0.
> > + actualScopeIfOptimized
> > + ifNil:
> > + [self addTempNode: remoteTempNode.
> > + remoteTempNode definingScope: self]
> > + ifNotNil: [actualScopeIfOptimized addHoistedTemps: {
> remoteTempNode }]].
> > + remoteTempNode addRemoteTemp: aTempVariableNode encoder: rootNode
> encoder.
> > + "use remove:ifAbsent: because the deferred analysis for optimized
> > + loops can result in the temp has already been hoised into the
> root."
> > + self removeTempNode: aTempVariableNode ifAbsent: [
> > + self actualScope removeTempNode: aTempVariableNode ifAbsent:
> ["should not happen"]].
> > + ^remoteTempNode!
> >
> > Item was added:
> > + ----- Method: BlockNode>>addTempNode: (in category 'closure analysis')
> -----
> > + addTempNode: aTempVariableNode
> > + "Utilities for when we want to add some temporaries."
> > +
> > + self makeTemporariesRemovable.
> > + ^temporaries add: aTempVariableNode!
> >
> > Item was added:
> > + ----- Method: BlockNode>>analyseArguments:temporaries:rootNode: (in
> category 'closure analysis') -----
> > + analyseArguments: methodArguments temporaries: methodTemporaries
> rootNode: rootNode "<MethodNode>" "^<Sequence of: <TempVarNade>>"
> > + "Top level entry-point for analysing temps within the hierarchy of
> blocks in the receiver's method.
> > + Answer the (possibly modified) sequence of temp vars.
> > + Need to hoist temps out of macro-optimized blocks into their
> actual blocks.
> > + Need to note reads and writes to temps from blocks other than
> their actual blocks to determine
> > + whether blocks can be local (simple slots within a block/method
> context) or remote (slots in
> > + indirection vectors that are shared between contexts by sharing
> indirection vectors).
> > +
> > + The algorithm is based on numbering temporary reads and writes and
> block extents.
> > + The index used for numbering starts at zero and is incremented on
> every block entry
> > + and block exit. So the following
> > + | a b blk r1 r2 t |
> > + a := 1. b := 2. t := 0.
> > + blk := [ | s | s := a + b. t := t + s].
> > + r1 := blk value.
> > + b := -100.
> > + r2 := blk value.
> > + r1 -> r2 -> t
> > + is numbered as
> > + method block 0 to: 6:
> > + | a b blk r1 r2 t |
> > + a w at 1 := 1. b w at 1 := 2. t w at 1 := 0.
> > + blk w at 5 := [entry at 2 | s |
> > + t w at 3 := t r at 3 + a r at 3 + b r at 3
> > + ] exit at 4.
> > + r1 w at 5 := blk r at 5 value.
> > + b w at 5 := nil.
> > + r2 w at 5 := blk r at 5 value.
> > + r1 r at 5 -> r2 r at 5 -> t r at 5
> > + So:
> > + b and blk cannot be copied because for both there exists a
> write @5 that follows a
> > + read @4 within block 2 through 4
> > + t must be remote because there exists a write @3 within block
> (2 to: 4)
> > + Complications are introduced by optimized blocks. In the following
> temp is written to
> > + after it is closed over by [ temp ] since the inlined block is
> executed more than once.
> > + | temp coll |
> > + coll := OrderedCollection new.
> > + 1 to: 5 do: [ :index |
> > + temp := index.
> > + coll add: [ temp ] ].
> > + self assert: (coll collect: [:ea| ea value]) asArray = #(5 5 5
> 5 5)
> > + In the following i is local to the block and must be initialized
> each time around the loop
> > + but if the block is inlined it must be declared at method level.
> > + | col |
> > + col := OrderedCollection new.
> > + 1 to: 3 do: [ :each | | i | i := each. col add: [ i ]. i := i +
> 1 ].
> > + self assert: (col collect: [ :each | each value ]) asArray =
> #(2 3 4)"
> > + self assert: (arguments isEmpty or: [arguments hasEqualElements:
> methodArguments]).
> > + arguments := methodArguments asArray. "won't change"
> > + self assert: (temporaries isNil or: [temporaries isEmpty or:
> [temporaries hasEqualElements: methodTemporaries]]).
> > + temporaries := OrderedCollection withAll: methodTemporaries.
> > +
> > + self assert: optimized not. "the top-level block should not be
> optimized."
> > + self analyseTempsWithin: self rootNode: rootNode assignmentPools:
> Dictionary new.
> > +
> > + "The top-level block needs to reindex temporaries since analysis
> may have rearranged them.
> > + This happens when temps are made remote and/or a remote node is
> added."
> > + temporaries withIndexDo:
> > + [:temp :offsetPlusOne| temp index: arguments size +
> offsetPlusOne - 1].
> > +
> > + "Answer the (possibly modified) sequence of temps."
> > + ^temporaries asArray!
> >
> > Item was added:
> > + ----- Method: BlockNode>>analyseTempsWithin:rootNode:assignmentPools:
> (in category 'closure analysis') -----
> > + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode
> "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + | effectiveScope blockStart |
> > + effectiveScope := optimized
> > + ifTrue: [actualScopeIfOptimized := scopeBlock]
> > + ifFalse: [self].
> > +
> > + arguments ifNotNil:
> > + [arguments do: [:temp| temp definingScope: self]].
> > + temporaries ifNotNil:
> > + [temporaries do: [:temp| temp definingScope: self]].
> > +
> > + optimized ifFalse: "if optimized this isn't an actual scope"
> > + [rootNode noteBlockEntry:
> > + [:entryNumber|
> > + blockExtent := (blockStart := entryNumber) to: 0]].
> > +
> > + "Need to enumerate a copy because closure analysis can add a
> statement
> > + via ifHasRemoteTempNodeEnsureInitializationStatementExists:."
> > + statements copy do:
> > + [:statement|
> > + statement analyseTempsWithin: effectiveScope rootNode:
> rootNode assignmentPools: assignmentPools].
> > +
> > + optimized
> > + ifTrue: "if optimized loop need to add nils for any temps read
> before written"
> > + [optimizedMessageNode isOptimizedLoop ifTrue:
> > + [self nilReadBeforeWrittenTemps]]
> > + ifFalse: "if optimized this isn't an actual scope"
> > + [rootNode noteBlockExit:
> > + [:exitNumber|
> > + blockExtent := blockStart to: exitNumber]].
> > +
> > + "Now that the analysis is done move any temps that need to be
> moved."
> > + self postNumberingProcessTempsWithin: effectiveScope rootNode:
> rootNode.
> > +
> > + "This is simply a nicety for compiler developers..."
> > + temporaries do:
> > + [:temp|
> > + (temp isIndirectTempVector and: [temp name includes: $?])
> ifTrue:
> > + [temp name: temp definingScope remoteTempNodeName]]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>arguments (in category 'accessing') -----
> > + arguments
> > + ^arguments ifNil: [#()]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>arguments: (in category 'accessing') -----
> > + arguments: argNodes
> > + "Decompile."
> > +
> > + arguments := argNodes!
> >
> > Item was added:
> > + ----- Method: BlockNode>>arguments:statements:returns:from: (in
> category 'initialize-release') -----
> > + arguments: argNodes statements: statementsCollection returns:
> returnBool from: encoder
> > + "Compile."
> > +
> > + arguments := argNodes.
> > + statements := statementsCollection size > 0
> > + ifTrue: [statementsCollection]
> > + ifFalse: [Array with: NodeNil].
> > + optimized := false.
> > + returns := returnBool!
> >
> > Item was added:
> > + ----- Method: BlockNode>>block (in category 'accessing') -----
> > + block
> > + ^ self!
> >
> > Item was added:
> > + ----- Method: BlockNode>>blockExtent (in category 'closure analysis')
> -----
> > + blockExtent "^<nil | Interval>"
> > + ^blockExtent!
> >
> > Item was added:
> > + ----- Method: BlockNode>>code (in category 'code generation') -----
> > + code
> > +
> > + ^statements first code!
> >
> > Item was added:
> > + ----- Method: BlockNode>>computeCopiedValues: (in category 'closure
> analysis') -----
> > + computeCopiedValues: rootNode
> > + | referencedValues |
> > + referencedValues := rootNode referencedValuesWithinBlockExtent:
> blockExtent.
> > + ^(referencedValues reject: [:temp| temp isDefinedWithinBlockExtent:
> blockExtent])
> > + asArray sort: ParseNode tempSortBlock!
> >
> > Item was added:
> > + ----- Method: BlockNode>>constructClosureCreationNode: (in category
> 'code generation') -----
> > + constructClosureCreationNode: encoder
> > + copiedValues := self computeCopiedValues: encoder rootNode.
> > + ^self ensureClosureCreationNode: encoder!
> >
> > Item was added:
> > + ----- Method: BlockNode>>createBlockLiteral: (in category 'code
> generation') -----
> > + createBlockLiteral: encoder
> > + ^self
> > + reindexingLocalsDo: [encoder blockLiteralFor: self]
> > + encoder: encoder!
> >
> > Item was added:
> > + ----- Method: BlockNode>>decompileString (in category 'printing') -----
> > + decompileString
> > + "Answer a string description of the parse tree whose root is the
> receiver."
> > +
> > + ^ self decompileText asString
> > + !
> >
> > Item was added:
> > + ----- Method: BlockNode>>decompileText (in category 'printing') -----
> > + decompileText
> > + "Answer a text description of the parse tree whose root is the
> receiver."
> > +
> > + ^ ColoredCodeStream contents: [:strm | self printOn: strm indent: 0]
> > + !
> >
> > Item was added:
> > + ----- Method: BlockNode>>deoptimize (in category 'closure analysis')
> -----
> > + deoptimize
> > + optimized := false.
> > + optimizedMessageNode := nil!
> >
> > Item was added:
> > + ----- Method: BlockNode>>emitCodeExceptLast:encoder: (in category
> 'code generation') -----
> > + emitCodeExceptLast: stack encoder: encoder
> > + | position nextToLast |
> > + position := stack position.
> > + nextToLast := statements size - 1.
> > + 1 to: nextToLast do:
> > + [:i | | statement |
> > + statement := statements at: i.
> > + statement emitCodeForEffect: stack encoder: encoder.
> > + self assert: stack position = position].!
> >
> > Item was added:
> > + ----- Method: BlockNode>>emitCodeForEvaluatedClosureValue:encoder: (in
> category 'code generation') -----
> > + emitCodeForEvaluatedClosureValue: stack encoder: encoder
> > + | position |
> > + position := stack position.
> > + stack position: arguments size + temporaries size + copiedValues
> size.
> > + encoder genPushNClosureTemps: temporaries size.
> > + self
> > + reindexingLocalsDo: [self emitCodeForEvaluatedValue: stack
> encoder: encoder]
> > + encoder: encoder.
> > + self returns ifFalse:
> > + [encoder genReturnTopToCaller.
> > + pc := encoder pc].
> > + stack position: position!
> >
> > Item was added:
> > + ----- Method: BlockNode>>emitCodeForEvaluatedEffect:encoder: (in
> category 'code generation') -----
> > + emitCodeForEvaluatedEffect: stack encoder: encoder
> > + | position |
> > + position := stack position.
> > + self returns
> > + ifTrue:
> > + [self emitCodeForEvaluatedValue: stack encoder: encoder.
> > + stack pop: 1]
> > + ifFalse:
> > + [self emitCodeExceptLast: stack encoder: encoder.
> > + statements last emitCodeForEffect: stack encoder: encoder].
> > + self assert: stack position = position!
> >
> > Item was added:
> > + ----- Method: BlockNode>>emitCodeForEvaluatedFullClosureValue:encoder:
> (in category 'code generation') -----
> > + emitCodeForEvaluatedFullClosureValue: stack encoder: encoder
> > + | position |
> > + position := stack position.
> > + self emitCodeExceptLast: stack encoder: encoder.
> > + (statements last == NodeNil
> > + and: [self returns not])
> > + ifTrue:
> > + [stack push: 1.
> > + encoder genReturnNilToCaller.
> > + pc := encoder pc]
> > + ifFalse:
> > + [statements last emitCodeForBlockValue: stack encoder:
> encoder.
> > + self returns ifFalse:
> > + [encoder genReturnTopToCaller.
> > + pc := encoder pc]].
> > + self assert: stack position - 1 = position!
> >
> > Item was added:
> > + ----- Method: BlockNode>>emitCodeForEvaluatedValue:encoder: (in
> category 'code generation') -----
> > + emitCodeForEvaluatedValue: stack encoder: encoder
> > + | position |
> > + position := stack position.
> > + self emitCodeExceptLast: stack encoder: encoder.
> > + statements last emitCodeForBlockValue: stack encoder: encoder.
> > + self assert: stack position - 1 = position!
> >
> > Item was added:
> > + ----- Method: BlockNode>>emitCodeForFullBlockValue:encoder: (in
> category 'code generation') -----
> > + emitCodeForFullBlockValue: stack encoder: encoder
> > + copiedValues do:
> > + [:copiedValue| copiedValue emitCodeForValue: stack encoder:
> encoder].
> > + closureCreationNode pc: encoder nextPC.
> > + encoder
> > + genPushFullClosure: closureCreationNode index
> > + numCopied: copiedValues size.
> > + stack
> > + pop: copiedValues size;
> > + push: 1!
> >
> > Item was added:
> > + ----- Method: BlockNode>>emitCodeForValue:encoder: (in category 'code
> generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + encoder supportsFullBlocks ifTrue:
> > + [^self emitCodeForFullBlockValue: stack encoder: encoder].
> > + copiedValues do:
> > + [:copiedValue| copiedValue emitCodeForValue: stack encoder:
> encoder].
> > + closureCreationNode pc: encoder nextPC.
> > + encoder
> > + genPushClosureCopyNumCopiedValues: copiedValues size
> > + numArgs: arguments size
> > + jumpSize: size.
> > + stack
> > + pop: copiedValues size;
> > + push: 1.
> > + "Emit the body of the block"
> > + self emitCodeForEvaluatedClosureValue: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: BlockNode>>ensureClosureCreationNode: (in category
> 'accessing') -----
> > + ensureClosureCreationNode: encoder
> > + closureCreationNode ifNil:
> > + [closureCreationNode := LiteralNode new
> > + key: #closureCreationNode
> > + code: (encoder supportsFullBlocks
> ifTrue: [LdLitType negated])].
> > + ^closureCreationNode!
> >
> > Item was added:
> > + ----- Method: BlockNode>>ensureNotQuick: (in category 'converting')
> -----
> > + ensureNotQuick: encoder
> > + "If the receiver is quick (can be generated as a Quick method,
> ^self,^inst var or ^ special constant)
> > + make it not so. This is used to create break-pointable versions
> of quick methods. Answer if the
> > + receiver was quick."
> > + self isQuick ifFalse:
> > + [^false].
> > + "Making statements size > 1 is sufficient to cause isQuick to
> answer false (see BlockNode>>isQuick).
> > + N.B. This is a no-op since statements generate via
> emitCodeForEffect: and VariableNodes have no effect."
> > + statements addFirst: (encoder encodeVariable: 'self').
> > + ^true!
> >
> > Item was added:
> > + ----- Method: BlockNode>>firstArgument (in category 'accessing') -----
> > + firstArgument
> > + ^ arguments first!
> >
> > Item was added:
> > + ----- Method:
> BlockNode>>ifHasRemoteTempNodeEnsureInitializationStatementExists: (in
> category 'closure analysis') -----
> > + ifHasRemoteTempNodeEnsureInitializationStatementExists: rootNode
> > + "If a remoteTempNode has been added ensure a statement exists to
> initialize it."
> > + remoteTempNode ~~ nil ifTrue:
> > + [(statements notEmpty
> > + and: [statements first isAssignmentNode
> > + and: [statements first variable isTemp
> > + and: [statements first variable isIndirectTempVector]]])
> > + ifTrue: "If this is a decompiled tree, or if a temporary
> has been added later in
> > + the analysis then there already is a temp vector
> initialization node."
> > + [(statements first variable ~~ remoteTempNode) ifTrue:
> > + [statements first variable become: remoteTempNode].
> > + statements first value numElements: remoteTempNode
> remoteTemps size]
> > + ifFalse:
> > + [statements addFirst: (remoteTempNode nodeToInitialize:
> rootNode encoder)]].!
> >
> > Item was added:
> > + ----- Method: BlockNode>>isBlockNode (in category 'testing') -----
> > + isBlockNode
> > + ^true!
> >
> > Item was added:
> > + ----- Method: BlockNode>>isComplex (in category 'testing') -----
> > + isComplex
> > +
> > + ^statements size > 1 or: [statements size = 1 and: [statements
> first isComplex]]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>isJust: (in category 'testing') -----
> > + isJust: node
> > +
> > + returns ifTrue: [^false].
> > + ^statements size = 1 and: [statements first == node]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>isJustCaseError (in category 'testing') -----
> > + isJustCaseError
> > +
> > + ^ statements size = 1 and:
> > + [statements first
> > + isMessage: #caseError
> > + receiver: [:r | r==NodeSelf]
> > + arguments: nil]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>isQuick (in category 'testing') -----
> > + isQuick
> > + ^ statements size = 1
> > + and: [statements first isVariableReference
> > + or: [statements first isSpecialConstant]]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>localsNodes (in category 'accessing') -----
> > + localsNodes
> > + "Answer the correctly ordered sequence of local nodes (arguments
> and temporaries) in the receiver."
> > + ^arguments asArray, copiedValues, temporaries!
> >
> > Item was added:
> > + ----- Method: BlockNode>>makeTemporariesRemovable (in category
> 'closure analysis') -----
> > + makeTemporariesRemovable
> > + "Utilities for when we want to remove some temporaries."
> > +
> > + temporaries isArray ifTrue:
> > + [temporaries := temporaries asOrderedCollection].!
> >
> > Item was added:
> > + ----- Method: BlockNode>>nArgsSlot (in category 'accessing') -----
> > + nArgsSlot
> > + "Private for the Encoder to use in bindArg"
> > + ^nArgsNode!
> >
> > Item was added:
> > + ----- Method: BlockNode>>nArgsSlot: (in category 'accessing') -----
> > + nArgsSlot: anInteger
> > + "Private for the Encoder to use in bindArg"
> > + nArgsNode := anInteger!
> >
> > Item was added:
> > + ----- Method: BlockNode>>nilReadBeforeWrittenTemps (in category
> 'closure analysis') -----
> > + nilReadBeforeWrittenTemps
> > + | visitor readBeforeWritten |
> > + temporaries isEmpty ifTrue:
> > + [^self].
> > + self accept: (visitor :=
> OptimizedBlockLocalTempReadBeforeWrittenVisitor new).
> > + readBeforeWritten := visitor readBeforeWritten.
> > + temporaries reverseDo:
> > + [:temp|
> > + ((readBeforeWritten includes: temp)
> > + and: [temp isRemote not]) ifTrue:
> > + [statements addFirst: (AssignmentNode new variable: temp
> value: NodeNil)]]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>noteOptimizedIn: (in category 'closure
> analysis') -----
> > + noteOptimizedIn: anOptimizedMessageNode
> > + optimized := true.
> > + optimizedMessageNode := anOptimizedMessageNode!
> >
> > Item was added:
> > + ----- Method: BlockNode>>noteSourceRangeStart:end:encoder: (in
> category 'initialize-release') -----
> > + noteSourceRangeStart: start end: end encoder: encoder
> > + "Note two source ranges for this node. One is for the debugger
> > + and is of the last expression, the result of the block. One is for
> > + source analysis and is for the entire block."
> > + encoder
> > + noteSourceRange: (start to: end)
> > + forNode: (self ensureClosureCreationNode: encoder).
> > + startOfLastStatement
> > + ifNil:
> > + [encoder
> > + noteSourceRange: (start to: end)
> > + forNode: self]
> > + ifNotNil:
> > + [encoder
> > + noteSourceRange: (startOfLastStatement to: end - 1)
> > + forNode: self]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>numberOfArguments (in category 'accessing')
> -----
> > + numberOfArguments
> > +
> > + ^arguments size!
> >
> > Item was added:
> > + ----- Method: BlockNode>>optimized (in category 'accessing') -----
> > + optimized
> > + ^optimized!
> >
> > Item was added:
> > + ----- Method: BlockNode>>optimizedBlockHoistTempsInto: (in category
> 'closure analysis') -----
> > + optimizedBlockHoistTempsInto: scopeBlock "<BlockNode>"
> > + "This is a No-op for all nodes except non-optimized BlockNodes."
> > + "Let's assume the special > 0 guard in
> MessageNode>>analyseTempsWithin:forValue:encoder: is correct.
> > + Then we can simply hoist our temps up."
> > + self assert: (arguments isNil or: [arguments size <= 1]).
> > + (arguments notNil and: [arguments notEmpty]) ifTrue:
> > + [scopeBlock addHoistedTemps: arguments.
> > + arguments := #()].
> > + temporaries notEmpty ifTrue:
> > + [scopeBlock addHoistedTemps: temporaries.
> > + temporaries := #()]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>postNumberingProcessTempsWithin:rootNode: (in
> category 'closure analysis') -----
> > + postNumberingProcessTempsWithin: scopeBlock "<BlockNode>" rootNode:
> rootNode "<MethodNode>"
> > + "A temp can be local (and copied) if it is not written to after it
> is captured.
> > + A temp cannot be local if it is written to remotely.
> > + Need to enumerate a copy of the temporaries because any temps
> becoming remote
> > + will be removed from temporaries in analyseClosure: (and a single
> remote temp node
> > + will get added)"
> > + temporaries copy do:
> > + [:each|
> > + each isIndirectTempVector ifFalse:
> > + [each analyseClosure: rootNode]].
> > +
> > + "If this is an optimized node we need to hoist temporaries up into
> the relevant block scope."
> > + optimized ifTrue:
> > + [self optimizedBlockHoistTempsInto: scopeBlock].
> > +
> > + "Now we may have added a remoteTempNode. So we need a statement to
> initialize it."
> > + self ifHasRemoteTempNodeEnsureInitializationStatementExists:
> rootNode.
> > +
> > + "Now add all arguments and locals to the pool so that copiedValues
> can be computed during sizing."
> > + rootNode
> > + addLocalsToPool: arguments;
> > + addLocalsToPool: temporaries!
> >
> > Item was added:
> > + ----- Method: BlockNode>>printArgumentsOn:indent: (in category
> 'printing') -----
> > + printArgumentsOn: aStream indent: level
> > + arguments size = 0 ifTrue: [^ self].
> > + arguments do:
> > + [:arg | aStream nextPut: $:; nextPutAll: arg key; space].
> > + aStream nextPut: $|; space.
> > + "If >0 args and >1 statement, put all statements on separate lines"
> > + statements size > 1 ifTrue:
> > + [aStream crtab: level]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>printOn:indent: (in category 'printing') -----
> > + printOn: aStream indent: level
> > +
> > + "statements size <= 1 ifFalse: [aStream crtab: level]."
> > + aStream nextPut: $[.
> > + self printArgumentsOn: aStream indent: level.
> > + (self printTemporaries: temporaries on: aStream doPrior: []) ifTrue:
> > + ["If >0 temps and >1 statement, put all statements on separate
> lines"
> > + statements size > 1
> > + ifTrue: [aStream crtab: level]
> > + ifFalse: [aStream space]].
> > + self printStatementsOn: aStream indent: level.
> > + aStream nextPut: $]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>printStatementsOn:indent: (in category
> 'printing') -----
> > + printStatementsOn: aStream indent: levelOrZero
> > + | len shown thisStatement level |
> > + level := 1 max: levelOrZero.
> > + comment ifNotNil:
> > + [self printCommentOn: aStream indent: level.
> > + aStream crtab: level].
> > + len := shown := statements size.
> > + (levelOrZero = 0 "top level" and: [statements last isReturnSelf])
> > + ifTrue: [shown := 1 max: shown - 1]
> > + ifFalse: ["should a trailing nil be printed or not? Not if it
> is an implicit result, not if the last statement answers nil."
> > + ((arguments size > 0 and: [len = 0])
> > + or: [(statements at: len) == NodeNil
> > + and: [len = 1
> > + or: [len > 1
> > + and: [(statements at: len - 1) isMessageNode
> > + and: [(statements at: len - 1) isNilIf
> > + or: [(statements at: len - 1)
> isOptimizedWhileLoop]]]]]])
> > + ifTrue: [shown := shown - 1]].
> > + 1 to: shown do:
> > + [:i |
> > + thisStatement := statements at: i.
> > + thisStatement printOn: aStream indent: level.
> > + i < shown ifTrue: [aStream nextPut: $.; crtab: level].
> > + (thisStatement comment ~~ nil and: [thisStatement comment size
> > 0])
> > + ifTrue:
> > + [i = shown ifTrue: [aStream crtab: level].
> > + thisStatement printCommentOn: aStream indent: level.
> > + i < shown ifTrue: [aStream crtab: level]]]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>printTemporaries:on:doPrior: (in category
> 'printing') -----
> > + printTemporaries: tempSequence on: aStream doPrior: aBlock
> > + "Print any in-scope temporaries. If there are any evaluate aBlock
> > + prior to printing. Answer whether any temporaries were printed."
> > + | tempStream seen |
> > + tempSequence ifNil:
> > + [^false].
> > + tempStream := (String new: 16) writeStream.
> > + "This is for the decompiler which canmot work out which optimized
> block a particular temp is
> > + local to and hence may produce diplicates as in
> > + expr ifTrue: [| aTemp | ...] ifFalse: [| aTemp | ...]"
> > + seen := Set new.
> > + tempSequence do:
> > + [:tempNode |
> > + tempNode isIndirectTempVector
> > + ifTrue:
> > + [tempNode remoteTemps do:
> > + [:tempVariableNode|
> > + (tempVariableNode scope >= 0
> > + and: [
> > + "This is for the deocmpiler which may create a
> block arg when converting
> > + a ifTrue:ifFalse: into a ifNil:ifNotNil: but
> won't remove it from temporaries"
> > + tempVariableNode isBlockArg not
> > + and: [(seen includes: tempNode key) not]]) ifTrue:
> > + [tempStream space; nextPutAll: (seen add:
> tempVariableNode key)]]]
> > + ifFalse:
> > + [(tempNode scope >= -1
> > + and: ["This is for the decompiler which may create a
> block arg when converting
> > + a while into a to:do: but won't remove it from
> temporaries"
> > + tempNode isBlockArg not
> > + and: [(seen includes: tempNode key) not]]) ifTrue:
> > + [tempStream space; nextPutAll: (seen add: tempNode
> key)]]].
> > + tempStream position = 0 ifTrue:
> > + [^false].
> > + aBlock value.
> > + aStream nextPut: $|; nextPutAll: tempStream contents; space;
> nextPut: $|.
> > + ^true!
> >
> > Item was added:
> > + ----- Method: BlockNode>>printWithClosureAnalysisArgumentsOn:indent:
> (in category 'printing') -----
> > + printWithClosureAnalysisArgumentsOn: aStream indent: level
> > + arguments size = 0 ifTrue: [^self].
> > + arguments do:
> > + [:tempNode |
> > + aStream space; nextPut: $:.
> > + tempNode printDefinitionForClosureAnalysisOn: aStream].
> > + aStream nextPut: $|; space.
> > + "If >0 args and >1 statement, put all statements on separate lines"
> > + statements size > 1 ifTrue:
> > + [aStream crtab: level]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level
> > + aStream nextPut: $[.
> > + blockExtent ifNotNil: [aStream print: blockExtent].
> > + self printWithClosureAnalysisArgumentsOn: aStream indent: level.
> > + self printWithClosureAnalysisTemporariesOn: aStream indent: level.
> > + self printWithClosureAnalysisStatementsOn: aStream indent: level.
> > + aStream nextPut: $]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>printWithClosureAnalysisStatementsOn:indent:
> (in category 'printing') -----
> > + printWithClosureAnalysisStatementsOn: aStream indent: levelOrZero
> > + | len shown thisStatement level |
> > + level := 1 max: levelOrZero.
> > + comment == nil
> > + ifFalse:
> > + [self printCommentOn: aStream indent: level.
> > + aStream crtab: level].
> > + len := shown := statements size.
> > + (levelOrZero = 0 "top level" and: [statements last isReturnSelf])
> > + ifTrue: [shown := 1 max: shown - 1]
> > + ifFalse: [(len = 1 and: [((statements at: 1) == NodeNil) &
> (arguments size = 0)])
> > + ifTrue: [shown := shown - 1]].
> > + 1 to: shown do:
> > + [:i |
> > + thisStatement := statements at: i.
> > + thisStatement printWithClosureAnalysisOn: aStream indent: level.
> > + i < shown ifTrue: [aStream nextPut: $.; crtab: level].
> > + (thisStatement comment ~~ nil and: [thisStatement comment size
> > 0])
> > + ifTrue:
> > + [i = shown ifTrue: [aStream crtab: level].
> > + thisStatement printCommentOn: aStream indent: level.
> > + i < shown ifTrue: [aStream crtab: level]]]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>printWithClosureAnalysisTemporariesOn:indent:
> (in category 'printing') -----
> > + printWithClosureAnalysisTemporariesOn: aStream indent: level
> > +
> > + (temporaries == nil or: [temporaries size = 0]) ifFalse:
> > + [aStream nextPut: $|.
> > + temporaries do:
> > + [:tempNode |
> > + aStream space.
> > + tempNode printDefinitionForClosureAnalysisOn: aStream].
> > + aStream nextPutAll: ' | '.
> > + "If >0 args and >1 statement, put all statements on separate
> lines"
> > + statements size > 1 ifTrue: [aStream crtab: level]]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>reindexingLocalsDo:encoder: (in category
> 'closure analysis') -----
> > + reindexingLocalsDo: aBlock encoder: encoderOrNil
> > + "Evaluate aBlock wih arguments, temporaries and copiedValues
> reindexed for
> > + their positions within the receiver's block, restoring the correct
> indices afterwards.
> > + If encoder is not nil remember the temps for this block's extent."
> > + | tempIndices result tempsToReindex |
> > + self assert: copiedValues notNil.
> > + tempsToReindex := arguments asArray, copiedValues, temporaries.
> > + tempIndices := tempsToReindex collect: [:temp| temp index].
> > + tempsToReindex withIndexDo:
> > + [:temp :newIndex| temp index: newIndex - 1. self assert: temp
> index + 1 = newIndex].
> > + encoderOrNil ifNotNil:
> > + [encoderOrNil noteBlockExtent: blockExtent hasLocals:
> tempsToReindex].
> > + result := aBlock ensure:
> > + ["Horribly pragmatic hack. The copiedValues will have
> completely
> > + unrelated indices within the closure method and
> sub-method.
> > + Avoiding the effort of rebinding temps in the inner
> scope simply
> > + update the indices to their correct ones during the
> generation of
> > + the closure method and restore the indices immedately
> there-after."
> > + tempsToReindex with: tempIndices do:
> > + [:temp :oldIndex| temp index: oldIndex. self
> assert: temp index = oldIndex]].
> > + ^result!
> >
> > Item was added:
> > + ----- Method: BlockNode>>remoteTempNodeName (in category 'closure
> analysis') -----
> > + remoteTempNodeName
> > + "Answer a useful name for a RemoteTempVectorNode in the receiver."
> > + | prefix scope extent |
> > + prefix := actualScopeIfOptimized ifNil: ['<'] ifNotNil: [ '<...'].
> > + scope := self.
> > + [extent := scope blockExtent.
> > + extent == nil
> > + and: [scope actualScope ~~ scope]] whileTrue:
> > + [scope := scope actualScope].
> > + ^extent
> > + ifNil: [prefix, '?-?>']
> > + ifNotNil:
> > + [prefix, extent first printString, '-',
> > + (extent last isZero
> > + ifTrue: ['?']
> > + ifFalse: [extent last printString]), '>']!
> >
> > Item was added:
> > + ----- Method: BlockNode>>removeTempNode:ifAbsent: (in category
> 'closure analysis') -----
> > + removeTempNode: aTempVariableNode ifAbsent: aBlock
> > + "Utilities for when we want to remove some temporaries."
> > +
> > + self makeTemporariesRemovable.
> > + ^temporaries remove: aTempVariableNode ifAbsent: aBlock
> > + !
> >
> > Item was added:
> > + ----- Method: BlockNode>>returnLast (in category 'accessing') -----
> > + returnLast
> > +
> > + self returns
> > + ifFalse:
> > + [returns := true.
> > + statements at: statements size put: statements last
> asReturnNode]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>returnNilIfNoOther (in category 'accessing')
> -----
> > + returnNilIfNoOther
> > +
> > + self returns
> > + ifFalse:
> > + [statements last == NodeNil ifFalse: [statements add:
> NodeNil].
> > + self returnLast]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>returnSelfIfNoOther: (in category
> 'accessing') -----
> > + returnSelfIfNoOther: encoder
> > +
> > + self returns ifTrue:[^self].
> > + statements last == NodeSelf ifFalse: [
> > + statements := statements copyWith: (encoder encodeVariable:
> 'self').
> > + ].
> > + self returnLast.
> > + !
> >
> > Item was added:
> > + ----- Method: BlockNode>>returns (in category 'testing') -----
> > + returns
> > +
> > + ^returns or: [statements last isReturningIf]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>sizeCodeExceptLast: (in category 'code
> generation') -----
> > + sizeCodeExceptLast: encoder
> > + | codeSize |
> > + codeSize := 0.
> > + 1 to: statements size - 1 do:
> > + [:i | | statement |
> > + statement := statements at: i.
> > + codeSize := codeSize + (statement sizeCodeForEffect: encoder)].
> > + ^codeSize!
> >
> > Item was added:
> > + ----- Method: BlockNode>>sizeCodeForEvaluatedClosureValue: (in
> category 'code generation') -----
> > + sizeCodeForEvaluatedClosureValue: encoder
> > + "The closure value primitives push the arguments and the copied
> values.
> > + The compiler guarantees that any copied values come before all
> local temps.
> > + So on closure activation we only need to push nils for the
> remaining temporaries."
> > + ^(encoder sizePushNClosureTemps: temporaries size)
> > + + (self
> > + reindexingLocalsDo: [self sizeCodeForEvaluatedValue: encoder]
> > + encoder: nil "don't store temps yet")
> > + + (self returns ifTrue: [0] ifFalse: [encoder
> sizeReturnTopToCaller])!
> >
> > Item was added:
> > + ----- Method: BlockNode>>sizeCodeForEvaluatedEffect: (in category
> 'code generation') -----
> > + sizeCodeForEvaluatedEffect: encoder
> > +
> > + ^self returns
> > + ifTrue: [self sizeCodeForEvaluatedValue: encoder]
> > + ifFalse: [(self sizeCodeExceptLast: encoder)
> > + + (statements last sizeCodeForEffect: encoder)]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>sizeCodeForEvaluatedFullClosureValue: (in
> category 'code generation') -----
> > + sizeCodeForEvaluatedFullClosureValue: encoder
> > + "The closure value primitives push the arguments and the copied
> values.
> > + The compiler guarantees that any copied values come before all
> local temps.
> > + So on full closure activation we need do nothing."
> > + (statements last == NodeNil
> > + and: [self returns not]) ifTrue:
> > + [^(self sizeCodeExceptLast: encoder)
> > + + encoder sizeReturnNilToCaller].
> > + ^(self sizeCodeForEvaluatedValue: encoder)
> > + + (self returns ifTrue: [0] ifFalse: [encoder
> sizeReturnTopToCaller])!
> >
> > Item was added:
> > + ----- Method: BlockNode>>sizeCodeForEvaluatedValue: (in category 'code
> generation') -----
> > + sizeCodeForEvaluatedValue: encoder
> > +
> > + ^(self sizeCodeExceptLast: encoder)
> > + + (statements last sizeCodeForBlockValue: encoder)!
> >
> > Item was added:
> > + ----- Method: BlockNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + "Compute the size for the creation of the block and its code."
> > + copiedValues := self computeCopiedValues: encoder rootNode.
> > + self ensureClosureCreationNode: encoder.
> > + encoder supportsFullBlocks ifTrue:
> > + [^(copiedValues inject: 0 into: [:sum :node| sum + (node
> sizeCodeForValue: encoder)])
> > + + (encoder
> > + sizePushFullClosure:
> > + (closureCreationNode
> > + key: (self createBlockLiteral: encoder);
> > + reserve: encoder;
> > + index)
> > + numCopied: copiedValues size)].
> > + "Remember size of body for emit time so we know the size of the
> jump around it."
> > + size := self sizeCodeForEvaluatedClosureValue: encoder.
> > + ^(copiedValues inject: 0 into: [:sum :node| sum + (node
> sizeCodeForValue: encoder)])
> > + + (encoder sizePushClosureCopyNumCopiedValues: copiedValues size
> numArgs: arguments size jumpSize: size)
> > + + size!
> >
> > Item was added:
> > + ----- Method: BlockNode>>startOfLastStatement (in category
> 'accessing') -----
> > + startOfLastStatement
> > + ^startOfLastStatement!
> >
> > Item was added:
> > + ----- Method: BlockNode>>startOfLastStatement: (in category
> 'accessing') -----
> > + startOfLastStatement: anInteger
> > + "Note the source index of the start of the last full statement. The
> > + last full statement is the value answered by a block and hence the
> > + expression the debugger should display as the value of the block."
> > + startOfLastStatement := anInteger!
> >
> > Item was added:
> > + ----- Method: BlockNode>>statements (in category 'accessing') -----
> > + statements
> > + ^statements!
> >
> > Item was added:
> > + ----- Method: BlockNode>>statements: (in category 'accessing') -----
> > + statements: val
> > + statements := val!
> >
> > Item was added:
> > + ----- Method: BlockNode>>statements:returns: (in category
> 'initialize-release') -----
> > + statements: statementsCollection returns: returnBool
> > + "Decompile."
> > +
> > + | returnLast |
> > + returnLast := returnBool.
> > + returns := false.
> > + statements :=
> > + (statementsCollection size > 1
> > + and: [(statementsCollection at: statementsCollection size -
> 1)
> > + isReturningIf])
> > + ifTrue:
> > + [returnLast := false.
> > + statementsCollection allButLast]
> > + ifFalse: [statementsCollection size = 0
> > + ifTrue: [Array with: NodeNil]
> > + ifFalse: [statementsCollection]].
> > + arguments := #().
> > + temporaries := #().
> > + optimized := false.
> > + returnLast ifTrue: [self returnLast]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>temporaries (in category 'accessing') -----
> > + temporaries
> > + ^temporaries ifNil: [#()]!
> >
> > Item was added:
> > + ----- Method: BlockNode>>temporaries: (in category 'accessing') -----
> > + temporaries: aCollection
> > + temporaries := aCollection!
> >
> > Item was added:
> > + ----- Method: BlockNode>>tempsMark (in category 'accessing') -----
> > + tempsMark
> > + ^tempsMark!
> >
> > Item was added:
> > + ----- Method: BlockNode>>tempsMark: (in category 'accessing') -----
> > + tempsMark: anInteger
> > + tempsMark := anInteger!
> >
> > 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:
> > + ParseNode subclass: #BraceNode
> > + instanceVariableNames: 'elements sourceLocations emitNode'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !BraceNode commentStamp: '<historical>' prior: 0!
> > + Used for compiling and decompiling brace constructs.
> > +
> > + These now compile into either a fast short form for 4 elements or less:
> > + Array braceWith: a with: b ...
> > + or a long form of indefinfite length:
> > + (Array braceStream: N) nextPut: a; nextPut: b; ...; braceArray.
> > +
> > + The erstwhile brace assignment form is no longer supported.!
> >
> > Item was added:
> > + ----- Method: BraceNode class>>example (in category 'examples') -----
> > + example
> > + "Test the {a. b. c} syntax."
> > +
> > + | x |
> > + x := {1. {2. 3}. 4}.
> > + ^ {x first. x second first. x second last. x last. 5} as: Set
> > +
> > + "BraceNode example Set (0 1 2 3 4 5 )"
> > + !
> >
> > Item was added:
> > + ----- Method: BraceNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitBraceNode: self!
> >
> > Item was added:
> > + ----- Method: BraceNode>>analyseTempsWithin:rootNode:assignmentPools:
> (in category 'closure analysis') -----
> > + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode
> "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + elements do:
> > + [:node|
> > + node analyseTempsWithin: scopeBlock rootNode: rootNode
> assignmentPools: assignmentPools]!
> >
> > Item was added:
> > + ----- Method: BraceNode>>blockAssociationCheck: (in category
> 'testing') -----
> > + blockAssociationCheck: encoder
> > + "If all elements are MessageNodes of the form [block]->[block], and
> there is at
> > + least one element, answer true.
> > + Otherwise, notify encoder of an error."
> > +
> > + elements size = 0
> > + ifTrue: [^encoder notify: 'At least one case required'].
> > + elements with: sourceLocations do:
> > + [:x :loc |
> > + (x isMessage: #->
> > + receiver:
> > + [:rcvr |
> > + rcvr isBlockNode and: [rcvr numberOfArguments = 0]]
> > + arguments:
> > + [:arg |
> > + arg isBlockNode and: [arg numberOfArguments = 0]])
> > + ifFalse:
> > + [^encoder notify: 'Association between 0-argument
> blocks required' at: loc]].
> > + ^true!
> >
> > Item was added:
> > + ----- Method: BraceNode>>casesForwardDo: (in category 'enumerating')
> -----
> > + casesForwardDo: aBlock
> > + "For each case in forward order, evaluate aBlock with three
> arguments:
> > + the key block, the value block, and whether it is the last case."
> > +
> > + | numCases case |
> > + 1 to: (numCases := elements size) do:
> > + [:i |
> > + case := elements at: i.
> > + aBlock value: case receiver value: case arguments first value:
> i=numCases]!
> >
> > Item was added:
> > + ----- Method: BraceNode>>casesReverseDo: (in category 'enumerating')
> -----
> > + casesReverseDo: aBlock
> > + "For each case in reverse order, evaluate aBlock with three
> arguments:
> > + the key block, the value block, and whether it is the last case."
> > +
> > + | numCases case |
> > + (numCases := elements size) to: 1 by: -1 do:
> > + [:i |
> > + case := elements at: i.
> > + aBlock value: case receiver value: case arguments first value:
> i=numCases]!
> >
> > Item was added:
> > + ----- Method: BraceNode>>deoptimize (in category 'closure analysis')
> -----
> > + deoptimize
> > + "Deoptimize the blocks in a caseOf:[otherwise:] that is being used
> in a cascade."
> > + elements do:
> > + [:aMessage|
> > + self assert: aMessage selector key == #->.
> > + aMessage receiver deoptimize.
> > + aMessage arguments first deoptimize]!
> >
> > Item was added:
> > + ----- Method: BraceNode>>elements (in category 'code generation') -----
> > + elements
> > + ^elements!
> >
> > Item was added:
> > + ----- Method: BraceNode>>elements: (in category 'initialize-release')
> -----
> > + elements: collection
> > + "Decompile."
> > +
> > + elements := collection!
> >
> > Item was added:
> > + ----- Method: BraceNode>>elements:sourceLocations: (in category
> 'initialize-release') -----
> > + elements: collection sourceLocations: locations
> > + "Compile."
> > +
> > + elements := collection.
> > + sourceLocations := locations!
> >
> > Item was added:
> > + ----- Method: BraceNode>>emitCodeForValue:encoder: (in category 'code
> generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + "Hack; when sizing we have no way of knowing how much stack space
> is available."
> > + elements size <= self maxElementsForConsArray ifTrue:
> > + [elements do: [:node| node emitCodeForValue: stack encoder:
> encoder].
> > + encoder genPushConsArray: elements size.
> > + stack
> > + pop: elements size;
> > + push: 1.
> > + ^self].
> > + ^emitNode emitCodeForValue: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: BraceNode>>isBraceNode (in category 'testing') -----
> > + isBraceNode
> > + ^true!
> >
> > Item was added:
> > + ----- Method: BraceNode>>matchBraceStreamReceiver:messages: (in
> category 'initialize-release') -----
> > + matchBraceStreamReceiver: receiver messages: messages
> > +
> > + ((receiver isMessage: #braceStream: receiver: nil arguments: [:arg
> | arg isConstantNumber])
> > + and: [messages last isMessage: #braceArray receiver: nil
> arguments: nil])
> > + ifFalse: [^ nil "no match"].
> > +
> > + "Appears to be a long form brace construct"
> > + self elements: (messages allButLast collect:
> > + [:msg | (msg isMessage: #nextPut: receiver: nil arguments: nil)
> > + ifFalse: [^ nil "not a brace element"].
> > + msg arguments first])!
> >
> > Item was added:
> > + ----- Method: BraceNode>>maxElementsForConsArray (in category 'code
> generation') -----
> > + maxElementsForConsArray
> > + "Hack; we have no way of knowing how much stack space is available
> during sizing"
> > + ^8!
> >
> > Item was added:
> > + ----- Method: BraceNode>>numElements (in category 'testing') -----
> > + numElements
> > +
> > + ^ elements size!
> >
> > Item was added:
> > + ----- Method: BraceNode>>printOn:indent: (in category 'printing') -----
> > + printOn: aStream indent: level
> > +
> > + aStream nextPut: ${.
> > + 1 to: elements size do:
> > + [:i | (elements at: i) printOn: aStream indent: level.
> > + i < elements size ifTrue: [aStream nextPutAll: '. ']].
> > + aStream nextPut: $}!
> >
> > Item was added:
> > + ----- Method: BraceNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level
> > +
> > + aStream nextPut: ${.
> > + 1 to: elements size do:
> > + [:i | (elements at: i) printWithClosureAnalysisOn: aStream
> indent: level.
> > + i < elements size ifTrue: [aStream nextPutAll: '. ']].
> > + aStream nextPut: $}!
> >
> > Item was added:
> > + ----- Method: BraceNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > +
> > + "Hack; we have no way of knowing how much stack space is available."
> > + elements size <= self maxElementsForConsArray ifTrue:
> > + [^(elements inject: 0 into: [:sum :node| sum + (node
> sizeCodeForValue: encoder)])
> > + + (encoder sizePushConsArray: elements size)].
> > + "Long form: (Array braceStream: N) nextPut: a; nextPut: b; ...;
> braceArray"
> > + emitNode := CascadeNode new
> > + receiver: (MessageNode new
> > + receiver: (encoder encodeVariable:
> #Array)
> > + selector: #braceStream:
> > + arguments: {encoder encodeLiteral:
> elements size}
> > + precedence: 3 from: encoder)
> > + messages: ((elements collect: [:elt |
> > + MessageNode new
> > + receiver: nil
> > + selector: #nextPut:
> > + arguments: {elt}
> > + precedence: 3
> > + from: encoder])
> > + copyWith: (MessageNode new
> > + receiver: nil
> > + selector: #braceArray
> > + arguments: #()
> > + precedence: 1
> > + from: encoder)).
> > + ^emitNode sizeCodeForValue: encoder!
> >
> > Item was added:
> > + Encoder subclass: #BytecodeEncoder
> > + instanceVariableNames: 'stream position rootNode
> blockExtentsToLocals blockMethod'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> > +
> > + !BytecodeEncoder commentStamp: 'eem 1/10/2018 17:28' prior: 0!
> > + I am an abstract superclass for different bytecode set encoders.
> Subclasses inherit the literal management of Encoder and encapsulate the
> mapping of opcodes to specific bytecodes.
> > +
> > + Instance Variables
> > + blockExtentsToLocals: <Dictionary from: Interval to: (Array of:
> String)>
> > + blockMethod: <CompiledBlock>
> > + position: <Integer>
> > + rootNode: <MethodNode>
> > + stream: <WriteStream | BytecodeEncoder>
> > +
> > + blockExtentsToLocals
> > + - is a map from block extent to the sequence of temps defined in
> the block with that extent
> > +
> > + blockMethod
> > + - the compiled block being generated in
> generateBlockMethodOfClass:trailer:from:
> > +
> > + position
> > + - used to size bytecodes by having the receiver masquerade as a
> stream during sizeOpcodeSelector:withArguments:
> > +
> > + rootNode
> > + - the MethodNode for the method being generated
> > +
> > + stream
> > + - during bytecode sizing this is the receiver. During bytecode
> generation this is the WriteStream on the method!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>bindingReadScanBlockFor:using:
> (in category 'compiled method support') -----
> > + bindingReadScanBlockFor: litVarIndex using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for reads of the value of the binding with zero-relative index
> litVarIndex.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>bindingWriteScanBlockFor:using:
> (in category 'compiled method support') -----
> > + bindingWriteScanBlockFor: litVarIndex using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for writes of the value of the binding with zero-relative index
> litVarIndex.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>blockMethodOrNilFor:in:at: (in
> category 'instruction stream support') -----
> > + blockMethodOrNilFor: anInstructionStream in: method at: pc
> > + "If anInstructionStream is at a block creation bytecode then answer
> the block's
> > + CompiledBlock, otherwise answer nil.
> > + Subclasses override as appropriate."
> > +
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>bytecodeSetName (in category
> 'compiled method support') -----
> > + bytecodeSetName
> > + ^self name copyReplaceAll: 'EncoderFor' with: ''!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>bytecodeSize: (in category
> 'instruction stream support') -----
> > + bytecodeSize: aByte
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>callPrimitiveCode (in category
> 'bytecode decoding') -----
> > + callPrimitiveCode
> > + "Answer the call primitive bytecode, if it exists in the encoder's
> byetcode set, or nil if not."
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>canBeSpecialLiteral: (in category
> 'testing') -----
> > + canBeSpecialLiteral: aLiteral
> > + "This check can be used to prevent unnecessary use of
> #scanBlockOrNilForLiteral:. For performance, this method summarizes
> specializations from all known bytecode encoders. It is not meant to be
> refined per bytecode encoder."
> > +
> > + aLiteral isVariableBinding ifTrue: [^false]. "a common case; don't
> waste time analysing..."
> > +
> > + aLiteral isSymbol ifTrue: [^ Smalltalk specialSelectors
> identityIncludes: aLiteral].
> > + aLiteral isCharacter ifTrue: [^ aLiteral asInteger <= 65535].
> > + aLiteral isInteger ifTrue: [^ aLiteral between: -32768 and: 32767].
> > +
> > + aLiteral == true ifTrue: [^ true].
> > + aLiteral == false ifTrue: [^ true].
> > + aLiteral == nil ifTrue: [^ true].
> > +
> > + ^ false!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>createClosureCode (in category
> 'bytecode decoding') -----
> > + createClosureCode
> > + "Answer the create closure bytecode, if it exists in the encoder's
> bytecode set, or nil if not."
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>createClosureScanBlock (in
> category 'compiled method support') -----
> > + createClosureScanBlock
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for block closure creation bytecodes."
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>extensionsAt:in:into: (in
> category 'instruction stream support') -----
> > + extensionsAt: pc in: aCompiledMethod into: trinaryBlock
> > + "If the bytecode at pc is an extension then evaluate aTrinaryBlock
> > + with the values of extA and extB and number of extension *bytes*.
> > + If the bytecode at pc is not an extension then evaluate with 0, 0,
> 0."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>extensionsFor:in:into: (in
> category 'instruction stream support') -----
> > + extensionsFor: pc in: aCompiledMethod into: trinaryBlock
> > + "If the bytecode at pc is an extension, or if the bytecode at pc is
> preceded by extensions,
> > + then evaluate aTrinaryBlock with the values of extA and extB and
> number of extension *bytes*.
> > + If the bytecode at pc is neither an extension or extended then
> evaluate with 0, 0, 0."
> > +
> > + | prevPC |
> > + "If there is what appears to be an extension bytecode before this
> bytecode
> > + then scan for the previous pc to confirm."
> > + (pc - 2 >= aCompiledMethod initialPC
> > + and: [self isExtension: (aCompiledMethod at: pc - 2)]) ifTrue:
> > + [prevPC := aCompiledMethod pcPreviousTo: pc.
> > + (self nonExtensionPcAt: prevPC in: aCompiledMethod) = pc
> ifTrue:
> > + [^self extensionsAt: prevPC in: aCompiledMethod into:
> trinaryBlock]].
> > + ^self extensionsAt: pc in: aCompiledMethod into: trinaryBlock!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>instVarReadScanBlockFor:using:
> (in category 'compiled method support') -----
> > + instVarReadScanBlockFor: varIndexCode using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for reads of the inst var with zero-relative index varIndexCode.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>instVarWriteScanBlockFor:using:
> (in category 'compiled method support') -----
> > + instVarWriteScanBlockFor: varIndexCode using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for writes of the inst var with zero-relative index varIndexCode.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>interpretJumpIfCondIn: (in
> category 'instruction stream support') -----
> > + interpretJumpIfCondIn: anInstructionStream
> > + "Double-dispatch through the encoder to select the correct
> conditional jump decoder for the instruction set."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>interpretJumpIn: (in category
> 'instruction stream support') -----
> > + interpretJumpIn: anInstructionStream
> > + "Double-dispatch through the encoder to select the correct jump
> decoder for the instruction set."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>interpretNextInstructionFor:in:
> (in category 'instruction stream support') -----
> > + interpretNextInstructionFor: aClient in: anInstructionStream
> > + "Double-dispatch instruction interpretation through the encoder
> > + to select the correct instruction set decoder."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isBlockReturnAt:in: (in category
> 'instruction stream support') -----
> > + isBlockReturnAt: pc in: method
> > + "Answer whether the bytecode at pc is a return from block."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isBranchIfFalseAt:in: (in
> category 'instruction stream support') -----
> > + isBranchIfFalseAt: pc in: method
> > + "Answer whether the bytecode at pc is a conditional
> branch-if-false."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isBranchIfTrueAt:in: (in category
> 'instruction stream support') -----
> > + isBranchIfTrueAt: pc in: method
> > + "Answer whether the bytecode at pc is a conditional branch-if-true."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isExtension: (in category
> 'instruction stream support') -----
> > + isExtension: bytecode
> > + "Answer if the bytecode is an extension bytecode, i.e. one that
> extends
> > + the range of the following bytecode."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isJumpAt:in: (in category
> 'instruction stream support') -----
> > + isJumpAt: pc in: method
> > + "Answer whether the bytecode at pc is an (unconditional) jump."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isJustPopAt:in: (in category
> 'instruction stream support') -----
> > + isJustPopAt: pc in: method
> > + "Answer whether the bytecode at pc is a pop."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isNonSyntheticStoreAt:in:for: (in
> category 'instruction stream support') -----
> > + isNonSyntheticStoreAt: pc in: method for: anInstructionStream
> > + "Answer whether the bytecode at pc is a store or store-pop into an
> explicit variable.
> > + This eliminates stores into indirect temp vectors, which implement
> mutable closed-over
> > + variables in the the closure implementation, and hence stores into
> temp vectors are not real stores."
> > +
> > + ^(self isStoreAt: pc in: method)
> > + and: [(self isSyntheticStoreAt: pc in: method for:
> anInstructionStream) not]!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isRealSendAt:in: (in category
> 'instruction stream support') -----
> > + isRealSendAt: pc in: method
> > + "Answer whether the bytecode at pc is a real message-send, not
> blockCopy:."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isReturnAt:in: (in category
> 'instruction stream support') -----
> > + isReturnAt: pc in: method
> > + "Answer whether the bytecode at pc is a return."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isReturnSelfFromMethodAt:in: (in
> category 'instruction stream support') -----
> > + isReturnSelfFromMethodAt: pc in: method
> > + "Answer whether the bytecode at pc is a return self from method."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isReturnTopFromMethodAt:in: (in
> category 'instruction stream support') -----
> > + isReturnTopFromMethodAt: pc in: method
> > + "Answer whether the bytecode at pc is a return stack top from
> method."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isSendAt:in: (in category
> 'instruction stream support') -----
> > + isSendAt: pc in: method
> > + "Answer whether the bytecode at pc is a message-send."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isStoreAt:in: (in category
> 'instruction stream support') -----
> > + isStoreAt: pc in: method
> > + "Answer whether the bytecode at pc is a store or store-pop."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isStorePopAt:in: (in category
> 'instruction stream support') -----
> > + isStorePopAt: pc in: method
> > + "Answer whether the bytecode at pc is a store-pop."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>isSyntheticStoreAt:in:for: (in
> category 'instruction stream support') -----
> > + isSyntheticStoreAt: pc in: method for: anInstructionStream
> > + "Answer whether the bytecode at pc is a store or store-pop of an
> indirect temp vector,
> > + which implement mutable closed-over variables in the the closure
> implementation.
> > + Stores into temp vectors are not real stores."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>markerOrNilFor: (in category
> 'compiled method support') -----
> > + markerOrNilFor: aMethod
> > + "If aMethod is a marker method, answer the symbol used to mark it.
> Otherwise
> > + answer nil. What is a marker method? It is method with body like
> > + 'self subclassResponsibility' or '^ self
> subclassResponsibility'
> > + used to indicate ('mark') a special property.
> > +
> > + Marker methods compile to two bytecode forms, this:
> > + self
> > + send: <literal 1>
> > + pop
> > + returnSelf
> > + or this:
> > + self
> > + send: <literal 1>
> > + returnTop"
> > + ^self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>method:readsField: (in category
> 'scanning') -----
> > + method: method readsField: varIndex
> > + "Answer if method loads the instance variable indexed by varIndex."
> > + ^self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>method:writesField: (in category
> 'scanning') -----
> > + method: method writesField: varIndex
> > + "Answer if method stores into the instance variable indexed by
> varIndex."
> > + ^self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>nonExtensionBytecodeAt:in: (in
> category 'instruction stream support') -----
> > + nonExtensionBytecodeAt: pc in: method
> > + "Answer the actual bytecode at pc in method, skipping past any
> preceding extensions."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>nonExtensionPcAt:in: (in category
> 'instruction stream support') -----
> > + nonExtensionPcAt: pc in: method
> > + "Answer the pc of the actual bytecode at pc in method, skipping
> past any preceding extensions."
> > + | thePC bytecode |
> > + thePC := pc.
> > + [self isExtension: (bytecode := method at: thePC)] whileTrue:
> > + [thePC := thePC + (self bytecodeSize: bytecode)].
> > + ^thePC!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>pcFollowingBlockAt:in: (in
> category 'bytecode decoding') -----
> > + pcFollowingBlockAt: pc in: method
> > + "Assuming the pc is that of a block creation bytecode, answer the
> pc immediately following the block,
> > + i.e. the next pc after the block creation."
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder
> class>>pcOfBlockCreationBytecodeForBlockStartingAt:in: (in category
> 'bytecode decoding') -----
> > + pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method
> > + "Answer the pc of the push closure bytecode whose block starts at
> startpc in method."
> > + ^self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>pcPreviousTo:in:for: (in category
> 'bytecode decoding') -----
> > + pcPreviousTo: thePC in: method for: anInstructionStreamOrContext
> > + "Answer the pc of the bytecode before the bytecode at thePC.
> > + Unlike CompiledMethod>>pcPreviousTo:, this version answers nil for
> > + the first bytecode of an embedded block, and answers the pc of the
> > + block creation bytecode for a bytecode following an embedded
> block."
> > + | pc nextPc prevPc byte createClosureCode |
> > + thePC > method endPC ifTrue:
> > + [^method endPC].
> > + pc := method initialPC.
> > + "We could save time by scanning from the block creation bytecode of
> an embedded block,
> > + using the following, but it saves less time than it loses in
> additional tests."
> > + "(anInstructionStreamOrContext isContext
> > + and: [anInstructionStreamOrContext isClosureContext
> > + and: [(nextPc := anInstructionStreamOrContext startpc) > pc]])
> ifTrue:
> > + [pc := self pcOfBlockCreationBytecodeForBlockStartingAt: nextPc
> in: method]."
> > + createClosureCode := self createClosureCode.
> > + [pc < thePC] whileTrue:
> > + [byte := method at: (prevPc := pc).
> > + [pc := createClosureCode = byte
> > + ifTrue:
> > + [nextPc := self pcFollowingBlockAt: pc in:
> method.
> > + nextPc = thePC ifTrue: "first bytecode
> following block"
> > + [^prevPc].
> > + nextPc > thePC
> > + ifTrue:
> > + [pc + (self bytecodeSize: byte) = thePC
> ifTrue: "first bytecode of block"
> > + [^nil].
> > + pc + (self bytecodeSize: byte)]
> > + ifFalse: [nextPc]]
> > + ifFalse: [pc + (self bytecodeSize: byte)].
> > + self isExtension: byte] whileTrue:
> > + [byte := method at: pc]].
> > + ^prevPc
> > +
> > + "Here's code to measure the effect of short-cutting scanning for
> blocks by starting at the startpc.
> > + It measures how much time is used to scan for the pcs from the last
> block to the end of all methods containing blocks. Uncomment out the
> short-cut above to compare time with the optimization and time without. I
> see approximately 290ms for all such methods with the optimization and 292
> ms without, so given that this slows down the substantial majority of
> methods without blocks, we KISS."
> > + "| candidates |
> > + candidates := Dictionary new.
> > + self systemNavigation allSelect:
> > + [:m| | ebc |
> > + (m isQuick or: [(ebc := m embeddedBlockClosures) isEmpty]) ifFalse:
> > + [candidates at: m put: { ebc last.
> > + Array streamContents:
> > + [:s| | is |
> > + (is:= InstructionStream on: m)
> > + pc: ebc last startpc;
> > + scanFor:
> > + [:b|
> > + s nextPut: is pc.
> > + false]] }].
> > + false].
> > + (1 to: 10) collect:
> > + [:ign|
> > + { [candidates keysAndValuesDo:
> > + [:m :tuple|
> > + [:ebc :pcs| | c |
> > + c := ebc outerContext.
> > + pcs do:
> > + [:pc| m encoderClass pcPreviousTo: pc in: m for: c]]
> valueWithArguments: tuple]] timeToRun.
> > + [candidates keysAndValuesDo:
> > + [:m :tuple|
> > + [:ebc :pcs| | c |
> > + c := ebc outerContext.
> > + pcs do:
> > + [:pc| m encoderClass pcPreviousTo: pc in: m for: nil]]
> valueWithArguments: tuple]] timeToRun. }]"!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>pushClosureBytecodeSize (in
> category 'bytecode decoding') -----
> > + pushClosureBytecodeSize
> > + "Answer the size of the push closure bytecode, if there is one."
> > + ^self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>pushNewArrayCode (in category
> 'bytecode decoding') -----
> > + pushNewArrayCode
> > + "Answer the pushNewArray bytecode, if it exists in the encoder's
> bytecode set, or nil if not."
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>pushNilCode (in category
> 'bytecode decoding') -----
> > + pushNilCode
> > + "Answer the pushNil bytecode."
> > + ^self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>scanBlockOrNilForLiteral: (in
> category 'scanning') -----
> > + scanBlockOrNilForLiteral: aLiteral
> > + "Answer a block argument for CompiledMethod>>#scanFor: that answers
> > + if the method refers to the literal implicitly via a special
> bytecode.
> > + If the literal is not accessible via a special bytecode, answer
> nil.
> > + Subclasses override as appropriate"
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>selectorToSendOrItselfFor:in:at:
> (in category 'instruction stream support') -----
> > + selectorToSendOrItselfFor: anInstructionStream in: method at: pc
> > + "If anInstructionStream is at a send bytecode then answer the
> send's selector,
> > + otherwise answer anInstructionStream itself. The rationale for
> answering
> > + anInstructionStream instead of, say, nil, is that potentially any
> existing object
> > + can be used as a selector, but since anInstructionStream postdates
> the method,
> > + it can't be one of them."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>stackDeltaForPrimitive:in: (in
> category 'bytecode decoding') -----
> > + stackDeltaForPrimitive: primitiveIndex in: method
> > + "This is the default implementation. Subclasses with inline
> primitives will need to override."
> > + ^0!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>superSendScanBlockUsing: (in
> category 'compiled method support') -----
> > + superSendScanBlockUsing: scanner
> > + "Answer a block argument for InstructionStream>>scanFor:
> > + that answers true for super sends."
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>supportsClosures (in category
> 'compiled method support') -----
> > + supportsClosures
> > + "Answer if the instruction set supports closures (contains
> > + closure creation and indirect temp access bytecodes)."
> > +
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>supportsFullBlocks (in category
> 'testing') -----
> > + supportsFullBlocks
> > + "Answer if the instruction set supports full closures (closure
> creation from
> > + specfic methods instead of bytecodes embedded in an outer home
> method)."
> > +
> > + ^self basicNew supportsFullBlocks!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder class>>unusedBytecode (in category
> 'bytecode decoding') -----
> > + unusedBytecode
> > + "Answer the opcode of a single-byte unused bytecode, if it exists
> in the encoder's bytecode set, or nil if not."
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>allLiteralsForBlockMethod (in category
> 'results') -----
> > + allLiteralsForBlockMethod
> > + addedExtraLiterals ifFalse:
> > + [addedExtraLiterals := true.
> > + "Put the optimized selectors in literals so as to browse
> senders more easily"
> > + optimizedSelectors := optimizedSelectors reject: [:e|
> literalStream originalContents hasLiteral: e].
> > + optimizedSelectors isEmpty ifFalse: [
> > + "Use one entry per literal if enough room, else make
> anArray"
> > + literalStream position + optimizedSelectors size + 2 >=
> self maxNumLiterals
> > + ifTrue: [self litIndex: optimizedSelectors asArray]
> > + ifFalse: [optimizedSelectors do: [:e | self litIndex:
> e]]].
> > + "Add a slot for outerCode"
> > + self litIndex: nil].
> > + ^literalStream contents!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>bindAndJuggle: (in category 'temps')
> -----
> > + bindAndJuggle: name
> > + "This is used to insert a new temp and reorcder temps on editing.
> > + It doesn't really work for closure compilation since we have
> multiple
> > + locations for temps. Simply signal a reparse is necessary."
> > +
> > + ReparseAfterSourceEditing signal!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>bindBlockArg:within: (in category
> 'temps') -----
> > + bindBlockArg: name within: aBlockNode
> > + | nArgs |
> > + (nArgs := aBlockNode nArgsSlot) isNil ifTrue:
> > + [aBlockNode nArgsSlot: (nArgs := 0)].
> > + nArgs >= 15 ifTrue:
> > + [^self notify: 'Too many arguments'].
> > + aBlockNode nArgsSlot: nArgs + 1.
> > + ^(self bindTemp: name)
> > + beBlockArg;
> > + nowHasDef;
> > + nowHasRef;
> > + yourself!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>bindBlockTemp: (in category 'temps')
> -----
> > + bindBlockTemp: name
> > + "This shouldn't be used with BytecodeEncoder. Use
> bindBlockTemp:within: instead."
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>bindBlockTemp:within: (in category
> 'temps') -----
> > + bindBlockTemp: name within: aBlockNode
> > + | nArgs |
> > + (nArgs := aBlockNode nArgsSlot) ifNil:
> > + [aBlockNode nArgsSlot: (nArgs := 0)].
> > + nArgs >= (CompiledMethod fullFrameSize - 1) ifTrue:
> > + [^self notify: 'Too many temporaries'].
> > + aBlockNode nArgsSlot: nArgs + 1.
> > + ^self bindTemp: name!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>bindTemp: (in category 'temps') -----
> > + bindTemp: name
> > + "Declare a temporary; error not if a field or class variable or
> out-of-scope temp."
> > + scopeTable at: name ifPresent:
> > + [:node|
> > + "When non-interactive raise the error only if it is a duplicate"
> > + node isTemp
> > + ifTrue:[node scope >= 0 ifTrue:
> > + [^self notify: 'Name already used in this
> method']]
> > + ifFalse:[self warnAboutShadowed: name]].
> > + ^self reallyBind: name!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>blockExtentsToTempsMap (in category
> 'temps') -----
> > + blockExtentsToTempsMap
> > + "Answer a Dictionary of blockExtent to temp locations for the
> current method.
> > + This is used by the debugger to locate temp vars in contexts. A
> temp map
> > + entry is a pair of the temp's name and its index, where an index
> is either an
> > + integer for a normal temp or a pair of the index of the indirect
> temp vector
> > + containing the temp and the index of the temp in its indirect
> temp vector."
> > + | blockExtentsToTempsMap |
> > + blockExtentsToLocals ifNil:
> > + [^nil].
> > + blockExtentsToTempsMap := Dictionary new.
> > + blockExtentsToLocals keysAndValuesDo:
> > + [:blockExtent :locals|
> > + blockExtentsToTempsMap
> > + at: blockExtent
> > + put: (Array streamContents:
> > + [:aStream|
> > + locals withIndexDo:
> > + [:local :index|
> > + local isIndirectTempVector
> > + ifTrue: [local remoteTemps withIndexDo:
> > + [:remoteLocal :innerIndex|
> aStream nextPut: { remoteLocal key. { index. innerIndex } }]]
> > + ifFalse: [aStream nextPut: { local key.
> index }]]])].
> > + ^blockExtentsToTempsMap!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>blockLiteralFor: (in category 'full
> blocks') -----
> > + blockLiteralFor: aBlockNode
> > + "Answer a new CompiledBlock for the code in aBlockNode"
> > + ^self reindexingLiteralsDo:
> > + [self shallowCopy resetForFullBlockGeneration
> > + generateBlockMethodOfClass: CompiledBlock
> > + trailer: CompiledMethodTrailer empty
> > + from: aBlockNode]!
> >
> > Item was added:
> > + ----- Method:
> BytecodeEncoder>>computeMethodHeaderForNumArgs:numTemps:numLits:primitive:
> (in category 'method generation') -----
> > + computeMethodHeaderForNumArgs: numArgs numTemps: numTemps numLits:
> numLits primitive: primitiveIndex
> > + numArgs > 15 ifTrue:
> > + [^self error: 'Cannot compile -- too many arguments'].
> > + numTemps > 63 ifTrue:
> > + [^self error: 'Cannot compile -- too many temporary
> variables'].
> > + numLits > self maxNumLiterals ifTrue:
> > + [^self error: 'Cannot compile -- too many literals'].
> > + ^(CompiledMethod headerFlagForEncoder: self)
> > + + (numArgs bitShift: 24)
> > + + (numTemps bitShift: 18)
> > + "+ (largeBit bitShift: 17)" "largeBit gets filled in later"
> > + + (primitiveIndex > 0 ifTrue: [1 bitShift: 16] ifFalse: [0])
> > + "+ (optimizedBit bitShift: 15)" "Sista marker may get filled in
> later"
> > + + numLits!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>genPushNClosureTemps: (in category
> 'bytecode generation') -----
> > + genPushNClosureTemps: numTemps
> > + "To reduce the number of bytecodes required, the embedded
> > + block closure implementation uses explicit push nil instructions
> > + to create block-local temps. In bytecode sets supporting
> > + FullBlockClosure/CompiledBlock this isn't needed and the
> > + number of temps is derived from the block method header."
> > + numTemps timesRepeat: [self genPushSpecialLiteral: nil]!
> >
> > Item was added:
> > + ----- Method:
> BytecodeEncoder>>generateBlockMethodOfClass:trailer:from: (in category
> 'method generation') -----
> > + generateBlockMethodOfClass: aCompiledBlockClass trailer: trailer from:
> blockNode
> > + "Generate a CompiledBlock for the block whose parse tree is
> blockNode."
> > +
> > + "The closure analysis should already have been done."
> > + | blkSize header literals locals method nLits stack |
> > + self assert: blockNode blockExtent notNil.
> > + self assert: rootNode notNil.
> > + blkSize := blockNode sizeCodeForEvaluatedFullClosureValue: self.
> > + locals := blockNode localsNodes.
> > + self noteBlockExtent: blockNode blockExtent hasLocals: locals.
> > + header := self computeMethodHeaderForNumArgs: blockNode arguments
> size
> > + numTemps: locals size
> > + numLits: (nLits := (literals := self
> allLiteralsForBlockMethod) size)
> > + primitive: 0.
> > + method := trailer
> > + createMethod: blkSize
> > + class: aCompiledBlockClass
> > + header: header.
> > + 1 to: nLits do:
> > + [:lit |
> > + (method literalAt: lit put: (literals at: lit)) isCompiledCode
> ifTrue:
> > + [(literals at: lit) outerCode: method]].
> > + self streamToMethod: method.
> > + stack := ParseStack new init.
> > + stack position: method numTemps.
> > + blockMethod := method. "For BytecodeEncoder>>pc &
> BytecodeEncoder>>nextPC"
> > + [blockNode emitCodeForEvaluatedFullClosureValue: stack encoder:
> self]
> > + on: Error "If an attempt is made to write too much code the
> method will be asked"
> > + do: [:ex| "to grow, and the grow attempt will fail in
> CompiledCode class>>#newMethodViaNewError"
> > + ex signalerContext sender method = (CompiledCode
> class>>#newMethodViaNewError)
> > + ifTrue: [^self error: 'Compiler code size discrepancy']
> > + ifFalse: [ex pass]].
> > + stack position ~= (method numTemps + 1) ifTrue:
> > + [^self error: 'Compiler stack discrepancy'].
> > + stream position ~= (method size - trailer size) ifTrue:
> > + [^self error: 'Compiler code size discrepancy'].
> > + method needsFrameSize: stack size - method numTemps.
> > + ^method!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>generateMethodOfClass:trailer:from: (in
> category 'method generation') -----
> > + generateMethodOfClass: aCompiledMethodClass trailer: trailer from:
> methodNode
> > + "The receiver is the root of a parse tree. Answer an instance of
> aCompiledMethodClass.
> > + The argument, trailer, is arbitrary but is typically either the
> reference to the source code
> > + that is stored with every CompiledMethod, or an encoding of the
> method's temporary names."
> > +
> > + | primErrNode blkSize nLits locals literals header method stack |
> > + primErrNode := methodNode primitiveErrorVariableName ifNotNil:
> > + [self fixTemp: methodNode
> primitiveErrorVariableName].
> > + methodNode ensureClosureAnalysisDone.
> > + self rootNode: methodNode. "this is for
> BlockNode>>sizeCodeForClosureValue:"
> > + blkSize := (methodNode block sizeCodeForEvaluatedValue: self)
> > + + (methodNode primitive > 0
> > + ifTrue: [self sizeCallPrimitive: methodNode
> primitive]
> > + ifFalse: [0])
> > + + (primErrNode
> > + ifNil: [0]
> > + ifNotNil:
> > + [primErrNode
> > + index: methodNode arguments size +
> methodNode temporaries size;
> > + sizeCodeForStore: self "The VM relies on
> storeIntoTemp: (129)"]).
> > + locals := methodNode arguments, methodNode temporaries,
> (primErrNode ifNil: [#()] ifNotNil: [{primErrNode}]).
> > + self noteBlockExtent: methodNode block blockExtent hasLocals:
> locals.
> > + header := self computeMethodHeaderForNumArgs: methodNode arguments
> size
> > + numTemps: locals size
> > + numLits: (nLits := (literals := self allLiterals)
> size)
> > + primitive: methodNode primitive.
> > + method := trailer
> > + createMethod: blkSize
> > + class: aCompiledMethodClass
> > + header: header.
> > + 1 to: nLits do:
> > + [:lit |
> > + (method literalAt: lit put: (literals at: lit)) isCompiledCode
> ifTrue:
> > + [(literals at: lit) outerCode: method]].
> > + self streamToMethod: method.
> > + stack := ParseStack new init.
> > + methodNode primitive > 0 ifTrue:
> > + [self genCallPrimitive: methodNode primitive].
> > + primErrNode ifNotNil:
> > + [primErrNode emitCodeForStore: stack encoder: self].
> > + stack position: method numTemps.
> > + [methodNode block emitCodeForEvaluatedValue: stack encoder: self]
> > + on: Error "If an attempt is made to write too much code the
> method will be asked"
> > + do: [:ex| "to grow, and the grow attempt will fail in
> CompiledCode class>>#newMethodViaNewError"
> > + ex signalerContext sender method = (CompiledCode
> class>>#newMethodViaNewError)
> > + ifTrue: [^self error: 'Compiler code size discrepancy']
> > + ifFalse: [ex pass]].
> > + stack position ~= (method numTemps + 1) ifTrue:
> > + [^self error: 'Compiler stack discrepancy'].
> > + stream position ~= (method size - trailer size) ifTrue:
> > + [^self error: 'Compiler code size discrepancy'].
> > + method needsFrameSize: stack size - method numTemps.
> > + ^method!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>generatingFullBlock (in category
> 'testing') -----
> > + generatingFullBlock
> > + "Answer if the encoder is currently generating a FullBlock,
> embedded in some method."
> > +
> > + "When generating a FullBlock a copy of the encoder for the home
> emthod (rootNode)
> > + is used, and hence the following is true."
> > + ^rootNode encoder ~~ self!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>hasGeneratedMethod (in category
> 'testing') -----
> > + hasGeneratedMethod
> > + ^blockExtentsToLocals notNil!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>if:isSpecialLiteralForPush: (in
> category 'special literal encodings') -----
> > + if: code isSpecialLiteralForPush: aBlock
> > + "If code is that of a special literal for push then evaluate aBlock
> with the special literal
> > + The special literals for push are at least nil true false which
> have special encodings
> > + in the blue book bytecode set. Answer whether it was a special
> literal."
> > + ^(code between: LdTrue and: LdNil)
> > + and: [aBlock value: (#(true false nil) at: code - LdSelf).
> > + true]!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>if:isSpecialLiteralForReturn: (in
> category 'special literal encodings') -----
> > + if: code isSpecialLiteralForReturn: aBlock
> > + "If code is that of a special literal for return then evaluate
> aBlock with the special literal.
> > + The special literals for return are nil true false which have
> special encodings
> > + in the blue book bytecode set. Answer whether it was a special
> literal."
> > + ^(code between: LdTrue and: LdNil)
> > + and: [aBlock value: (#(true false nil) at: code - LdSelf).
> > + true]!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>methodStreamPosition (in category
> 'accessing') -----
> > + methodStreamPosition
> > + ^stream position!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>nextPC (in category 'accessing') -----
> > + nextPC
> > + "Answer the pc to store in a node for source range identification
> when the node is associated with its following pc."
> > + ^blockMethod
> > + ifNil: [stream position + 1]
> > + ifNotNil: [:proxy| proxy -> (stream position + 1)]!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>nextPut: (in category 'opcode sizing')
> -----
> > + nextPut: aByte
> > + "For sizing make the encoder its own stream and
> > + keep track of position with this version of nextPut:"
> > + position := position + 1!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>noteBlockExtent:hasLocals: (in category
> 'temps') -----
> > + noteBlockExtent: blockExtent hasLocals: tempNodes
> > + blockExtentsToLocals ifNil:
> > + [blockExtentsToLocals := Dictionary new].
> > + blockExtentsToLocals at: blockExtent put: tempNodes asArray!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>outOfRangeError:index:range:to: (in
> category 'bytecode generation') -----
> > + outOfRangeError: string index: index range: rangeStart to: rangeEnd
> > + "For now..."
> > + ^self error: thisContext sender method selector, ' ', string
> > + , ' index ', index printString
> > + , ' is out of range ', rangeStart printString, ' to ',
> rangeEnd printString!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>pc (in category 'accessing') -----
> > + pc
> > + "Answer the pc to store in a node for source range identification."
> > + ^blockMethod
> > + ifNil: [stream position]
> > + ifNotNil: [:aCompiledBlock| aCompiledBlock -> stream position]!
> >
> > Item was added:
> > + ----- Method:
> BytecodeEncoder>>printSchematicTempNamesOn:blockExtents:fromIndex: (in
> category 'results') -----
> > + printSchematicTempNamesOn: aStream blockExtents: blockExtents
> fromIndex: startIndex
> > + "Print the locals in the blockExtent startIndex, recursing to print
> any locals in nested blockExtents.
> > + Answer the index of the last blockExtent printed."
> > + | blockExtent subsequentIndex |
> > + blockExtent := blockExtents at: startIndex.
> > + blockExtent first > 0 ifTrue:
> > + [aStream nextPut: $[ ].
> > + ((blockExtentsToLocals at: blockExtent) reject: [:local| local
> isRemote])
> > + do: [:local|
> > + local isIndirectTempVector
> > + ifTrue:
> > + [aStream nextPut: $(.
> > + local remoteTemps
> > + do: [:remoteLocal| aStream nextPutAll:
> remoteLocal key]
> > + separatedBy: [aStream space].
> > + aStream nextPut: $)]
> > + ifFalse: [aStream nextPutAll: local key]]
> > + separatedBy: [aStream space].
> > + subsequentIndex := startIndex + 1.
> > + [subsequentIndex <= blockExtents size
> > + and: [(blockExtents at: subsequentIndex) last < blockExtent last]]
> whileTrue:
> > + [subsequentIndex := self printSchematicTempNamesOn: aStream
> > + blockExtents: blockExtents
> > + fromIndex: subsequentIndex].
> > + blockExtent first > 0 ifTrue:
> > + [aStream nextPut: $] ].
> > + ^subsequentIndex!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>reindexingLiteralsDo: (in category
> 'code generation') -----
> > + reindexingLiteralsDo: aBlock
> > + "Reset any and all literals so that they will be given new indices
> in
> > + the literalStream during aBlock (which will be used to generate a
> > + nested block method). Afterwards restore those same literals to
> > + their original state, and reset any and all new literals added
> during
> > + aBlock so that they will be given new indices if used
> subsequently."
> > + | savedNodes saveBlock |
> > + savedNodes := IdentityDictionary new.
> > + saveBlock := [:node|
> > + savedNodes at: node put: node shallowCopy.
> > + node resetForBlockGeneration].
> > + litSet do: saveBlock.
> > + litIndSet do: saveBlock.
> > + selectorSet do: saveBlock.
> > + ^aBlock ensure:
> > + [| restoreBlock |
> > + restoreBlock := [:node|
> > + savedNodes
> > + at: node
> > + ifPresent: [:copy| node resetFromCopy:
> copy]
> > + ifAbsent: [node
> resetForBlockGeneration]].
> > + litSet do: restoreBlock.
> > + litIndSet do: restoreBlock.
> > + selectorSet do: restoreBlock]!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>resetForFullBlockGeneration (in
> category 'code generation') -----
> > + resetForFullBlockGeneration
> > + literalStream := WriteStream on: (Array new: 8).
> > + addedExtraLiterals := false.
> > + optimizedSelectors := Set new!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>resetLiteralStreamForFullBlock (in
> category 'code generation') -----
> > + resetLiteralStreamForFullBlock
> > + literalStream := WriteStream on: (Array new: 32).
> > + addedExtraLiterals := false.
> > + optimizedSelectors := Set new!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>rootNode (in category 'accessing') -----
> > + rootNode "^<BlockNode>"
> > + ^rootNode!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>rootNode: (in category 'accessing')
> -----
> > + rootNode: node "<BlockNode>"
> > + rootNode := node!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>schematicTempNamesString (in category
> 'results') -----
> > + schematicTempNamesString
> > + "Answer the temp names for the current method node in a form that
> captures
> > + temp structure. The temps at each method and block scope level
> occurr
> > + space-separated, with any indirect temps enclosed in parentheses.
> Each block
> > + level is enclosed in square brackets. e.g.
> > + 'method level temps (indirect temp)[block args and temps
> (indirect)]'
> > + This representation can be reconstituted into a
> blockExtentsToTempsMap
> > + by a CompiledMethod that has been copied with teh
> schematicTempNamesString."
> > + blockExtentsToLocals ifNil:
> > + [self error: 'blockExtentsToLocals uninitialized. method not
> yet generated?'].
> > + ^String streamContents:
> > + [:aStream|
> > + self printSchematicTempNamesOn: aStream
> > + blockExtents: (blockExtentsToLocals keys asArray sort:
> > + [:range1 :range2|
> > + range1 first <= range2 first])
> > + fromIndex: 1]!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeBranchPopFalse: (in category
> 'opcode sizing') -----
> > + sizeBranchPopFalse: distance
> > + ^self sizeOpcodeSelector: #genBranchPopFalse: withArguments:
> {distance}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeBranchPopTrue: (in category 'opcode
> sizing') -----
> > + sizeBranchPopTrue: distance
> > + ^self sizeOpcodeSelector: #genBranchPopTrue: withArguments:
> {distance}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeCallPrimitive: (in category 'opcode
> sizing') -----
> > + sizeCallPrimitive: primitiveIndex
> > + ^self sizeOpcodeSelector: #genCallPrimitive: withArguments:
> {primitiveIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeDup (in category 'opcode sizing')
> -----
> > + sizeDup
> > + ^self sizeOpcodeSelector: #genDup withArguments: #()!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeJump: (in category 'opcode sizing')
> -----
> > + sizeJump: distance
> > + ^self sizeOpcodeSelector: #genJump: withArguments: {distance}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeJumpLong: (in category 'opcode
> sizing') -----
> > + sizeJumpLong: distance
> > + ^self sizeOpcodeSelector: #genJumpLong: withArguments: {distance}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeOpcodeSelector:withArguments: (in
> category 'opcode sizing') -----
> > + sizeOpcodeSelector: genSelector withArguments: args
> > + stream := self.
> > + position := 0.
> > + self perform: genSelector withArguments: args.
> > + ^position!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePop (in category 'opcode sizing')
> -----
> > + sizePop
> > + ^self sizeOpcodeSelector: #genPop withArguments: #()!
> >
> > Item was added:
> > + ----- Method:
> BytecodeEncoder>>sizePushClosureCopyNumCopiedValues:numArgs:jumpSize: (in
> category 'opcode sizing') -----
> > + sizePushClosureCopyNumCopiedValues: numCopied numArgs: numArgs
> jumpSize: jumpSize
> > + ^self
> > + sizeOpcodeSelector:
> #genPushClosureCopyNumCopiedValues:numArgs:jumpSize:
> > + withArguments: {numCopied. numArgs. jumpSize}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushConsArray: (in category 'opcode
> sizing') -----
> > + sizePushConsArray: numElements
> > + ^self sizeOpcodeSelector: #genPushConsArray: withArguments:
> {numElements}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushFullClosure:numCopied: (in
> category 'opcode sizing') -----
> > + sizePushFullClosure: compiledBlockLiteralIndex numCopied: numCopied
> > + ^self sizeOpcodeSelector: #genPushFullClosure:numCopied:
> > + withArguments: {compiledBlockLiteralIndex. numCopied}!
> >
> > Item was added:
> > + ----- Method:
> BytecodeEncoder>>sizePushFullClosure:numCopied:receiverOnStack:ignoreOuterContext:
> (in category 'opcode sizing') -----
> > + sizePushFullClosure: compiledBlockLiteralIndex numCopied: numCopied
> receiverOnStack: receiverOnStack ignoreOuterContext: ignoreOuterContext
> > + ^self sizeOpcodeSelector:
> #genPushFullClosure:numCopied:receiverOnStack:ignoreOuterContext:
> > + withArguments: {compiledBlockLiteralIndex. numCopied.
> receiverOnStack. ignoreOuterContext}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushInstVar: (in category 'opcode
> sizing') -----
> > + sizePushInstVar: instVarIndex
> > + ^self sizeOpcodeSelector: #genPushInstVar: withArguments:
> {instVarIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushInstVarLong: (in category
> 'opcode sizing') -----
> > + sizePushInstVarLong: instVarIndex
> > + ^self sizeOpcodeSelector: #genPushInstVarLong: withArguments:
> {instVarIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushLiteral: (in category 'opcode
> sizing') -----
> > + sizePushLiteral: literalIndex
> > + ^self sizeOpcodeSelector: #genPushLiteral: withArguments:
> {literalIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushLiteralVar: (in category
> 'opcode sizing') -----
> > + sizePushLiteralVar: literalIndex
> > + ^self sizeOpcodeSelector: #genPushLiteralVar: withArguments:
> {literalIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushNClosureTemps: (in category
> 'opcode sizing') -----
> > + sizePushNClosureTemps: numTemps
> > + ^self sizeOpcodeSelector: #genPushNClosureTemps: withArguments:
> {numTemps}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushNewArray: (in category 'opcode
> sizing') -----
> > + sizePushNewArray: size
> > + ^self sizeOpcodeSelector: #genPushNewArray: withArguments: {size}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushReceiver (in category 'opcode
> sizing') -----
> > + sizePushReceiver
> > + ^self sizeOpcodeSelector: #genPushReceiver withArguments: #()!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushRemoteTemp:inVectorAt: (in
> category 'opcode sizing') -----
> > + sizePushRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> > + ^self sizeOpcodeSelector: #genPushRemoteTemp:inVectorAt:
> withArguments: {tempIndex. tempVectorIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushSpecialLiteral: (in category
> 'opcode sizing') -----
> > + sizePushSpecialLiteral: specialLiteral
> > + ^self sizeOpcodeSelector: #genPushSpecialLiteral: withArguments:
> {specialLiteral}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushTemp: (in category 'opcode
> sizing') -----
> > + sizePushTemp: tempIndex
> > + ^self sizeOpcodeSelector: #genPushTemp: withArguments: {tempIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushTempLong: (in category 'opcode
> sizing') -----
> > + sizePushTempLong: tempIndex
> > + ^self sizeOpcodeSelector: #genPushTempLong: withArguments:
> {tempIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizePushThisContext (in category
> 'opcode sizing') -----
> > + sizePushThisContext
> > + ^self sizeOpcodeSelector: #genPushThisContext withArguments: #()!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeReturnNilToCaller (in category
> 'opcode sizing') -----
> > + sizeReturnNilToCaller
> > + ^self sizeOpcodeSelector: #genReturnNilToCaller withArguments: #()!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeReturnReceiver (in category 'opcode
> sizing') -----
> > + sizeReturnReceiver
> > + ^self sizeOpcodeSelector: #genReturnReceiver withArguments: #()!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeReturnSpecialLiteral: (in category
> 'opcode sizing') -----
> > + sizeReturnSpecialLiteral: specialLiteral
> > + ^self sizeOpcodeSelector: #genReturnSpecialLiteral: withArguments:
> {specialLiteral}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeReturnTop (in category 'opcode
> sizing') -----
> > + sizeReturnTop
> > + ^self sizeOpcodeSelector: #genReturnTop withArguments: #()!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeReturnTopToCaller (in category
> 'opcode sizing') -----
> > + sizeReturnTopToCaller
> > + ^self sizeOpcodeSelector: #genReturnTopToCaller withArguments: #()!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeSend:numArgs: (in category 'opcode
> sizing') -----
> > + sizeSend: selectorLiteralIndex numArgs: nArgs
> > + ^self sizeOpcodeSelector: #genSend:numArgs: withArguments:
> {selectorLiteralIndex. nArgs}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeSendDirectedSuper:numArgs: (in
> category 'opcode sizing') -----
> > + sizeSendDirectedSuper: selectorLiteralIndex numArgs: numArgs
> > + ^self sizeOpcodeSelector: #genSendDirectedSuper:numArgs:
> withArguments: {selectorLiteralIndex. numArgs}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeSendSpecial:numArgs: (in category
> 'opcode sizing') -----
> > + sizeSendSpecial: specialSelectorIndex numArgs: nArgs
> > + ^self sizeOpcodeSelector: #genSendSpecial:numArgs: withArguments:
> {specialSelectorIndex. nArgs}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeSendSuper:numArgs: (in category
> 'opcode sizing') -----
> > + sizeSendSuper: selectorLiteralIndex numArgs: nArgs
> > + ^self sizeOpcodeSelector: #genSendSuper:numArgs: withArguments:
> {selectorLiteralIndex. nArgs}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeStoreInstVar: (in category 'opcode
> sizing') -----
> > + sizeStoreInstVar: instVarIndex
> > + ^self sizeOpcodeSelector: #genStoreInstVar: withArguments:
> {instVarIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeStoreInstVarLong: (in category
> 'opcode sizing') -----
> > + sizeStoreInstVarLong: instVarIndex
> > + ^self sizeOpcodeSelector: #genStoreInstVarLong: withArguments:
> {instVarIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeStoreLiteralVar: (in category
> 'opcode sizing') -----
> > + sizeStoreLiteralVar: literalIndex
> > + ^self sizeOpcodeSelector: #genStoreLiteralVar: withArguments:
> {literalIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeStorePopInstVar: (in category
> 'opcode sizing') -----
> > + sizeStorePopInstVar: instVarIndex
> > + ^self sizeOpcodeSelector: #genStorePopInstVar: withArguments:
> {instVarIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeStorePopInstVarLong: (in category
> 'opcode sizing') -----
> > + sizeStorePopInstVarLong: instVarIndex
> > + ^self sizeOpcodeSelector: #genStorePopInstVarLong: withArguments:
> {instVarIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeStorePopLiteralVar: (in category
> 'opcode sizing') -----
> > + sizeStorePopLiteralVar: literalIndex
> > + ^self sizeOpcodeSelector: #genStorePopLiteralVar: withArguments:
> {literalIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeStorePopRemoteTemp:inVectorAt: (in
> category 'opcode sizing') -----
> > + sizeStorePopRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> > + ^self sizeOpcodeSelector: #genStorePopRemoteTemp:inVectorAt:
> withArguments: {tempIndex. tempVectorIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeStorePopTemp: (in category 'opcode
> sizing') -----
> > + sizeStorePopTemp: tempIndex
> > + ^self sizeOpcodeSelector: #genStorePopTemp: withArguments:
> {tempIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeStoreRemoteTemp:inVectorAt: (in
> category 'opcode sizing') -----
> > + sizeStoreRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> > + ^self sizeOpcodeSelector: #genStoreRemoteTemp:inVectorAt:
> withArguments: {tempIndex. tempVectorIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeStoreTemp: (in category 'opcode
> sizing') -----
> > + sizeStoreTemp: tempIndex
> > + ^self sizeOpcodeSelector: #genStoreTemp: withArguments: {tempIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>sizeTrapIfNotInstanceOf: (in category
> 'opcode sizing') -----
> > + sizeTrapIfNotInstanceOf: litIndex
> > + ^self sizeOpcodeSelector: #genTrapIfNotInstanceOf: withArguments:
> {litIndex}!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>streamToMethod: (in category
> 'initialize-release') -----
> > + streamToMethod: aCompiledMethod
> > + stream := WriteStream with: aCompiledMethod.
> > + stream position: aCompiledMethod initialPC - 1!
> >
> > Item was added:
> > + ----- Method: BytecodeEncoder>>supportsFullBlocks (in category
> 'testing') -----
> > + supportsFullBlocks
> > + "Answer if the instruction set supports full closures (closure
> creation from
> > + specfic methods instead of bytecodes embedded in an outer home
> method)."
> > +
> > + ^self subclassResponsibility!
> >
> > Item was added:
> > + ParseNode subclass: #CascadeNode
> > + instanceVariableNames: 'receiver messages'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !CascadeNode commentStamp: '<historical>' prior: 0!
> > + The first message has the common receiver, the rest have receiver ==
> nil, which signifies cascading.!
> >
> > Item was added:
> > + ----- Method: CascadeNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitCascadeNode: self!
> >
> > Item was added:
> > + ----- Method:
> CascadeNode>>analyseTempsWithin:rootNode:assignmentPools: (in category
> 'closure analysis') -----
> > + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode
> "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + { receiver }, messages do:
> > + [:node| node analyseTempsWithin: scopeBlock rootNode: rootNode
> assignmentPools: assignmentPools]!
> >
> > Item was added:
> > + ----- Method: CascadeNode>>emitCodeForValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + receiver emitCodeForValue: stack encoder: encoder.
> > + 1 to: messages size - 1 do:
> > + [:i |
> > + encoder genDup.
> > + stack push: 1.
> > + (messages at: i) emitCodeForValue: stack encoder: encoder.
> > + encoder genPop.
> > + stack pop: 1].
> > + messages last emitCodeForValue: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: CascadeNode>>messages (in category 'accessing') -----
> > + messages
> > + ^messages!
> >
> > Item was added:
> > + ----- Method: CascadeNode>>printOn:indent: (in category 'printing')
> -----
> > + printOn: aStream indent: level
> > + self printOn: aStream indent: level precedence: 0!
> >
> > Item was added:
> > + ----- Method: CascadeNode>>printOn:indent:precedence: (in category
> 'printing') -----
> > + printOn: aStream indent: level precedence: p
> > +
> > + p > 0 ifTrue: [aStream nextPut: $(].
> > + messages first printReceiver: receiver on: aStream indent: level.
> > + 1 to: messages size do:
> > + [:i | (messages at: i) printOn: aStream indent: level.
> > + i < messages size ifTrue:
> > + [aStream nextPut: $;.
> > + messages first precedence >= 2 ifTrue: [aStream crtab:
> level + 1]]].
> > + p > 0 ifTrue: [aStream nextPut: $)]!
> >
> > Item was added:
> > + ----- Method: CascadeNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level
> > + self printWithClosureAnalysisOn: aStream indent: level precedence:
> 0!
> >
> > Item was added:
> > + ----- Method:
> CascadeNode>>printWithClosureAnalysisOn:indent:precedence: (in category
> 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level precedence: p
> > +
> > + p > 0 ifTrue: [aStream nextPut: $(].
> > + messages first printWithClosureAnalysisReceiver: receiver on:
> aStream indent: level.
> > + 1 to: messages size do:
> > + [:i | (messages at: i) printWithClosureAnalysisOn: aStream
> indent: level.
> > + i < messages size ifTrue:
> > + [aStream nextPut: $;.
> > + messages first precedence >= 2 ifTrue: [aStream crtab:
> level + 1]]].
> > + p > 0 ifTrue: [aStream nextPut: $)]!
> >
> > Item was added:
> > + ----- Method: CascadeNode>>receiver (in category 'accessing') -----
> > + receiver
> > + ^receiver!
> >
> > Item was added:
> > + ----- Method: CascadeNode>>receiver:messages: (in category
> 'initialize-release') -----
> > + receiver: receivingObject messages: msgs
> > + " Transcript show: 'abc'; cr; show: 'def' "
> > +
> > + receiver := receivingObject.
> > + messages := msgs!
> >
> > Item was added:
> > + ----- Method: CascadeNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + | size |
> > + size := (receiver sizeCodeForValue: encoder)
> > + + (messages size - 1 * (encoder sizeDup + encoder
> sizePop)).
> > + messages do: [:aMessage | size := size + (aMessage
> sizeCodeForValue: encoder)].
> > + ^size!
> >
> > Item was added:
> > + TextStream subclass: #ColoredCodeStream
> > + instanceVariableNames: 'dialect colorTable'
> > + classVariableNames: 'ST80ColorTable'
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> >
> > Item was added:
> > + ----- Method: ColoredCodeStream class>>contents: (in category
> 'instance creation') -----
> > + contents: blockWithArg
> > + "Evaluate blockWithArg on a DialectStream of the given description"
> > +
> > + | stream |
> > + stream := self on: (Text new: 400).
> > + blockWithArg value: stream.
> > + ^ stream contents!
> >
> > Item was added:
> > + ----- Method: ColoredCodeStream class>>initialize (in category 'class
> initialization') -----
> > + initialize
> > + "Initialize the colors that characterize the ST80 dialect"
> > +
> > + ST80ColorTable := IdentityDictionary new.
> > + #( (temporaryVariable blue italic)
> > + (methodArgument blue normal)
> > + (methodSelector black bold)
> > + (blockArgument red normal)
> > + (comment brown normal)
> > + (variable magenta normal)
> > + (literal orange normal)
> > + (keyword darkGray bold)
> > + (prefixKeyword veryDarkGray bold)
> > + (setOrReturn black bold)) do:
> > + [:aTriplet |
> > + ST80ColorTable at: aTriplet first put: aTriplet
> allButFirst]
> > +
> > + "ColoredCodeStream initialize"!
> >
> > Item was added:
> > + ----- Method: ColoredCodeStream>>colorTable (in category
> 'color/style') -----
> > + colorTable
> > + "Answer the table to use to determine colors"
> > +
> > + ^ colorTable ifNil: [colorTable := ST80ColorTable]!
> >
> > Item was added:
> > + ----- Method: ColoredCodeStream>>withColor:emphasis:do: (in category
> 'color/style') -----
> > + withColor: colorSymbol emphasis: emphasisSymbol do: aBlock
> > + "Evaluate the given block with the given color and style text
> attribute"
> > +
> > + ^ self withAttributes: {TextColor color: (Color perform:
> colorSymbol).
> > + TextEmphasis perform: emphasisSymbol}
> > + do: aBlock!
> >
> > Item was added:
> > + ----- Method: ColoredCodeStream>>withStyleFor:do: (in category
> 'color/style') -----
> > + withStyleFor: elementType do: aBlock
> > + "Evaluate aBlock with appropriate emphasis and color for the given
> elementType"
> > +
> > + | colorAndStyle |
> > + colorAndStyle := self colorTable at: elementType.
> > + ^ self withColor: colorAndStyle first emphasis: colorAndStyle
> second do: aBlock!
> >
> > Item was added:
> > + ParseNode subclass: #CommentNode
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> >
> > Item was added:
> > + ----- Method: CommentNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitCommentNode: self!
> >
> > Item was added:
> > + Object subclass: #CompilationCue
> > + instanceVariableNames: 'source sourceStream context receiver class
> environment requestor encoderClass methodTrailer'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> > +
> > + !CompilationCue commentStamp: 'eem 3/30/2017 17:32' prior: 0!
> > + A CompilationCue is a helper class holding enough context for
> evaluating/compiling Smalltalk code.
> > +
> > + That is mainly the source code, and the source code editor to interact
> with if the Compiler is used interactively.
> > + But that is also any additional information necessary to resolve
> variable names.
> > +
> > + When compiling a method, the Compiler typically need to know the
> target class in which to install the method.
> > +
> > + When evaluating an expression, the Compiler also needs a receiver (for
> accessing the value of its instance variables), its class (for resolving
> instance/class variable names), and optionnally a context of execution when
> debugging a method (for accessing values of temporaries and parameters).
> > +
> > + Instance Variables
> > + class: <Behavior>
> > + context: <Context | nil>
> > + environment: <Environment | nil>
> > + receiver: <Object>
> > + requestor: <TextEditor | nil>
> > + source: <Stream>
> > +
> > + class
> > + - the target class in which to install the compiled method;
> > + this enables to resolve the instance variable names, class
> variable names and shared pool variable names.
> > + When evaluating, this should be the receiver class
> > +
> > + context
> > + - the context introspected when evaluating the code: this is
> typically for accessing parameters and temporary variables when debugging
> > +
> > + environment
> > + - the environment in which to resolve global variable names
> > +
> > + receiver
> > + - the receiver into which to evaluate the code: this is typically
> for accessing instance variables in an inspector
> > +
> > + requestor
> > + - typically the text editor containing the source code being
> compiled/evaluated. This enables the Compiler to interact in case of syntax
> error.
> > +
> > + source
> > + - a ReadStream on the source code to be compiled
> > + !
> >
> > Item was added:
> > + ----- Method: CompilationCue class>>class: (in category 'instance
> creation') -----
> > + class: aClass
> > + ^ self
> > + source: nil
> > + context: nil
> > + receiver: nil
> > + class: aClass
> > + environment: (aClass ifNotNil: [aClass environment])
> > + requestor: nil!
> >
> > Item was added:
> > + ----- Method: CompilationCue class>>source: (in category 'instance
> creation') -----
> > + source: aTextOrStream
> > + ^ self
> > + source: aTextOrStream
> > + class: nil
> > + requestor: nil!
> >
> > Item was added:
> > + ----- Method: CompilationCue
> class>>source:class:environment:requestor: (in category 'instance
> creation') -----
> > + source: aTextOrStream class: aClass environment: anEnvironment
> requestor: anObject
> > + ^ self
> > + source: aTextOrStream
> > + context: nil
> > + receiver: nil
> > + class: aClass
> > + environment: anEnvironment
> > + requestor: anObject!
> >
> > Item was added:
> > + ----- Method: CompilationCue class>>source:class:requestor: (in
> category 'instance creation') -----
> > + source: aTextOrStream class: aClass requestor: anObject
> > + ^ self
> > + source: aTextOrStream
> > + context: nil
> > + receiver: nil
> > + class: aClass
> > + environment: (aClass ifNotNil: [aClass environment])
> > + requestor: anObject!
> >
> > Item was added:
> > + ----- Method: CompilationCue
> class>>source:context:class:environment:requestor: (in category 'instance
> creation') -----
> > + source: aTextOrStream context: aContext class: aClass environment:
> anEnvironment requestor: reqObject
> > + ^ self basicNew
> > + initializeWithSource: aTextOrStream
> > + context: aContext
> > + receiver: (aContext ifNotNil: [aContext receiver])
> > + class: aClass
> > + environment: anEnvironment
> > + requestor: reqObject!
> >
> > Item was added:
> > + ----- Method: CompilationCue class>>source:context:class:requestor:
> (in category 'instance creation') -----
> > + source: aTextOrStream context: aContext class: aClass requestor:
> anObject
> > + ^ self
> > + source: aTextOrStream
> > + context: aContext
> > + receiver: (aContext ifNotNil: [aContext receiver])
> > + class: aClass
> > + environment: (aClass ifNotNil: [aClass environment])
> > + requestor: anObject!
> >
> > Item was added:
> > + ----- Method: CompilationCue
> class>>source:context:receiver:class:environment:requestor: (in category
> 'instance creation') -----
> > + source: aTextOrStream context: aContext receiver: recObject class:
> aClass environment: anEnvironment requestor: reqObject
> > + ^ self basicNew
> > + initializeWithSource: aTextOrStream
> > + context: aContext
> > + receiver: recObject
> > + class: aClass
> > + environment: anEnvironment
> > + requestor: reqObject!
> >
> > Item was added:
> > + ----- Method: CompilationCue class>>source:environment: (in category
> 'instance creation') -----
> > + source: aString environment: anEnvironment
> > + ^ self
> > + source: aString
> > + context: nil
> > + receiver: nil
> > + class: UndefinedObject
> > + environment: anEnvironment
> > + requestor: nil!
> >
> > Item was added:
> > + ----- Method: CompilationCue class>>source:environment:requestor: (in
> category 'instance creation') -----
> > + source: aString environment: anEnvironment requestor: aRequestor
> > + ^ self
> > + source: aString
> > + context: nil
> > + receiver: nil
> > + class: UndefinedObject
> > + environment: anEnvironment
> > + requestor: aRequestor!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>bindingOf: (in category 'binding') -----
> > + bindingOf: aSymbol
> > + ^ class bindingOf: aSymbol environment: environment!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>context (in category 'accessing') -----
> > + context
> > + ^ context!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>encoderClass (in category 'accessing')
> -----
> > + encoderClass
> > + ^encoderClass!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>encoderClass: (in category 'accessing')
> -----
> > + encoderClass: aBytecodeEncoderClass
> > + encoderClass := aBytecodeEncoderClass!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>environment (in category 'accessing')
> -----
> > + environment
> > + ^ environment!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>getClass (in category 'accessing') -----
> > + getClass
> > + ^ class!
> >
> > Item was added:
> > + ----- Method:
> CompilationCue>>initializeWithSource:context:receiver:class:environment:requestor:
> (in category 'initialization') -----
> > + initializeWithSource: aTextOrStringOrStream context: aContext
> receiver: recObject class: aClass environment: anEnvironment requestor:
> reqObject
> > + self initialize.
> > + aTextOrStringOrStream isStream
> > + ifTrue: [sourceStream := aTextOrStringOrStream]
> > + ifFalse:
> > + [source := aTextOrStringOrStream.
> > + sourceStream := ReadStream on: aTextOrStringOrStream
> asString].
> > + context := aContext.
> > + receiver := recObject.
> > + class := aClass.
> > + environment := anEnvironment.
> > + requestor := reqObject!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>methodTrailer (in category 'accessing')
> -----
> > + methodTrailer
> > + ^methodTrailer!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>methodTrailer: (in category 'accessing')
> -----
> > + methodTrailer: aCompiledMethodTrailer
> > + methodTrailer := aCompiledMethodTrailer!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>receiver (in category 'accessing') -----
> > + receiver
> > + ^ receiver!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>requestor (in category 'accessing') -----
> > + requestor
> > + ^ requestor!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>source (in category 'accessing') -----
> > + source
> > + ^source!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>source: (in category 'accessing') -----
> > + source: aString
> > +
> > + source := aString.
> > + sourceStream := source readStream.!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>sourceStream (in category 'accessing')
> -----
> > + sourceStream
> > + ^sourceStream!
> >
> > Item was added:
> > + ----- Method: CompilationCue>>stringToLog (in category 'accessing')
> -----
> > + stringToLog
> > + "Answer a string to be logged in a change log.
> > + Implementation note:
> > + If the requestor is a TextEditor, preferably take its selection.
> > + This convoluted code is presumably crafted to avoid broken contents
> > + (ReadStream on: '123456' from: 3 to: 4) contents -> '1234'
> > + As long as selectionAsStream is using such construct this might be
> required."
> > + | itsSelection itsSelectionString |
> > + source ifNotNil:
> > + [^source].
> > + ((requestor respondsTo: #selection)
> > + and:[(itsSelection := requestor selection) notNil
> > + and:[(itsSelectionString := itsSelection asString) isEmptyOrNil
> not]]) ifTrue:
> > + [^itsSelectionString].
> > + ^sourceStream contents!
> >
> > Item was added:
> > + ----- Method: CompiledMethod>>mapFromBlockKeys:toSchematicTemps: (in
> category '*Compiler-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 := self newBlockStartMap.
> > + 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>>newBlockStartMap (in category
> '*Compiler-private') -----
> > + newBlockStartMap
> > + "If blocks are embedded then keys in the map are simple integer pcs
> and a Dictionary can be used.
> > + If blocks are full (separate method objects) then keys in the map
> are CompiledBlocks and
> > + IdentityDictionary must be used to avoid confusing blocks with
> identical code."
> > + ^(self encoderClass supportsFullBlocks
> > + ifTrue: [IdentityDictionary]
> > + ifFalse: [Dictionary]) new!
> >
> > Item was added:
> > + Object subclass: #CompiledMethodWithNode
> > + instanceVariableNames: 'node method'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> >
> > Item was added:
> > + ----- Method: CompiledMethodWithNode
> class>>generateMethodFromNode:trailer: (in category 'instance creation')
> -----
> > + generateMethodFromNode: aMethodNode trailer: bytes
> > + ^ self method: (aMethodNode generate: bytes) node: aMethodNode.!
> >
> > Item was added:
> > + ----- Method: CompiledMethodWithNode class>>method:node: (in category
> 'instance creation') -----
> > + method: aCompiledMethod node: aMethodNode
> > + ^ self new method: aCompiledMethod; node: aMethodNode.!
> >
> > Item was added:
> > + ----- Method: CompiledMethodWithNode>>method (in category 'accessing')
> -----
> > + method
> > + ^ method!
> >
> > Item was added:
> > + ----- Method: CompiledMethodWithNode>>method: (in category 'private')
> -----
> > + method: aCompiledMethod
> > + method := aCompiledMethod!
> >
> > Item was added:
> > + ----- Method: CompiledMethodWithNode>>node (in category 'accessing')
> -----
> > + node
> > + ^ node!
> >
> > Item was added:
> > + ----- Method: CompiledMethodWithNode>>node: (in category 'private')
> -----
> > + node: aMethodNode
> > + node := aMethodNode!
> >
> > Item was added:
> > + ----- Method: CompiledMethodWithNode>>selector (in category
> 'accessing') -----
> > + selector
> > + ^ self node selector!
> >
> > Item was added:
> > + Object subclass: #Compiler
> > + instanceVariableNames: 'parser cue'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> > +
> > + !Compiler commentStamp: 'cwp 12/26/2012 23:17' prior: 0!
> > + The compiler accepts Smalltalk source code and compiles it with
> respect to a given class. The user of the compiler supplies a context so
> that temporary variables are accessible during compilation. If there is an
> error, a requestor (usually a kind of StringHolderController) is sent the
> message notify:at:in: so that the error message can be displayed. If there
> is no error, then the result of compilation is a MethodNode, which is the
> root of a parse tree whose nodes are kinds of ParseNodes. The parse tree
> can be sent messages to (1) generate code for a CompiledMethod (this is
> done for compiling methods or evaluating expressions); (2) pretty-print the
> code (for formatting); or (3) produce a map from object code back to source
> code (used by debugger program-counter selection). See also Parser,
> Encoder, ParseNode.!
> >
> > Item was added:
> > + ----- Method: Compiler class>>couldEvaluate: (in category 'accessing')
> -----
> > + couldEvaluate: anObject
> > + "Answer true if anObject can be passed to my various #evaluate:
> methods."
> > + ^anObject isString or: [ anObject isText or: [ anObject isStream ]]!
> >
> > Item was added:
> > + ----- Method: Compiler class>>decompilerClass (in category
> 'accessing') -----
> > + decompilerClass
> > + ^Decompiler!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate: (in category 'evaluating')
> -----
> > + evaluate: textOrString
> > + "See Compiler|evaluate:for:notifying:logged:. If a compilation
> error occurs,
> > + a Syntax Error view is created rather than notifying any requestor.
> > + Compilation is carried out with respect to nil, i.e., no object,
> and the
> > + invocation is not logged."
> > +
> > + ^self evaluate: textOrString for: nil!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate:environment: (in category
> 'evaluating') -----
> > + evaluate: aString environment: anEnvironment
> > + ^ self new
> > + evaluateCue: (CompilationCue
> > + source: aString
> > + environment: anEnvironment)
> > + ifFail: [^ nil]!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate:environment:logged: (in
> category 'evaluating logged') -----
> > + evaluate: aString environment: anEnvironment logged: aBoolean
> > + ^ self new
> > + evaluateCue: (CompilationCue
> > + source: aString
> > + environment: anEnvironment)
> > + ifFail: [^ nil]
> > + logged: aBoolean!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate:for: (in category 'evaluating')
> -----
> > + evaluate: textOrString for: anObject
> > + "See Compiler|evaluate:for:notifying:. If a compilation error
> occurs,
> > + a Syntax Error view is created rather than notifying any requestor."
> > +
> > + ^self evaluate: textOrString for: anObject notifying: nil!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate:for:logged: (in category
> 'evaluating logged') -----
> > + evaluate: textOrString for: anObject logged: logFlag
> > + "See Compiler|evaluate:for:notifying:logged:. If a compilation
> error occurs,
> > + a Syntax Error view is created rather than notifying any requestor."
> > +
> > + ^self evaluate: textOrString for: anObject notifying: nil logged:
> logFlag!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate:for:notifying: (in category
> 'evaluating') -----
> > + evaluate: textOrString for: anObject notifying: aController
> > + "Compile and execute the argument, textOrString with respect to the
> class
> > + of anObject. If a compilation error occurs, notify aController."
> > +
> > + ^ self new
> > + evaluate: textOrString
> > + in: nil
> > + to: anObject
> > + notifying: aController
> > + ifFail: [^nil]!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate:for:notifying:logged: (in
> category 'evaluating logged') -----
> > + evaluate: textOrString for: anObject notifying: aController logged:
> logFlag
> > + "Compile and execute the argument, textOrString with respect to the
> class
> > + of anObject. If a compilation error occurs, notify aController. If
> both
> > + compilation and execution are successful then, if logFlag is true,
> log
> > + (write) the text onto a system changes file so that it can be
> replayed if
> > + necessary."
> > +
> > + ^ self new
> > + evaluate: textOrString
> > + in: nil
> > + to: anObject
> > + notifying: aController
> > + ifFail: [^nil]
> > + logged: logFlag.!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate:in:notifying:logged: (in
> category 'evaluating logged') -----
> > + evaluate: textOrString in: anEnvironment notifying: aController
> logged: logFlag
> > + "Compile and execute the argument, textOrString in anEnvironment.
> > + If a compilation error occurs, notify aController. If both
> > + compilation and execution are successful then, if logFlag is true,
> log
> > + (write) the text onto a system changes file so that it can be
> replayed if
> > + necessary."
> > +
> > + ^ self new
> > + evaluate: textOrString
> > + in: anEnvironment
> > + notifying: aController
> > + logged: logFlag.!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate:logged: (in category
> 'evaluating logged') -----
> > + evaluate: textOrString logged: logFlag
> > + "See Compiler|evaluate:for:notifying:logged:. If a compilation
> error occurs,
> > + a Syntax Error view is created rather than notifying any requestor.
> > + Compilation is carried out with respect to nil, i.e., no object."
> > +
> > + ^self evaluate: textOrString for: nil logged: logFlag!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate:notifying: (in category
> 'evaluating') -----
> > + evaluate: textOrString notifying: aController
> > + "See Compiler|evaluate:for:notifying:logged:. Compilation is
> carried out
> > + with respect to nil, i.e., no object."
> > +
> > + ^self evaluate: textOrString for: nil notifying: aController!
> >
> > Item was added:
> > + ----- Method: Compiler class>>evaluate:notifying:logged: (in category
> 'evaluating logged') -----
> > + evaluate: textOrString notifying: aController logged: logFlag
> > + "See Compiler|evaluate:for:notifying:logged:. Compilation is
> carried out
> > + with respect to nil, i.e., no object."
> > +
> > + ^self evaluate: textOrString for: nil notifying: aController
> logged: logFlag!
> >
> > Item was added:
> > + ----- Method: Compiler class>>format:in:notifying: (in category
> 'evaluating') -----
> > + format: textOrStream in: aClass notifying: aRequestor
> > + ^self new format: textOrStream in: aClass notifying: aRequestor!
> >
> > Item was added:
> > + ----- Method: Compiler class>>format:in:notifying:decorated: (in
> category 'evaluating') -----
> > + format: textOrStream in: aClass notifying: aRequestor decorated:
> aBoolean
> > + ^self new format: textOrStream in: aClass notifying: aRequestor
> decorated: aBoolean!
> >
> > Item was added:
> > + ----- Method: Compiler class>>initialize (in category 'class
> initialization') -----
> > + initialize
> > + "For the benefit of MC running a required script in the proper
> order."
> > + self recompileAll.!
> >
> > Item was added:
> > + ----- Method: Compiler class>>new (in category 'accessing') -----
> > + new
> > + ^ super new parser: self newParser!
> >
> > Item was added:
> > + ----- Method: Compiler class>>parserClass (in category 'accessing')
> -----
> > + parserClass
> > + "Answer a parser class to use for parsing methods compiled by
> instances of the receiver."
> > +
> > + ^Parser!
> >
> > Item was added:
> > + ----- Method: Compiler class>>recompileAll (in category 'utilities')
> -----
> > + recompileAll "Compiler recompileAll"
> > + "Recompile all classes and traits in the system.
> > + After recompilation invoke the postRecompileAction on any "
> > +
> > + | classesWithRecompileActions |
> > + classesWithRecompileActions := OrderedCollection new.
> > + Smalltalk allClassesAndTraits "This is unordered; I find that
> unsatisfactory and fragile, because
> > + if there is a bug it could be
> difficult to reproduce. eem 10/8/2019"
> > + do: [:classOrTrait |
> > + classOrTrait compileAll.
> > + (classOrTrait class includesSelector: #postRecompileAction)
> ifTrue:
> > + [classesWithRecompileActions addLast: classOrTrait]]
> > + displayingProgress:[:classOrTrait| 'Recompiling ',
> classOrTrait].
> > +
> > + classesWithRecompileActions do: [:classOrTrait| classOrTrait
> postRecompileAction]!
> >
> > Item was added:
> > + ----- Method: Compiler class>>recompileAllFrom: (in category
> 'utilities') -----
> > + recompileAllFrom: firstName
> > + "Recompile all classes, starting with given name."
> > + | classesWithRecompileActions |
> > + classesWithRecompileActions := OrderedCollection new.
> > +
> > + Smalltalk allClassesDo:
> > + [:class |
> > + class name >= firstName ifTrue:
> > + [Transcript show: class name; cr.
> > + class compileAll.
> > + (class class includesSelector: #postRecompileAction)
> ifTrue:
> > + [classesWithRecompileActions addLast: class]]].
> > +
> > + classesWithRecompileActions do:
> > + [:classOrTrait| classOrTrait postRecompileAction]
> > +
> > + "Compiler recompileAllFrom: 'AAABodyShop'"!
> >
> > Item was added:
> > + ----- Method: Compiler>>classForReceiver:context: (in category
> 'private') -----
> > + classForReceiver: receiver context: contextOrNil
> > + "Answer the class to compile in for a receiver and aContext.
> > + If aContext is non-nil use its receiver's class (if we use the
> context's
> > + methodClass we may exclude instance variables of the receiver).
> > + Access the class of the receiver via the mirror primitive to avoid
> issues with proxies."
> > +
> > + ^thisContext objectClass: (contextOrNil ifNil: [receiver] ifNotNil:
> [contextOrNil receiver])!
> >
> > Item was added:
> > + ----- Method: Compiler>>compile:ifFail: (in category 'public access')
> -----
> > + compile: aCue ifFail: failBlock
> > + "Answer a MethodNode. If the MethodNode can not be created, notify
> > + the requestor in the contxt. If the requestor is nil, evaluate
> failBlock
> > + instead. The MethodNode is the root of a parse tree. It can be
> told
> > + to generate a CompiledMethod to be installed in the method
> dictionary
> > + of the class specified by the context."
> > +
> > + ^self
> > + compileCue: aCue
> > + noPattern: false
> > + ifFail: failBlock !
> >
> > Item was added:
> > + ----- Method: Compiler>>compile:in:environment:notifying:ifFail: (in
> category 'public access') -----
> > + compile: textOrStream in: aClass environment: anEnvironment notifying:
> aRequestor ifFail: failBlock
> > + "Answer a MethodNode for the argument, textOrStream. If the
> > + MethodNode can not be created, notify the argument, aRequestor; if
> > + aRequestor is nil, evaluate failBlock instead. The MethodNode is
> the root
> > + of a parse tree. It can be told to generate a CompiledMethod to be
> > + installed in the method dictionary of the argument, aClass."
> > +
> > + ^self
> > + compileCue: (CompilationCue
> > + source: textOrStream
> > + class: aClass
> > + environment: anEnvironment
> > + requestor: aRequestor)
> > + noPattern: false
> > + ifFail: failBlock
> > + !
> >
> > Item was added:
> > + ----- Method: Compiler>>compile:in:notifying:ifFail: (in category
> 'public access') -----
> > + compile: textOrStream in: aClass notifying: aRequestor ifFail:
> failBlock
> > + "Answer a MethodNode for the argument, textOrStream. If the
> > + MethodNode can not be created, notify the argument, aRequestor; if
> > + aRequestor is nil, evaluate failBlock instead. The MethodNode is
> the root
> > + of a parse tree. It can be told to generate a CompiledMethod to be
> > + installed in the method dictionary of the argument, aClass."
> > +
> > + ^self
> > + compileCue: (CompilationCue
> > + source: textOrStream
> > + class: aClass
> > + requestor: aRequestor)
> > + noPattern: false
> > + ifFail: failBlock
> > + !
> >
> > Item was added:
> > + ----- Method: Compiler>>compileCue:noPattern:ifFail: (in category
> 'private') -----
> > + compileCue: aCue noPattern: aBoolean ifFail: failBlock
> > + "Answer a MethodNode corresponding to cue source.
> > + If the MethodNode can not be created, notify the cue requestor.
> > + If the cue requestor is nil, evaluate failBlock instead.
> > + The MethodNode is the root of a parse tree.
> > + It can be told to generate a CompiledMethod
> > + - either to be evaluated in cue context if aBoolean is true, with
> cue receiver as method receiver,
> > + - or to be installed in the method dictionary of the target class
> specified by the cue if aBoolean is false."
> > +
> > + self setCue: aCue.
> > + ^self translateNoPattern: aBoolean ifFail: failBlock!
> >
> > Item was added:
> > + ----- Method:
> Compiler>>compileNoPattern:in:context:environment:notifying:ifFail: (in
> category 'public access') -----
> > + compileNoPattern: textOrStream in: aClass context: aContext
> environment: anEnvironment notifying: aRequestor ifFail: failBlock
> > + "Similar to #compile:in:notifying:ifFail:, but the compiled code is
> > + expected to be a do-it expression, with no message pattern,
> > + and it will be in an explicit environment."
> > +
> > + ^self
> > + compileCue: (CompilationCue
> > + source: textOrStream
> > + context: aContext
> > + class: aClass
> > + environment: anEnvironment
> > + requestor: aRequestor)
> > + noPattern: true
> > + ifFail: failBlock
> > + !
> >
> > Item was added:
> > + ----- Method: Compiler>>compileNoPattern:in:context:notifying:ifFail:
> (in category 'public access') -----
> > + compileNoPattern: textOrStream in: aClass context: aContext notifying:
> aRequestor ifFail: failBlock
> > + "Similar to #compile:in:notifying:ifFail:, but the compiled code is
> > + expected to be a do-it expression, with no message pattern."
> > +
> > + ^self
> > + compileCue: (CompilationCue
> > + source: textOrStream
> > + context: aContext
> > + class: aClass
> > + requestor: aRequestor)
> > + noPattern: true
> > + ifFail: failBlock
> > + !
> >
> > Item was added:
> > + ----- Method: Compiler>>compileNoPattern:in:notifying:ifFail: (in
> category 'public access') -----
> > + compileNoPattern: textOrStream in: aClass notifying: aRequestor
> ifFail: failBlock
> > + "Similar to #compile:in:notifying:ifFail:, but the compiled code is
> > + expected to be a do-it expression, with no message pattern."
> > +
> > + ^self
> > + compileCue: (CompilationCue
> > + source: textOrStream
> > + class: aClass
> > + requestor: aRequestor)
> > + noPattern: true
> > + ifFail: failBlock
> > + !
> >
> > Item was added:
> > + ----- Method: Compiler>>compiledMethodFor:in:to:notifying:ifFail: (in
> category 'public access') -----
> > + compiledMethodFor: textOrStream in: aContext to: receiver notifying:
> aRequestor ifFail: failBlock
> > + "Compiles the sourceStream into a parse tree, then generates code
> > + into a method, and answers it. If receiver is not nil, then the
> text can
> > + refer to instance variables of that receiver (the Inspector uses
> this).
> > + If aContext is not nil, the text can refer to temporaries in that
> context
> > + (the Debugger uses this). If aRequestor is not nil, then it will
> receive a
> > + notify:at: message before the attempt to evaluate is aborted."
> > +
> > + | methodNode method |
> > + methodNode := self
> > + compileNoPattern: textOrStream
> > + in: (self classForReceiver: receiver context: aContext)
> > + context: aContext
> > + notifying: aRequestor
> > + ifFail: [^failBlock value].
> > + method := self interactive
> > + ifTrue: [ methodNode generateWithTempNames ]
> > + ifFalse: [ methodNode generate ].
> > + ^method!
> >
> > Item was added:
> > + ----- Method:
> Compiler>>compiledMethodFor:in:to:notifying:ifFail:logged: (in category
> 'public access logging') -----
> > + compiledMethodFor: textOrStream in: aContext to: receiver notifying:
> aRequestor ifFail: failBlock logged: logFlag
> > + "Compiles the sourceStream into a parse tree, then generates code
> > + into a method, and answers it. If receiver is not nil, then the
> text can
> > + refer to instance variables of that receiver (the Inspector uses
> this).
> > + If aContext is not nil, the text can refer to temporaries in that
> context
> > + (the Debugger uses this). If aRequestor is not nil, then it will
> receive a
> > + notify:at: message before the attempt to evaluate is aborted."
> > +
> > + | method |
> > + method := self
> > + compiledMethodFor: textOrStream
> > + in: aContext
> > + to: receiver
> > + notifying: aRequestor
> > + ifFail: [^failBlock value].
> > + logFlag ifTrue:
> > + [SystemChangeNotifier uniqueInstance evaluated: cue stringToLog
> context: aContext].
> > + ^method!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate: (in category 'public access') -----
> > + evaluate: textOrString
> > + "See evaluate:for:notifying:logged:. If a compilation error occurs,
> > + a Syntax Error view is created rather than notifying any requestor.
> > + Compilation is carried out with respect to nil, i.e., no object,
> and the
> > + invocation is not logged."
> > +
> > + ^self evaluate: textOrString for: nil!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:for: (in category 'public access')
> -----
> > + evaluate: textOrString for: anObject
> > + "See evaluate:for:notifying:logged:. If a compilation error occurs,
> > + a Syntax Error view is created rather than notifying any requestor."
> > +
> > + ^self evaluate: textOrString for: anObject notifying: nil!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:for:logged: (in category 'public
> access logging') -----
> > + evaluate: textOrString for: anObject logged: logFlag
> > + "See evaluate:for:notifying:logged:. If a compilation error occurs,
> > + a Syntax Error view is created rather than notifying any requestor."
> > +
> > + ^self evaluate: textOrString for: anObject notifying: nil logged:
> logFlag!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:for:notifying: (in category 'public
> access') -----
> > + evaluate: textOrString for: anObject notifying: aController
> > + "Compile and execute the argument, textOrString with respect to the
> class
> > + of anObject. If a compilation error occurs, notify aController."
> > +
> > + ^ self
> > + evaluate: textOrString
> > + in: nil
> > + to: anObject
> > + notifying: aController
> > + ifFail: [^nil]!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:for:notifying:logged: (in category
> 'public access logging') -----
> > + evaluate: textOrString for: anObject notifying: aController logged:
> logFlag
> > + "Compile and execute the argument, textOrString with respect to the
> class
> > + of anObject. If a compilation error occurs, notify aController. If
> both
> > + compilation and execution are successful then, if logFlag is true,
> log
> > + (write) the text onto a system changes file so that it can be
> replayed if
> > + necessary."
> > +
> > + ^ self
> > + evaluate: textOrString
> > + in: nil
> > + to: anObject
> > + notifying: aController
> > + ifFail: [^nil]
> > + logged: logFlag.!
> >
> > Item was added:
> > + ----- Method:
> Compiler>>evaluate:in:environment:notifying:ifFail:logged: (in category
> 'public access logging') -----
> > + evaluate: textOrStream in: aContext environment: anEnvironment
> notifying: aRequestor ifFail: failBlock logged: logFlag
> > + "Compiles the sourceStream into a parse tree, then generates code
> into
> > + a method. If aContext is not nil, the text can refer to
> temporaries in that
> > + context (the Debugger uses this). If aRequestor is not nil, then
> it will receive
> > + a notify:at: message before the attempt to evaluate is aborted.
> Finally, the
> > + compiled method is invoked from here via withArgs:executeMethod:,
> hence
> > + the system no longer creates Doit method litter on errors."
> > + ^self
> > + evaluateCue: (CompilationCue
> > + source: textOrStream
> > + context: aContext
> > + receiver: nil
> > + class: UndefinedObject
> > + environment: anEnvironment
> > + requestor: aRequestor)
> > + ifFail: failBlock
> > + logged: logFlag!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:in:notifying:logged: (in category
> 'public access logging') -----
> > + evaluate: textOrString in: anEnvironment notifying: aController
> logged: logFlag
> > + "Compile and execute the argument, textOrString in anEnvironment.
> > + If a compilation error occurs, notify aController. If both
> > + compilation and execution are successful then, if logFlag is true,
> log
> > + (write) the text onto a system changes file so that it can be
> replayed if
> > + necessary."
> > +
> > + ^self
> > + evaluate: textOrString
> > + in: nil
> > + environment: anEnvironment
> > + notifying: aController
> > + ifFail: [^nil]
> > + logged: logFlag!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:in:to: (in category 'public access')
> -----
> > + evaluate: aString in: aContext to: aReceiver
> > + "evaluate aString in the given context, and return the result.
> 2/2/96 sw"
> > + ^self
> > + evaluate: aString
> > + in: aContext
> > + to: aReceiver
> > + notifying: nil
> > + ifFail: [^ #failedDoit]!
> >
> > Item was added:
> > + ----- Method:
> Compiler>>evaluate:in:to:environment:notifying:ifFail:logged: (in category
> 'public access logging') -----
> > + evaluate: textOrStream in: aContext to: receiver environment:
> anEnvironment notifying: aRequestor ifFail: failBlock logged: logFlag
> > + "Same as #evaluate:in:to:notifying:ifFail:logged: but with an
> explicit environment"
> > + ^self
> > + evaluateCue: (CompilationCue
> > + source: textOrStream
> > + context: aContext
> > + receiver: receiver
> > + class: (self classForReceiver: receiver context: aContext)
> > + environment: anEnvironment
> > + requestor: aRequestor)
> > + ifFail: failBlock
> > + logged: logFlag!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:in:to:notifying:ifFail: (in category
> 'public access') -----
> > + evaluate: textOrStream in: aContext to: receiver notifying: aRequestor
> ifFail: failBlock
> > + "Compiles the sourceStream into a parse tree, then generates code
> into
> > + a method. If aContext is not nil, the text can refer to
> temporaries in that
> > + context (the Debugger uses this). If aRequestor is not nil, then
> it will receive
> > + a notify:at: message before the attempt to evaluate is aborted.
> Finally, the
> > + compiled method is invoked from here via withArgs:executeMethod:,
> hence
> > + the system no longer creates Doit method litter on errors."
> > +
> > + | theClass |
> > + theClass := self classForReceiver: receiver context: aContext.
> > + ^self
> > + evaluateCue: (CompilationCue
> > + source: textOrStream
> > + context: aContext
> > + receiver: receiver
> > + class: theClass
> > + environment: theClass environment
> > + requestor: aRequestor)
> > + ifFail: failBlock!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:in:to:notifying:ifFail:logged: (in
> category 'public access logging') -----
> > + evaluate: textOrStream in: aContext to: receiver notifying: aRequestor
> ifFail: failBlock logged: logFlag
> > + "Compiles the sourceStream into a parse tree, then generates code
> into
> > + a method. If aContext is not nil, the text can refer to
> temporaries in that
> > + context (the Debugger uses this). If aRequestor is not nil, then
> it will receive
> > + a notify:at: message before the attempt to evaluate is aborted.
> Finally, the
> > + compiled method is invoked from here via withArgs:executeMethod:,
> hence
> > + the system no longer creates Doit method litter on errors."
> > + | theClass |
> > + theClass := self classForReceiver: receiver context: aContext.
> > + ^self
> > + evaluateCue: (CompilationCue
> > + source: textOrStream
> > + context: aContext
> > + receiver: receiver
> > + class: theClass
> > + environment: theClass environment
> > + requestor: aRequestor)
> > + ifFail: failBlock
> > + logged: logFlag!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:logged: (in category 'public access
> logging') -----
> > + evaluate: textOrString logged: logFlag
> > + "See evaluate:for:notifying:logged:. If a compilation error occurs,
> > + a Syntax Error view is created rather than notifying any requestor.
> > + Compilation is carried out with respect to nil, i.e., no object."
> > +
> > + ^self evaluate: textOrString for: nil logged: logFlag!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:notifying: (in category 'public
> access') -----
> > + evaluate: textOrString notifying: aController
> > + "See evaluate:for:notifying:. Compilation is carried out
> > + with respect to nil, i.e., no object."
> > +
> > + ^self evaluate: textOrString for: nil notifying: aController!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluate:notifying:logged: (in category
> 'public access logging') -----
> > + evaluate: textOrString notifying: aController logged: logFlag
> > + "See evaluate:for:notifying:logged:. Compilation is carried out
> > + with respect to nil, i.e., no object."
> > +
> > + ^self evaluate: textOrString for: nil notifying: aController
> logged: logFlag!
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluateCue:ifFail: (in category 'private')
> -----
> > + evaluateCue: aCue ifFail: failBlock
> > + "Compiles the cue source into a parse tree, then generates code into
> > + a method. Finally, the compiled method is invoked from here via
> withArgs:executeMethod:, hence the system no longer creates Doit method
> > + litter on errors."
> > +
> > + | methodNode method value |
> > + methodNode := self compileCue: aCue noPattern: true ifFail:
> [^failBlock value].
> > +
> > + method := self interactive
> > + ifTrue: [methodNode generateWithTempNames]
> > + ifFalse: [methodNode generate].
> > +
> > + value := cue receiver
> > + withArgs: (cue context ifNil: [#()] ifNotNil: [{cue
> context}])
> > + executeMethod: method.
> > + ^ value
> > + !
> >
> > Item was added:
> > + ----- Method: Compiler>>evaluateCue:ifFail:logged: (in category
> 'private') -----
> > + evaluateCue: aCue ifFail: failBlock logged: logFlag
> > + "Compiles the cue source into a parse tree, then generates code into
> > + a method. Finally, the compiled method is invoked from here via
> withArgs:executeMethod:, hence the system no longer creates Doit method
> > + litter on errors."
> > +
> > + | value |
> > + value := self evaluateCue: aCue ifFail: [^failBlock value].
> > + logFlag ifTrue:
> > + [SystemChangeNotifier uniqueInstance evaluated: cue stringToLog
> context: cue context].
> > + ^ value
> > + !
> >
> > Item was added:
> > + ----- Method: Compiler>>format:in:notifying: (in category 'public
> access') -----
> > + format: textOrStream in: aClass notifying: aRequestor
> > + "Compile a parse tree from the argument, textOrStream. Answer a
> string containing the original code, formatted nicely. If aBoolean is
> true, then decorate the resulting text with color and hypertext actions"
> > +
> > + | aNode |
> > + self from: textOrStream
> > + class: aClass
> > + notifying: aRequestor.
> > + aNode := self formatNoPattern: false ifFail: [^ nil].
> > +
> > + "aSymbol == #colorPrint ifTrue:
> > + [^aNode asColorizedSmalltalk80Text]." "deprecating #colorPrint
> in favor of Shout --Ron Spengler"
> > +
> > + ^aNode decompileString!
> >
> > Item was added:
> > + ----- Method: Compiler>>format:in:notifying:decorated: (in category
> 'public access') -----
> > + format: textOrStream in: aClass notifying: aRequestor decorated:
> aBoolean
> > + "Compile a parse tree from the argument, textOrStream. Answer a
> string containing the original code, formatted nicely. If aBoolean is
> true, then decorate the resulting text with color and hypertext actions"
> > + | aNode |
> > + self from: textOrStream
> > + class: aClass
> > + notifying: aRequestor.
> > + aNode := self formatNoPattern: false ifFail: [^ nil].
> > + ^ aBoolean
> > + ifTrue: [aNode decompileText]
> > + ifFalse: [aNode decompileString]!
> >
> > Item was added:
> > + ----- Method: Compiler>>formatNoPattern:environment: (in category
> 'public access') -----
> > + formatNoPattern: textOrStream environment: env
> > + "Pretty-print a code snippet. Removes leading 'DoIt' and the '^' in
> the last statement. To be used in workspace-like tools."
> > +
> > + | aNode |
> > + self setCue: (CompilationCue
> > + source: textOrStream
> > + environment: env).
> > +
> > + aNode := self formatNoPattern: true ifFail: [^ nil].
> > +
> > + ^ (aNode decompileString lines allButFirst "DoIt" collect: [:ea |
> > + ea allButFirst "tab" in: [:result | (result beginsWith: '^ ')
> ifTrue: [result allButFirst: 2] ifFalse: [result]]])
> > + joinSeparatedBy: String cr!
> >
> > Item was added:
> > + ----- Method: Compiler>>formatNoPattern:ifFail: (in category
> 'private') -----
> > + formatNoPattern: noPattern ifFail: failBlock
> > + ^(self parser
> > + parseCue: cue
> > + noPattern: noPattern
> > + ifFail: [^failBlock value]) preen!
> >
> > Item was added:
> > + ----- Method: Compiler>>from:class:notifying: (in category 'private')
> -----
> > + from: textOrStream class: aClass notifying: req
> > + self setCue:
> > + (CompilationCue
> > + source: textOrStream
> > + class: aClass
> > + requestor: req)
> > + !
> >
> > Item was added:
> > + ----- Method: Compiler>>interactive (in category 'private') -----
> > + interactive
> > + "The compilation is interactive if there is a requestor and that
> requestor does either not care or explicitly allow interactive error
> correction."
> > +
> > + ^ cue requestor notNil
> > + and: [(cue requestor respondsTo:
> #wantsInteractiveErrorCorrection) not
> > + or: [cue requestor perform:
> #wantsInteractiveErrorCorrection]]!
> >
> > Item was added:
> > + ----- Method: Compiler>>parse:in:notifying: (in category 'public
> access') -----
> > + parse: textOrStream in: aClass notifying: req
> > + "Compile the argument, textOrStream, with respect to the class,
> aClass, and
> > + answer the MethodNode that is the root of the resulting parse
> tree. Notify the
> > + argument, req, if an error occurs. The failBlock is defaulted to
> an empty block."
> > +
> > + self from: textOrStream class: aClass notifying: req.
> > + ^self parser
> > + parseCue: cue
> > + noPattern: false
> > + ifFail: []!
> >
> > Item was added:
> > + ----- Method: Compiler>>parser (in category 'public access') -----
> > + parser
> > +
> > + parser ifNil: [parser := (cue getClass ifNil: [self class])
> newParser].
> > + ^parser!
> >
> > Item was added:
> > + ----- Method: Compiler>>parser: (in category 'public access') -----
> > + parser: aParser
> > +
> > + parser := aParser!
> >
> > Item was added:
> > + ----- Method: Compiler>>parserClass: (in category 'public access')
> -----
> > + parserClass: aParserClass
> > +
> > + parser := aParserClass new!
> >
> > Item was added:
> > + ----- Method: Compiler>>setCue: (in category 'private') -----
> > + setCue: aCue
> > + cue := aCue!
> >
> > Item was added:
> > + ----- Method: Compiler>>translate:noPattern:ifFail: (in category
> 'private') -----
> > + translate: ignored noPattern: noPattern ifFail: failBlock
> > + ^self translateNoPattern: noPattern ifFail: failBlock!
> >
> > Item was added:
> > + ----- Method: Compiler>>translate:noPattern:ifFail:parser: (in
> category 'public access') -----
> > + translate: aStream noPattern: noPattern ifFail: failBlock parser:
> parser
> > + | tree |
> > + tree := parser
> > + parseCue: cue
> > + noPattern: noPattern
> > + ifFail: [^ failBlock value].
> > + ^ tree!
> >
> > Item was added:
> > + ----- Method: Compiler>>translateNoPattern:ifFail: (in category
> 'private') -----
> > + translateNoPattern: noPattern ifFail: failBlock
> > + ^self parser
> > + parseCue: cue
> > + noPattern: noPattern
> > + ifFail: [^failBlock value]!
> >
> > Item was added:
> > + InstructionStream subclass: #Decompiler
> > + instanceVariableNames: 'constructor method instVars tempVars
> constTable stack statements lastPc exit caseExits lastJumpPc lastReturnPc
> limit hasValue blockStackBase numLocalTemps blockStartsToTempVars
> tempVarCount lastJumpIfPcStack tempReadCounts'
> > + classVariableNames: 'ArgumentFlag CascadeFlag CaseFlag IfNilFlag
> OtherwiseFlag'
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> > +
> > + !Decompiler commentStamp: 'nice 2/3/2011 22:54' prior: 0!
> > + I decompile a method in three phases:
> > + Reverser: postfix byte codes -> prefix symbolic codes (nodes and
> atoms)
> > + Parser: prefix symbolic codes -> node tree (same as the compiler)
> > + Printer: node tree -> text (done by the nodes)
> > +
> > +
> > + instance vars:
> > +
> > + constructor <DecompilerConstructor> an auxiliary knowing how to
> generate Abstract Syntax Tree (node tree)
> > + method <CompiledMethod> the method being decompiled
> > + instVars <Array of: String> the instance variables of the class
> implementing method
> > + tempVars <String | (OrderedCollection of: String)> hold the names
> of temporary variables (if known)
> > + NOTE: POLYMORPHISM WILL BE RESOLVED IN #initSymbols:
> > + constTable <Collection of: ParseNode> parse node associated with
> byte encoded constants (nil true false 0 1 -1 etc...)
> > + stack <OrderedCollection of: (ParseNode | String | Integer) >
> multipurpose...
> > + statements <OrderedCollection of: ParseNode> the statements of the
> method being decompiled
> > + lastPc <Integer>
> > + exit <Integer>
> > + caseExits <OrderedCollection of: Integer> - stack of exit addresses
> that have been seen in the branches of caseOf:'s
> > + lastJumpPc <Integer>
> > + lastReturnPc <Integer>
> > + limit <Integer>
> > + hasValue <Boolean>
> > + blockStackBase <Integer>
> > + numLocaltemps <Integer | Symbol> - number of temps local to a
> block; also a flag indicating decompiling a block
> > + blockStartsToTempVars <Dictionary key: Integer value:
> (OrderedCollection of: String)>
> > + tempVarCount <Integer> number of temp vars used by the method
> > + lastJumpIfPcStack <OrderedCollection of: Integer> the value of
> program counter just before the last encountered conditional jumps!
> >
> > Item was added:
> > + ----- Method: Decompiler class>>initialize (in category 'class
> initialization') -----
> > + initialize
> > +
> > + CascadeFlag := 'cascade'. "A unique object"
> > + CaseFlag := 'case'. "Ditto"
> > + OtherwiseFlag := 'otherwise'. "Ditto"
> > + ArgumentFlag := 'argument'. "Ditto"
> > + IfNilFlag := 'ifNil'. "Ditto"
> > +
> > + "Decompiler initialize"!
> >
> > Item was added:
> > + ----- Method: Decompiler>>blockForCaseTo: (in category 'control') -----
> > + blockForCaseTo: end
> > + "Decompile a range of code as in statementsForCaseTo:, but return a
> block node."
> > + | exprs block oldBase |
> > + oldBase := blockStackBase.
> > + blockStackBase := stack size.
> > + exprs := self statementsForCaseTo: end.
> > + block := constructor codeBlock: exprs returns: lastReturnPc =
> lastPc.
> > + blockStackBase := oldBase.
> > + lastReturnPc := -1. "So as not to mislead outer calls"
> > + ^block!
> >
> > Item was added:
> > + ----- Method: Decompiler>>blockReturnConstant: (in category
> 'instruction decoding') -----
> > + blockReturnConstant: value
> > +
> > + self pushConstant: value; blockReturnTop!
> >
> > Item was added:
> > + ----- Method: Decompiler>>blockReturnTop (in category 'instruction
> decoding') -----
> > + blockReturnTop
> > + "No action needed"!
> >
> > Item was added:
> > + ----- Method: Decompiler>>blockTo: (in category 'control') -----
> > + blockTo: end
> > + "Decompile a range of code as in statementsTo:, but return a block
> node. NB: end is an exclusive index."
> > + | exprs block oldBase lastStatementOfBlockIsNil |
> > + oldBase := blockStackBase.
> > + blockStackBase := stack size.
> > + exprs := self statementsTo: end.
> > + lastStatementOfBlockIsNil := pc < method endPC and: [exprs notEmpty
> and: [exprs last == (constTable at: 4)]].
> > + lastStatementOfBlockIsNil ifTrue:
> > + [exprs := exprs allButLast].
> > + block := constructor codeBlock: exprs returns: lastReturnPc =
> lastPc.
> > + blockStackBase := oldBase.
> > + lastReturnPc := -1. "So as not to mislead outer calls"
> > + ^block!
> >
> > Item was added:
> > + ----- Method: Decompiler>>case: (in category 'instruction decoding')
> -----
> > + case: dist
> > + "statements = keyStmts CascadeFlag keyValueBlock ... keyStmts"
> > +
> > + | nextCase thenJump stmtStream elements b node cases otherBlock
> myExits |
> > + nextCase := pc + dist.
> > +
> > + "Now add CaseFlag & keyValueBlock to statements"
> > + statements addLast: stack removeLast.
> > + "Trick: put a flag on the stack.
> > + If it is the last case before otherwise: block, then
> > + - there won't be a dup of caseOf: receiver before sending =
> > + - there won't be a pop in the case handling block"
> > + stack addLast: OtherwiseFlag. "set for next pop"
> > + statements addLast: (self blockForCaseTo: nextCase).
> > +
> > + stack last == OtherwiseFlag
> > + ifTrue: "Last case"
> > + ["ensure jump is within block (in case thenExpr returns
> wierdly I guess)"
> > + stack removeLast. "get rid of CaseFlag"
> > + stmtStream := ReadStream on: (self popTo: stack removeLast).
> > +
> > + elements := OrderedCollection new.
> > + b := OrderedCollection new.
> > + [stmtStream atEnd] whileFalse:
> > + [(node := stmtStream next) == CaseFlag
> > + ifTrue:
> > + [elements addLast: (constructor
> > + codeMessage: (constructor codeBlock: b
> returns: false)
> > + selector: (constructor codeSelector: #->
> code: #macro)
> > + arguments: (Array with: stmtStream next)).
> > + b := OrderedCollection new]
> > + ifFalse: [b addLast: node]].
> > + b size > 0 ifTrue: [self error: 'Bad cases'].
> > + cases := constructor codeBrace: elements.
> > +
> > + "try find the end of the case"
> > + myExits := caseExits removeLast: elements size.
> > + myExits := myExits reject: [ :e | e isNil or: [ e < 0 or: [
> e > method endPC ] ] ].
> > + thenJump := myExits isEmpty
> > + ifTrue: [ nextCase ]
> > + ifFalse: [ myExits max ].
> > +
> > + otherBlock := self blockTo: thenJump.
> > + stack addLast:
> > + (constructor
> > + codeMessage: stack removeLast
> > + selector: (constructor codeSelector:
> #caseOf:otherwise: code: #macro)
> > + arguments: (Array with: cases with: otherBlock))].!
> >
> > Item was added:
> > + ----- Method: Decompiler>>checkForClosureCopy:arguments: (in category
> 'control') -----
> > + checkForClosureCopy: receiver arguments: arguments
> > + "We just saw a closureCopy:copiedValues: message. Check for and
> construct a following block."
> > +
> > + | savePc jump |
> > + receiver == constructor codeThisContext ifFalse: [^false].
> > + savePc := pc.
> > + (jump := self interpretJump) notNil ifFalse:
> > + [pc := savePc.
> > + ^nil].
> > + "Definitely a block"
> > + self doClosureCopyCopiedValues: arguments last "<BraceNode>"
> elements
> > + numArgs: arguments first key
> > + blockSize: jump.
> > + ^true!
> >
> > Item was added:
> > + ----- Method: Decompiler>>constructorForMethod: (in category
> 'private') -----
> > + constructorForMethod: aMethod
> > + ^DecompilerConstructor new!
> >
> > Item was added:
> > + ----- Method: Decompiler>>convertToDoLoop: (in category 'private')
> -----
> > + convertToDoLoop: blockBodyTempCounts
> > + "If statements contains the pattern
> > + var := startExpr.
> > + [var <= limit] whileTrue: [...statements... var := var +
> incConst]
> > + or
> > + var := startExpr.
> > + limit := limitExpr.
> > + [var <= limit] whileTrue: [...statements... var := var +
> incConst]
> > + then replace this by
> > + startExpr to: limit by: incConst do: [:var | ...statements...]
> > + and answer true."
> > + | whileStmt incrStmt initStmt limitStmt toDoStmt |
> > + whileStmt := statements last.
> > + incrStmt := whileStmt arguments first statements last.
> > + incrStmt isAssignmentNode ifFalse:
> > + [^false].
> > + (self startAndLimitFor: incrStmt variable from: stack into:
> > + [:startExpr :limitExpr| initStmt :=
> startExpr. limitStmt := limitExpr])
> > + ifTrue:
> > + [| limitInStatements |
> > + limitInStatements := limitStmt isNil
> > + and: [statements size > 1
> > + and: [self startAndLimitFor:
> incrStmt variable from: { stack last. (statements last: 2) first } into:
> > + [:startExpr :limitExpr|
> limitStmt := limitExpr]]].
> > + (toDoStmt := statements last toDoFromWhileWithCounts:
> blockBodyTempCounts init: initStmt limit: limitStmt) ifNil:
> > + [^false].
> > + limitInStatements
> > + ifTrue:
> > + [stack
> > + removeLast;
> > + addLast: toDoStmt.
> > + statements removeLast: 2]
> > + ifFalse:
> > + [stack
> > + removeLast: (limitStmt ifNil: [1] ifNotNil:
> [2]);
> > + addLast: toDoStmt.
> > + statements removeLast]]
> > + ifFalse:
> > + [(self startAndLimitFor: incrStmt variable from: statements
> allButLast into:
> > + [:startExpr :limitExpr| initStmt :=
> startExpr. limitStmt := limitExpr]) ifFalse:
> > + [^false].
> > + (toDoStmt := statements last toDoFromWhileWithCounts:
> blockBodyTempCounts init: initStmt limit: limitStmt) ifNil:
> > + [^false].
> > + statements
> > + removeLast: (limitStmt ifNil: [2] ifNotNil: [3]);
> > + addLast: toDoStmt].
> > + self markTemp: initStmt variable asOutOfScope: -1. "Flag arg as out
> of scope"
> > + initStmt variable beBlockArg.
> > + limitStmt ifNotNil:
> > + [self markTemp: limitStmt variable asOutOfScope: -2.
> > + toDoStmt arguments at: 1 put: limitStmt value]. "Flag limit as
> hidden"
> > + ^true!
> >
> > Item was added:
> > + ----- Method: Decompiler>>decompile:in: (in category 'public access')
> -----
> > + decompile: aSelector in: aClass
> > + "See Decompiler|decompile:in:method:. The method is found by
> looking up
> > + the message, aSelector, in the method dictionary of the class,
> aClass."
> > +
> > + ^self
> > + decompile: aSelector
> > + in: aClass
> > + method: (aClass compiledMethodAt: aSelector) methodForDecompile!
> >
> > Item was added:
> > + ----- Method: Decompiler>>decompile:in:method: (in category 'public
> access') -----
> > + decompile: aSelector in: aClass method: aMethod
> > + "Answer a MethodNode that is the root of the parse tree for the
> > + argument, aMethod, which is the CompiledMethod associated with the
> > + message, aSelector. Variables are determined with respect to the
> > + argument, aClass."
> > +
> > + ^self
> > + decompile: aSelector
> > + in: aClass
> > + method: aMethod
> > + using: (self constructorForMethod: aMethod)!
> >
> > Item was added:
> > + ----- Method: Decompiler>>decompile:in:method:using: (in category
> 'public access') -----
> > + decompile: aSelector in: aClass method: aMethod using: aConstructor
> > +
> > + | block node |
> > + constructor := aConstructor.
> > + method := aMethod.
> > + self initSymbols: aClass. "create symbol tables"
> > + method isQuick
> > + ifTrue: [block := self quickMethod]
> > + ifFalse:
> > + [stack := OrderedCollection new: method frameSize.
> > + lastJumpIfPcStack := OrderedCollection new.
> > + caseExits := OrderedCollection new.
> > + statements := OrderedCollection new: 20.
> > + numLocalTemps := 0.
> > + self method: method pc: method initialPC.
> > + "skip primitive error code store if necessary"
> > + (method primitive ~= 0 and: [self skipCallPrimitive;
> willStore]) ifTrue:
> > + [pc := pc + (method encoderClass bytecodeSize: self
> firstByte).
> > + tempVars := tempVars asOrderedCollection].
> > + block := self blockTo: method endPC + 1.
> > + stack isEmpty ifFalse: [self error: 'stack not empty']].
> > + node := constructor
> > + codeMethod: aSelector
> > + block: block
> > + tempVars: tempVars
> > + primitive: method primitive
> > + class: aClass.
> > + method primitive > 0 ifTrue:
> > + [node removeAndRenameLastTempIfErrorCode].
> > + ^node preen!
> >
> > Item was added:
> > + ----- Method: Decompiler>>decompileBlock: (in category 'public
> access') -----
> > + decompileBlock: aBlock
> > + "Decompile aBlock, returning the result as a BlockNode.
> > + Show temp names from source if available."
> > + "Decompiler new decompileBlock: [3 + 4]"
> > + "[3 + 4] decompile decompileString"
> > + aBlock method decompileWithTemps
> > + ifNil: [^nil]
> > + ifNotNil:
> > + [:methodNode|
> > + methodNode nodesDo:
> > + (aBlock isFullBlock
> > + ifTrue: [[:node| (node pc isVariableBinding and:
> [node pc key == aBlock method]) ifTrue: [^node]]]
> > + ifFalse: [[:node| node pc = aBlock startpc ifTrue:
> [^node]]])].
> > + ^self error: 'cannot find block node matching aBlock'!
> >
> > Item was added:
> > + ----- Method: Decompiler>>directedSuperSend:numArgs: (in category
> 'instruction decoding') -----
> > + directedSuperSend: selector numArgs: numArgs
> > + stack removeLast. "Discard the pushed class."
> > + ^self send: selector super: true numArgs: numArgs!
> >
> > Item was added:
> > + ----- Method: Decompiler>>doClosureCopy:copiedValues: (in category
> 'control') -----
> > + doClosureCopy: aCompiledBlock copiedValues: blockCopiedValues
> > + "implementation note: must be invoked on a copy because it modifies
> states"
> > + | savedPC blockArgs blockTemps blockTempsOffset block mark |
> > + numLocalTemps := aCompiledBlock numTemps - aCompiledBlock numArgs -
> blockCopiedValues size.
> > + blockTempsOffset := aCompiledBlock numArgs + blockCopiedValues size.
> > + (blockStartsToTempVars notNil "implies we were intialized with temp
> names."
> > + and: [blockStartsToTempVars includesKey: aCompiledBlock])
> > + ifTrue:
> > + [tempVars := blockStartsToTempVars at: aCompiledBlock]
> > + ifFalse:
> > + [blockArgs := (1 to: aCompiledBlock numArgs) collect:
> > + [:i| (constructor
> > + codeTemp: i - 1
> > + named: 't', (tempVarCount + i)
> printString)
> > + beBlockArg].
> > + blockTemps := (1 to: numLocalTemps) collect:
> > + [:i| constructor
> > + codeTemp: i + blockTempsOffset - 1
> > + named: 't', (tempVarCount + i +
> aCompiledBlock numArgs) printString].
> > + tempVars := blockArgs, blockCopiedValues, blockTemps].
> > + tempVarCount := tempVarCount + aCompiledBlock numArgs +
> numLocalTemps.
> > + lastJumpIfPcStack := OrderedCollection new.
> > + caseExits := OrderedCollection new.
> > + statements := OrderedCollection new: 20.
> > + savedPC := pc.
> > + self method: (method := aCompiledBlock) pc: aCompiledBlock
> initialPC.
> > + mark := stack size.
> > + block := self blockTo: aCompiledBlock endPC + 1.
> > + mark = stack size ifFalse: [self error: 'block did alter the
> stack'].
> > + ^((constructor
> > + codeArguments: (tempVars copyFrom: 1 to: aCompiledBlock
> numArgs)
> > + temps: (tempVars copyFrom: blockTempsOffset + 1 to:
> blockTempsOffset + numLocalTemps)
> > + block: block)
> > + pc: aCompiledBlock -> savedPC; "c.f.
> BytecodeEncoder>>pc"
> > + yourself).!
> >
> > Item was added:
> > + ----- Method: Decompiler>>doClosureCopyCopiedValues:numArgs:blockSize:
> (in category 'control') -----
> > + doClosureCopyCopiedValues: blockCopiedValues numArgs: numArgs
> blockSize: blockSize
> > + | startpc savedTemps savedTempVarCount savedNumLocalTemps
> > + jump blockArgs blockTemps blockTempsOffset block |
> > + savedTemps := tempVars.
> > + savedTempVarCount := tempVarCount.
> > + savedNumLocalTemps := numLocalTemps.
> > + jump := blockSize + (startpc := pc).
> > + numLocalTemps := BlockLocalTempCounter
> > + tempCountForBlockStartingAt: pc
> > + in: method.
> > + blockTempsOffset := numArgs + blockCopiedValues size.
> > + (blockStartsToTempVars notNil "implies we were intialized with temp
> names."
> > + and: [blockStartsToTempVars includesKey: pc])
> > + ifTrue:
> > + [tempVars := blockStartsToTempVars at: pc]
> > + ifFalse:
> > + [blockArgs := (1 to: numArgs) collect:
> > + [:i| (constructor
> > + codeTemp: i - 1
> > + named: 't', (tempVarCount + i)
> printString)
> > + beBlockArg].
> > + blockTemps := (1 to: numLocalTemps) collect:
> > + [:i| constructor
> > + codeTemp: i + blockTempsOffset - 1
> > + named: 't', (tempVarCount + i +
> numArgs) printString].
> > + tempVars := blockArgs, blockCopiedValues, blockTemps].
> > + numLocalTemps timesRepeat:
> > + [self interpretNextInstructionFor: self.
> > + stack removeLast].
> > + tempVarCount := tempVarCount + numArgs + numLocalTemps.
> > + block := self blockTo: jump.
> > + stack addLast: ((constructor
> > + codeArguments: (tempVars copyFrom: 1 to:
> numArgs)
> > + temps: (tempVars copyFrom: blockTempsOffset + 1
> to: blockTempsOffset + numLocalTemps)
> > + block: block)
> > + pc: startpc;
> > + yourself).
> > + tempVars := savedTemps.
> > + tempVarCount := savedTempVarCount.
> > + numLocalTemps := savedNumLocalTemps!
> >
> > Item was added:
> > + ----- Method: Decompiler>>doDup (in category 'instruction decoding')
> -----
> > + doDup
> > + stack last == CaseFlag
> > + ifTrue:
> > + ["We are in the process of decompiling a caseOf:"
> > + stack addLast: CaseFlag.
> > + ^self].
> > + stack last == CascadeFlag
> > + ifFalse:
> > + ["Save position and mark cascade"
> > + stack addLast: statements size.
> > + stack addLast: CascadeFlag].
> > + stack addLast: CascadeFlag!
> >
> > Item was added:
> > + ----- Method: Decompiler>>doPop (in category 'instruction decoding')
> -----
> > + doPop
> > +
> > + stack isEmpty ifTrue:
> > + ["Ignore pop in first leg of ifNil for value"
> > + ^ self].
> > + stack last == OtherwiseFlag
> > + ifTrue: [stack removeLast]
> > + ifFalse: [statements addLast: stack removeLast].!
> >
> > Item was added:
> > + ----- Method: Decompiler>>doStore: (in category 'instruction
> decoding') -----
> > + doStore: stackOrBlock
> > + "Only called internally, not from InstructionStream. StackOrBlock
> is stack
> > + for store, statements for storePop."
> > +
> > + | var expr |
> > + var := stack removeLast.
> > + expr := stack removeLast.
> > + stackOrBlock addLast: (expr == ArgumentFlag
> > + ifTrue: [var]
> > + ifFalse: [constructor codeAssignTo: var value: expr])!
> >
> > Item was added:
> > + ----- Method: Decompiler>>initSymbols: (in category
> 'initialize-release') -----
> > + initSymbols: aClass
> > + constructor method: method class: aClass literals: method literals.
> > + constTable := constructor codeConstants.
> > + instVars := Array new: aClass instSize.
> > + tempVarCount := method numTemps.
> > + "(tempVars isNil
> > + and: [method holdsTempNames]) ifTrue:
> > + [tempVars := method tempNamesString]."
> > + tempVars isString
> > + ifTrue:
> > + [blockStartsToTempVars := self mapFromBlockKeysIn: method
> > + toTempVarsFrom: tempVars
> > + constructor: constructor.
> > + tempVars := blockStartsToTempVars at: method initialPC]
> > + ifFalse:
> > + [| namedTemps |
> > + namedTemps := tempVars ifNil: [(1 to: tempVarCount)
> collect: [:i| 't', i printString]].
> > + tempVars := (1 to: tempVarCount) collect:
> > + [:i | i <= namedTemps size
> > + ifTrue: [constructor codeTemp: i - 1
> named: (namedTemps at: i)]
> > + ifFalse: [constructor codeTemp: i -
> 1]]].
> > + 1 to: method numArgs do:
> > + [:i|
> > + (tempVars at: i) beMethodArg].
> > + tempReadCounts := Dictionary new!
> >
> > Item was added:
> > + ----- Method: Decompiler>>interpretNextInstructionFor: (in category
> 'private') -----
> > + interpretNextInstructionFor: client
> > +
> > + | code varNames |
> > +
> > + "Change false here will trace all state in Transcript."
> > + true ifTrue: [^super interpretNextInstructionFor: client].
> > +
> > + varNames := self class allInstVarNames.
> > + code := (self method at: pc) radix: 16.
> > + Transcript cr; cr; print: pc; space; nextPutAll: '<' , code, '>'.
> > + (varNames indexOf: 'stack') to: varNames size do:
> > + [:i |
> > + i <= 10 ifTrue: [Transcript cr] ifFalse: [Transcript space;
> space].
> > + Transcript nextPutAll: (varNames at: i); nextPutAll: ': ';
> print: (self instVarAt: i)].
> > + Transcript flush.
> > + ^super interpretNextInstructionFor: client!
> >
> > Item was added:
> > + ----- Method: Decompiler>>jump: (in category 'instruction decoding')
> -----
> > + jump: dist
> > + | blockBody destPc nextPC |
> > + destPc := pc + dist.
> > + (lastJumpIfPcStack isEmpty or: [dist < 0 and: [destPc >
> lastJumpIfPcStack last]])
> > + ifTrue:
> > + ["Rule: aBackward jump not crossing a Bfp/Btp must be a
> repeat"
> > + nextPC := pc.
> > + pc := destPc.
> > + blockBody := self statementsTo: lastPc.
> > + blockBody size timesRepeat: [statements removeLast].
> > + pc := nextPC.
> > + statements addLast:
> > + (constructor
> > + codeMessage: (constructor codeBlock: blockBody
> returns: false)
> > + selector: (constructor
> > + codeSelector: #repeat
> > + code: #macro)
> > + arguments: #()).
> > + ]
> > + ifFalse:
> > + [exit := destPc.
> > + lastJumpPc := lastPc]!
> >
> > Item was added:
> > + ----- Method: Decompiler>>jump:if: (in category 'instruction
> decoding') -----
> > + jump: dist if: condition
> > +
> > + | savePc sign elsePc elseStart end cond ifExpr thenBlock elseBlock
> > + thenJump elseJump condHasValue isIfNil saveStack |
> > + lastJumpIfPcStack addLast: lastPc.
> > + stack last == CaseFlag ifTrue: [^ [self case: dist] ensure:
> [lastJumpIfPcStack removeLast]].
> > + elsePc := lastPc.
> > + elseStart := pc + dist.
> > + end := limit.
> > + "Check for bfp-jmp to invert condition.
> > + Don't be fooled by a loop with a null body."
> > + sign := condition.
> > + savePc := pc.
> > + self interpretJump ifNotNil:
> > + [:elseDist|
> > + (elseDist >= 0 and: [elseStart = pc]) ifTrue:
> > + [sign := sign not. elseStart := pc + elseDist]].
> > + pc := savePc.
> > + ifExpr := stack removeLast.
> > + (isIfNil := stack size > 0 and: [stack last == IfNilFlag]) ifTrue:
> > + [stack removeLast].
> > + saveStack := stack.
> > + stack := OrderedCollection new.
> > + thenBlock := self blockTo: elseStart.
> > + condHasValue := hasValue or: [isIfNil].
> > + "ensure jump is within block (in case thenExpr returns)"
> > + thenJump := exit <= end ifTrue: [exit] ifFalse: [elseStart].
> > + "if jump goes back, then it's a loop"
> > + thenJump < elseStart
> > + ifTrue:
> > + [| blockBody blockArgs savedReadCounts blockBodyReadCounts
> selector |
> > + "Must be a while loop...
> > + thenJump will jump to the beginning of the while expr.
> In the case of while's
> > + with a block in the condition, the while expr should
> include more than just
> > + the last expression: find all the statements needed by
> searching for the node
> > + with the relevant pc."
> > + stack := saveStack.
> > + savedReadCounts := tempReadCounts copy.
> > + pc := thenJump.
> > + blockBody := self statementsTo: elsePc.
> > + blockBodyReadCounts := tempReadCounts.
> > + savedReadCounts keysAndValuesDo:
> > + [:temp :count|
> > + blockBodyReadCounts at: temp put: (blockBodyReadCounts
> at: temp) - count].
> > + tempReadCounts := savedReadCounts.
> > + "discard unwanted statements from block"
> > + blockBody size - 1 timesRepeat: [statements removeLast].
> > + blockArgs := thenBlock statements = constructor
> codeEmptyBlock statements
> > + ifTrue: [#()]
> > + ifFalse: [{ thenBlock }].
> > + selector := blockArgs isEmpty
> > + ifTrue: [sign ifTrue: [#whileFalse]
> ifFalse: [#whileTrue]]
> > + ifFalse: [sign ifTrue: [#whileFalse:]
> ifFalse: [#whileTrue:]].
> > + statements addLast:
> > + (constructor
> > + codeMessage: (constructor codeBlock: blockBody
> returns: false)
> > + selector: (constructor codeSelector: selector code:
> #macro)
> > + arguments: blockArgs).
> > + pc := elseStart.
> > + selector == #whileTrue: ifTrue:
> > + [self convertToDoLoop: blockBodyReadCounts]]
> > + ifFalse:
> > + ["Must be a conditional..."
> > + elseBlock := self blockTo: thenJump.
> > + elseJump := exit.
> > + "if elseJump is backwards, it is not part of the elseExpr"
> > + elseJump < elsePc ifTrue:
> > + [pc := lastPc].
> > + cond := isIfNil
> > + ifTrue:
> > + [constructor
> > + codeMessage: ifExpr ifNilReceiver
> > + selector: (constructor
> > + codeSelector: (sign ifTrue:
> [#ifNotNil:] ifFalse: [#ifNil:])
> > + code: #macro)
> > + arguments: (Array with: thenBlock)]
> > + ifFalse:
> > + [(sign
> > + ifTrue: [{elseBlock. thenBlock}]
> > + ifFalse: [{thenBlock. elseBlock}]) in:
> > + [:args |
> > + (constructor
> > + decodeIfNilWithReceiver: ifExpr
> > + selector: #ifTrue:ifFalse:
> > + arguments: args
> > + tempReadCounts: tempReadCounts)
> ifNil:
> > + [constructor
> > + codeMessage: ifExpr
> > + selector: (constructor
> codeSelector: #ifTrue:ifFalse: code: #macro)
> > + arguments: args]]].
> > + stack := saveStack.
> > + condHasValue
> > + ifTrue: [stack addLast: cond]
> > + ifFalse: [statements addLast: cond]].
> > + lastJumpIfPcStack removeLast.!
> >
> > Item was added:
> > + ----- Method:
> Decompiler>>mapFromBlockKeysIn:toTempVarsFrom:constructor: (in category
> 'initialize-release') -----
> > + mapFromBlockKeysIn: aMethod toTempVarsFrom: schematicTempNamesString
> constructor: aDecompilerConstructor
> > + "Answer a (n Identity) Dictionary from block start key to sequence
> of TermpVarNode & RemoteTempVarNode"
> > + | startMap tempMap |
> > + "This rather odd construct is to avoid recursion if we used aMethod
> methodNode startKeysToBlockExtents,
> > + which will invoke this Decompiler if a method has no source."
> > + startMap := (DebuggerMethodMap
> > + forMethod: aMethod
> > + methodNode: nil) startKeysToBlockExtents.
> > + tempMap := aMethod
> > + mapFromBlockKeys: (startMap keys asArray sort: [:a
> :b| (startMap at: a) first <= (startMap at: b) first])
> > + toSchematicTemps: schematicTempNamesString.
> > + tempMap keysAndValuesDo:
> > + [:startKey :tempNameTupleVector|
> > + tempNameTupleVector isEmpty ifFalse:
> > + [| subMap numTemps tempVector |
> > + subMap := Dictionary new.
> > + "Find how many temp slots there are (direct & indirect temp
> vectors)
> > + and for each indirect temp vector find how big it is."
> > + tempNameTupleVector do:
> > + [:tuple|
> > + tuple last isArray
> > + ifTrue:
> > + [subMap at: tuple last first put: tuple last
> last.
> > + numTemps := tuple last first]
> > + ifFalse:
> > + [numTemps := tuple last]].
> > + "create the temp vector for this scope level."
> > + tempVector := Array new: numTemps.
> > + "fill it in with any indirect temp vectors"
> > + subMap keysAndValuesDo:
> > + [:index :size|
> > + tempVector at: index put: (Array new: size)].
> > + "fill it in with temp nodes."
> > + tempNameTupleVector do:
> > + [:tuple| | itv |
> > + tuple last isArray
> > + ifTrue:
> > + [itv := tempVector at: tuple last first.
> > + itv at: tuple last last
> > + put: (aDecompilerConstructor
> > + codeTemp: tuple last last - 1
> > + named: tuple first)]
> > + ifFalse:
> > + [tempVector
> > + at: tuple last
> > + put: (aDecompilerConstructor
> > + codeTemp: tuple last - 1
> > + named: tuple first)]].
> > + "replace any indirect temp vectors with proper
> RemoteTempVectorNodes"
> > + subMap keysAndValuesDo:
> > + [:index :size|
> > + tempVector
> > + at: index
> > + put: (aDecompilerConstructor
> > + codeRemoteTemp: index
> > + remoteTemps: (tempVector at: index))].
> > + "and update the entry in the map"
> > + tempMap at: startKey put: tempVector]].
> > + ^tempMap!
> >
> > Item was added:
> > + ----- Method: Decompiler>>markTemp:asOutOfScope: (in category
> 'private') -----
> > + markTemp: tempVarNode asOutOfScope: scopeFlag
> > + tempVarNode scope: scopeFlag.
> > + tempReadCounts removeKey: tempVarNode ifAbsent: []!
> >
> > Item was added:
> > + ----- Method: Decompiler>>methodRefersOnlyOnceToTemp: (in category
> 'private') -----
> > + methodRefersOnlyOnceToTemp: offset
> > + | nRefs byteCode extension scanner |
> > + nRefs := 0.
> > + offset <= 15
> > + ifTrue:
> > + [byteCode := 16 + offset.
> > + (InstructionStream on: method) scanFor:
> > + [:instr | instr = byteCode ifTrue: [nRefs := nRefs + 1].
> > + nRefs > 1]]
> > + ifFalse:
> > + [extension := 64 + offset.
> > + scanner := InstructionStream on: method.
> > + scanner scanFor:
> > + [:instr | (instr = 128 and: [scanner followingByte =
> extension])
> > + ifTrue: [nRefs := nRefs + 1].
> > + nRefs > 1]].
> > + ^ nRefs = 1
> > + !
> >
> > Item was added:
> > + ----- Method: Decompiler>>methodReturnConstant: (in category
> 'instruction decoding') -----
> > + methodReturnConstant: value
> > +
> > + self pushConstant: value; methodReturnTop!
> >
> > Item was added:
> > + ----- Method: Decompiler>>methodReturnReceiver (in category
> 'instruction decoding') -----
> > + methodReturnReceiver
> > +
> > + self pushReceiver; methodReturnTop!
> >
> > Item was added:
> > + ----- Method: Decompiler>>methodReturnTop (in category 'instruction
> decoding') -----
> > + methodReturnTop
> > + | last |
> > + last := stack removeLast "test test" asReturnNode.
> > + stack size > blockStackBase "get effect of elided pop before
> return"
> > + ifTrue: [statements addLast: stack removeLast].
> > + exit := pc.
> > + lastJumpPc := lastReturnPc := lastPc.
> > + statements addLast: last!
> >
> > Item was added:
> > + ----- Method: Decompiler>>popIntoLiteralVariable: (in category
> 'instruction decoding') -----
> > + popIntoLiteralVariable: value
> > +
> > + self pushLiteralVariable: value; doStore: statements!
> >
> > Item was added:
> > + ----- Method: Decompiler>>popIntoReceiverVariable: (in category
> 'instruction decoding') -----
> > + popIntoReceiverVariable: offset
> > +
> > + self pushReceiverVariable: offset; doStore: statements!
> >
> > Item was added:
> > + ----- Method: Decompiler>>popIntoRemoteTemp:inVectorAt: (in category
> 'instruction decoding') -----
> > + popIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
> > + self pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex;
> doStore: statements!
> >
> > Item was added:
> > + ----- Method: Decompiler>>popIntoTemporaryVariable: (in category
> 'instruction decoding') -----
> > + popIntoTemporaryVariable: offset
> > + | maybeTVTag tempVector start |
> > + maybeTVTag := stack last.
> > + ((maybeTVTag isMemberOf: Association)
> > + and: [maybeTVTag key == #pushNewArray]) ifTrue:
> > + [blockStartsToTempVars "implies we were intialized with temp
> names."
> > + ifNotNil: "Use the provided temps"
> > + [self assert: ((tempVector := tempVars at: offset + 1
> ifAbsent: [ParseNode basicNew]) isTemp
> > + and: [tempVector isIndirectTempVector
> > + and: [tempVector remoteTemps size =
> maybeTVTag value size]])]
> > + ifNil: "Synthesize some remote temps"
> > + [tempVector := maybeTVTag value.
> > + offset + 1 <= tempVars size
> > + ifTrue:
> > + [start := 2.
> > + tempVector at: 1 put: (tempVars at: offset +
> 1)]
> > + ifFalse:
> > + [tempVars := (Array new: offset + 1)
> > + replaceFrom: 1
> > + to: tempVars size
> > + with: tempVars.
> > + start := 1].
> > + start to: tempVector size do:
> > + [:i|
> > + tempVector
> > + at: i
> > + put: (constructor
> > + codeTemp: numLocalTemps + offset + i - 1
> > + named: 't', (tempVarCount + i)
> printString)].
> > + tempVars at: offset + 1 put: (constructor
> codeRemoteTemp: offset + 1 remoteTemps: tempVector)].
> > + tempVarCount := tempVarCount + maybeTVTag value size.
> > + stack removeLast.
> > + ^self].
> > + stack addLast: (offset >= tempVars size
> > + ifTrue: "Handle the case of chained
> LiteralVariableBinding assigments"
> > + [stack at: (offset + 1 - tempVars size)]
> > + ifFalse: "A regular argument or temporary"
> > + [tempVars at: offset + 1]).
> > + self doStore: statements!
> >
> > Item was added:
> > + ----- Method: Decompiler>>popTo: (in category 'private') -----
> > + popTo: oldPos
> > +
> > + | t |
> > + t := Array new: statements size - oldPos.
> > + (t size to: 1 by: -1) do:
> > + [:i | t at: i put: statements removeLast].
> > + ^t!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushActiveContext (in category 'instruction
> decoding') -----
> > + pushActiveContext
> > +
> > + stack addLast: constructor codeThisContext!
> >
> > Item was added:
> > + ----- Method:
> Decompiler>>pushClosureCopyNumCopiedValues:numArgs:blockSize: (in category
> 'instruction decoding') -----
> > + pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize:
> blockSize
> > + | copiedValues |
> > + copiedValues := ((1 to: numCopied) collect: [:ign| stack
> removeLast]) reversed.
> > + self doClosureCopyCopiedValues: copiedValues numArgs: numArgs
> blockSize: blockSize!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushConsArrayWithElements: (in category
> 'instruction decoding') -----
> > + pushConsArrayWithElements: numElements
> > + | array |
> > + array := Array new: numElements.
> > + numElements to: 1 by: -1 do:
> > + [:i|
> > + array at: i put: stack removeLast].
> > + stack addLast: (constructor codeBrace: array)!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushConstant: (in category 'instruction
> decoding') -----
> > + pushConstant: value
> > +
> > + | node |
> > + node := value == true ifTrue: [constTable at: 2]
> > + ifFalse: [value == false ifTrue: [constTable at: 3]
> > + ifFalse: [value == nil ifTrue: [constTable at: 4]
> > + ifFalse: [constructor codeAnyLiteral: value]]].
> > + stack addLast: node!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushFullClosure:numCopied: (in category
> 'instruction decoding') -----
> > + pushFullClosure: aCompiledBlock numCopied: numCopied
> > + | copiedValues |
> > + copiedValues := ((1 to: numCopied) collect: [:ign| stack
> removeLast]) reversed.
> > + stack addLast: (self shallowCopy doClosureCopy: aCompiledBlock
> copiedValues: copiedValues)!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushLiteralVariable: (in category
> 'instruction decoding') -----
> > + pushLiteralVariable: assoc
> > +
> > + stack addLast: (constructor codeAnyLitInd: assoc)!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushNewArrayOfSize: (in category
> 'instruction decoding') -----
> > + pushNewArrayOfSize: size
> > + stack addLast: #pushNewArray -> (Array new: size)!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushReceiver (in category 'instruction
> decoding') -----
> > + pushReceiver
> > +
> > + stack addLast: (constTable at: 1)!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushReceiverVariable: (in category
> 'instruction decoding') -----
> > + pushReceiverVariable: offset
> > +
> > + | var |
> > + (var := instVars at: offset + 1 ifAbsent: []) == nil
> > + ifTrue:
> > + ["Not set up yet"
> > + var := constructor codeInst: offset.
> > + instVars size < (offset + 1) ifTrue: [
> > + instVars := (Array new: offset + 1)
> > + replaceFrom: 1 to: instVars size with: instVars;
> yourself ].
> > + instVars at: offset + 1 put: var].
> > + stack addLast: var!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushRemoteTemp:inVectorAt: (in category
> 'instruction decoding') -----
> > + pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
> > + stack addLast: ((tempVars at: tempVectorIndex + 1) remoteTemps at:
> remoteTempIndex + 1)!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushSpecialConstant: (in category
> 'instruction decoding') -----
> > + pushSpecialConstant: value
> > + ^self pushConstant: value!
> >
> > Item was added:
> > + ----- Method: Decompiler>>pushTemporaryVariable: (in category
> 'instruction decoding') -----
> > + pushTemporaryVariable: offset
> > + | node |
> > + offset >= tempVars size
> > + ifTrue: "Handle the case of chained
> LiteralVariableBinding assigments"
> > + [self halt.
> > + node := stack at: offset + 1 - tempVars size]
> > + ifFalse: "A regular argument or temporary"
> > + [node := tempVars at: offset + 1.
> > + node isArg ifFalse: "count temp reads for the
> whileTrue: => to:do: transformation."
> > + [tempReadCounts at: node put: (tempReadCounts
> at: node ifAbsent: [0]) + 1]].
> > + stack addLast: node!
> >
> > Item was added:
> > + ----- Method: Decompiler>>quickMethod (in category 'private') -----
> > + quickMethod
> > + | |
> > + method isReturnSpecial
> > + ifTrue: [^ constructor codeBlock:
> > + (Array with: (constTable at: method primitive - 255))
> returns: true].
> > + method isReturnField
> > + ifTrue: [^ constructor codeBlock:
> > + (Array with: (constructor codeInst: method
> returnField)) returns: true].
> > + self error: 'improper short method'!
> >
> > Item was added:
> > + ----- Method: Decompiler>>send:super:numArgs: (in category
> 'instruction decoding') -----
> > + send: selector super: superFlag numArgs: numArgs
> > +
> > + | args rcvr selNode msgNode messages |
> > + args := Array new: numArgs.
> > + (numArgs to: 1 by: -1) do:
> > + [:i | args at: i put: stack removeLast].
> > + rcvr := stack removeLast.
> > + superFlag ifTrue: [rcvr := constructor codeSuper].
> > + selNode := constructor codeAnySelector: selector.
> > + rcvr == CaseFlag
> > + ifTrue:
> > + [| cases stmtStream elements node b |
> > + selector == #= ifTrue:
> > + [" = signals a case statement..."
> > + statements addLast: args first.
> > + stack addLast: rcvr. "restore CaseFlag"
> > + ^ self].
> > + selector = #caseError ifFalse: [self error: 'unexpected
> message send while decompiling a caseOf:'].
> > + stmtStream := ReadStream on: (self popTo: stack removeLast).
> > +
> > + elements := OrderedCollection new.
> > + b := OrderedCollection new.
> > + [stmtStream atEnd] whileFalse:
> > + [(node := stmtStream next) == CaseFlag
> > + ifTrue:
> > + [elements addLast: (constructor
> > + codeMessage: (constructor codeBlock: b
> returns: false)
> > + selector: (constructor codeSelector: #->
> code: #macro)
> > + arguments: (Array with: stmtStream next)).
> > + b := OrderedCollection new]
> > + ifFalse: [b addLast: node]].
> > + b size > 0 ifTrue: [self error: 'Bad cases'].
> > + cases := constructor codeBrace: elements.
> > +
> > + stack addLast:
> > + (constructor
> > + codeMessage: stack removeLast
> > + selector: (constructor codeSelector: #caseOf: code:
> #macro)
> > + arguments: (Array with: cases)).
> > + ^self].
> > + rcvr == CascadeFlag
> > + ifTrue:
> > + ["May actually be a cascade or an ifNil: for value."
> > + self willJumpIfFalse
> > + ifTrue: "= generated by a case macro"
> > + [selector == #= ifTrue:
> > + [" = signals a case statement..."
> > + statements addLast: args first.
> > + stack removeLast; addLast: CaseFlag; addLast:
> CaseFlag. "Properly mark the case statement"
> > + ^ self].
> > + selector == #== ifTrue:
> > + [" == signals an ifNil: for value..."
> > + stack removeLast; removeLast.
> > + rcvr := stack removeLast.
> > + stack addLast: IfNilFlag;
> > + addLast: (constructor
> > + codeMessage: rcvr
> > + selector: selNode
> > + arguments: args).
> > + ^ self]]
> > + ifFalse:
> > + [(self willJumpIfTrue and: [selector == #==])
> ifTrue:
> > + [" == signals an ifNotNil: for value..."
> > + stack removeLast; removeLast.
> > + rcvr := stack removeLast.
> > + stack addLast: IfNilFlag;
> > + addLast: (constructor
> > + codeMessage: rcvr
> > + selector: selNode
> > + arguments: args).
> > + ^ self]].
> > + msgNode := constructor
> > + codeCascadedMessage: selNode
> > + arguments: args.
> > + stack last == CascadeFlag ifFalse:
> > + ["Last message of a cascade"
> > + statements addLast: msgNode.
> > + messages := self popTo: stack removeLast. "Depth saved
> by first dup"
> > + msgNode := constructor
> > + codeCascade: stack removeLast
> > + messages: messages]]
> > + ifFalse:
> > + [msgNode := constructor
> > + codeMessage: rcvr
> > + selector: selNode
> > + arguments: args].
> > + stack addLast: msgNode!
> >
> > Item was added:
> > + ----- Method: Decompiler>>sendSpecial:numArgs: (in category
> 'instruction decoding') -----
> > + sendSpecial: selector numArgs: numArgs
> > + ^self send: selector super: false numArgs: numArgs!
> >
> > Item was added:
> > + ----- Method: Decompiler>>startAndLimitFor:from:into: (in category
> 'private') -----
> > + startAndLimitFor: incrVar from: aStack into: binaryBlock
> > + "If incrVar matches the increment of a whileLoop at the end of
> statements
> > + evaluate binaryBlock with the init statement for incrVar and the
> init statement
> > + for the block's limit, if any, and answer true. Otherwise answer
> false. Used to
> > + help convert whileTrue: loops into to:[by:]do: loops."
> > + | guard initExpr limitInit size |
> > + ((size := aStack size) >= 1
> > + and: [(initExpr := aStack at: size) ~~ CaseFlag]
> > + and: [initExpr isAssignmentNode]) ifFalse:
> > + [^false].
> > + initExpr variable == incrVar ifTrue:
> > + [binaryBlock value: initExpr value: nil.
> > + ^true].
> > + limitInit := initExpr.
> > + (size >= 2
> > + and: [(initExpr := aStack at: size - 1) isAssignmentNode
> > + and: [initExpr variable == incrVar
> > + and: [(guard := statements last receiver) isBlockNode
> > + and: [guard statements size = 1
> > + and: [(guard := guard statements first) isMessageNode
> > + and: [guard receiver == incrVar
> > + and: [guard arguments first == limitInit variable]]]]]]]) ifTrue:
> > + [binaryBlock value: initExpr value: limitInit.
> > + ^true].
> > + ^false!
> >
> > Item was added:
> > + ----- Method: Decompiler>>statementsForCaseTo: (in category 'control')
> -----
> > + statementsForCaseTo: end
> > + "Decompile the method from pc up to end and return an array of
> > + expressions. If at run time this block will leave a value on the
> stack,
> > + set hasValue to true. If the block ends with a jump or return, set
> exit
> > + to the destination of the jump, or the end of the method;
> otherwise, set
> > + exit = end. Leave pc = end.
> > + Note that stack initially contains a OtherwiseFlag which will be
> removed by
> > + a subsequent Pop instruction, so adjust the StackPos accordingly."
> > +
> > + | blockPos stackPos |
> > + blockPos := statements size.
> > + stackPos := stack size - 1. "Adjust for OtherwiseFlag"
> > + [pc < end]
> > + whileTrue:
> > + [lastPc := pc. limit := end. "for performs"
> > + self interpretNextInstructionFor: self].
> > + "If there is an additional item on the stack, it will be the value
> > + of this block."
> > + (hasValue := stack size > stackPos)
> > + ifTrue:
> > + [stack last == OtherwiseFlag
> > + ifFalse: [ statements addLast: stack removeLast] ].
> > + lastJumpPc = lastPc ifFalse: [exit := pc].
> > + caseExits add: exit.
> > + ^self popTo: blockPos!
> >
> > Item was added:
> > + ----- Method: Decompiler>>statementsTo: (in category 'control') -----
> > + statementsTo: end
> > + "Decompile the method from pc up to end and return an array of
> > + expressions. If at run time this block will leave a value on the
> stack,
> > + set hasValue to true. If the block ends with a jump or return, set
> exit
> > + to the destination of the jump, or the end of the method;
> otherwise, set
> > + exit = end. Leave pc = end."
> > +
> > + | encoderClass blockPos stackPos localLastPC |
> > + encoderClass := method encoderClass.
> > + blockPos := statements size.
> > + stackPos := stack size.
> > + [pc < end]
> > + whileTrue:
> > + [lastPc := localLastPC := pc. limit := end. "for performs"
> > + "If you want instrumentation replace the following
> statement with this one,
> > + and edit the implementation:
> > + self interpretNextInstructionFor: self"
> > + encoderClass interpretNextInstructionFor: self in: self].
> > + "If there is an additional item on the stack, it will be the value
> > + of this block."
> > + (hasValue := stack size > stackPos)
> > + ifTrue:
> > + [statements addLast: stack removeLast].
> > + lastJumpPc = lastPc ifFalse: [exit := pc].
> > + ^self popTo: blockPos!
> >
> > Item was added:
> > + ----- Method: Decompiler>>storeIntoLiteralVariable: (in category
> 'instruction decoding') -----
> > + storeIntoLiteralVariable: assoc
> > +
> > + self pushLiteralVariable: assoc; doStore: stack!
> >
> > Item was added:
> > + ----- Method: Decompiler>>storeIntoReceiverVariable: (in category
> 'instruction decoding') -----
> > + storeIntoReceiverVariable: offset
> > +
> > + self pushReceiverVariable: offset; doStore: stack!
> >
> > Item was added:
> > + ----- Method: Decompiler>>storeIntoRemoteTemp:inVectorAt: (in category
> 'instruction decoding') -----
> > + storeIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
> > + self pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex;
> doStore: stack!
> >
> > Item was added:
> > + ----- Method: Decompiler>>storeIntoTemporaryVariable: (in category
> 'instruction decoding') -----
> > + storeIntoTemporaryVariable: offset
> > + stack addLast: (offset >= tempVars size
> > + ifTrue: "Handle the case of chained
> LiteralVariableBinding assigments"
> > + [stack at: (offset + 1 - tempVars size)]
> > + ifFalse: "A regular argument or temporary"
> > + [tempVars at: offset + 1]).
> > + self doStore: stack!
> >
> > Item was added:
> > + ----- Method: Decompiler>>tempAt: (in category 'public access') -----
> > + tempAt: offset
> > + "Needed by BraceConstructor<PopIntoTemporaryVariable"
> > +
> > + ^tempVars at: offset + 1!
> >
> > Item was added:
> > + ----- Method: Decompiler>>withTempNames: (in category
> 'initialize-release') -----
> > + withTempNames: tempNames "<Array|String>"
> > + "Optionally initialize the temp names to be used when decompiling.
> > + For backward-copmpatibility, if tempNames is an Array it is a
> single
> > + vector of temp names, probably for a blue-book-compiled method.
> > + If tempNames is a string it is a schematic string that encodes the
> > + layout of temp vars in the method and any closures/blocks within
> it.
> > + Decoding encoded tempNames is done in decompile:in:method:using:
> > + which has the method from which to derive blockStarts.
> > + See e.g. BytecodeEncoder>>schematicTempNamesString for syntax."
> > + tempVars := tempNames!
> >
> > Item was added:
> > + ParseNode subclass: #DecompilerConstructor
> > + instanceVariableNames: 'method instVars nArgs literalValues
> tempVars'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> > +
> > + !DecompilerConstructor commentStamp: '<historical>' prior: 0!
> > + I construct the node tree for a Decompiler.!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>accept: (in category 'visiting')
> -----
> > + accept: aVisitor
> > + "I am not really a ParseNode. Only here to access constants
> defined in parseNode."
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeAnyLitInd: (in category
> 'constructor') -----
> > + codeAnyLitInd: association
> > +
> > + ^LiteralVariableNode new
> > + name: association key
> > + key: association
> > + index: nil
> > + type: LdLitIndType!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeAnyLiteral: (in category
> 'constructor') -----
> > + codeAnyLiteral: value
> > +
> > + ^LiteralNode new
> > + key: value
> > + index: 0
> > + type: LdLitType!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeAnySelector: (in category
> 'constructor') -----
> > + codeAnySelector: selector
> > +
> > + ^SelectorNode new
> > + key: selector
> > + index: nil
> > + type: SendType!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeArguments:temps:block: (in
> category 'constructor') -----
> > + codeArguments: args temps: temps block: block
> > + block
> > + arguments: args;
> > + temporaries: temps.
> > + ^block!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeAssignTo:value: (in category
> 'constructor') -----
> > + codeAssignTo: variable value: expression
> > +
> > + ^AssignmentNode new variable: variable value: expression!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeBlock:returns: (in category
> 'constructor') -----
> > + codeBlock: statements returns: returns
> > + ^ BlockNode statements: statements returns: returns!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeBrace: (in category
> 'constructor') -----
> > + codeBrace: elements
> > +
> > + ^BraceNode new elements: elements!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeCascade:messages: (in
> category 'constructor') -----
> > + codeCascade: receiver messages: messages
> > +
> > + ^ (BraceNode new matchBraceStreamReceiver: receiver messages:
> messages)
> > + ifNil: [CascadeNode new receiver: receiver messages: messages]!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeCascadedMessage:arguments:
> (in category 'constructor') -----
> > + codeCascadedMessage: selector arguments: arguments
> > +
> > + ^self
> > + codeMessage: nil
> > + selector: selector
> > + arguments: arguments!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeConstants (in category
> 'constructor') -----
> > + codeConstants
> > + "Answer with an array of the objects representing self, true,
> false, nil,
> > + -1, 0, 1, 2."
> > +
> > + ^(Array with: NodeSelf with: NodeTrue with: NodeFalse with: NodeNil)
> > + , ((-1 to: 2) collect: [:i | LiteralNode new key: i code:
> LdMinus1 + i + 1])!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeEmptyBlock (in category
> 'constructor') -----
> > + codeEmptyBlock
> > + ^ BlockNode withJust: NodeNil!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeInst: (in category
> 'constructor') -----
> > + codeInst: index
> > +
> > + ^InstanceVariableNode new
> > + name: (instVars at: index + 1 ifAbsent: ['unknown', index
> asString])
> > + index: index + 1!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeMessage:selector:arguments:
> (in category 'constructor') -----
> > + codeMessage: receiver selector: selector arguments: arguments
> > + | symbol |
> > + symbol := selector key.
> > + (self
> > + decodeLiteralVariableValueDereferenceWithReceiver: receiver
> > + selector: symbol
> > + arguments: arguments) ifNotNil: [:node| ^node].
> > +
> > + ^MessageNode new
> > + receiver: receiver selector: selector
> > + arguments: arguments
> > + precedence: symbol precedence!
> >
> > Item was added:
> > + ----- Method:
> DecompilerConstructor>>codeMethod:block:tempVars:primitive:class: (in
> category 'constructor') -----
> > + codeMethod: selector block: block tempVars: vars primitive: primitive
> class: class
> > +
> > + | blockNode selectorNode visibleTemps invisibleTemps arguments
> temporaries properties |
> > + selectorNode := self codeSelector: selector code: nil.
> > + tempVars := vars.
> > + visibleTemps := OrderedCollection new.
> > + invisibleTemps := OrderedCollection new.
> > + tempVars do: [:t|
> > + ((t isIndirectTempVector or: [t scope >= 0])
> > + ifTrue: [visibleTemps]
> > + ifFalse: [invisibleTemps]) addLast: t].
> > + arguments := visibleTemps copyFrom: 1 to: nArgs.
> > + temporaries := visibleTemps copyFrom: nArgs + 1 to: visibleTemps
> size.
> > + block
> > + arguments: arguments;
> > + temporaries: temporaries.
> > + properties := method properties copy.
> > + (properties at: #onceCache ifAbsent: []) ifNotNil:
> > + [:onceCache|
> > + properties := properties copyWithout: (Association
> > + key: #onceCache
> > + value: onceCache)].
> > + blockNode := MethodNode new
> > + selector: selectorNode
> > + arguments: arguments
> > + precedence: selector precedence
> > + temporaries: temporaries
> > + block: block
> > + encoder: (method encoderClass new initScopeAndLiteralTables
> > + temps: visibleTemps, invisibleTemps
> > + literals: literalValues
> > + class: class)
> > + primitive: primitive
> > + properties: properties.
> > + blockNode properties method: blockNode.
> > + ^blockNode!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeRemoteTemp:remoteTemps: (in
> category 'as yet unclassified') -----
> > + codeRemoteTemp: index remoteTemps: tempVector
> > +
> > + ^(RemoteTempVectorNode new
> > + name: '_r', index printString
> > + index: index
> > + type: LdTempType
> > + scope: 0)
> > + remoteTemps: tempVector;
> > + yourself!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeSelector:code: (in category
> 'constructor') -----
> > + codeSelector: sel code: code
> > +
> > + ^SelectorNode new key: sel code: code!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeSuper (in category
> 'constructor') -----
> > + codeSuper
> > +
> > + ^NodeSuper!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeTemp: (in category
> 'constructor') -----
> > + codeTemp: index
> > +
> > + ^ TempVariableNode new
> > + name: 't' , (index + 1) printString
> > + index: index
> > + type: LdTempType
> > + scope: 0!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeTemp:named: (in category
> 'constructor') -----
> > + codeTemp: index named: tempName
> > +
> > + ^ TempVariableNode new
> > + name: tempName
> > + index: index
> > + type: LdTempType
> > + scope: 0!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>codeThisContext (in category
> 'constructor') -----
> > + codeThisContext
> > +
> > + ^NodeThisContext!
> >
> > Item was added:
> > + ----- Method:
> DecompilerConstructor>>decodeIfNilWithReceiver:selector:arguments:tempReadCounts:
> (in category 'constructor') -----
> > + decodeIfNilWithReceiver: receiver selector: selector arguments:
> arguments tempReadCounts: tempReadCounts
> > +
> > + | node temp |
> > + receiver ifNil: [ ^nil ]. "For instance, when cascading"
> > + selector == #ifTrue:ifFalse:
> > + ifFalse: [^ nil].
> > +
> > + (receiver isMessage: #==
> > + receiver: nil
> > + arguments: [:argNode | argNode == NodeNil])
> > + ifFalse: [^ nil].
> > +
> > + "Like #to:(by:)do:, support only local temps."
> > + (((temp := receiver ifNilTemporary) isNil or: [tempReadCounts
> includesKey: temp]) or: [
> > + "What about 'object ifNotNil: [:o | ]', which as not read the
> blockArg? Just check that there is no remote vector pointing to it."
> > + tempReadCounts keys noneSatisfy:
> > + [:otherTemp |
> > + otherTemp isIndirectTempVector
> > + ifTrue: [otherTemp remoteTemps anySatisfy:
> > + [:remoteTemp |
> > + remoteTemp name = temp name]]
> > + ifFalse: [otherTemp name = temp name]]
> > + ])
> > + ifFalse: [^ nil].
> > +
> > + node := (MessageNode new
> > + receiver: receiver
> > + selector: (SelectorNode new key: #ifTrue:ifFalse: code:
> #macro)
> > + arguments: arguments
> > + precedence: 3).
> > +
> > + "Reconfigure the message node to #ifNil:ifNotNil:. Note that
> original* instance variables keep their optimized format. See MessageNode
> >> #printIfNilNotNil:indent:."
> > + node
> > + noteSpecialSelector: #ifNil:ifNotNil:;
> > + selector: (SelectorNode new key: #ifNil:ifNotNil:).
> > +
> > + temp ifNil: [^ node].
> > + temp isTemp ifFalse: [^ node].
> > +
> > + (arguments second isJust: NodeNil) not ifTrue:
> > + [temp beBlockArg.
> > + node arguments: {
> > + arguments first.
> > + arguments second copy arguments: { temp }; yourself }].
> > +
> > + ^ node!
> >
> > Item was added:
> > + ----- Method:
> DecompilerConstructor>>decodeLiteralVariableValueDereferenceWithReceiver:selector:arguments:
> (in category 'constructor') -----
> > + decodeLiteralVariableValueDereferenceWithReceiver: receiver selector:
> selector arguments: arguments
> > + | varNode |
> > + (receiver notNil "cascades"
> > + and: [receiver isLiteralNode
> > + and: [receiver key isVariableBinding]]) ifFalse:
> > + [^nil].
> > + varNode := self codeAnyLitInd: receiver key.
> > + selector = #value ifTrue:
> > + [^varNode].
> > + ^selector = #value: ifTrue:
> > + [self codeAssignTo: varNode value: arguments first]!
> >
> > Item was added:
> > + ----- Method: DecompilerConstructor>>method:class:literals: (in
> category 'initialize-release') -----
> > + method: aMethod class: aClass literals: literals
> > +
> > + method := aMethod.
> > + instVars := aClass allInstVarNames.
> > + nArgs := method numArgs.
> > + literalValues := literals!
> >
> > Item was added:
> > + ----- Method: Dictionary>>bindingOf: (in category '*Compiler') -----
> > + bindingOf: varName
> > +
> > + ^self associationAt: varName ifAbsent: nil!
> >
> > Item was added:
> > + ----- Method: Dictionary>>bindingOf:ifAbsent: (in category
> '*Compiler') -----
> > + bindingOf: varName ifAbsent: aBlock
> > +
> > + ^self associationAt: varName ifAbsent: aBlock!
> >
> > Item was added:
> > + ----- Method: Dictionary>>bindingsDo: (in category '*Compiler') -----
> > + bindingsDo: aBlock
> > + ^self associationsDo: aBlock!
> >
> > Item was added:
> > + ParseNode subclass: #Encoder
> > + instanceVariableNames: 'scopeTable nTemps supered requestor class
> selector literalStream selectorSet litIndSet litSet sourceRanges
> globalSourceRanges addedExtraLiterals optimizedSelectors cue'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> > +
> > + !Encoder commentStamp: 'cwp 12/26/2012 23:29' prior: 0!
> > + I encode names and literals into tree nodes with byte codes for the
> compiler. Byte codes for literals are not assigned until the tree-sizing
> pass of the compiler, because only then is it known which literals are
> actually needed. I also keep track of sourceCode ranges during parsing and
> code generation so I can provide an inverse map for the debugger.!
> >
> > Item was added:
> > + ----- Method: Encoder>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + "I am not really a ParseNode. Only here to access constants
> defined in parseNode."
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: Encoder>>allLiterals (in category 'results') -----
> > + allLiterals
> > + addedExtraLiterals ifFalse:
> > + [addedExtraLiterals := true.
> > + "Put the optimized selectors in literals so as to browse
> senders more easily"
> > + optimizedSelectors := optimizedSelectors reject: [:e|
> literalStream originalContents hasLiteral: e].
> > + optimizedSelectors isEmpty ifFalse: [
> > + "Use one entry per literal if enough room, else make
> anArray"
> > + literalStream position + optimizedSelectors size + 2 >=
> self maxNumLiterals
> > + ifTrue: [self litIndex: optimizedSelectors asArray]
> > + ifFalse: [optimizedSelectors do: [:e | self litIndex:
> e]]].
> > + "Add a slot for selector or MethodProperties"
> > + self litIndex: nil.
> > + self litIndex: self associationForClass].
> > + ^literalStream contents!
> >
> > Item was added:
> > + ----- Method: Encoder>>associationForClass (in category 'results')
> -----
> > + associationForClass
> > + | assoc |
> > + assoc := self environment associationAt: cue getClass name
> ifAbsent: [nil].
> > + ^assoc value == cue getClass
> > + ifTrue: [assoc]
> > + ifFalse: [Association new value: cue getClass]!
> >
> > Item was added:
> > + ----- Method: Encoder>>autoBind: (in category 'temps') -----
> > + autoBind: name
> > + "Declare a block argument as a temp if not already declared."
> > + | node |
> > + node := scopeTable
> > + at: name
> > + ifAbsent:
> > + [(self lookupInPools: name ifFound: [:assoc | assoc])
> > + ifTrue: [self warnAboutShadowed: name].
> > + ^ (self reallyBind: name) nowHasDef nowHasRef scope: 1].
> > + node isTemp
> > + ifTrue: [node scope >= 0 ifTrue:
> > + [^ self notify: 'Name already used in this method'].
> > + node nowHasDef nowHasRef scope: 1]
> > + ifFalse: [^ self notify: 'Name already used in this class'].
> > + ^node!
> >
> > Item was added:
> > + ----- Method: Encoder>>bindArg: (in category 'temps') -----
> > + bindArg: name
> > + "Declare an argument."
> > + | node |
> > + nTemps >= 15
> > + ifTrue: [^self notify: 'Too many arguments'].
> > + node := self bindTemp: name.
> > + ^ node nowHasDef nowHasRef!
> >
> > Item was added:
> > + ----- Method: Encoder>>bindBlockArg:within: (in category 'temps') -----
> > + bindBlockArg: name within: aBlockNode
> > + "With standard Smalltalk-80 (BlueBook) blocks it used to be legal
> to use a
> > + method temp as a block argument. This shouldn't be the case with
> the
> > + current compiler, which checks for temp names already being used as
> > + block arguments. But it is easily fooled by local block temps in
> optimized
> > + blocks, e.g.
> > + false
> > + ifTrue: [| temp |]
> > + ifFalse:[[:temp|]]
> > + Rather than fix this we keep the semantics and fix it in the
> closure compiler."
> > + ^self autoBind: name!
> >
> > Item was added:
> > + ----- Method: Encoder>>bindBlockTemp: (in category 'temps') -----
> > + bindBlockTemp: name
> > + "Declare a temporary block variable; complain if it's not a field
> or class variable."
> > +
> > + | node |
> > +
> > + node := scopeTable at: name ifAbsent: [^self reallyBind: name].
> > + node isTemp
> > + ifTrue: [
> > + node scope >= 0 ifTrue: [^ self notify: 'Name already used
> in this method'].
> > + node scope: 0]
> > + ifFalse: [^self notify: 'Name already used in this class'].
> > + ^node
> > + !
> >
> > Item was added:
> > + ----- Method: Encoder>>bindBlockTemp:within: (in category 'temps')
> -----
> > + bindBlockTemp: name within: aBlockNode
> > + "The BlockContext compiler (the Smalltalk-80 BlueBook compiler)
> > + does provide support for ANSI block syntax, but not for ANSI block
> > + semantics. Here all temps live at the same level, the method
> level.
> > + The approach taken to two block-local temps in different blocks is
> to
> > + merge them into a single temp. e.g.
> > + expr
> > + ifTrue: [|temp| self statementOne]
> > + ifFalse: [|temp| self statementTwo]
> > + is effectvely transformed into
> > + | temp |
> > + expr
> > + ifTrue: [self statementOne]
> > + ifFalse: [self statementTwo]
> > + and
> > + expr do: [:each| | temp | ...].
> > + expr do: [:each| | temp | ...].
> > + is also effectively transformed into
> > + | temp |
> > + expr do: [:each| ...].
> > + expr do: [:each| ...].
> > +
> > + The closure compiler treats the former similarly, but not the
> latter.
> > + The indirection through #bindBlockTemp:within: allows the closure
> encoder to do this."
> > + ^self bindBlockTemp: name!
> >
> > Item was added:
> > + ----- Method: Encoder>>bindTemp: (in category 'temps') -----
> > + bindTemp: name
> > + "Declare a temporary; error not if a field or class variable."
> > + scopeTable at: name ifPresent:[:node|
> > + "When non-interactive raise the error only if its a duplicate"
> > + node isTemp
> > + ifTrue:[^self notify:'Name already used in this method']
> > + ifFalse:[self warnAboutShadowed: name]].
> > + ^self reallyBind: name!
> >
> > Item was added:
> > + ----- Method: Encoder>>bindTemp:in: (in category 'temps') -----
> > + bindTemp: name in: methodSelector
> > + "Declare a temporary; error not if a field or class variable."
> > + scopeTable at: name ifPresent:[:node|
> > + "When non-interactive raise the error only if its a duplicate"
> > + (node isTemp or:[requestor interactive])
> > + ifTrue:[^self notify:'Name already used in this method']
> > + ifFalse:[Transcript
> > + show: '(', name, ' is shadowed in "' , cue getClass
> printString , '>>' , methodSelector printString , '")']].
> > + ^self reallyBind: name!
> >
> > Item was added:
> > + ----- Method: Encoder>>bindUndeclaredTemp: (in category 'private')
> -----
> > + bindUndeclaredTemp: name
> > + ^scopeTable at: name put: (self newUndeclaredTemp: name)!
> >
> > Item was added:
> > + ----- Method: Encoder>>cantStoreInto: (in category 'encoding') -----
> > + cantStoreInto: varName
> > +
> > + ^StdVariables includesKey: varName!
> >
> > Item was added:
> > + ----- Method: Encoder>>classEncoding (in category 'private') -----
> > + classEncoding
> > + "This is a hack so that the parser may findout what class it was
> parsing for when it wants to create a syntax error view."
> > + ^ cue getClass!
> >
> > Item was added:
> > + ----- Method: Encoder>>doItInContextName (in category 'encoding') -----
> > + doItInContextName
> > + ^'ThisContext'!
> >
> > Item was added:
> > + ----- Method: Encoder>>encodeLiteral: (in category 'encoding') -----
> > + encodeLiteral: object
> > + ^self
> > + name: object
> > + key: object
> > + class: LiteralNode
> > + type: LdLitType
> > + set: litSet!
> >
> > Item was added:
> > + ----- Method: Encoder>>encodeSelector: (in category 'encoding') -----
> > + encodeSelector: aSelector
> > +
> > + ^self
> > + name: aSelector
> > + key: aSelector
> > + class: SelectorNode
> > + type: SendType
> > + set: selectorSet!
> >
> > Item was added:
> > + ----- Method: Encoder>>encodeVariable: (in category 'encoding') -----
> > + encodeVariable: name
> > + ^ self encodeVariable: name sourceRange: nil ifUnknown: [ self
> undeclared: name ]!
> >
> > Item was added:
> > + ----- Method: Encoder>>encodeVariable:ifUnknown: (in category
> 'encoding') -----
> > + encodeVariable: name ifUnknown: action
> > + ^self encodeVariable: name sourceRange: nil ifUnknown: action!
> >
> > Item was added:
> > + ----- Method: Encoder>>encodeVariable:sourceRange:ifUnknown: (in
> category 'encoding') -----
> > + encodeVariable: name sourceRange: range ifUnknown: action
> > + | varNode |
> > + varNode := scopeTable
> > + at: name
> > + ifAbsent:
> > + [(self lookupInPools: name
> > + ifFound: [:assoc | varNode := self global:
> assoc name: name])
> > + ifTrue: [varNode]
> > + ifFalse: [^action value]].
> > + range ifNotNil:
> > + [name first canBeGlobalVarInitial ifTrue:
> > + [globalSourceRanges addLast: { name. range. false }]].
> > +
> > + (varNode isTemp and: [varNode scope < 0]) ifTrue:
> > + [^OutOfScopeNotification signal
> > + ifTrue: [action value]
> > + ifFalse: [self notify: 'out of scope']].
> > + ^varNode!
> >
> > Item was added:
> > + ----- Method: Encoder>>environment (in category 'encoding') -----
> > + environment
> > + "Answer the environment of the current compilation context,
> > + be it in a class or global (e.g. a workspace)"
> > + ^cue environment!
> >
> > Item was added:
> > + ----- Method: Encoder>>fillDict:with:mapping:to: (in category
> 'initialize-release') -----
> > + fillDict: dict with: nodeClass mapping: keys to: codeArray
> > + | codeStream |
> > + codeStream := ReadStream on: codeArray.
> > + keys do:
> > + [:key | dict
> > + at: key
> > + put: (nodeClass new name: key key: key code:
> codeStream next)]!
> >
> > Item was added:
> > + ----- Method: Encoder>>fixTemp: (in category 'temps') -----
> > + fixTemp: name
> > + | node |
> > + node := scopeTable at: name ifAbsent: [].
> > + (node isTemp and: [node isIndirectTempVector not]) ifFalse:
> > + [self error: 'can only fix a floating temp var'].
> > + node index: nTemps.
> > + nTemps := nTemps + 1.
> > + ^node!
> >
> > Item was added:
> > + ----- Method: Encoder>>floatTemp: (in category 'temps') -----
> > + floatTemp: node
> > + (node == (scopeTable at: node name ifAbsent: [])
> > + and: [node isTemp
> > + and: [node index = (nTemps - 1)]]) ifFalse:
> > + [self error: 'can only float the last allocated temp var'].
> > + nTemps := nTemps - 1!
> >
> > Item was added:
> > + ----- Method: Encoder>>global:name: (in category 'private') -----
> > + global: ref name: name
> > +
> > + ^self
> > + name: name
> > + key: ref
> > + class: LiteralVariableNode
> > + type: LdLitIndType
> > + set: litIndSet!
> >
> > Item was added:
> > + ----- Method: Encoder>>globalSourceRanges (in category 'source
> mapping') -----
> > + globalSourceRanges
> > +
> > + ^ globalSourceRanges!
> >
> > Item was added:
> > + ----- Method: Encoder>>init:notifying: (in category
> 'initialize-release') -----
> > + init: aCue notifying: anObject
> > + "The use of the variable requestor is a bit confusing here. This is
> > + *not* the original requestor, which is available through the cue.
> > + It's the Parser instance that is using the encoder."
> > +
> > + self setCue: aCue.
> > + requestor := anObject.
> > + nTemps := 0.
> > + supered := false.
> > + self initScopeAndLiteralTables.
> > + cue getClass variablesAndOffsetsDo:
> > + [:variable "<String|CFieldDefinition>" :offset "<Integer|nil>" |
> > + offset isNil
> > + ifTrue: [scopeTable at: variable name put: (FieldNode new
> fieldDefinition: variable)]
> > + ifFalse: [scopeTable
> > + at: variable
> > + put: (offset >= 0
> > + ifTrue: [InstanceVariableNode new
> > + name: variable index:
> offset]
> > + ifFalse:
> [MaybeContextInstanceVariableNode new
> > + name: variable index:
> offset negated])]].
> > + cue context ifNotNil:
> > + [| homeNode |
> > + homeNode := self bindArg: self doItInContextName.
> > + "0th temp = aContext passed as arg"
> > + cue context tempNames withIndexDo:
> > + [:variable :index|
> > + variable ~= self doItInContextName ifTrue:
> > + [scopeTable
> > + at: variable
> > + put: (MessageAsTempNode new
> > + receiver: homeNode
> > + selector: #namedTempAt:
> > + arguments: (Array with: (self
> encodeLiteral: index))
> > + precedence: 3
> > + from: self)]]].
> > + sourceRanges := Dictionary new: 32.
> > + globalSourceRanges := OrderedCollection new: 32!
> >
> > Item was added:
> > + ----- Method: Encoder>>initScopeAndLiteralTables (in category
> 'initialize-release') -----
> > + initScopeAndLiteralTables
> > +
> > + scopeTable := StdVariables copy.
> > + litSet := StdLiterals copy.
> > + "comments can be left hanging on nodes from previous compilations.
> > + probably better than this hack fix is to create the nodes afresh
> on each compilation."
> > + scopeTable do:
> > + [:varNode| varNode comment: nil].
> > + litSet do:
> > + [:varNode| varNode comment: nil].
> > + selectorSet := StdSelectors copy.
> > + litIndSet := Dictionary new: 16.
> > + literalStream := WriteStream on: (Array new: 32).
> > + addedExtraLiterals := false.
> > + optimizedSelectors := Set new!
> >
> > Item was added:
> > + ----- Method: Encoder>>interactive (in category 'private') -----
> > + interactive
> > + "Answer true if compilation is interactive"
> > +
> > + ^requestor interactive!
> >
> > Item was added:
> > + ----- Method: Encoder>>litIndex: (in category 'encoding') -----
> > + litIndex: literal
> > + | p |
> > + p := literalStream position.
> > + p = self maxNumLiterals ifTrue:
> > + [self notify: 'More than ', self maxNumLiterals printString, '
> literals referenced.\You must split or otherwise simplify this method.\The
> ' withCRs, (self maxNumLiterals + 1) printString, 'th literal is: ',
> literal printString. ^nil].
> > + literal isLiteral ifTrue: "filters out BlockClosures,
> ExternalLibraryFunctions"
> > + [self setReadOnlyIfAppropriate: literal].
> > + "Would like to show where it is in the source code, but that info
> is hard to get."
> > + literalStream nextPut: literal.
> > + ^p!
> >
> > Item was added:
> > + ----- Method: Encoder>>literals (in category 'results') -----
> > + literals
> > + "Should only be used for decompiling primitives"
> > + ^ literalStream contents!
> >
> > Item was added:
> > + ----- Method: Encoder>>lookupInPools:ifFound: (in category 'private')
> -----
> > + lookupInPools: varName ifFound: assocBlock
> > +
> > + ^(Symbol lookup: varName)
> > + ifNil: [ false ]
> > + ifNotNil: [ :symbol |
> > + (cue bindingOf: symbol)
> > + ifNil: [ false ]
> > + ifNotNil: [:assoc|
> > + assocBlock value: assoc.
> > + true ]]!
> >
> > Item was added:
> > + ----- Method: Encoder>>lookupVariable:ifAbsent: (in category
> 'encoding') -----
> > + lookupVariable: name ifAbsent: aBlock
> > + "Answer the binding of name in the scope table or aBlock's vaue if
> none.
> > + Do not bind and do not lookup in pools. Used for correction,
> explanation etc"
> > + ^scopeTable at: name ifAbsent: aBlock!
> >
> > Item was added:
> > + ----- Method: Encoder>>maxIndexableLiterals (in category 'accessing')
> -----
> > + maxIndexableLiterals
> > + "Answer the maximum number of literals supported by the receiver's
> > + bytecode set. This is a nominal value based on the Blue Book
> bytecode
> > + set; subclasses answer a more accurate value."
> > + ^63!
> >
> > Item was added:
> > + ----- Method: Encoder>>maxNumLiterals (in category 'accessing') -----
> > + maxNumLiterals
> > + ^CompiledMethod maxNumLiterals min: self maxIndexableLiterals!
> >
> > Item was added:
> > + ----- Method: Encoder>>maxTemp (in category 'temps') -----
> > + maxTemp
> > +
> > + ^nTemps!
> >
> > Item was added:
> > + ----- Method: Encoder>>methodNodeClass (in category 'accessing') -----
> > + methodNodeClass
> > + ^MethodNode!
> >
> > Item was added:
> > + ----- Method: Encoder>>name:key:class:type:set: (in category
> 'private') -----
> > + name: name key: key class: leafNodeClass type: type set: dict
> > + ^dict at: key
> > + ifAbsentPut:
> > + [leafNodeClass new
> > + name: name
> > + key: key
> > + index: nil
> > + type: type]!
> >
> > Item was added:
> > + ----- Method: Encoder>>newTemp: (in category 'temps') -----
> > + newTemp: name
> > +
> > + nTemps := nTemps + 1.
> > + ^ TempVariableNode new
> > + name: name
> > + index: nTemps - 1
> > + type: LdTempType
> > + scope: 0!
> >
> > Item was added:
> > + ----- Method: Encoder>>newUndeclaredTemp: (in category 'temps') -----
> > + newUndeclaredTemp: name
> > + ^UndeclaredVariableNode new name: name!
> >
> > Item was added:
> > + ----- Method: Encoder>>noteOptimizedSelector: (in category 'encoding')
> -----
> > + noteOptimizedSelector: aSymbol
> > + "Register a selector as being optimized.
> > + These optimized selectors will later be registered into the
> literals so that tools can easily browse senders."
> > + optimizedSelectors add: aSymbol!
> >
> > Item was added:
> > + ----- Method: Encoder>>noteSourceRange:forNode: (in category 'source
> mapping') -----
> > + noteSourceRange: range forNode: node
> > +
> > + sourceRanges at: node put: range!
> >
> > Item was added:
> > + ----- Method: Encoder>>noteSuper (in category 'initialize-release')
> -----
> > + noteSuper
> > +
> > + supered := true!
> >
> > Item was added:
> > + ----- Method: Encoder>>notify: (in category 'error handling') -----
> > + notify: string
> > + "Put a separate notifier on top of the requestor's window"
> > + | req |
> > + requestor == nil
> > + ifFalse:
> > + [req := requestor.
> > + self release.
> > + req notify: string].
> > + ^false!
> >
> > Item was added:
> > + ----- Method: Encoder>>notify:at: (in category 'error handling') -----
> > + notify: string at: location
> > +
> > + | req |
> > + requestor == nil
> > + ifFalse:
> > + [req := requestor.
> > + self release.
> > + req notify: string at: location].
> > + ^false!
> >
> > Item was added:
> > + ----- Method: Encoder>>possibleNamesFor: (in category 'private') -----
> > + possibleNamesFor: proposedName
> > + | results |
> > + results := cue getClass
> > + possibleVariablesFor: proposedName
> > + continuedFrom: nil.
> > + ^ proposedName correctAgainst: nil continuedFrom: results.
> > + !
> >
> > Item was added:
> > + ----- Method: Encoder>>possibleVariablesFor: (in category 'private')
> -----
> > + possibleVariablesFor: proposedVariable
> > +
> > + | results |
> > + results := proposedVariable correctAgainstDictionary: scopeTable
> > + continuedFrom: nil.
> > + proposedVariable first canBeGlobalVarInitial ifTrue:
> > + [ results := cue getClass possibleVariablesFor: proposedVariable
> > + continuedFrom: results ].
> > + ^ proposedVariable correctAgainst: nil continuedFrom: results.
> > + !
> >
> > Item was added:
> > + ----- Method: Encoder>>rawSourceRanges (in category 'source mapping')
> -----
> > + rawSourceRanges
> > +
> > + ^ sourceRanges !
> >
> > Item was added:
> > + ----- Method: Encoder>>reallyBind: (in category 'private') -----
> > + reallyBind: name
> > +
> > + | node |
> > + node := self newTemp: name.
> > + scopeTable at: name put: node.
> > + ^node!
> >
> > Item was added:
> > + ----- Method: Encoder>>release (in category 'initialize-release') -----
> > + release
> > +
> > + requestor := nil!
> >
> > Item was added:
> > + ----- Method: Encoder>>selector (in category 'accessing') -----
> > + selector
> > + ^selector!
> >
> > Item was added:
> > + ----- Method: Encoder>>selector: (in category 'accessing') -----
> > + selector: aSymbol
> > + selector := aSymbol!
> >
> > Item was added:
> > + ----- Method: Encoder>>setCue: (in category 'private') -----
> > + setCue: aCue
> > + cue := aCue.
> > +
> > + "Also set legacy instance variables for methods that
> > + don't use cue yet"
> > + class := cue getClass.!
> >
> > Item was added:
> > + ----- Method: Encoder>>setReadOnlyIfAppropriate: (in category
> 'encoding') -----
> > + setReadOnlyIfAppropriate: literal
> > + "If literal is not read-only and should be, set it to be read-only,
> along with any other such literals it may contain."
> > + (literal isReadOnlyObject
> > + or: [literal isVariableBinding]) ifFalse:
> > + [literal setIsReadOnlyObject: true.
> > + literal isArray ifTrue:
> > + [literal do: [:subLiteral| self setReadOnlyIfAppropriate:
> subLiteral]]]!
> >
> > Item was added:
> > + ----- Method: Encoder>>sharableLitIndex: (in category 'encoding') -----
> > + sharableLitIndex: literal
> > + "Special access prevents multiple entries for post-allocated super
> send special selectors"
> > + 1 to: literalStream position do:
> > + [:index|
> > + (literal literalEqual: (literalStream originalContents at:
> index)) ifTrue:
> > + [^index - 1]].
> > + ^self litIndex: literal!
> >
> > Item was added:
> > + ----- Method: Encoder>>sourceMap (in category 'source mapping') -----
> > + sourceMap
> > + "Answer with a sorted set of associations (pc range)."
> > +
> > + ^sourceRanges associations
> > + replace: [ :association | Association key: association key
> pc value: association value ];
> > + sort!
> >
> > Item was added:
> > + ----- Method: Encoder>>sourceRangeFor: (in category 'source mapping')
> -----
> > + sourceRangeFor: node
> > +
> > + ^sourceRanges at: node!
> >
> > Item was added:
> > + ----- Method: Encoder>>tempNames (in category 'results') -----
> > + tempNames
> > +
> > + ^ self tempNodes collect:
> > + [:node | (node isMemberOf: MessageAsTempNode)
> > + ifTrue: [scopeTable keyAtValue: node]
> > + ifFalse: [node key]]!
> >
> > Item was added:
> > + ----- Method: Encoder>>tempNodes (in category 'results') -----
> > + tempNodes
> > +
> > + | tempNodes |
> > + tempNodes := OrderedCollection new.
> > + scopeTable associationsDo:
> > + [:assn |
> > + assn value isArray
> > + ifTrue: [assn value do: [:temp| tempNodes add: temp]]
> > + ifFalse: [assn value isTemp ifTrue: [tempNodes add: assn
> value]]].
> > + ^tempNodes sort: [:n1 :n2 | n1 index <= n2 index]!
> >
> > Item was added:
> > + ----- Method: Encoder>>temps:literals:class: (in category
> 'initialize-release') -----
> > + temps: tempVars literals: lits class: cl
> > + "Initialize this encoder for decompilation."
> > +
> > + self setCue: (CompilationCue class: cl).
> > + supered := false.
> > + nTemps := tempVars size.
> > + tempVars do: [:node | scopeTable at: node name put: node].
> > + literalStream := WriteStream on: (Array new: lits size).
> > + literalStream nextPutAll: lits.
> > + sourceRanges := Dictionary new: 32.
> > + globalSourceRanges := OrderedCollection new: 32.!
> >
> > Item was added:
> > + ----- Method: Encoder>>tempsAndBlockArgs (in category 'results') -----
> > + tempsAndBlockArgs
> > + | tempNodes |
> > + tempNodes := OrderedCollection new.
> > + scopeTable associationsDo:
> > + [:assn | | var |
> > + var := assn value.
> > + (var isTemp
> > + and: [var isMethodArg not
> > + and: [var scope = 0 or: [var scope = -1]]]) ifTrue:
> > + [tempNodes add: var]].
> > + ^tempNodes!
> >
> > Item was added:
> > + ----- Method: Encoder>>undeclared: (in category 'encoding') -----
> > + undeclared: name
> > + | sym |
> > + (requestor notNil and: [requestor interactive]) ifTrue:
> > + [ requestor requestor == #error: ifTrue: [ requestor error:
> 'Undeclared' ].
> > + ^ self notify: 'Undeclared' ].
> > + "Allow knowlegeable clients to squash the undeclared warning if
> they want (e.g.
> > + Diffing pretty printers that are simply formatting text). As this
> breaks
> > + compilation it should only be used by clients that want to discard
> the result
> > + of the compilation. To squash the warning use e.g.
> > + [Compiler format: code in: class notifying: nil decorated:
> false]
> > + on: UndeclaredVariableNotification
> > + do: [:ex| ex resume: false]"
> > + sym := name asSymbol.
> > + ^ (UndeclaredVariableNotification new
> > + name: name
> > + selector: selector
> > + class: cue getClass) signal
> > + ifTrue:
> > + [ | undeclared assoc |
> > + undeclared := cue environment undeclared.
> > + assoc := [ undeclared add: (undeclared associationClass
> key: sym value: nil) ]
> > + on: AttemptToWriteReadOnlyGlobal
> > + do: [ : noti | noti resume: true ].
> > + self
> > + global: assoc
> > + name: sym ]
> > + ifFalse:
> > + [ self
> > + global: (Association key: sym)
> > + name: sym ]!
> >
> > Item was added:
> > + ----- Method: Encoder>>undeclaredTemps (in category 'results') -----
> > + undeclaredTemps
> > + ^(scopeTable select: [:var | var isVariableNode and: [var
> isUndeclared]]) values!
> >
> > Item was added:
> > + ----- Method: Encoder>>unusedTempNames (in category 'results') -----
> > + unusedTempNames
> > + | unused |
> > + unused := OrderedCollection new.
> > + scopeTable associationsDo:
> > + [:assn | | name |
> > + (assn value isUnusedTemp) ifTrue:
> > + [name := assn value key.
> > + name ~= self doItInContextName ifTrue: [unused add:
> name]]].
> > + ^ unused!
> >
> > Item was added:
> > + ----- Method: Encoder>>warnAboutShadowed: (in category 'private') -----
> > + warnAboutShadowed: name
> > +
> > + requestor addWarning: name,' is shadowed'.
> > + selector ifNil: [^ self].
> > + (ShadowedVariableNotification new
> > + name: name
> > + selector: selector
> > + class: cue getClass) signal.!
> >
> > Item was added:
> > + BytecodeEncoder subclass: #EncoderForSistaV1
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> > +
> > + !EncoderForSistaV1 commentStamp: 'eem 3/10/2022 10:59' prior: 0!
> > + EncoderForSistaV1 encodes a bytecode set for Smalltalk that lifts
> limits on the number of literals, branch distances, the number of temporary
> variables, and provides extended push integer and push character
> bytecodes. The bytecode set also supports creating FullBlockClosures,
> closures whose method is separate from their home method's. Bytecodes are
> ordered by length to make decoding easier. Bytecodes marked with an * are
> extensible via a prefix extension bytecode.
> > +
> > + N.B. Extension bytecodes can only come before extensible bytecodes,
> and only if valid (one cannot extend a bytecode extensible by Ext A with an
> Ext B). An extensible bytecode consumes (and zeros) its extension(s).
> Hence the hidden implicit variables holding extensions are always zero
> except after a valid sequence of extension bytecodes. The implication is
> that a bytecode interpreter should maintain the extension values in static
> variables initialized to zero at start-up, and live only from the start of
> a sequence of extension bytecodes to the end of the extended bytecode
> immediately following.
> > +
> > + While the bytecode set lifts limits, it still assumes there are no
> more than 65535 literals (as of 2020 the CompiledCode header word imposes a
> 32,767 limit on number of literals), and no more than 256 stack slots (used
> for arguments, temporaries, and stack contents) in a Context.
> > +
> > + EncoderForSistaV1 also includes an extended set of bytecodes for
> Sista, the Speculative Inlining Smalltalk Architecture, a project by
> Clément Bera and Eliot Miranda. Scorch is an optimizer that exists in the
> Smalltalk image, /not/ in the VM, and optimizes by substituting normal
> bytecoded methods by optimized bytecoded methods that may use special
> bytecodes for which the Cogit can generate faster code. These bytecodes
> eliminate overheads such as bounds checks or polymorphic code (indexing
> Array, ByteArray, String etc). But the bulk of the optimization performed
> is in inlining blocks and sends for the common path. This bytecode set
> therefore differs from a normal Smalltalk set in providing a set of inlined
> primitives that do not validate their arguments that the compiler generates
> only when it can prove that the primitives' arguments are valid.
> > +
> > + The basic scheme is that the Cogit generates code containing
> performance counters. When these counters trip, a callback into the image
> is performed, at which point Scorch analyses some portion of the stack,
> looking at performance data for the methods on the stack, and optimises
> based on the stack and performance data. Execution then resumes in the
> optimized code.
> > +
> > + The Sista Cogit (e.g. SistaStackToRegisterMappingCogit) adds counters
> to conditional branches. Each branch has an executed and a taken count.
> On execution the executed count is decremented and if the count goes below
> zero the VM sends a message at a special index in the specialObjectsArray
> (as of writing, conditionalCounterTrippedOn:). Then if the branch is taken
> the taken count is decremented. The two counter values allow the Sista
> optimizer to collect basic block execution paths and to know what are the
> "hot" paths through execution that are worth agressively optimizing. Since
> conditional branches are about 1/6 as frequent as sends, and since they can
> be used to determine the hot path through code, they are a better choice to
> count than, for example, method or block entry.
> > +
> > + The VM provides a primitive that fills an Array with the state of the
> counters, and the state of each linked send in a method. The optimizer
> obtains the branch and send data for a method via this primitive.
> > +
> > + Instance Variables (inherited)
> > +
> > + Here is the list of bytecodes. An asterisk implies the bytecode takes
> either extA or extB extensions. Two asterisks imply it takes both extA and
> extB extensions. A number in parentheses is a note. See the notes at the
> end of the table.
> > +
> > + 1 Byte Bytecodes
> > + code (note) binary name
> > + 0-15 0000 iiii Push Receiver Variable #iiii
> > + 16-31 0001 iiii Push Literal Variable #iiii
> > + 32-63 001 iiiii Push Literal #iiiii
> > + 64-71 01000 iii Push Temp #iii
> > + 72-75 010010 ii Push Temp #ii + 8
> > + 76 01001100 Push Receiver
> > + 77 01001101 Push true
> > + 78 01001110 Push false
> > + 79 01001111 Push nil
> > + 80 01010000 Push 0
> > + 81 01010001 Push 1
> > + * 82 01010010 Push thisContext, (then Extend
> B = 1 => push thisProcess)
> > + 83 01010011 Duplicate Stack Top
> > + 84-87 010101 ii UNASSIGNED
> > + 88-91 010110 ii Return Receiver/true/false/nil
> > + 92 01011100 Return top
> > + 93 01011101 BlockReturn nil
> > + * 94 01011110 BlockReturn Top [* return from
> enclosing block N, N = Extend A, then jump by Ext B ]
> > + * 95 01011111 Nop
> > + 96-111 0110 iiii Send Arithmetic Message #iiii (+
> - < > <= >= = ~= * / \\ @ bitShift: // bitAnd: bitOr:)
> > + 112-119 01110 iii Send Special Message #iii + 0 (at:
> at:put: size next nextPut: atEnd == class)
> > + 120-127 01111 iii Send Special Message #iii + 8 (~~
> value value: do: new new: x y)
> > + 128-143 1000 iiii Send Literal Selector #iiii With 0
> Argument
> > + 144-159 1001 iiii Send Literal Selector #iiii With 1
> Arguments
> > + 160-175 1010 iiii Send Literal Selector #iiii With 2
> Arguments
> > + 176-183 10110 iii Jump iii + 1 (i.e., 1 through 8)
> > + 184-191 10111 iii Pop and Jump 0n True iii +1 (i.e.,
> 1 through 8)
> > + 192-199 11000 iii Pop and Jump 0n False iii +1 (i.e.,
> 1 through 8)
> > + 200-207 11001 iii Pop and Store Receiver Variable #iii
> > + 208-215 11010 iii Pop and Store Temporary Variable
> #iii
> > + 216 11011000 Pop Stack Top
> > + 217 (5) 11011001 Unconditional trap
> > + 218-219 1101101 i UNASSIGNED
> > + 220-223 110111 ii UNASSIGNED
> > +
> > + 2 Byte Bytecodes
> > + * 224 11100000 aaaaaaaa Extend A (Ext A = Ext A prev *
> 256 + Ext A) A is an unsigned extension.
> > + * 225 11100001 bbbbbbbb Extend B (Ext B = Ext B prev *
> 256 + Ext B) B is a signed extension.
> > + * 226 11100010 iiiiiiii Push Receiver Variable
> #iiiiiiii (+ Extend A * 256)
> > + * 227 11100011 iiiiiiii Push Literal Variable
> #iiiiiiii (+ Extend A * 256)
> > + * 228 11100100 iiiiiiii Push Literal #iiiiiiii (+
> Extend A * 256)
> > + 229 11100101 iiiiiiii Push Temporary Variable
> #iiiiiiii
> > + 230 11100110 iiiiiiii UNASSIGNED (was
> pushNClosureTemps)
> > + 231 11100111 jkkkkkkk Push (Array new: kkkkkkk) (j = 0)
> > + & Pop kkkkkkk elements into:
> (Array new: kkkkkkk) (j = 1)
> > + * 232 11101000 iiiiiiii Push Integer #iiiiiiii (+
> Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, d=0, s=1)
> > + * 233 11101001 iiiiiiii Push Character #iiiiiiii
> (+ Extend A * 256)
> > + ** 234 11101010 iiiiijjj Send Literal Selector
> #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments
> > + ** 235 (1) 11101011 iiiiijjj ExtendB < 64
> > + ifTrue: [Send To Superclass
> Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8)
> Arguments]
> > + ifFalse: [Send To Superclass of
> Stacked Class Literal Selector #iiiii (+ Extend A * 32) with jjj (+ (Extend
> B bitAnd: 63) * 8) Arguments]
> > + 236 11101100 iiiiiiii UNASSIGNED
> > + * 237 11101101 iiiiiiii Jump #iiiiiiii (+ Extend B
> * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, d=0, s=1)
> > + ** 238 (4) 11101110 iiiiiiii Pop and Jump 0n True
> #iiiiiiii (+ Extend B * 256, where Extend B >= 0)
> > + ** 239 (4) 11101111 iiiiiiii Pop and Jump 0n False
> #iiiiiiii (+ Extend B * 256, where Extend B >= 0)
> > + ** 240 (3) 11110000 iiiiiiii Pop and Store Receiver
> Variable #iiiiiii (+ Extend A * 256)
> > + ** 241 (3) 11110001 iiiiiiii Pop and Store Literal
> Variable #iiiiiiii (+ Extend A * 256)
> > + 242 11110010 iiiiiiii Pop and Store Temporary
> Variable #iiiiiiii
> > + ** 243 (3) 11110011 iiiiiiii Store Receiver
> Variable #iiiiiii (+ Extend A * 256)
> > + ** 244 (3) 11110100 iiiiiiii Store Literal Variable
> #iiiiiiii (+ Extend A * 256)
> > + 245 11110110 iiiiiiii Store Temporary Variable
> #iiiiiiii
> > + 246-247 1111011 i xxxxxxxx UNASSIGNED
> > +
> > + 3 Byte Bytecodes
> > + 248 (2) 11111000 iiiiiiii mssjjjjj Call
> Primitive #iiiiiiii + (jjjjj * 256)
> > + m=1 means inlined primitive, no hard
> return after execution.
> > + ss defines the unsafe operation set
> used to encode the operations.
> > + (ss = 0 means sista unsafe operations,
> ss = 01 means lowcode operations, other numbers are as yet used)
> > + Lowcode inlined primitives may have
> extensions.
> > + * 249 11111001 xxxxxxxx siyyyyyy Push Closure
> Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy
> receiverOnStack: s = 1 ignoreOuterContext: i = 1
> > + ** 250 11111010 eeiiikkk jjjjjjjj Push
> Closure Num Copied iii (+ExtA//16*8) Num Args kkk (+ ExtA\\16*8) BlockSize
> jjjjjjjj (+ExtB*256). ee = num extensions
> > + 251 11111011 kkkkkkkk sjjjjjjj Push Temp At
> kkkkkkkk In Temp Vector At: jjjjjjj, s = 1 implies remote inst var access
> instead of remote temp vector access
> > + * 252 (3) 11111100 kkkkkkkk sjjjjjjj Store Temp
> At kkkkkkkk In Temp Vector At: jjjjjjj s = 1 implies remote inst var access
> instead of remote temp vector access
> > + * 253 (3) 11111101 kkkkkkkk sjjjjjjj Pop and
> Store Temp At kkkkkkkk In Temp Vector At: jjjjjjj s = 1 implies remote inst
> var access instead of remote temp vector access
> > + ** 254 (5) 11111110 kkkkkkkk jjjjjjjj branch If
> Not Instance Of Behavior/Array Of Behavior literal kkkkkkkk (+ Extend A *
> 256, where Extend A >= 0) distance jjjjjjjj (+ Extend B * 256, where Extend
> B >= 0 and <= 127)
> > + ** 254 (5) 11111110 kkkkkkkk jjjjjjjj branch If
> Instance Of Behavior/Array Of Behavior literal kkkkkkkk (+ Extend A * 256,
> where Extend A >= 0) distance jjjjjjjj (+ (Extend B bitAnd: 127) * 256,
> where Extend B >= 128 and <= 255)
> > + * 255 11111111 xxxxxxxx jjjjjjjj UNASSIGNED
> > +
> > + (1) Bytecode 235 is a super send bytecode that starts the lookup in
> the superclass of some class. It has two forms, "normal" and "directed".
> In the normal form, the class is the value of the method's
> methodClassAssociation which must be the last literal. In the directed
> form the class is the class on top of stack.
> > +
> > + (2) The Call Primitive Bytecode (see below) specifies either a
> primitive in the primitive table (m=0) or an inlined primitive (m=1).
> Non-inlined primitives from the primitive table have index (jjjjjjj * 256)
> + iiiiiiii and return from the method if they succeed. This bytecode is
> only valid as the first bytecode of a method. Inline primitives have index
> (jjjjjjj * 256) + iiiiiiii, cannot fail, and do not return when they
> succeed, yielding a result (typically on top of stack after popping their
> arguments, but possibly in a byte data stack, for example for unboxed
> floating-point primitives).
> > +
> > + (3) ExtB lowest bit implies no store check is needed, ExtB second bit
> implies the object may be a context, ExtB third bit implies no
> immutability/read-only check is needed, other bits in the extension are
> unused.
> > +
> > + (4) ExtA = 1 implies no mustBeBoolean trampoline is needed, other bits
> in the extension are unused
> > +
> > + (5) these are Scorch/Sista bytecodes generated by an optimizing
> compiler and not used in normal Smalltalk code.
> > +
> > +
> > + The CallPrimitive bytecode is divided into two halves, those for
> normal primtiives, occurring at the beginning of a method, and those for
> inline primitives, anywhere within the body of a method. This is a three
> byte bytecode, the first byte being 248, and the second byte being a
> big-endian 16-bit primitive index. If the top bit of the first byte of the
> primitive index is 1 then this is a normal primitive invocation. If it is
> zero then the remaining 15 bits define 32k primitives, organized as four 8k
> "pages". The first page is used for and reserved by the Sista optimizing
> compiler. The second page is usd for and reserved by the Lowcode FFI
> marshalling primitive set. The other two sets are unspecified and unused.
> > +
> > + Here is the specification of the Sista unsafe instructions (unsafe
> operations, set 00). The lowcode set uses external specifications.
> > + We sort the inline primitive operations by arity. Nullary primitives
> occupy the 0-999 range. Unary primitives occupy the 1-1999 range, up until
> 8 args. 8191 instructions can be encoded in each unsafe operation set,
> instructions from 0 to 7 arguments can have 1000 different instructions
> each, while 8 args instructions can have 192 different instructions.
> > +
> > + Sista defines the following inlined primitives (CallPrimitive iiiiiiii
> 100jjjjj, n = jjjjjiiiiiiii)
> > + 1000 class
> > + 1001 pointer numSlots
> > + 1002 pointer basicSize
> > + 1003 byte8Type format numBytes (includes CompiledMethod)
> > + 1004 short16Type format numShorts
> > + 1005 word32Type format numWords
> > + 1006 doubleWord64Type format numDoubleWords
> > +
> > + 1010 ensure number of bytes available.
> > + 1011 fixed-sized new. (objects with 0 to n inst vars)
> > +
> > + 1020 identityHash (non-immediate, non-Behavior)
> > + 1021 identityHash (SmallInteger)
> > + 1022 identityHash (Character)
> > + 1023 identityHash (SmallFloat64)
> > + 1024 identityHash (Behavior, has hash?)
> > +
> > + 1030 immediateAsInteger (Character)
> > + 1031 immediateAsInteger (SmallFloat64)
> > + 1035 immediateAsFloat (Smallinteger)
> > +
> > + 2000 SmallInteger #+. Both arguments are SmallIntegers and the
> result fits in a SmallInteger (* depends on word size)
> > + 2001 SmallInteger #-. Both arguments are SmallIntegers and the
> result fits in a SmallInteger (* depends on word size)
> > + 2002 SmallInteger #*. Both arguments are SmallIntegers and the
> result fits in a SmallInteger (* depends on word size)
> > + 2003 SmallInteger #/. Both arguments are SmallIntegers and the
> result fits in a SmallInteger (* depends on word size)
> > + 2004 SmallInteger #//. Both arguments are SmallIntegers and the
> result fits in a SmallInteger (* depends on word size)
> > + 2005 SmallInteger #\\. Both arguments are SmallIntegers and the
> result fits in a SmallInteger (* depends on word size)
> > + 2006 SmallInteger #quo:. Both arguments are SmallIntegers and the
> result fits in a SmallInteger (* depends on word size)
> > +
> > + 2011 Variable-sized pointers new (new:). Array, etc.
> > + 2012 Variable-sized byte new (new:). ByteArray, ByteString, etc.
> > + 2013 Variable-sized 16-bit new (new:). DoubleByteArray, etc.
> > + 2014 Variable-sized 32-bit new (new:). Bitmap, FloatArray, etc.
> > + 2015 Variable-sized 64-bit new (new:). DoubleWordArray, etc.
> > +
> > + 2016 SmallInteger #bitAnd:. Both arguments are SmallIntegers and
> the result fits in a SmallInteger (* depends on word size)
> > + 2017 SmallInteger #bitOr:. Both arguments are SmallIntegers and
> the result fits in a SmallInteger (* depends on word size)
> > + 2018 SmallInteger #bitXor:. Both arguments are SmallIntegers and
> the result fits in a SmallInteger (* depends on word size)
> > + 2019 SmallInteger #bitShiftLeft:. Both arguments are SmallIntegers
> and the result fits in a SmallInteger (* depends on word size)
> > + 2020 SmallInteger #bitShiftRight:. Both arguments are
> SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> > +
> > + 2032 SmallInteger #>. Both arguments are SmallIntegers
> > + 2033 SmallInteger #<. Both arguments are SmallIntegers
> > + 2034 SmallInteger #>=. Both arguments are SmallIntegers
> > + 2035 SmallInteger #<=. Both arguments are SmallIntegers
> > + 2036 SmallInteger #=. Both arguments are SmallIntegers
> > + 2037 SmallInteger #~=. Both arguments are SmallIntegers
> > +
> > + 2064 Pointer Object>>at:. The receiver is guaranteed to be a
> pointer object. The 0-relative (1-relative?) index is an in-range
> SmallInteger
> > + 2065 Byte Object>>at:. The receiver is guaranteed to be
> a non-pointer object. The 0-relative (1-relative?) index is an in-range
> SmallInteger. The result is a SmallInteger.
> > + 2066 16-bit Word Object>>at:. The receiver is guaranteed
> to be a non-pointer object. The 0-relative (1-relative?) index is an
> in-range SmallInteger. The result is a SmallInteger.
> > + 2067 32-bit DoubleWord Object>>at:. The receiver is
> guaranteed to be a non-pointer object. The 0-relative (1-relative?) index
> is an in-range SmallInteger. The result is a SmallInteger or a
> LargePositiveInteger.
> > + 2068 64-bit QuadWord Object>>at:. The receiver is guaranteed to
> be a non-pointer object. The 0-relative (1-relative?) index is an in-range
> SmallInteger. The result is a SmallInteger or a LargePositiveInteger.
> > +
> > + The following instructions can have the ExtB check flag (See (3)).
> > + 3000 Pointer Object>>at:put:. The receiver is guaranteed
> to be a pointer object. The 0-relative (1-relative?) index is an in-range
> SmallInteger
> > + 3001 Byte Object>>at:put:. The receiver is guaranteed to
> be a non-pointer object. The 0-relative (1-relative?) index is an in-range
> SmallInteger. The argument is a SmallInteger. The primitive stores the
> least significant 8 bits.
> > + 3002 Word Object>>at:put:. The receiver is guaranteed to
> be a non-pointer object. The 0-relative (1-relative?) index is an in-range
> SmallInteger. The argument is a SmallInteger. The primitive stores the
> least significant 16 bits.
> > + 3003 DoubleWord Object>>at:put:. The receiver is guaranteed to
> be a non-pointer object. The 0-relative (1-relative?) index is an in-range
> SmallInteger. The argument is a SmallInteger. The primitive stores the
> least significant 32 bits.
> > + 3004 QuadWord Object>>at:put:. The receiver is guaranteed to
> be a non-pointer object. The 0-relative (1-relative?) index is an in-range
> SmallInteger. The argument is a SmallInteger. The primitive stores the
> least significant 64 bits.
> > +
> > + 3021 Byte Object >> equals:length: The receiver and the
> arguments are both byte objects and have both the same size (length). The
> length argument is a smallinteger. Answers true if all fields are equal,
> false if not. Comparison is bulked to word comparison.
> > +
> > + 4000 Pointer Object>> fillFrom:to:with: The receiver is a Pointer
> object. the middle two arguments are smallintegers. Last argument is any
> object. Fills the object in between the two indexes with last argument.
> Receiver is guaranteed to be mutable. The pointer accesses are raw (no inst
> var check). If ExtB is set to 1, no store check is present. Else a single
> store check is done for the bulk operation. Answers the receiver.
> > +
> > + 5000 Pointer Object>> replaceFrom:to:with:startingAt: Src and dest
> are pointer objects. ScrPos, scrLast and destLast are smallintegers.
> Receiver is guaranteed to be mutable. Both ranges are in-bounds. The
> pointer accesses are raw (no inst var check). As for the normal primitive,
> the copy is linear. Answers the receiver.
> > +
> > +
> > + Lowcode defines inlined primitives for the range CallPrimitive
> iiiiiiii 101jjjjj, n = jjjjjiiiiiiii.!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>bindingReadScanBlockFor:using:
> (in category 'compiled method support') -----
> > + bindingReadScanBlockFor: litVarIndex using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for reads of the value of the binding with zero-relative index
> litVarIndex.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > +
> > + " 16-31 0001 i i i i Push Literal Variable
> #iiii
> > + * 224 11100000 aaaaaaaa Extend A (Ext A = Ext A
> prev * 256 + Ext A)
> > + * 227 11100011 i i i i i i i i Push Literal
> Variable #iiiiiiii (+ Extend A * 256)"
> > + | extension |
> > + extension := 0.
> > + ^[:b| | prevext |
> > + prevext := extension.
> > + extension := b = 224 ifTrue: [scanner followingByte bitShift: 8]
> ifFalse: [0].
> > + (b < 32 and: [b >= 16 and: [b - 16 = litVarIndex]])
> > + or: [b = 227
> > + and: [scanner followingByte + prevext = litVarIndex]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>bindingWriteScanBlockFor:using:
> (in category 'compiled method support') -----
> > + bindingWriteScanBlockFor: litVarIndex using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for writes of the value of the binding with zero-relative index
> litVarIndex.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > +
> > + "* 224 11100000 aaaaaaaa Extend A (Ext A = Ext A
> prev * 256 + Ext A)
> > + * 241 11110001 iiiiiiii Pop and Store Literal
> Variable #iiiiiiii (+ Extend A * 256)
> > + * 244 11110100 iiiiiiii Store Literal Variable
> #iiiiiiii (+ Extend A * 256)"
> > + | extension |
> > + extension := 0.
> > + ^[:b| | prevext |
> > + prevext := extension.
> > + extension := b = 224 ifTrue: [scanner followingByte bitShift: 8]
> ifFalse: [0].
> > + (b = 241 or: [b = 244])
> > + and: [scanner followingByte + prevext = litVarIndex]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>blockMethodOrNilFor:in:at: (in
> category 'instruction stream support') -----
> > + blockMethodOrNilFor: anInstructionStream in: method at: pc
> > + "If anInstructionStream is at a block creation bytecode then answer
> the block's
> > + CompiledBlock, otherwise answer nil.
> > +
> > + The complication is that for convenience we allow the pc to point
> to the
> > + raw send bytecode after its extension(s), or at the extension(s)
> preceding it.
> > + 249 11111001 xxxxxxxx siyyyyyy push Closure
> Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy
> receiverOnStack: s = 1 ignoreOuterContext: i = 1"
> > +
> > + | byte |
> > + byte := method at: pc.
> > + byte = 249 ifTrue:
> > + ["it could be extended..."
> > + ^self extensionsFor: pc in: method into:
> > + [:extA :extB :nExtBytes|
> > + method literalAt: (method at: pc + nExtBytes + 1) + (extA
> bitShift: 8) + 1]].
> > + ^byte = 16rE0 ifTrue:
> > + [self extensionsAt: pc in: method into:
> > + [:extA :extB :nExtBytes|
> > + (method at: pc + nExtBytes) = 249 ifTrue:
> > + [method literalAt: (method at: pc + nExtBytes + 1) +
> (extA bitShift: 8) + 1]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>bytecodeSize: (in category
> 'instruction stream support') -----
> > + bytecodeSize: bytecode
> > + "Answer the number of bytes in the bytecode."
> > + bytecode < 224 ifTrue: [^1].
> > + bytecode < 248 ifTrue: [^2].
> > + ^3!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>callPrimitiveCode (in category
> 'bytecode decoding') -----
> > + callPrimitiveCode
> > + "Answer the call primitive bytecode, if it exists in the encoder's
> bytecode set, or nil if not.
> > + 248 11111000 iiiiiiii mjjjjjjj Call Primitive
> #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return
> after execution."
> > + ^248!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>canBeSpecialLiteral: (in
> category 'testing') -----
> > + canBeSpecialLiteral: aLiteral
> > + "This check can be used to prevent unnecessary use of
> #scanBlockOrNilForLiteral:."
> > +
> > + aLiteral isVariableBinding ifTrue: [^false]. "a common case; don't
> waste time analysing..."
> > +
> > + aLiteral isSymbol ifTrue: [^ Smalltalk specialSelectors
> identityIncludes: aLiteral].
> > + aLiteral isCharacter ifTrue: [^ aLiteral asInteger <= 65535].
> > + aLiteral isInteger ifTrue: [^ aLiteral between: -32768 and: 32767].
> > +
> > + aLiteral == true ifTrue: [^ true].
> > + aLiteral == false ifTrue: [^ true].
> > + aLiteral == nil ifTrue: [^ true].
> > +
> > + ^ false!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>createClosureCode (in category
> 'bytecode decoding') -----
> > + createClosureCode
> > + "Answer the create closure bytecode, if it exists in the encoder's
> bytecode set, or nil if not.
> > + Actually this code is that for a closure whose bytecodes are
> nested within its home method's."
> > +
> > + ^250!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>createClosureScanBlock (in
> category 'compiled method support') -----
> > + createClosureScanBlock
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for block closure creation bytecodes. Note that with this
> interface we can't answer
> > + true for the extension in front of a push closure bytecode and so
> the interface may
> > + have to change at some point."
> > +
> > + "* 224 11100000 aaaaaaaa Extend A (Ext A = Ext A prev *
> 256 + Ext A)
> > + * 225 11100001 bbbbbbbb Extend B (Ext B = Ext B prev *
> 256 + Ext B)
> > + ** 249 11111001 xxxxxxxx siyyyyyy push Closure
> Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy
> receiverOnStack: s = 1 ignoreOuterContext: i = 1
> > + ** 250 11111010 eeiiikkk jjjjjjjj Push
> Closure Num Copied iii (+ExtA//16*8) Num Args kkk (+ ExtA\\16*8) BlockSize
> jjjjjjjj (+ExtB*256). ee = num extensions"
> > + ^[:b| b >= 249 and: [b <= 250]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>extensionsAt:in:into: (in
> category 'compiled method support') -----
> > + extensionsAt: bcpc in: method into: aTrinaryBlock
> > + "If the bytecode at pc is an extension then evaluate aBinaryBlock
> with the values of extA and extB and number of extension *bytes*.
> > + If the bytecode at pc is not extended then evaluate aBinaryBlock
> with 0 and 0.
> > + 224 11100000 aaaaaaaa Extend A (Ext A = Ext A prev *
> 256 + Ext A)
> > + 225 11100001 bbbbbbbb Extend B (Ext B = Ext B prev *
> 256 + Ext B)"
> > +
> > + | scanpc byte extByte extA extB |
> > + scanpc := bcpc.
> > + "There may be an extension (it could be a false positive). We must
> scan as fast as possible..."
> > + extA := extB := 0.
> > + [byte := method at: scanpc.
> > + byte >= 224 and: [byte <= 225]] whileTrue:
> > + [extByte := method at: scanpc + 1.
> > + scanpc := scanpc + 2.
> > + byte = 224
> > + ifTrue:
> > + [extA := (extA bitShift: 8) + extByte]
> > + ifFalse:
> > + [extB := (extB = 0 and: [extByte > 127])
> > + ifTrue: [extByte - 256]
> > + ifFalse: [(extB bitShift: 8) + extByte]]].
> > + ^aTrinaryBlock value: extA value: extB value: scanpc - bcpc
> > +
> > +
> > + "Why use
> > + byte >= 224 and: [byte <= 225]
> > + and not
> > + (byte bitAnd: 16rFE) = 16rE0
> > + ?
> > + | n |
> > + n := 100000000.
> > + #(0 224) collect:
> > + [:byte|
> > + { Time millisecondsToRun: [1 to: n do: [:i| (byte >= 224 and: [byte
> <= 225]) ifTrue: []]].
> > + Time millisecondsToRun: [1 to: n do: [:i| (byte bitAnd: 16rFE) =
> 16rE0 ifTrue: []]] }] #(#(297 599) #(702 671))"!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>instVarReadScanBlockFor:using:
> (in category 'compiled method support') -----
> > + instVarReadScanBlockFor: varIndexCode using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for reads of the inst var with zero-relative index varIndexCode.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > +
> > + " 0-15 0000 i i i i Push Receiver Variable
> #iiii
> > + * 224 11100000 aaaaaaaa Extend A (Ext A = Ext A
> prev * 256 + Ext A)
> > + * 226 11100010 i i i i i i i i Push Receiver
> Variable #iiiiiiii (+ Extend A * 256)"
> > + | extension |
> > + extension := 0.
> > + ^[:b| | prevext |
> > + prevext := extension.
> > + extension := b = 224 ifTrue: [scanner followingByte bitShift: 8]
> ifFalse: [0].
> > + (b < 16 and: [b = varIndexCode])
> > + or: [b = 226
> > + and: [scanner followingByte + prevext = varIndexCode]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>instVarWriteScanBlockFor:using:
> (in category 'compiled method support') -----
> > + instVarWriteScanBlockFor: varIndexCode using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for writes of the inst var with zero-relative index varIndexCode.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > +
> > + " 200-207 11001 iii Pop and Store Receiver
> Variable #iii
> > + * 224 11100000 aaaaaaaa Extend A (Ext A = Ext A
> prev * 256 + Ext A)
> > + * 240 11110000 iiiiiiii Pop and Store Receiver
> Variable #iiiiiii (+ Extend A * 256)
> > + * 243 11110011 iiiiiiii Store Receiver Variable
> #iiiiiii (+ Extend A * 256)"
> > + | extension |
> > + extension := 0.
> > + ^[:b| | prevext |
> > + prevext := extension.
> > + extension := b = 224 ifTrue: [scanner followingByte bitShift: 8]
> ifFalse: [0].
> > + (b >= 200
> > + and: [b < 208
> > + and: [b - 200 = varIndexCode]])
> > + or: [(b = 240 or: [b = 243])
> > + and: [scanner followingByte + prevext = varIndexCode]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>interpretJumpIfCondIn: (in
> category 'compiled method support') -----
> > + interpretJumpIfCondIn: anInstructionStream
> > + "Double-dispatch through the encoder to select the correct
> conditional jump decoder for the instruction set."
> > + ^anInstructionStream interpretSistaV1JumpIfCond!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>interpretJumpIn: (in category
> 'compiled method support') -----
> > + interpretJumpIn: anInstructionStream
> > + "Double-dispatch through the encoder to select the correct
> unconditional jump decoder for the instruction set."
> > + ^anInstructionStream interpretSistaV1Jump!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>interpretNextInstructionFor:in:
> (in category 'instruction stream support') -----
> > + interpretNextInstructionFor: aClient in: anInstructionStream
> > + "Double-dispatch through the encoder to select the correct
> instruction set decoder."
> > + ^anInstructionStream interpretNextSistaV1InstructionFor: aClient!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isBlockReturnAt:in: (in
> category 'instruction stream support') -----
> > + isBlockReturnAt: pc in: method
> > + "Answer whether the bytecode at pc is a return from block."
> > + " 93 01011101 BlockReturn nil
> > + * 94 01011110 BlockReturn Top [* return
> from enclosing block N, N = Extend A, then jump by Ext B ]"
> > + ^(self nonExtensionBytecodeAt: pc in: method) between: 93 and: 94!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isBranchIfFalseAt:in: (in
> category 'instruction stream support') -----
> > + isBranchIfFalseAt: pc in: method
> > + "Answer whether the bytecode at pc is a conditional
> branch-if-false."
> > +
> > + " 192-199 11000 iii Pop and Jump 0n False iii
> +1 (i.e., 1 through 8)
> > + * 239 11101111 iiiiiiii Pop and Jump 0n False
> #iiiiiiii (+ Extend B * 256, where Extend B >= 0)"
> > + | byte |
> > + byte := self nonExtensionBytecodeAt: pc in: method.
> > + ^byte >= 192 and: [byte <= 199 or: [byte = 239]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isBranchIfTrueAt:in: (in
> category 'instruction stream support') -----
> > + isBranchIfTrueAt: pc in: method
> > + "Answer whether the bytecode at pc is a conditional branch-if-true."
> > +
> > + " 184-191 10111 iii Pop and Jump 0n True iii
> +1 (i.e., 1 through 8)
> > + * 238 11101110 iiiiiiii Pop and Jump 0n True
> #iiiiiiii (+ Extend B * 256, where Extend B >= 0))"
> > + | byte |
> > + byte := self nonExtensionBytecodeAt: pc in: method.
> > + ^byte >= 184 and: [byte <= 191 or: [byte = 238]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isExtension: (in category
> 'instruction stream support') -----
> > + isExtension: bytecode
> > + "Answer if the bytecode is an extension bytecode, i.e. one that
> extends
> > + the range of the following bytecode."
> > + ^bytecode >= 16rE0 and: [bytecode <= 16rE1]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isJumpAt:in: (in category
> 'instruction stream support') -----
> > + isJumpAt: pc in: method
> > + "Answer whether the bytecode at pc is an (unconditional) jump."
> > +
> > + " 176-183 10110 iii Jump iii + 1 (i.e., 1
> through 8)
> > + * 225 11100001 bbbbbbbb Extend B (Ext B = Ext B
> prev * 256 + Ext B)
> > + * 237 11101101 iiiiiiii Jump #iiiiiiii (+
> Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)"
> > + | byte |
> > + byte := self nonExtensionBytecodeAt: pc in: method.
> > + ^byte >= 176 and: [byte <= 183 or: [byte = 237]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isJustPopAt:in: (in category
> 'instruction stream support') -----
> > + isJustPopAt: pc in: method
> > + "Answer whether the bytecode at pc is a pop."
> > +
> > + ^(method at: pc) = 216 "216 11011000 Pop Stack
> Top"!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isRealSendAt:in: (in category
> 'instruction stream support') -----
> > + isRealSendAt: pc in: method
> > + "Answer whether the bytecode at pc is a real message-send, not
> blockCopy:."
> > +
> > + ^self isSendAt: pc in: method!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isReturnAt:in: (in category
> 'instruction stream support') -----
> > + isReturnAt: pc in: method
> > + "Answer whether the bytecode at pc is a return from block."
> > + " 88-91 010110 ii Return
> Receiver/true/false/nil
> > + 92 01011100 Return top
> > + 93 01011101 BlockReturn nil
> > + * 94 01011110 BlockReturn Top [* return
> from enclosing block N, N = Extend A, then jump by Ext B ]"
> > + ^(self nonExtensionBytecodeAt: pc in: method) between: 88 and: 94!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isReturnSelfFromMethodAt:in:
> (in category 'instruction stream support') -----
> > + isReturnSelfFromMethodAt: pc in: method
> > + "Answer whether the bytecode at pc is a return self from method."
> > +
> > + ^(method at: pc) = 88!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isReturnTopFromMethodAt:in: (in
> category 'instruction stream support') -----
> > + isReturnTopFromMethodAt: pc in: method
> > + "Answer whether the bytecode at pc is a return stack top from
> method."
> > +
> > + ^(method at: pc) = 92!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isSendAt:in: (in category
> 'instruction stream support') -----
> > + isSendAt: pc in: method
> > + "Answer whether the bytecode at pc is a message-send."
> > +
> > + " 96-111 0110 iiii Send Arithmetic Message
> #iiii #(#+ #- #< #> #'<=' #'>=' #= #'~=' #* #/ #'\\' #@ #bitShift: #'//'
> #bitAnd: #bitOr:)
> > + 112-119 01110 iii Send Special Message #iii
> #(#at: #at:put: #size #next #nextPut: #atEnd #'==' class)
> > + 120 01111000 UNASSIGNED (was: blockCopy:)
> > + 121 01111001 Send Special Message #value
> > + 122-123 0111101 i Send Special Message #i
> #(#value: #do:)
> > + 124-127 011111 ii Send Special Message #ii #(#new
> #new: #x #y))
> > + 128-143 1000 iiii Send Literal Selector #iiii
> With 0 Argument
> > + 144-159 1001 iiii Send Literal Selector #iiii
> With 1 Arguments
> > + 160-175 1010 iiii Send Literal Selector #iiii
> With 2 Arguments
> > + ** 234 11101010 iiiiijjj Send Literal Selector
> #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments
> > + ** 235 11101011 iiiiijjj Send To Superclass
> Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8)
> Arguments"
> > +
> > + | byte |
> > + byte := self nonExtensionBytecodeAt: pc in: method.
> > + ^byte >= 96
> > + and: [byte <= 175
> > + or: [byte >= 234 and: [byte <= 235]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isStoreAt:in: (in category
> 'instruction stream support') -----
> > + isStoreAt: pc in: method
> > + "Answer whether the bytecode at pc is a store or store-pop."
> > +
> > + " 200-207 11001 iii Pop and Store
> Receiver Variable #iii
> > + 208-215 11010 iii Pop and Store
> Temporary Variable #iii
> > + * 224 11100000 aaaaaaaa Extend A (Ext A =
> Ext A prev * 256 + Ext A)
> > + * 240 11110000 iiiiiiii Pop and Store
> Receiver Variable #iiiiiii (+ Extend A * 256)
> > + * 241 11110001 iiiiiiii Pop and Store
> Literal Variable #iiiiiiii (+ Extend A * 256)
> > + 242 11110010 iiiiiiii Pop and Store
> Temporary Variable #iiiiiiii
> > + * 243 11110011 iiiiiiii Store Receiver
> Variable #iiiiiii (+ Extend A * 256)
> > + * 244 11110100 iiiiiiii Store Literal
> Variable #iiiiiiii (+ Extend A * 256)
> > + 245 11110110 iiiiiiii Store Temporary
> Variable #iiiiiiii
> > +
> > + 252 11111100 kkkkkkkk jjjjjjjj Store Temp At
> kkkkkkkk In Temp Vector At: jjjjjjjj
> > + 253 11111101 kkkkkkkk jjjjjjjj Pop and Store
> Temp At kkkkkkkk In Temp Vector At: jjjjjjjj"
> > +
> > + | byte |
> > + byte := self nonExtensionBytecodeAt: pc in: method.
> > + ^byte >= 200
> > + and: [byte <= 215
> > + or: [(byte between: 240 and: 245)
> > + or: [(byte between: 252 and: 253)]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isStorePopAt:in: (in category
> 'instruction stream support') -----
> > + isStorePopAt: pc in: method
> > + "Answer whether the bytecode at pc is a store or store-pop."
> > +
> > + " 200-207 11001 iii Pop and Store
> Receiver Variable #iii
> > + 208-215 11010 iii Pop and Store
> Temporary Variable #iii
> > + * 224 11100000 aaaaaaaa Extend A (Ext A =
> Ext A prev * 256 + Ext A)
> > + * 240 11110000 iiiiiiii Pop and Store
> Receiver Variable #iiiiiii (+ Extend A * 256)
> > + * 241 11110001 iiiiiiii Pop and Store
> Literal Variable #iiiiiiii (+ Extend A * 256)
> > + 242 11110010 iiiiiiii Pop and Store
> Temporary Variable #iiiiiiii
> > +
> > + 253 11111101 kkkkkkkk jjjjjjjj Pop and Store
> Temp At kkkkkkkk In Temp Vector At: jjjjjjjj"
> > +
> > + | byte |
> > + byte := self nonExtensionBytecodeAt: pc in: method.
> > + ^byte >= 200
> > + and: [byte <= 215
> > + or: [(byte between: 240 and: 242)
> > + or: [byte = 253]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isSyntheticStoreAt:in:for: (in
> category 'instruction stream support') -----
> > + isSyntheticStoreAt: pc in: method for: anInstructionStream
> > + "Answer whether the bytecode at pc is a store or store-pop of an
> indirect temp vector,
> > + which implement mutable closed-over variables in the the closure
> implementation.
> > + Stores into temp vectors are not real stores. N.B.
> pcPreviousTo:in:for: is slow, so filter
> > + out any preceding bytecodes other than what looks like a
> pushNewArrayCode. But the
> > + pcPreviousTo:in:for: is still necessary, since the presence of a
> pcPreviousTo:in:for: in the
> > + right place is potentially ambiguous, possibly part of a different
> bytecode sequence."
> > +
> > + ^(self isTempStoreAt: pc in: method)
> > + and: [pc - 2 >= method initialPC
> > + and: [(method at: pc - 2) = self pushNewArrayCode
> > + and: [(method at: pc - 1) <= 127
> > + and: [pc - 2 = (self pcPreviousTo: pc in: method for:
> anInstructionStream)]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>isTempStoreAt:in: (in category
> 'instruction stream support') -----
> > + isTempStoreAt: pc in: method
> > + "Answer if the bytecode at pc is a store or store-pop into a
> temporary variable.
> > + 208-215 11010 iii Pop and Store Temporary Variable
> #iii
> > + 242 11110010 iiiiiiii Pop and Store Temporary
> Variable #iiiiiiii
> > + 245 11110110 iiiiiiii Store Temporary Variable
> #iiiiiiii"
> > +
> > + | byte |
> > + byte := method at: pc.
> > + ^byte >= 208
> > + and: [byte <= 215
> > + or: [byte = 242 or: [byte = 245]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>markerOrNilFor: (in category
> 'compiled method support') -----
> > + markerOrNilFor: aMethod
> > + "If aMethod is a marker method, answer the symbol used to mark it.
> Otherwise
> > + answer nil. What is a marker method? It is method with body like
> > + 'self subclassResponsibility' or '^ self
> subclassResponsibility'
> > + used to indicate ('mark') a special property.
> > +
> > + Marker methods compile to two bytecode forms, this:
> > + self
> > + send: <literal 1>
> > + pop
> > + returnSelf
> > + or this:
> > + self
> > + send: <literal 1>
> > + returnTop"
> > + | expectedHeaderPlusLliteralSize e byte |
> > + expectedHeaderPlusLliteralSize := Smalltalk wordSize * 4.
> > + ^(((e := aMethod endPC - expectedHeaderPlusLliteralSize) = 3 or: [e
> = 4])
> > + and: [aMethod numLiterals = 3
> > + and: [(aMethod at: expectedHeaderPlusLliteralSize + 1) = 16r4C
> "push self"
> > + and: [(aMethod at: expectedHeaderPlusLliteralSize + 2) = 16r80
> "send"
> > + and: [(byte := aMethod at: expectedHeaderPlusLliteralSize + 3) =
> 16rD8 "pop" or: [byte = 16r5C "returnTop"]]]]])
> > + ifTrue: [aMethod literalAt: 1]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1
> class>>method:refersInBytecodeToLiteral:specialSelectorIndex: (in category
> 'scanning') -----
> > + method: method refersInBytecodeToLiteral: aLiteral
> specialSelectorIndex: specialOrNil
> > + "Answer if method refers to the literal aLiteral in the bytecode,
> as opposed to in its literal frame."
> > +
> > + " 77 01001101 Push true
> > + 78 01001110 Push false
> > + 79 01001111 Push nil
> > + 80 01010000 Push 0
> > + 81 01010001 Push 1
> > + 88-91 010110 ii Return
> Receiver/true/false/nil
> > + 93 01011101 BlockReturn nil
> > + 96-111 0110 iiii Send Arithmetic Message
> #iiii #(#+ #- #< #> #'<=' #'>=' #= #'~=' #* #/ #'\\' #@ #bitShift: #'//'
> #bitAnd: #bitOr:)
> > + 112-119 01110 iii Send Special Message #iii
> #(#at: #at:put: #size #next #nextPut: #atEnd #'==' class)
> > + 120 01111000 UNASSIGNED (was: blockCopy:)
> > + 121 01111001 Send Special Message #value
> > + 122-123 0111101 i Send Special Message #i
> #(#value: #do:)
> > + 124-127 011111 ii Send Special Message #ii
> #(#new #new: #x #y))
> > + * 224 11100000 aaaaaaaa Extend A (Ext A = Ext A
> prev * 256 + Ext A)
> > + * 225 11100001 sbbbbbbb Extend B (Ext B = Ext B
> prev * 256 + Ext B)
> > + * 232 11101000 iiiiiiii Push Integer #iiiiiiii
> (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)
> > + * 233 11101001 iiiiiiii Push Character
> #iiiiiiii (+ Extend B * 256)
> > + 249 11111001 xxxxxxxx syyyyyyy Reserved for
> Push Float"
> > + | byte extended scanner |
> > + specialOrNil ifNotNil:
> > + [byte := specialOrNil + 95.
> > + ^(InstructionStream on: method) scanFor: [:b| b = byte]].
> > + extended := false.
> > + aLiteral isInteger ifTrue:
> > + [(aLiteral >= -32768 and: [aLiteral <= 32767]) ifFalse:
> [^false].
> > + scanner := InstructionStream on: method.
> > + (aLiteral >= 0 and: [aLiteral <= 255]) ifTrue:
> > + [aLiteral <= 1 ifTrue:
> > + [byte := aLiteral + 80.
> > + ^scanner scanFor: [:b| b = byte]].
> > + ^scanner scanFor:
> > + [:b|
> > + (b = 232
> > + and: [extended not
> > + and: [scanner followingByte = aLiteral]])
> > + or: [extended := b = 225.
> > + false]]].
> > + byte := (aLiteral bitShift: -8) bitAnd: 255.
> > + ^scanner scanFor:
> > + [:b|
> > + (b = 232
> > + and: [extended
> > + and: [scanner followingByte = (aLiteral bitAnd: 255)]])
> > + or: [extended := b = 225 and: [scanner followingByte =
> byte].
> > + false]]].
> > + aLiteral isCharacter ifTrue:
> > + [aLiteral asciiValue <= 65535 ifFalse: [^false].
> > + scanner := InstructionStream on: method.
> > + aLiteral asciiValue <= 255 ifTrue:
> > + [^scanner scanFor:
> > + [:b|
> > + (b = 233
> > + and: [extended not
> > + and: [scanner followingByte = aLiteral]])
> > + or: [extended := b = 225.
> > + false]]].
> > + byte := (aLiteral bitShift: -8) bitAnd: 255.
> > + ^scanner scanFor:
> > + [:b|
> > + (b = 233
> > + and: [extended
> > + and: [scanner followingByte = (aLiteral bitAnd: 255)]])
> > + or: [extended := b = 225 and: [scanner followingByte =
> byte].
> > + false]]].
> > + aLiteral == nil ifTrue:
> > + [^(InstructionStream on: method) scanFor: [:b| b = 79 or: [b =
> 91 or: b = 93]]].
> > + aLiteral == true ifTrue:
> > + [^(InstructionStream on: method) scanFor: [:b| b = 77 or: [b =
> 89]]].
> > + aLiteral == false ifTrue:
> > + [^(InstructionStream on: method) scanFor: [:b| b = 78 or: [b =
> 90]]].
> > +
> > + ^false!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>nonExtensionBytecodeAt:in: (in
> category 'instruction stream support') -----
> > + nonExtensionBytecodeAt: pc in: method
> > + "Answer the actual bytecode at pc in method, skipping past any
> preceding extensions."
> > + | thePC bytecode |
> > + thePC := pc.
> > + [self isExtension: (bytecode := method at: thePC)] whileTrue:
> > + [thePC := thePC + (self bytecodeSize: bytecode)].
> > + ^bytecode!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>nopCode (in category 'bytecode
> decoding') -----
> > + nopCode
> > + "Answer the call primitive bytecode, if it exists in the encoder's
> bytecode set, or nil if not.
> > + 95 01011111 Nop"
> > + ^95!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1
> class>>pcOfBlockCreationBytecodeForBlockStartingAt:in: (in category
> 'bytecode decoding') -----
> > + pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method
> > + "Answer the pc of the push closure bytecode whose block starts at
> startpc in method.
> > + May need to back up to include extension bytecodes."
> > +
> > + "* 224 11100000 aaaaaaaa Extend A (Ext A =
> Ext A prev * 256 + Ext A)
> > + * 225 11100001 bbbbbbbb Extend B (Ext B =
> Ext B prev * 256 + Ext B)
> > + ** 250 11111010 eeiiikkk jjjjjjjj Push
> Closure Num Copied iii (+ExtA//16*8) Num Args kkk (+ ExtA\\16*8) BlockSize
> jjjjjjjj (+ExtB*256). ee = num extensions"
> > + | numExtensions |
> > + self assert: (method at: startpc - 3) = 250.
> > + numExtensions := (method at: startpc - 2) >> 6.
> > + ^startpc - 3 - (numExtensions * 2)!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>pushClosureBytecodeSize (in
> category 'bytecode decoding') -----
> > + pushClosureBytecodeSize
> > + "Answer the size of the push closure bytecode.
> > + ** 250 11111010 eeiiikkk jjjjjjjj Push
> Closure Num Copied iii (+ExtA//16*8) Num Args kkk (+ ExtA\\16*8) BlockSize
> jjjjjjjj (+ExtB*256). ee = num extensions"
> > + ^3!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>pushNewArrayCode (in category
> 'bytecode decoding') -----
> > + pushNewArrayCode
> > + "231 11100111 jkkkkkkk Push (Array new: kkkkkkk) (j =
> 0)
> > + & Pop kkkkkkk elements into:
> (Array new: kkkkkkk) (j = 1)"
> > + ^231!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>pushNilCode (in category
> 'bytecode decoding') -----
> > + pushNilCode
> > + "Answer the pushNil bytecode.
> > + 79 01001111 Push nil"
> > + ^79!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>scanBlockOrNilForLiteral: (in
> category 'scanning') -----
> > + scanBlockOrNilForLiteral: aLiteral
> > + "Answer a block argument for CompiledMethod>>#scanFor: that answers
> > + if the method refers to the literal implicitly via a special
> bytecode.
> > + If the literal is not accessible via a special bytecode, answer
> nil."
> > + | value hi lo unextended |
> > +
> > + "96-111 0110 iiii Send Arithmetic Message #iiii (+ -
> < > <= >= = ~= * / \\ @ bitShift: // bitAnd: bitOr:)
> > + 112-119 01110 iii Send Special Message #iii + 0 (at:
> at:put: size next nextPut: atEnd == class)"
> > + aLiteral isSymbol ifTrue:
> > + [value := 96 + ((Smalltalk specialSelectors indexOf: aLiteral
> ifAbsent: [^nil]) // 2).
> > + ^[:byte| byte = value]].
> > +
> > + "80 01010000 Push 0
> > + 81 01010001 Push 1
> > + 232 11101000 iiiiiiii Push Integer #iiiiiiii (+
> Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, d=0, s=1)"
> > + aLiteral isInteger ifTrue:
> > + [aLiteral >= 0 ifTrue:
> > + [aLiteral <= 1 ifTrue:
> > + [value := aLiteral + 80.
> > + ^[:byte| byte = value]].
> > + aLiteral <= 255 ifTrue:
> > + [unextended := true. "Don't be fooled by extended cases
> with the same least significant byte!!"
> > + ^[:b1 :b2| | found |
> > + found := b1 = 232 and: [b2 = aLiteral and:
> [unextended]].
> > + unextended := b1 ~= 16rE1.
> > + found]]].
> > + (aLiteral between: -32768 and: 32767) ifFalse: [^nil].
> > + lo := aLiteral bitAnd: 255.
> > + hi := (aLiteral bitShift: -8) bitAnd: 255.
> > + ^[:b1 :b2 :b3 :b4| b1 = 16rE1 and: [b2 = hi and: [b3 = 232
> and: [b4 = lo]]]]].
> > +
> > + "233 11101001 iiiiiiii Push Character #iiiiiiii (+
> Extend B * 256)"
> > + aLiteral isCharacter ifTrue:
> > + [(value := aLiteral asInteger) <= 255 ifTrue:
> > + [unextended := true. "Don't be fooled by extended cases
> with the same least significant byte!!"
> > + ^[:b1 :b2| | found |
> > + found := b1 = 233 and: [b2 = value and: [unextended]].
> > + unextended := b1 ~= 16rE1.
> > + found]].
> > + ^value <= 65535 ifTrue:
> > + [lo := value bitAnd: 255.
> > + hi := (value bitShift: -8) bitAnd: 255.
> > + [:b1 :b2 :b3 :b4| b1 = 16rE1 and: [b2 = hi and: [b3 = 233
> and: [b4 = lo]]]]]].
> > +
> > + "77 01001101 Push true
> > + 78 01001110 Push false
> > + 79 01001111 Push nil
> > + 88-91 010110 ii Return Receiver/true/false/nil
> > + 93 01011101 BlockReturn nil"
> > + aLiteral == true ifTrue:
> > + [^[:byte| byte = 77 or: [byte = 89]]].
> > + aLiteral == false ifTrue:
> > + [^[:byte| byte = 78 or: [byte = 90]]].
> > + aLiteral == nil ifTrue:
> > + [^[:byte| byte = 79 or: [byte = 91 or: [byte = 93]]]].
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1
> class>>selectorToSendOrItselfFor:in:at: (in category 'instruction stream
> support') -----
> > + selectorToSendOrItselfFor: anInstructionStream in: method at: pc
> > + "If anInstructionStream is at a send bytecode then answer the
> send's selector,
> > + otherwise answer anInstructionStream itself. The rationale for
> answering
> > + anInstructionStream instead of, say, nil, is that potentially any
> existing object
> > + can be used as a selector, but since anInstructionStream postdates
> the method,
> > + it can't be one of them.
> > +
> > + The complication is that for convenience we allow the pc to point
> to the
> > + raw send bytecode after its extension(s), or at the extension(s)
> preceding it.
> > + 96-111 0110 iiii Send Arithmetic Message #iiii (+
> - < > <= >= = ~= * / \\ @ bitShift: // bitAnd: bitOr:)
> > + 112-119 01110 iii Send Special Message #iii + 0 (at:
> at:put: size next nextPut: atEnd == class)
> > + 120-127 01111 iii Send Special Message #iii + 8 (~~
> value value: do: new new: x y)
> > + 128-143 1000 iiii Send Literal Selector #iiii With 0
> Argument
> > + 144-159 1001 iiii Send Literal Selector #iiii With 1
> Arguments
> > + 160-175 1010 iiii Send Literal Selector #iiii With 2
> Arguments
> > + * 224 11100000 aaaaaaaa Extend A (Ext A = Ext A prev *
> 256 + Ext A)
> > + * 225 11100001 bbbbbbbb Extend B (Ext B = Ext B prev *
> 256 + Ext B)
> > + ** 234 11101010 iiiiijjj Send Literal Selector
> #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments
> > + ** 235 11101011 iiiiijjj ExtendB < 64
> > + ifTrue: [Send To Superclass
> Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8)
> Arguments]
> > + ifFalse: [Send To Superclass of
> Stacked Class Literal Selector #iiiii (+ Extend A * 32) with jjj (+ (Extend
> B bitAnd: 63) * 8) Arguments"
> > +
> > + | byte |
> > + byte := method at: pc.
> > + byte < 96 ifTrue:
> > + [^anInstructionStream].
> > + byte <= 175 ifTrue:
> > + ["special byte or short send"
> > + ^byte >= 128
> > + ifTrue: [method literalAt: (byte bitAnd: 15) + 1]
> > + ifFalse: [Smalltalk specialSelectorAt: byte - 95]].
> > + byte < 234 ifTrue: "need to check for either extension cuz order of
> extensions is not restricted. so extB could precede extA"
> > + [(byte >= 224 and: [byte <= 225]) ifTrue:
> > + [^self extensionsAt: pc in: method into:
> > + [:extA :extB :nExtBytes| | byteAfter index |
> > + byteAfter := method at: pc + nExtBytes.
> > + (byteAfter >= 234 and: [byteAfter <= 235])
> > + ifTrue:
> > + [index := ((method at: pc + nExtBytes + 1)
> bitShift: -3) + (extA bitShift: 5).
> > + method literalAt: index + 1]
> > + ifFalse: [anInstructionStream]]].
> > + ^anInstructionStream].
> > + byte > 235 ifTrue:
> > + [^anInstructionStream].
> > + "they could be extended..."
> > + ^self extensionsFor: pc in: method into:
> > + [:extA :extB :nExtBytes| | index |
> > + index := ((method at: pc + 1) bitShift: -3) + (extA bitShift:
> 5).
> > + method literalAt: index + 1]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>stackDeltaForPrimitive:in: (in
> category 'bytecode decoding') -----
> > + stackDeltaForPrimitive: primitiveIndex in: method
> > + "Answer the stack delta for the callPrimitive: bytecode (see my
> class comment).
> > + There is no delta for non-inlined primitives (its implicitly 0 -
> method numArgs).
> > + Inlined primitives are grouped by the thousand by argument count,
> 32 args max ;-)."
> > + ^primitiveIndex < 32678
> > + ifTrue: [0]
> > + ifFalse: [primitiveIndex - 32768 // 1000]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>superSendScanBlockUsing: (in
> category 'instruction stream support') -----
> > + superSendScanBlockUsing: scanner
> > + "Answer a block argument for InstructionStream>>scanFor:
> > + that answers true for super sends."
> > +
> > + "* 224 11100000 aaaaaaaa Extend A (Ext A = Ext A
> prev * 256 + Ext A)
> > + * 225 11100001 sbbbbbbb Extend B (Ext B = Ext B
> prev * 256 + Ext B)
> > + ** 235 11101011 iiiiijjj Send To Superclass
> Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8)
> Arguments"
> > +
> > + ^[:instr | instr = 235]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>supportsClosures (in category
> 'compiled method support') -----
> > + supportsClosures
> > + "Answer if the instruction set supports closures (contains
> > + closure creation and indirect temp access bytecodes)."
> > +
> > + ^true!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1 class>>unusedBytecode (in category
> 'bytecode decoding') -----
> > + unusedBytecode
> > + "Answer the opcode of a single-byte unused bytecode, if it exists
> in the encoder's bytecode set, or nil if not."
> > + ^223!
> >
> > Item was added:
> > + ----- Method:
> EncoderForSistaV1>>computeMethodHeaderForNumArgs:numTemps:numLits:primitive:
> (in category 'method generation') -----
> > + computeMethodHeaderForNumArgs: numArgs numTemps: numTemps numLits:
> numLits primitive: primitiveIndex
> > + numTemps > 63 ifTrue:
> > + [^self error: 'Cannot compile -- too many temporary
> variables'].
> > + numLits > 65535 ifTrue:
> > + [^self error: 'Cannot compile -- too many literals'].
> > + ^SmallInteger minVal "sign bit is the flag for the alternative
> bytecode set"
> > + + (numArgs bitShift: 24)
> > + + (numTemps bitShift: 18)
> > + "+ (largeBit bitShift: 17)" "largeBit gets filled in later"
> > + + numLits
> > + + (primitiveIndex > 0 ifTrue: [1 bitShift: 16] ifFalse: [0])!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genBranchPopFalse: (in category
> 'bytecode generation') -----
> > + genBranchPopFalse: distance
> > + (distance > 0 and: [distance < 9]) ifTrue:
> > + ["192-199 11000 iii Pop and Jump 0n False iii + 1
> (i.e., 1 through 8)"
> > + stream nextPut: 191 + distance.
> > + ^self].
> > + ^self genBranchPopFalseLong: distance!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genBranchPopFalseLong: (in category
> 'bytecode generation') -----
> > + genBranchPopFalseLong: distance
> > + "239 11101111 iiiiiiii Pop and Jump 0n False
> #iiiiiiii (+ Extend B * 256, where Extend B >= 0) "
> > + | distanceMod256 |
> > + (distance < 0 or: [distance > 32767]) ifTrue:
> > + [^self outOfRangeError: 'distance' index: distance range: 0 to:
> 32767].
> > + distanceMod256 := (distance < 0 or: [distance > 255])
> > + ifTrue:
> > + [self genUnsignedSingleExtendB:
> (distance bitShift: -8).
> > + distance bitAnd: 255]
> > + ifFalse: [distance].
> > + stream
> > + nextPut: 239;
> > + nextPut: distanceMod256!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genBranchPopTrue: (in category
> 'bytecode generation') -----
> > + genBranchPopTrue: distance
> > + (distance > 0 and: [distance < 9]) ifTrue:
> > + ["184-191 10111 iii Pop and Jump 0n True iii + 1
> (i.e., 1 through 8)"
> > + stream nextPut: 183 + distance.
> > + ^self].
> > + ^self genBranchPopTrueLong: distance!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genBranchPopTrueLong: (in category
> 'bytecode generation') -----
> > + genBranchPopTrueLong: distance
> > + "238 11101110 iiiiiiii Pop and Jump 0n True
> #iiiiiiii (+ Extend B * 256, where Extend B >= 0)"
> > + | distanceMod256 |
> > + (distance < 0 or: [distance > 32767]) ifTrue:
> > + [^self outOfRangeError: 'distance' index: distance range: 0 to:
> 32767].
> > + (distance > 0 and: [distance < 9]) ifTrue:
> > + ["184-191 10111 iii Pop and Jump 0n True iii + 1
> (i.e., 1 through 8)"
> > + stream nextPut: 183 + distance.
> > + ^self].
> > + distanceMod256 := (distance < 0 or: [distance > 255])
> > + ifTrue:
> > + [self genUnsignedSingleExtendB:
> (distance bitShift: -8).
> > + distance bitAnd: 255]
> > + ifFalse: [distance].
> > + stream
> > + nextPut: 238;
> > + nextPut: distanceMod256!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genCallInlinePrimitive: (in category
> 'bytecode generation') -----
> > + genCallInlinePrimitive: primitiveIndex
> > + " 248 (2) 11111000 iiiiiiii mssjjjjj Call
> Primitive #iiiiiiii + (jjjjj * 256)
> > + m=1 means inlined primitive, no hard
> return after execution.
> > + ss defines the unsafe operation set
> used to encode the operations.
> > + (ss = 0 means sista unsafe operations,
> ss = 01 means lowcode operations, other numbers are not used)"
> > + "N.B. We could have made CallPrimitive a 2-byte code taking an
> extension, but that would
> > + complicate the VM's determination of the primitive number and the
> primitive error code
> > + store since the extension, being optional, would make the sequence
> variable length."
> > + (primitiveIndex < 1 or: [primitiveIndex > 32767]) ifTrue:
> > + [self outOfRangeError: 'primitive index' index: primitiveIndex
> range: 1 to: 32767].
> > + stream
> > + nextPut: 248;
> > + nextPut: (primitiveIndex bitAnd: 255);
> > + nextPut: (primitiveIndex bitShift: -8) + 128!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genCallPrimitive: (in category
> 'bytecode generation') -----
> > + genCallPrimitive: primitiveIndex
> > + "248 (2) 11111000 iiiiiiii mssjjjjj Call
> Primitive #iiiiiiii + (jjjjj * 256)
> > + m=1 means inlined primitive, no hard
> return after execution.
> > + ss defines the unsafe operation set
> used to encode the operations.
> > + (ss = 0 means sista unsafe operations,
> ss = 01 means lowcode operations, other numbers are not used)"
> > + "N.B. We could have made CallPrimitive a 2-byte code taking an
> extension, but that would
> > + complicate the VM's determination of the primitive number and the
> primitive error code
> > + store since the extension, being optional, would make the sequence
> variable length."
> > + (primitiveIndex < 1 or: [primitiveIndex > 32767]) ifTrue:
> > + [self outOfRangeError: 'primitive index' index: primitiveIndex
> range: 1 to: 32767].
> > + stream
> > + nextPut: 248;
> > + nextPut: (primitiveIndex bitAnd: 255);
> > + nextPut: (primitiveIndex bitShift: -8)!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genDup (in category 'bytecode
> generation') -----
> > + genDup
> > + "83 01010011 Duplicate Stack Top"
> > + stream nextPut: 83!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genInlineSmallIntegerAdd (in category
> 'in-line primitive generation') -----
> > + genInlineSmallIntegerAdd
> > + ^self genCallInlinePrimitive: 0!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genJump: (in category 'bytecode
> generation') -----
> > + genJump: distance
> > + (distance > 0 and: [distance < 9]) ifTrue:
> > + ["176-183 10110 iii Jump iii + 1 (i.e., 1 through
> 8)"
> > + stream nextPut: 175 + distance.
> > + ^self].
> > + "237 11101101 iiiiiiii Jump #iiiiiiii (+ Extend B
> * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)"
> > + ^self genJumpLong: distance!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genJumpLong: (in category 'bytecode
> generation') -----
> > + genJumpLong: distance
> > + "237 11101101 iiiiiiii Jump #iiiiiiii (+ Extend B
> * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)"
> > + (distance between: -32768 and: 32767) ifFalse:
> > + [^self outOfRangeError: 'index' index: distance range: -32768
> to: 32767].
> > + (distance < 0 or: [distance > 255]) ifTrue:
> > + [self genSignedSingleExtendB: (distance bitShift: -8)].
> > + stream
> > + nextPut: 237;
> > + nextPut: (distance bitAnd: 255)!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genNop (in category 'bytecode
> generation') -----
> > + genNop
> > + "95 01011111 Nop"
> > + stream nextPut: 95!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPop (in category 'bytecode
> generation') -----
> > + genPop
> > + "216 11011000 Pop Stack Top"
> > + stream nextPut: 216!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushCharacter: (in category
> 'bytecode generation') -----
> > + genPushCharacter: aCharacterOrCode
> > + "233 11101001 i i i i i i i i Push Character #iiiiiiii
> (+ Extend A * 256)"
> > + "Why restrict the range to 16 bits when we could encode arbitrary
> 32-bit Characters?
> > + Well, 16 bits requires 4 bytes (extA + byte, 233 + byte) and so
> beyond this range we
> > + lose space verses a single-byte pushLiteral and a 4 byte Character
> literal on 32-bits.
> > + And generating the same bytecode on 64-bit and 32-bit versions is
> important if we
> > + want to be able to load binary code from one to the other (e.g.
> via Fuel)."
> > + | code |
> > + code := aCharacterOrCode isInteger ifTrue: [aCharacterOrCode]
> ifFalse: [aCharacterOrCode asInteger].
> > + (code < 0 or: [code > 65535]) ifTrue:
> > + [^self outOfRangeError: 'character' index: code range: 0 to:
> 65535].
> > + (code > 255) ifTrue:
> > + [self genUnsignedSingleExtendA: (code bitShift: -8)].
> > + stream
> > + nextPut: 233;
> > + nextPut: (code bitAnd: 255)!
> >
> > Item was added:
> > + ----- Method:
> EncoderForSistaV1>>genPushClosureCopyNumCopiedValues:numArgs:jumpSize: (in
> category 'bytecode generation') -----
> > + genPushClosureCopyNumCopiedValues: numCopied numArgs: numArgs
> jumpSize: jumpSize
> > + "250 11111010 eeiiikkk jjjjjjjj Push Closure
> Num Copied iii (+ Ext A // 16 * 8) Num Args kkk (+ Ext A \\ 16 * 8)
> BlockSize jjjjjjjj (+ Ext B * 256). ee = num extensions"
> > + "Including numExtensions makes decoding the bytecode quicker since
> it obviates having to scan from the beginning of a method."
> > + | numExtensions numCopiedMod8 numArgsMod8 extA |
> > + (jumpSize < 0 or: [jumpSize > 65535]) ifTrue:
> > + [^self outOfRangeError: 'block size' index: jumpSize range: 0
> to: 65535].
> > + (numCopied < 0 or: [numCopied > 127]) ifTrue:
> > + [^self outOfRangeError: 'num copied' index: numCopied range: 0
> to: 127].
> > + (numArgs < 0 or: [numArgs > 127]) ifTrue:
> > + [^self outOfRangeError: 'num args' index: numArgs range: 0 to:
> 127].
> > + extA := numExtensions := 0.
> > + (numArgsMod8 := numArgs) > 7 ifTrue:
> > + [extA := numArgs // 8.
> > + numArgsMod8 := numArgsMod8 \\ 8].
> > + (numCopiedMod8 := numCopied) > 7 ifTrue:
> > + [extA := extA + (numCopied // 8 * 16).
> > + numCopiedMod8 := numCopiedMod8 \\ 8].
> > + extA ~= 0 ifTrue:
> > + [self genUnsignedSingleExtendA: extA.
> > + numExtensions := 1].
> > + jumpSize > 255 ifTrue:
> > + [numExtensions := numExtensions + 1.
> > + self genUnsignedSingleExtendB: jumpSize // 256].
> > + stream
> > + nextPut: 250;
> > + nextPut: (numExtensions bitShift: 6) + (numCopiedMod8 bitShift:
> 3) + numArgsMod8;
> > + nextPut: (jumpSize bitAnd: 16rFF)!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushConsArray: (in category
> 'bytecode generation') -----
> > + genPushConsArray: size
> > + (size < 0 or: [size > 127]) ifTrue:
> > + [^self outOfRangeError: 'size' index: size range: 0 to: 127].
> > + "231 11100111 jkkkkkkk Push (Array new: kkkkkkk) (j =
> 0)
> > + & Pop kkkkkkk elements into:
> (Array new: kkkkkkk) (j = 1)"
> > + stream
> > + nextPut: 231;
> > + nextPut: size + 128!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushFullClosure:numCopied: (in
> category 'bytecode generation') -----
> > + genPushFullClosure: compiledBlockLiteralIndex numCopied: numCopied
> > + "By default the closure will have an outer context and the receiver
> will be fetched from the current context"
> > + self genPushFullClosure: compiledBlockLiteralIndex numCopied:
> numCopied receiverOnStack: false ignoreOuterContext: false!
> >
> > Item was added:
> > + ----- Method:
> EncoderForSistaV1>>genPushFullClosure:numCopied:receiverOnStack:ignoreOuterContext:
> (in category 'bytecode generation') -----
> > + genPushFullClosure: compiledBlockLiteralIndex numCopied: numCopied
> receiverOnStack: receiverOnStack ignoreOuterContext: ignoreOuterContext
> > + "* 249 11111001 xxxxxxxx siyyyyyy push Closure
> Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy
> receiverOnStack: s = 1 ignoreOuterContext: i = 1"
> > + | extendedIndex |
> > + (numCopied < 0 or: [numCopied > 64]) ifTrue:
> > + [self outOfRangeError: 'num copied' index: numCopied range: 1
> to: 64].
> > + (compiledBlockLiteralIndex < 0 or: [compiledBlockLiteralIndex >
> 32767]) ifTrue:
> > + [^self outOfRangeError: 'index' index:
> compiledBlockLiteralIndex range: 0 to: 32767].
> > + (extendedIndex := compiledBlockLiteralIndex) > 255 ifTrue:
> > + [self genUnsignedSingleExtendA: extendedIndex // 256.
> > + extendedIndex := extendedIndex \\ 256].
> > + stream
> > + nextPut: 249;
> > + nextPut: extendedIndex;
> > + nextPut: receiverOnStack asBit << 7 + (ignoreOuterContext asBit
> << 6) + numCopied!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushInstVar: (in category
> 'bytecode generation') -----
> > + genPushInstVar: instVarIndex
> > + (instVarIndex between: 0 and: 15) ifTrue:
> > + ["0-15 0000iiii Push Receiver Variable #iiii"
> > + stream nextPut: 0 + instVarIndex.
> > + ^self].
> > + self genPushInstVarLong: instVarIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushInstVarLong: (in category
> 'bytecode generation') -----
> > + genPushInstVarLong: instVarIndex
> > + "226 11100010 i i i i i i i i Push Receiver Variable
> #iiiiiiii (+ Extend A * 256)"
> > + "See also MaybeContextInstanceVariableNode"
> > + (instVarIndex < 0 or: [instVarIndex > 65535]) ifTrue:
> > + [^self outOfRangeError: 'index' index: instVarIndex range: 0
> to: 65535].
> > + instVarIndex > 255 ifTrue:
> > + [self genUnsignedSingleExtendA: instVarIndex // 256].
> > + stream
> > + nextPut: 226;
> > + nextPut: instVarIndex \\ 256!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushInteger: (in category
> 'bytecode generation') -----
> > + genPushInteger: anInteger
> > + "80 01010000 Push 0
> > + 81 01010001 Push 1
> > + 232 11101000 i i i i i i i i Push Integer #iiiiiiii
> (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)"
> > + "Why restrict the range to 16 bits when we could encode arbitrarily
> large integers?
> > + Well, 16 bits requires 4 bytes (extB + byte, 78 + byte) and so
> beyond this range we lose space
> > + verses a single-byte pushLiteral and a 4 byte integer literal on
> 32-bits. And generating the same
> > + bytecode on 64-bit and 32-bit is important if we want to be able
> to load binary code from one to
> > + the other (e.g. via Fuel)."
> > + anInteger = 0 ifTrue:
> > + [stream nextPut: 80.
> > + ^self].
> > + anInteger = 1 ifTrue:
> > + [stream nextPut: 81.
> > + ^self].
> > + (anInteger < -32768 or: [anInteger > 32767]) ifTrue:
> > + [^self outOfRangeError: 'integer' index: anInteger range:
> -32768 to: 32767].
> > + (anInteger < 0 or: [anInteger > 255]) ifTrue:
> > + [self genSignedSingleExtendB: (anInteger bitShift: -8)].
> > + stream
> > + nextPut: 232;
> > + nextPut: (anInteger bitAnd: 255)!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushLiteral: (in category
> 'bytecode generation') -----
> > + genPushLiteral: literalIndex
> > + | extendedIndex |
> > + (literalIndex < 0 or: [literalIndex > 65535]) ifTrue:
> > + [^self outOfRangeError: 'index' index: literalIndex range: 0
> to: 65535].
> > + literalIndex < 32 ifTrue:
> > + ["32-63 001iiiii Push Literal #iiiii"
> > + stream nextPut: 32 + literalIndex.
> > + ^self].
> > + "228 11100100 i i i i i i i i Push Literal #iiiiiiii
> (+ Extend A * 256)"
> > + (extendedIndex := literalIndex) > 255 ifTrue:
> > + [self genUnsignedSingleExtendA: extendedIndex // 256.
> > + extendedIndex := extendedIndex \\ 256].
> > + stream
> > + nextPut: 228;
> > + nextPut: extendedIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushLiteralVar: (in category
> 'bytecode generation') -----
> > + genPushLiteralVar: literalIndex
> > + | extendedIndex |
> > + (literalIndex < 0 or: [literalIndex > 65535]) ifTrue:
> > + [^self outOfRangeError: 'index' index: literalIndex range: 0
> to: 65535].
> > + literalIndex < 16 ifTrue:
> > + ["16-31 0001 i i i i Push Literal Variable #iiii"
> > + stream nextPut: 16 + literalIndex.
> > + ^self].
> > + "227 11100011 i i i i i i i i Push Literal Variable
> #iiiiiiii (+ Extend A * 256)"
> > + (extendedIndex := literalIndex) > 255 ifTrue:
> > + [self genUnsignedSingleExtendA: extendedIndex // 256.
> > + extendedIndex := extendedIndex \\ 256].
> > + stream
> > + nextPut: 227;
> > + nextPut: extendedIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushNewArray: (in category
> 'bytecode generation') -----
> > + genPushNewArray: size
> > + (size < 0 or: [size > 127]) ifTrue:
> > + [^self outOfRangeError: 'size' index: size range: 0 to: 127].
> > + "231 11100111 jkkkkkkk Push (Array new: kkkkkkk) (j =
> 0)
> > + & Pop kkkkkkk elements into:
> (Array new: kkkkkkk) (j = 1)"
> > + stream
> > + nextPut: 231;
> > + nextPut: size!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushReceiver (in category
> 'bytecode generation') -----
> > + genPushReceiver
> > + "76 01001100 Push Receiver"
> > + stream nextPut: 76!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushRemoteTemp:inVectorAt: (in
> category 'bytecode generation') -----
> > + genPushRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> > + "251 11111011 kkkkkkkk sjjjjjjj Push Temp At
> kkkkkkkk In Temp Vector At: jjjjjjj, s = 1 implies remote inst var access
> instead of remote temp vector access"
> > + (tempIndex < 0 or: [tempIndex >= 256]) ifTrue:
> > + [^self outOfRangeError: 'remoteTempIndex' index: tempIndex
> range: 0 to: 255].
> > + (tempVectorIndex < 0 or: [tempVectorIndex >= 128]) ifTrue:
> > + [^self outOfRangeError: 'tempVectorIndex' index:
> tempVectorIndex range: 0 to: 127].
> > + stream
> > + nextPut: 251;
> > + nextPut: tempIndex;
> > + nextPut: tempVectorIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushSpecialLiteral: (in category
> 'bytecode generation') -----
> > + genPushSpecialLiteral: aLiteral
> > + "77 01001101 Push true
> > + 78 01001110 Push false
> > + 79 01001111 Push nil
> > + 80 01010000 Push 0
> > + 81 01010001 Push 1
> > + 232 11101000 iiiiiiii Push Integer #iiiiiiii (+
> Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)
> > + 233 11101001 i i i i i i i i Push Character #iiiiiiii
> (+ Extend B * 256)"
> > + | index |
> > + aLiteral isInteger ifTrue:
> > + [aLiteral == 0 ifTrue:
> > + [stream nextPut: 80.
> > + ^self].
> > + aLiteral == 1 ifTrue:
> > + [stream nextPut: 81.
> > + ^self].
> > + ^self genPushInteger: aLiteral].
> > + aLiteral isCharacter ifTrue:
> > + [^self genPushCharacter: aLiteral].
> > + index := #(true false nil)
> > + indexOf: aLiteral
> > + ifAbsent: [^self error: 'push special literal: ',
> aLiteral printString, ' is not one of true false nil'].
> > + stream nextPut: 76 + index!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushTemp: (in category 'bytecode
> generation') -----
> > + genPushTemp: tempIndex
> > + (tempIndex < 0 or: [tempIndex > 63]) ifTrue:
> > + [^self outOfRangeError: 'index' index: tempIndex range: 0 to:
> 63].
> > + tempIndex < 12 ifTrue:
> > + ["64-71 01000 i i i Push Temporary Variable #iii
> > + 72-75 010010 i i Push Temporary Variable #ii + 8"
> > + stream nextPut: 64 + tempIndex.
> > + ^self].
> > + "229 11100101 i i i i i i i i Push Temporary Variable
> #iiiiiiii"
> > + stream
> > + nextPut: 229;
> > + nextPut: tempIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genPushThisContext (in category
> 'bytecode generation') -----
> > + genPushThisContext
> > + "82 01010010 Push thisContext, (then e.g.
> Extend B 1 = push thisProcess)"
> > + stream nextPut: 82!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genReturnNilToCaller (in category
> 'bytecode generation') -----
> > + genReturnNilToCaller
> > + "93 01011101 BlockReturn nil [* return from
> enclosing block N, ExtA]"
> > + "If extended, the least significant bit of the extension determines
> if we return to the caller or not
> > + and the most significant bits determine how many levels of the
> static chain to return from.
> > + ExtA = iiiiiiij
> > + iiiiiii=0,j=0 => return to caller
> > + iiiiiii=0,j=1 => illegal
> > + iiiiiii=1,j=0 => return to outerContext
> > + iiiiiii=1,j=1 => return to outerContext sender/return
> from outerContext
> > + iiiiiii=2,j=0 => return to outerContext outerContext
> > + iiiiiii=2,j=1 => return to outerContext outerContext
> sender/return from outerContext outerContext
> > + etc"
> > +
> > + stream nextPut: 93!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genReturnReceiver (in category
> 'bytecode generation') -----
> > + genReturnReceiver
> > + "88-91 010110 ii Return Receiver/true/false/nil"
> > + stream nextPut: 88!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genReturnSpecialLiteral: (in category
> 'bytecode generation') -----
> > + genReturnSpecialLiteral: aLiteral
> > + "88-91 010110 ii Return Receiver/true/false/nil"
> > + | index |
> > + index := #(true false nil) indexOf: aLiteral ifAbsent: 0.
> > + index = 0 ifTrue:
> > + [^self error: 'return special literal: ', aLiteral
> printString, ' is not one of true false nil'].
> > + stream nextPut: 88 + index!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genReturnTop (in category 'bytecode
> generation') -----
> > + genReturnTop
> > + "92 1011100 Return Stack Top From Message"
> > + stream nextPut: 92!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genReturnTopToCaller (in category
> 'bytecode generation') -----
> > + genReturnTopToCaller
> > + "94 01011110 Return Stack Top From Block [* return
> from enclosing block N, ExtA]"
> > + "If extended, the least significant bit of the extension determines
> if we return to the caller or not
> > + and the most significant bits determine how many levels of the
> static chain to return from.
> > + ExtA = iiiiiiij
> > + iiiiiii=0,j=0 => return to caller
> > + iiiiiii=0,j=1 => illegal
> > + iiiiiii=1,j=0 => return to outerContext
> > + iiiiiii=1,j=1 => return to outerContext sender/return
> from outerContext
> > + iiiiiii=2,j=0 => return to outerContext outerContext
> > + iiiiiii=2,j=1 => return to outerContext outerContext
> sender/return from outerContext outerContext
> > + etc"
> > +
> > + stream nextPut: 94!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genSend:numArgs: (in category
> 'bytecode generation') -----
> > + genSend: selectorLiteralIndex numArgs: nArgs
> > + | extendedIndex extendedNArgs |
> > + (selectorLiteralIndex < 0 or: [selectorLiteralIndex > 65535])
> ifTrue:
> > + [^self outOfRangeError: 'selectorLiteralIndex' index:
> selectorLiteralIndex range: 0 to: 65535].
> > + (nArgs < 0 or: [nArgs > 31]) ifTrue:
> > + [^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31
> "!!!!"].
> > + (selectorLiteralIndex < 16 and: [nArgs < 3]) ifTrue:
> > + ["128-143 1000 iiii Send Literal Selector #iiii
> With 0 Argument
> > + 144-159 1001 iiii Send Literal Selector #iiii
> With 1 Arguments
> > + 160-175 1010 iiii Send Literal Selector #iiii
> With 2 Arguments"
> > + stream nextPut: 128 + (nArgs * 16) + selectorLiteralIndex.
> > + ^self].
> > + (extendedIndex := selectorLiteralIndex) > 31 ifTrue:
> > + [self genUnsignedMultipleExtendA: extendedIndex // 32.
> > + extendedIndex := extendedIndex \\ 32].
> > + (extendedNArgs := nArgs) > 7 ifTrue:
> > + [self genUnsignedSingleExtendB: extendedNArgs // 8.
> > + extendedNArgs := extendedNArgs \\ 8].
> > + "234 11101010 i i i i i j j j Send Literal Selector
> #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments"
> > + stream
> > + nextPut: 234;
> > + nextPut: extendedNArgs + (extendedIndex * 8)!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genSendDirectedSuper:numArgs: (in
> category 'bytecode generation') -----
> > + genSendDirectedSuper: selectorLiteralIndex numArgs: nArgs
> > + | extendedIndex |
> > + (selectorLiteralIndex < 0 or: [selectorLiteralIndex > 65535])
> ifTrue:
> > + [^self outOfRangeError: 'selectorLiteralIndex' index:
> selectorLiteralIndex range: 0 to: 65535].
> > + (nArgs < 0 or: [nArgs > 31]) ifTrue:
> > + [^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31
> "!!!!"].
> > + (extendedIndex := selectorLiteralIndex) > 31 ifTrue:
> > + [self genUnsignedMultipleExtendA: extendedIndex // 32.
> > + extendedIndex := extendedIndex \\ 32].
> > + "Bit 6 of the ExtB byte is the directed send flag. Bit 6 allows
> for future expansion to up to 255 args."
> > + self genUnsignedSingleExtendB: nArgs // 8 + 64.
> > + "235 11101011 iiiiijjj Send To Superclass Literal
> Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments"
> > + stream
> > + nextPut: 235;
> > + nextPut: nArgs \\ 8 + (extendedIndex * 8)!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genSendSpecial:numArgs: (in category
> 'bytecode generation') -----
> > + genSendSpecial: specialSelectorIndex numArgs: nArgs
> > + self assert: (specialSelectorIndex between: 1 and: Smalltalk
> specialSelectorSize).
> > + self assert: nArgs = (Smalltalk specialNargsAt:
> specialSelectorIndex).
> > + "Special selector sends.
> > + 96-111 0110 iiii Send Arithmetic Message
> #iiii #(#+ #- #< #> #'<=' #'>=' #= #'~=' #* #/ #'\\' #@ #bitShift: #'//'
> #bitAnd: #bitOr:)
> > + 112-119 01110 iii Send Special Message #iii
> #(#at: #at:put: #size ? ? ? #'==' class ? value value: ? ? ? ? ?)"
> > +
> > + stream nextPut: specialSelectorIndex + 95!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genSendSuper:numArgs: (in category
> 'bytecode generation') -----
> > + genSendSuper: selectorLiteralIndex numArgs: nArgs
> > + | extendedIndex extendedNArgs |
> > + (selectorLiteralIndex < 0 or: [selectorLiteralIndex > 65535])
> ifTrue:
> > + [^self outOfRangeError: 'selectorLiteralIndex' index:
> selectorLiteralIndex range: 0 to: 65535].
> > + (nArgs < 0 or: [nArgs > 31]) ifTrue:
> > + [^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31
> "!!!!"].
> > + (extendedIndex := selectorLiteralIndex) > 31 ifTrue:
> > + [self genUnsignedMultipleExtendA: extendedIndex // 32.
> > + extendedIndex := extendedIndex \\ 32].
> > + (extendedNArgs := nArgs) > 7 ifTrue:
> > + [self genUnsignedSingleExtendB: extendedNArgs // 8.
> > + extendedNArgs := extendedNArgs \\ 8].
> > + "235 11101011 iiiiijjj Send To Superclass Literal
> Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments"
> > + stream
> > + nextPut: 235;
> > + nextPut: extendedNArgs + (extendedIndex * 8)!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genSignedSingleExtendB: (in category
> 'bytecode generation') -----
> > + genSignedSingleExtendB: extendedIndex
> > + (extendedIndex between: -128 and: 127) ifFalse:
> > + [^self outOfRangeError: 'index' index: extendedIndex range:
> -128 to: 127].
> > + "225 11100001 sbbbbbbb Extend B (Ext B = Ext B prev *
> 256 + Ext B)"
> > + stream
> > + nextPut: 225;
> > + nextPut: (extendedIndex >= 0 ifTrue: [extendedIndex] ifFalse:
> [extendedIndex + 256]) !
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genStoreInstVar: (in category
> 'bytecode generation') -----
> > + genStoreInstVar: instVarIndex
> > + "243 11110011 iiiiiiii Store Receiver Variable
> #iiiiiii (+ Extend A * 256)"
> > + self genStoreInstVarLong: instVarIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genStoreInstVarLong: (in category
> 'bytecode generation') -----
> > + genStoreInstVarLong: instVarIndex
> > + "243 11110011 iiiiiiii Store Receiver Variable
> #iiiiiii (+ Extend A * 256)"
> > + (instVarIndex < 0 or: [instVarIndex > 65535]) ifTrue:
> > + [^self outOfRangeError: 'index' index: instVarIndex range: 0
> to: 65535].
> > + instVarIndex > 255 ifTrue:
> > + [self genUnsignedSingleExtendA: instVarIndex // 256].
> > + stream
> > + nextPut: 243;
> > + nextPut: instVarIndex \\ 256!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genStoreLiteralVar: (in category
> 'bytecode generation') -----
> > + genStoreLiteralVar: literalIndex
> > + "244 11110100 iiiiiiii Store Literal Variable
> #iiiiiiii (+ Extend A * 256)"
> > + (literalIndex < 0 or: [literalIndex > 65535]) ifTrue:
> > + [^self outOfRangeError: 'index' index: literalIndex range: 0
> to: 65535].
> > + literalIndex > 255 ifTrue:
> > + [self genUnsignedSingleExtendA: literalIndex // 256].
> > + stream
> > + nextPut: 244;
> > + nextPut: literalIndex \\ 256!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genStorePopInstVar: (in category
> 'bytecode generation') -----
> > + genStorePopInstVar: instVarIndex
> > + "200-207 11001 iii Pop and Store Receiver Variable
> #iii
> > + 240 11110000 iiiiiiii Pop and Store Receiver Variable
> #iiiiiii (+ Extend A * 256)"
> > + (instVarIndex < 0 or: [instVarIndex > 7]) ifTrue:
> > + [^self genStorePopInstVarLong: instVarIndex].
> > + stream nextPut: 200 + instVarIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genStorePopInstVarLong: (in category
> 'bytecode generation') -----
> > + genStorePopInstVarLong: instVarIndex
> > + "240 11110000 iiiiiiii Pop and Store Receiver
> Variable #iiiiiii (+ Extend A * 256)"
> > + (instVarIndex < 0 or: [instVarIndex > 65535]) ifTrue:
> > + [^self outOfRangeError: 'index' index: instVarIndex range: 0
> to: 65535].
> > + instVarIndex > 255 ifTrue:
> > + [self genUnsignedSingleExtendA: instVarIndex // 256].
> > + stream
> > + nextPut: 240;
> > + nextPut: instVarIndex \\ 256!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genStorePopLiteralVar: (in category
> 'bytecode generation') -----
> > + genStorePopLiteralVar: literalIndex
> > + "241 11110001 iiiiiiii Pop and Store Literal
> Variable #iiiiiiii (+ Extend A * 256)"
> > + (literalIndex < 0 or: [literalIndex > 65535]) ifTrue:
> > + [^self outOfRangeError: 'index' index: literalIndex range: 0
> to: 65535].
> > + literalIndex > 255 ifTrue:
> > + [self genUnsignedSingleExtendA: literalIndex // 256].
> > + stream
> > + nextPut: 241;
> > + nextPut: literalIndex \\ 256!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genStorePopRemoteTemp:inVectorAt: (in
> category 'bytecode generation') -----
> > + genStorePopRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> > + "* 253 (3) 11111101 kkkkkkkk sjjjjjjj Pop and
> Store Temp At kkkkkkkk In Temp Vector At: jjjjjjj s = 1 implies remote inst
> var access instead of remote temp vector access"
> > + (tempIndex < 0 or: [tempIndex >= 256]) ifTrue:
> > + [^self outOfRangeError: 'remoteTempIndex' index: tempIndex
> range: 0 to: 255].
> > + (tempVectorIndex < 0 or: [tempVectorIndex >= 128]) ifTrue:
> > + [^self outOfRangeError: 'tempVectorIndex' index:
> tempVectorIndex range: 0 to: 127].
> > + stream
> > + nextPut: 253;
> > + nextPut: tempIndex;
> > + nextPut: tempVectorIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genStorePopTemp: (in category
> 'bytecode generation') -----
> > + genStorePopTemp: tempIndex
> > + "208-215 11010 iii Pop and Store Temporary Variable
> #iii
> > + 242 11110010 iiiiiiii Pop and Store Temporary
> Variable #iiiiiiii"
> > + (tempIndex < 0 or: [tempIndex > 63]) ifTrue:
> > + [^self outOfRangeError: 'index' index: tempIndex range: 0 to:
> 63].
> > + tempIndex < 8 ifTrue:
> > + [stream nextPut: 208 + tempIndex.
> > + ^self].
> > + stream
> > + nextPut: 242;
> > + nextPut: tempIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genStoreRemoteTemp:inVectorAt: (in
> category 'bytecode generation') -----
> > + genStoreRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> > + "*252 (3) 11111100 kkkkkkkk sjjjjjjj Store Temp
> At kkkkkkkk In Temp Vector At: jjjjjjj s = 1 implies remote inst var access
> instead of remote temp vector access"
> > + (tempIndex < 0 or: [tempIndex >= 256]) ifTrue:
> > + [^self outOfRangeError: 'remoteTempIndex' index: tempIndex
> range: 0 to: 255].
> > + (tempVectorIndex < 0 or: [tempVectorIndex >= 128]) ifTrue:
> > + [^self outOfRangeError: 'tempVectorIndex' index:
> tempVectorIndex range: 0 to: 127].
> > + stream
> > + nextPut: 252;
> > + nextPut: tempIndex;
> > + nextPut: tempVectorIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genStoreTemp: (in category 'bytecode
> generation') -----
> > + genStoreTemp: tempIndex
> > + "245 11110110 iiiiiiii Store Temporary Variable
> #iiiiiiii"
> > + (tempIndex < 0 or: [tempIndex > 63]) ifTrue:
> > + [^self outOfRangeError: 'index' index: tempIndex range: 0 to:
> 63].
> > + stream
> > + nextPut: 245;
> > + nextPut: tempIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genTrapIfNotInstanceOf: (in category
> 'bytecode generation') -----
> > + genTrapIfNotInstanceOf: literalIndex
> > + "* 236 11101100 iiiiiiii Trap If Not Instance
> Of Behavior/Array Of Behavior #iiiiiiii (+ Extend A * 256, where Extend A
> >= 0)"
> > +
> > + | extendedIndex |
> > + (literalIndex < 0 or: [literalIndex > 65535]) ifTrue:
> > + [^self outOfRangeError: 'index' index: literalIndex range: 0
> to: 65536].
> > + (extendedIndex := literalIndex) > 255 ifTrue:
> > + [self genUnsignedSingleExtendA: extendedIndex // 256.
> > + extendedIndex := extendedIndex \\ 256].
> > + stream
> > + nextPut: 236;
> > + nextPut: extendedIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genUnsignedMultipleExtendA: (in
> category 'bytecode generation') -----
> > + genUnsignedMultipleExtendA: extendedIndex
> > + "224 11100000 aaaaaaaa Extend A (Ext A = Ext A prev *
> 256 + Ext A)"
> > + extendedIndex > 255 ifTrue:
> > + [self genUnsignedMultipleExtendA: extendedIndex // 256].
> > + stream
> > + nextPut: 224;
> > + nextPut: extendedIndex \\ 256!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genUnsignedSingleExtendA: (in
> category 'bytecode generation') -----
> > + genUnsignedSingleExtendA: extendedIndex
> > + (extendedIndex between: 0 and: 255) ifFalse:
> > + [^self outOfRangeError: 'index' index: extendedIndex range: 0
> to: 255].
> > + "224 11100000 aaaaaaaa Extend A (Ext A = Ext A prev *
> 256 + Ext A)
> > + ExtA is normally unsigned."
> > + stream
> > + nextPut: 224;
> > + nextPut: extendedIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>genUnsignedSingleExtendB: (in
> category 'bytecode generation') -----
> > + genUnsignedSingleExtendB: extendedIndex
> > + (extendedIndex between: 0 and: 255) ifFalse:
> > + [^self outOfRangeError: 'index' index: extendedIndex range: 0
> to: 255].
> > + "225 11100001 sbbbbbbb Extend B (Ext B = Ext B prev *
> 256 + Ext B).
> > + ExtB is normally signed"
> > + stream
> > + nextPut: 225;
> > + nextPut: extendedIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>isSpecialLiteralForPush: (in category
> 'special literal encodings') -----
> > + isSpecialLiteralForPush: literal
> > + ^literal isInteger
> > + ifFalse:
> > + [literal isCharacter
> > + ifFalse:
> > + [false == literal
> > + or: [true == literal
> > + or: [nil == literal]]]
> > + ifTrue:
> > + [Smalltalk interpreterVMMakerVersion >= 3174
> > + ifTrue:
> > + [literal asInteger between: 0 and: 65535]
> > + ifFalse:
> > + ["Restrict character range due to VM bug at
> character value reconstruction
> > + See
> https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/618"
> > + literal asInteger between: 0 and: 16rFF]]]
> > + ifTrue:
> > + [literal between: -32768 and: 32767]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>isSpecialLiteralForReturn: (in
> category 'special literal encodings') -----
> > + isSpecialLiteralForReturn: literal
> > + ^literal == false
> > + or: [literal == true
> > + or: [literal == nil]]!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>maxIndexableLiterals (in category
> 'accessing') -----
> > + maxIndexableLiterals
> > + "Answer the maximum number of literals supported by the receiver's
> > + bytecode set."
> > + ^65536!
> >
> > Item was added:
> > + ----- Method: EncoderForSistaV1>>supportsFullBlocks (in category
> 'testing') -----
> > + supportsFullBlocks
> > + "Answer if the instruction set supports full closures (closure
> creation from
> > + specfic methods instead of bytecodes embedded in an outer home
> method)."
> > +
> > + ^true!
> >
> > Item was added:
> > + BytecodeEncoder subclass: #EncoderForV3
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> > +
> > + !EncoderForV3 commentStamp: 'eem 1/18/2019 12:38' prior: 0!
> > + I add behaviour to Encoder to size and emit bytecodes for the Squeak
> V3.x VM bytecode set, a close variant of the original Smalltalk-80 bytecode
> set defined in the Blue Book.
> > +
> > + 0-15 0000iiii Push Receiver Variable #iiii
> > + 16-31 0001iiii Push Temporary Location #iiii
> > + 32-63 001iiiii Push Literal Constant #iiiii
> > + 64-95 010iiiii Push Literal Variable #iiiii
> > + 96-103 01100iii Pop and Store Receiver Variable #iii
> > + 104-111 01101iii Pop and Store Temporary Location #iii
> > + 112-119 01110iii Push (receiver, true, false, nil, -1, 0, 1,
> 2) [iii]
> > + 120-123 011110ii Return (receiver, true, false, nil) [ii]
> From Message
> > + 124-125 0111110i Return Stack Top From (Message, Block) [i]
> > + (126-127 unassigned)
> > + 128 10000000 jjkkkkkk Push (Receiver Variable, Temporary
> Location, Literal Constant, Literal Variable) [jj] #kkkkkk
> > + 129 10000001 jjkkkkkk Store (Receiver Variable, Temporary
> Location, Illegal, Literal Variable) [jj] #kkkkkk
> > + 130 10000010 jjkkkkkk Pop and Store (Receiver Variable,
> Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk
> > + 131 10000011 jjjkkkkk Send Literal Selector #kkkkk With
> jjj Arguments
> > + 132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push
> Receiver Variable, Push Literal Constant, Push Literal Variable, Store
> Receiver Variable, Store-Pop Receiver Variable, Store Literal
> Variable)[iii] #kkkkkkkk jjjjj (for sends jjjjj = numArgs)
> > + 133 10000101 jjjkkkkk Send Literal Selector #kkkkk To
> Superclass With jjj Arguments
> > + 134 10000110 jjkkkkkk Send Literal Selector #kkkkkk With
> jj Arguments
> > + 135 10000111 Pop Stack Top
> > + 136 10001000 Duplicate Stack Top
> > + 137 10001001 Push Active Context
> > + (138-143 unassigned)
> > + 144-151 10010iii Jump iii + 1 (i.e., 1 through 8)
> > + 152-159 10011iii Pop and Jump 0n False iii +1 (i.e., 1
> through 8)
> > + 160-167 10100iii jjjjjjjj Jump(iii - 4) *256+jjjjjjjj
> > + 168-171 101010ii jjjjjjjj Pop and Jump On True ii
> *256+jjjjjjjj
> > + 172-175 101011ii jjjjjjjj Pop and Jump On False ii
> *256+jjjjjjjj
> > + 176-191 1011iiii Send Arithmetic Message #iiii
> > + 192-207 1100iiii Send Special Message #iiii
> > + 208-223 1101iiii Send Literal Selector #iiii With No
> Arguments
> > + 224-239 1110iiii Send Literal Selector #iiii With 1
> Argument
> > + 240-255 1111iiii Send Literal Selector #iiii With 2
> Arguments
> > + !
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>bindingReadScanBlockFor:using: (in
> category 'compiled method support') -----
> > + bindingReadScanBlockFor: bindingLitIndex using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for reads of the value of the binding with zero-relative index
> litVarIndex.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > + ^[:b|
> > + b >= 64
> > + and: [b <= 95
> > + ifTrue: [b - 64 = bindingLitIndex]
> > + ifFalse:
> > + [b = 128
> > + ifTrue: [scanner followingByte - 192 =
> bindingLitIndex]
> > + ifFalse:
> > + [b = 132
> > + and: [(scanner followingByte between: 128 and:
> 159)
> > + and: [scanner thirdByte =
> bindingLitIndex]]]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>bindingWriteScanBlockFor:using: (in
> category 'compiled method support') -----
> > + bindingWriteScanBlockFor: bindingLitIndex using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for writes of the value of the binding with zero-relative index
> bindingLitIndex.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > + ^[:b|
> > + (b = 129 or: [b = 130])
> > + ifTrue: [scanner followingByte - 192 = bindingLitIndex]
> > + ifFalse:
> > + [b = 132
> > + and: [scanner followingByte >= 224
> > + and: [scanner thirdByte = bindingLitIndex]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>bytecodeSize: (in category
> 'instruction stream support') -----
> > + bytecodeSize: bytecode
> > + "Answer the number of bytes in the bytecode."
> > + bytecode <= 125 ifTrue:
> > + [^1].
> > + bytecode >= 176 ifTrue:
> > + [^1].
> > + bytecode >= 160 ifTrue: "long jumps"
> > + [^2].
> > + bytecode >= 144 ifTrue: "short jumps"
> > + [^1].
> > + "extensions"
> > + bytecode >= 128 ifTrue:
> > + [^#(2 2 2 2 3 2 2 1 1 1 nil nil nil nil nil nil) at: bytecode -
> 127].
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>canBeSpecialLiteral: (in category
> 'testing') -----
> > + canBeSpecialLiteral: aLiteral
> > + "This check can be used to prevent unnecessary use of
> #scanBlockOrNilForLiteral:."
> > +
> > + aLiteral isVariableBinding ifTrue: [^false]. "a common case; don't
> waste time analysing..."
> > +
> > + aLiteral isSymbol ifTrue: [^ Smalltalk specialSelectors
> identityIncludes: aLiteral].
> > + aLiteral isInteger ifTrue: [^ aLiteral between: -1 and: 2].
> > +
> > + aLiteral == true ifTrue: [^ true].
> > + aLiteral == false ifTrue: [^ true].
> > + aLiteral == nil ifTrue: [^ true].
> > +
> > + ^ false!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>createClosureScanBlock (in category
> 'compiled method support') -----
> > + createClosureScanBlock
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for block closure creation bytecodes."
> > + ^[:b| false]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>extensionsAt:in:into: (in category
> 'instruction stream support') -----
> > + extensionsAt: pc in: aCompiledMethod into: trinaryBlock
> > + "If the bytecode at pc is an extension then evaluate aTrinaryBlock
> > + with the values of extA and extB and number of extension *bytes*.
> > + If the bytecode at pc is not an extension then evaluate with 0, 0,
> 0.
> > + There are no extensions in the SqueakV3/Smalltalk-80 bytecode set,
> so..."
> > + ^trinaryBlock value: 0 value: 0 value: 0!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>extensionsFor:in:into: (in category
> 'instruction stream support') -----
> > + extensionsFor: pc in: aCompiledMethod into: trinaryBlock
> > + "If the bytecode at pc is an extension, or if the bytecode at pc is
> preceded by extensions,
> > + then evaluate aTrinaryBlock with the values of extA and extB and
> number of extension *bytes*.
> > + If the bytecode at pc is neither an extension or extended then
> evaluate with 0, 0, 0.
> > + There are no extensions in the SqueakV3/Smalltalk-80 bytecode set,
> so..."
> > + ^trinaryBlock value: 0 value: 0 value: 0!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>instVarReadScanBlockFor:using: (in
> category 'compiled method support') -----
> > + instVarReadScanBlockFor: varIndexCode using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for reads of the inst var with zero-relative index varIndexCode.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > + ^[:b|
> > + b < 16
> > + ifTrue: [b = varIndexCode]
> > + ifFalse:
> > + [b = 128
> > + ifTrue: [scanner followingByte = varIndexCode and:
> [varIndexCode <= 63]]
> > + ifFalse:
> > + [b = 132
> > + and: [(scanner followingByte between: 64 and: 95)
> > + and: [scanner thirdByte = varIndexCode]]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>instVarWriteScanBlockFor:using: (in
> category 'compiled method support') -----
> > + instVarWriteScanBlockFor: varIndexCode using: scanner
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for writes of the inst var with zero-relative index varIndexCode.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available."
> > + ^[:b|
> > + b >= 96
> > + and: [b <= 103
> > + ifTrue: [b - 96 = varIndexCode]
> > + ifFalse:
> > + [(b = 129 or: [b = 130])
> > + ifTrue: [scanner followingByte = varIndexCode and:
> [varIndexCode <= 63]]
> > + ifFalse:
> > + [b = 132
> > + and: [(scanner followingByte between: 160 and:
> 223)
> > + and: [scanner thirdByte = varIndexCode]]]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>interpretJumpIfCondIn: (in category
> 'instruction stream support') -----
> > + interpretJumpIfCondIn: anInstructionStream
> > + "Double-dispatch through the encoder to select the correct
> conditional jump decoder for the instruction set."
> > + ^anInstructionStream interpretV3JumpIfCond!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>interpretJumpIn: (in category
> 'instruction stream support') -----
> > + interpretJumpIn: anInstructionStream
> > + "Double-dispatch through the encoder to select the correct jump
> interpreter for the instruction set."
> > + ^anInstructionStream interpretV3Jump!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>interpretNextInstructionFor:in: (in
> category 'instruction stream support') -----
> > + interpretNextInstructionFor: aClient in: anInstructionStream
> > + "Double-dispatch through the encoder to select the correct
> instruction set decoder."
> > + ^anInstructionStream interpretNextV3InstructionFor: aClient!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isBlockReturnAt:in: (in category
> 'instruction stream support') -----
> > + isBlockReturnAt: pc in: method
> > + "Answer whether the bytecode at pc is a return from block."
> > +
> > + ^(method at: pc) = 125!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isBranchIfFalseAt:in: (in category
> 'instruction stream support') -----
> > + isBranchIfFalseAt: pc in: method
> > + "Answer whether the bytecode at pc is a conditional
> branch-if-false."
> > + | bytecode |
> > + bytecode := method at: pc.
> > + ^(bytecode between: 152 and: 159) or: [bytecode between: 172 and:
> 175]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isBranchIfTrueAt:in: (in category
> 'instruction stream support') -----
> > + isBranchIfTrueAt: pc in: method
> > + "Answer whether the bytecode at pc is a conditional branch-if-true."
> > + ^(method at: pc) between: 168 and: 171!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isExtension: (in category
> 'instruction stream support') -----
> > + isExtension: bytecode
> > + "Answer if the bytecode is an extension bytecode, i.e. one that
> extends the
> > + range of the following bytecode. The Smalltalk-80/V3 sets don't
> use extensions."
> > + ^false!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isJumpAt:in: (in category
> 'instruction stream support') -----
> > + isJumpAt: pc in: method
> > + "Answer whether the bytecode at pc is an (unconditional) jump."
> > + | bytecode |
> > + bytecode := method at: pc.
> > + ^(bytecode between: 144 and: 151) or: [bytecode between: 160 and:
> 167]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isJustPopAt:in: (in category
> 'instruction stream support') -----
> > + isJustPopAt: pc in: method
> > + "Answer whether the bytecode at pc is a pop."
> > +
> > + ^(method at: pc) = 135 "135 10000111 Pop Stack Top"!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isRealSendAt:in: (in category
> 'instruction stream support') -----
> > + isRealSendAt: pc in: method
> > + "Answer whether the bytecode at pc is a real message-send, not
> blockCopy:."
> > +
> > + | byte |
> > + byte := method at: pc.
> > + ^byte >= 176 "special send or short send"
> > + or: [byte >= 131
> > + and: [byte <= 134 "long sends"
> > + and: [byte ~= 132 "double extended do anything"
> > + or: [(method at: pc + 1) // 32 <= 1]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isReturnAt:in: (in category
> 'instruction stream support') -----
> > + isReturnAt: pc in: method
> > + "Answer whether the bytecode at pc is a return."
> > +
> > + ^(method at: pc) between: 120 and: 125!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isReturnSelfFromMethodAt:in: (in
> category 'instruction stream support') -----
> > + isReturnSelfFromMethodAt: pc in: method
> > + "Answer whether the bytecode at pc is a return self from method."
> > +
> > + ^(method at: pc) = 120!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isReturnTopFromMethodAt:in: (in
> category 'instruction stream support') -----
> > + isReturnTopFromMethodAt: pc in: method
> > + "Answer whether the bytecode at pc is a return stack top from
> method."
> > +
> > + ^(method at: pc) = 124!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isSendAt:in: (in category
> 'instruction stream support') -----
> > + isSendAt: pc in: method
> > + "Answer whether the bytecode at pc is a message-send."
> > +
> > + | byte |
> > + byte := method at: pc.
> > + ^byte >= 176 "special send or short send"
> > + or: [byte >= 131
> > + and: [byte <= 134 "long sends"
> > + and: [byte ~= 132 "double extended do anything"
> > + or: [(method at: pc + 1) // 32 <= 1]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isStoreAt:in: (in category
> 'instruction stream support') -----
> > + isStoreAt: pc in: method
> > + "Answer whether the bytecode at pc is a store or store-pop."
> > +
> > + | byte |
> > + byte := method at: pc.
> > + ^(byte between: 96 and: 132)
> > + and: [byte <= 111 "96 103
> storeAndPopReceiverVariableBytecode"
> > + "104 111
> storeAndPopTemporaryVariableBytecode"
> > + or: [byte >= 129 "129
> extendedStoreBytecode"
> > + and: [byte <= 130 "130
> extendedStoreAndPopBytecode"
> > + or: [byte = 132 "132
> doubleExtendedDoAnythingBytecode"
> > + and: [(method at: pc+1) >= 160]]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isStorePopAt:in: (in category
> 'instruction stream support') -----
> > + isStorePopAt: pc in: method
> > + "Answer whether the bytecode at pc is a store-pop."
> > +
> > + | byte |
> > + byte := method at: pc.
> > + ^(byte between: 96 and: 111) "96 103
> storeAndPopReceiverVariableBytecode"
> > + "104 111
> storeAndPopTemporaryVariableBytecode"
> > + or: [byte = 130] "130
> extendedStoreAndPopBytecode"!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isSyntheticStoreAt:in:for: (in
> category 'instruction stream support') -----
> > + isSyntheticStoreAt: pc in: method for: anInstructionStream
> > + "Answer whether the bytecode at pc is a store or store-pop of an
> indirect temp vector,
> > + which implement mutable closed-over variables in the the closure
> implementation.
> > + Stores into temp vectors are not real stores."
> > +
> > + ^false!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>isTempStoreAt:in: (in category
> 'instruction stream support') -----
> > + isTempStoreAt: pc in: method
> > + "Answer whether the bytecode at pc is a store or store-pop into a
> temporary variable.
> > + 104-111 01101iii Pop and Store Temporary Location #iii
> > + 129 10000001 jjkkkkkk Store (Receiver Variable,
> Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk
> > + 130 10000010 jjkkkkkk Pop and Store (Receiver Variable,
> Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
> > +
> > + | byte |
> > + byte := method at: pc.
> > + ^byte >= 104
> > + and: [byte <= 111
> > + or: [byte <= 130 and: [byte >= 129 and: [(method at: pc +
> 1) >> 6 = 1]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>markerOrNilFor: (in category
> 'compiled method support') -----
> > + markerOrNilFor: aMethod
> > + "If aMethod is a marker method, answer the symbol used to mark it.
> Otherwise
> > + answer nil. What is a marker method? It is method with body like
> > + 'self subclassResponsibility' or '^ self
> subclassResponsibility'
> > + used to indicate ('mark') a special property.
> > +
> > + Marker methods compile to two bytecode forms, this:
> > + self
> > + send: <literal 1>
> > + pop
> > + returnSelf
> > + or this:
> > + self
> > + send: <literal 1>
> > + returnTop"
> > + | expectedHeaderPlusLliteralSize e byte |
> > + expectedHeaderPlusLliteralSize := Smalltalk wordSize * 4.
> > + ^(((e := aMethod endPC - expectedHeaderPlusLliteralSize) = 3 or: [e
> = 4])
> > + and: [aMethod numLiterals = 3
> > + and: [(aMethod at: expectedHeaderPlusLliteralSize + 1) = 16r70
> "push self"
> > + and: [(aMethod at: expectedHeaderPlusLliteralSize + 2) = 16rD0
> "send"
> > + and: [(byte := aMethod at: expectedHeaderPlusLliteralSize + 3) =
> 16r87 "pop" or: [byte = 16r7C "returnTop"]]]]])
> > + ifTrue: [aMethod literalAt: 1]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>method:readsField: (in category
> 'scanning') -----
> > + method: method readsField: varIndex
> > + "Answer if method loads the instance variable indexed by varIndex.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available.
> > + 0-15 0000iiii Push Receiver Variable #iiii
> > + 128 10000000 jjkkkkkk Push (Receiver Variable, Temporary
> Location, Literal Constant, Literal Variable) [jj] #kkkkkk
> > + 132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push
> Receiver Variable, Push Literal Constant, Push Literal Variable, Store
> Receiver Variable, Store-Pop Receiver Variable, Store Literal
> Variable)[iii] #kkkkkkkk jjjjj (for sends jjjjj = numArgs)"
> > + | varIndexCode scanner |
> > + varIndexCode := varIndex - 1.
> > + method isReturnField ifTrue:
> > + [^method returnField = varIndexCode].
> > + ^(scanner := InstructionStream on: method) scanFor:
> > + [:b|
> > + b < 16
> > + ifTrue: [b = varIndexCode]
> > + ifFalse:
> > + [b = 128
> > + ifTrue: [scanner followingByte = varIndexCode and:
> [varIndexCode <= 63]]
> > + ifFalse:
> > + [b = 132
> > + and: [(scanner followingByte between: 64 and:
> 95)
> > + and: [scanner thirdByte = varIndexCode]]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>method:writesField: (in category
> 'scanning') -----
> > + method: method writesField: varIndex
> > + "Answer if method stores into the instance variable indexed by
> varIndex.
> > + N.B. Don't assume the compiler uses the most compact encoding
> available.
> > + 96-103 01100iii Pop and Store Receiver Variable #iii
> > + 129 10000001 jjkkkkkk Store (Receiver Variable, Temporary
> Location, Illegal, Literal Variable) [jj] #kkkkkk
> > + 130 10000010 jjkkkkkk Pop and Store (Receiver Variable,
> Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk
> > + 132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push
> Receiver Variable, Push Literal Constant, Push Literal Variable, Store
> Receiver Variable, Store-Pop Receiver Variable, Store Literal
> Variable)[iii] #kkkkkkkk jjjjj (for sends jjjjj = numArgs)"
> > + | varIndexCode scanner |
> > + method isQuick ifTrue: [^false].
> > + varIndexCode := varIndex - 1.
> > + ^(scanner := InstructionStream on: method) scanFor:
> > + [:b|
> > + b >= 96
> > + and: [b <= 103
> > + ifTrue: [b - 96 = varIndexCode]
> > + ifFalse:
> > + [(b = 129 or: [b = 130])
> > + ifTrue: [scanner followingByte = varIndexCode
> and: [varIndexCode <= 63]]
> > + ifFalse:
> > + [b = 132
> > + and: [(scanner followingByte between: 160
> and: 223)
> > + and: [scanner thirdByte =
> varIndexCode]]]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>nonExtensionBytecodeAt:in: (in
> category 'instruction stream support') -----
> > + nonExtensionBytecodeAt: pc in: method
> > + "Answer the actual bytecode at pc in method, skipping past any
> preceding extensions."
> > + ^method at: pc!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>pushNilCode (in category 'bytecode
> decoding') -----
> > + pushNilCode
> > + "Answer the pushNil bytecode.
> > + 112-119 01110iii Push (receiver, true, false, nil, -1, 0, 1,
> 2) [iii]"
> > + ^115!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>scanBlockOrNilForLiteral: (in
> category 'scanning') -----
> > + scanBlockOrNilForLiteral: aLiteral
> > + "Answer a block argument for CompiledMethod>>#scanFor: that answers
> > + if the method refers to the literal implicitly via a special
> bytecode.
> > + If the literal is not accessible via a special bytecode, answer
> nil."
> > + | value |
> > + "176-191 1011iiii Send Arithmetic Message #iiii
> > + 192-207 1100iiii Send Special Message #iiii"
> > + (aLiteral isSymbol or: [aLiteral isInteger]) ifTrue:
> > + [value := aLiteral isSymbol
> > + ifTrue: [176 + ((Smalltalk specialSelectors
> indexOf: aLiteral ifAbsent: [^nil]) // 2)]
> > + ifFalse: [(aLiteral between: -1 and: 2) ifFalse:
> [^nil].
> > + aLiteral + 117].
> > + ^[:byte| byte = value]].
> > + "112-119 01110iii Push (receiver, true, false, nil, -1, 0, 1,
> 2) [iii]
> > + 120-123 011110ii Return (receiver, true, false, nil) [ii]
> From Message"
> > + aLiteral == true ifTrue:
> > + [^[:byte| byte = 113 or: [byte = 121]]].
> > + aLiteral == false ifTrue:
> > + [^[:byte| byte = 114 or: [byte = 122]]].
> > + aLiteral == nil ifTrue:
> > + [^[:byte| byte = 115 or: [byte = 123]]].
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>selectorToSendOrItselfFor:in:at: (in
> category 'instruction stream support') -----
> > + selectorToSendOrItselfFor: anInstructionStream in: method at: pc
> > + "If anInstructionStream is at a send bytecode then answer the
> send's selector,
> > + otherwise answer anInstructionStream itself. The rationale for
> answering
> > + anInstructionStream instead of, say, nil, is that potentially any
> existing object
> > + can be used as a selector, but since anInstructionStream postdates
> the method,
> > + it can't be one of them."
> > +
> > + | byte byte2 |
> > + byte := method at: pc.
> > + byte < 131 ifTrue: [^anInstructionStream].
> > + byte >= 176
> > + ifTrue:
> > + ["special byte or short send"
> > + byte >= 208
> > + ifTrue: [^method literalAt: (byte bitAnd: 15) + 1]
> > + ifFalse: [^Smalltalk specialSelectorAt: byte - 176 + 1]]
> > + ifFalse:
> > + [byte <= 134 ifTrue:
> > + [byte2 := method at: pc + 1.
> > + byte = 131 ifTrue: [^method literalAt: byte2 \\ 32 +
> 1].
> > + byte = 132 ifTrue: [byte2 < 64 ifTrue: [^method
> literalAt: (method at: pc + 2) + 1]].
> > + byte = 133 ifTrue: [^method literalAt: byte2 \\ 32 +
> 1].
> > + byte = 134 ifTrue: [^method literalAt: byte2 \\ 64 +
> 1]]].
> > + ^anInstructionStream!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>superSendScanBlockUsing: (in
> category 'compiled method support') -----
> > + superSendScanBlockUsing: scanner
> > + "Answer a block argument for InstructionStream>>scanFor:
> > + that answers true for super sends."
> > + ^[:instr |
> > + instr = 16r85
> > + or: [instr = 16r84
> > + and: [scanner followingByte between: 16r20 and: 16r3F]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>supportsClosures (in category
> 'compiled method support') -----
> > + supportsClosures
> > + "Answer if the instruction set supports closures (contains
> > + closure creation and indirect temp access bytecodes)."
> > +
> > + ^false!
> >
> > Item was added:
> > + ----- Method: EncoderForV3 class>>unusedBytecode (in category
> 'bytecode decoding') -----
> > + unusedBytecode
> > + "Answer the opcode of a single-byte unused bytecode, if it exists
> in the encoder's bytecode set, or nil if not."
> > + ^126!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genBranchPopFalse: (in category 'bytecode
> generation') -----
> > + genBranchPopFalse: distance
> > + "See BlueBook page 596"
> > + distance < 0 ifTrue:
> > + [^self outOfRangeError: 'distance' index: distance range: 0 to:
> 1023].
> > + (distance > 0 and: [distance < 9]) ifTrue:
> > + ["152-159 10011iii Pop and Jump 0n False iii +1 (i.e., 1
> through 8)"
> > + stream nextPut: 152 + distance - 1.
> > + ^self].
> > + distance < 1024 ifTrue:
> > + ["172-175 101011ii jjjjjjjj Pop and Jump On False ii
> *256+jjjjjjjj"
> > + stream
> > + nextPut: 172 + (distance bitShift: -8);
> > + nextPut: distance + 1024 \\ 256.
> > + ^self].
> > + ^self outOfRangeError: 'distance' index: distance range: 0 to: 1023!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genBranchPopTrue: (in category 'bytecode
> generation') -----
> > + genBranchPopTrue: distance
> > + "See BlueBook page 596"
> > + distance < 0 ifTrue:
> > + [^self outOfRangeError: 'distance' index: distance range: 0 to:
> 1023].
> > + distance < 1024 ifTrue:
> > + ["168-171 101010ii jjjjjjjj Pop and Jump On True ii
> *256+jjjjjjjj"
> > + stream
> > + nextPut: 168 + (distance bitShift: -8);
> > + nextPut: distance + 1024 \\ 256.
> > + ^self].
> > + ^self outOfRangeError: 'distance' index: distance range: 0 to: 1023!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genDup (in category 'bytecode generation')
> -----
> > + genDup
> > + "See BlueBook page 596"
> > + "136 10001000 Duplicate Stack Top"
> > + stream nextPut: 136!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genJump: (in category 'bytecode
> generation') -----
> > + genJump: distance
> > + "See BlueBook page 596"
> > + (distance > 0 and: [distance < 9]) ifTrue:
> > + ["144-151 10010iii Jump iii + 1 (i.e., 1 through 8)"
> > + stream nextPut: 144 + distance - 1.
> > + ^self].
> > + "160-167 10100iii jjjjjjjj Jump(iii - 4) *256+jjjjjjjj"
> > + ^self genJumpLong: distance!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genJumpLong: (in category 'bytecode
> generation') -----
> > + genJumpLong: distance
> > + "See BlueBook page 596"
> > + (distance >= -1024 and: [distance < 1024]) ifTrue:
> > + ["160-167 10100iii jjjjjjjj Jump(iii - 4) *256+jjjjjjjj"
> > + stream
> > + nextPut: 160 + (distance + 1024 bitShift: -8);
> > + nextPut: distance + 1024 \\ 256.
> > + ^self].
> > + ^self outOfRangeError: 'distance' index: distance range: -1024 to:
> 1023!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genPop (in category 'bytecode generation')
> -----
> > + genPop
> > + "See BlueBook page 596"
> > + "135 10000111 Pop Stack Top"
> > + stream nextPut: 135!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genPushInstVar: (in category 'bytecode
> generation') -----
> > + genPushInstVar: instVarIndex
> > + "See BlueBook page 596"
> > + instVarIndex >= 0 ifTrue:
> > + [instVarIndex < 16 ifTrue:
> > + ["0-15 0000iiii Push Receiver Variable #iiii"
> > + stream nextPut: 0 + instVarIndex.
> > + ^self].
> > + instVarIndex < 64 ifTrue:
> > + ["128 10000000 jjkkkkkk Push (Receiver Variable,
> Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 128;
> > + nextPut: instVarIndex.
> > + ^self]].
> > + self genPushInstVarLong: instVarIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genPushInstVarLong: (in category 'bytecode
> generation') -----
> > + genPushInstVarLong: instVarIndex
> > + "See BlueBook page 596"
> > + "See also MaybeContextInstanceVariableNode"
> > + (instVarIndex >= 0 and: [instVarIndex < 256]) ifTrue:
> > + ["132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push
> Receiver Variable, Push Literal Constant, Push Literal Variable, Store
> Receiver Variable, Store-Pop Receiver Variable, Store Literal
> Variable)[iii] #kkkkkkkk jjjjj"
> > + stream
> > + nextPut: 132;
> > + nextPut: 64;
> > + nextPut: instVarIndex.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 255!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genPushLiteral: (in category 'bytecode
> generation') -----
> > + genPushLiteral: literalIndex
> > + "See BlueBook page 596"
> > + literalIndex < 0 ifTrue:
> > + [^self outOfRangeError: 'index' index: literalIndex range: 0
> to: 255].
> > + literalIndex < 32 ifTrue:
> > + ["32-63 001iiiii Push Literal Constant #iiiii"
> > + stream nextPut: 32 + literalIndex.
> > + ^self].
> > + literalIndex < 64 ifTrue:
> > + ["128 10000000 jjkkkkkk Push (Receiver Variable,
> Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 128;
> > + nextPut: 128 + literalIndex.
> > + ^self].
> > + literalIndex < 256 ifTrue:
> > + ["132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push
> Receiver Variable, Push Literal Constant, Push Literal Variable, Store
> Receiver Variable, Store-Pop Receiver Variable, Store Literal
> Variable)[iii] #kkkkkkkk jjjjj"
> > + stream
> > + nextPut: 132;
> > + nextPut: 96;
> > + nextPut: literalIndex.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genPushLiteralVar: (in category 'bytecode
> generation') -----
> > + genPushLiteralVar: literalIndex
> > + "See BlueBook page 596"
> > + literalIndex < 0 ifTrue:
> > + [^self outOfRangeError: 'index' index: literalIndex range: 0
> to: 255].
> > + literalIndex < 32 ifTrue:
> > + ["64-95 010iiiii Push Literal Variable #iiiii"
> > + stream nextPut: 64 + literalIndex.
> > + ^self].
> > + literalIndex < 64 ifTrue:
> > + ["128 10000000 jjkkkkkk Push (Receiver Variable,
> Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 128;
> > + nextPut: 192 + literalIndex.
> > + ^self].
> > + literalIndex < 256 ifTrue:
> > + ["132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push
> Receiver Variable, Push Literal Constant, Push Literal Variable, Store
> Receiver Variable, Store-Pop Receiver Variable, Store Literal
> Variable)[iii] #kkkkkkkk jjjjj"
> > + stream
> > + nextPut: 132;
> > + nextPut: 128;
> > + nextPut: literalIndex.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genPushReceiver (in category 'bytecode
> generation') -----
> > + genPushReceiver
> > + "See BlueBook page 596"
> > + "112-119 01110iii Push (receiver, true, false, nil, -1, 0, 1,
> 2) [iii]"
> > + stream nextPut: 112!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genPushSpecialLiteral: (in category
> 'bytecode generation') -----
> > + genPushSpecialLiteral: aLiteral
> > + "112-119 01110iii Push (receiver, true, false, nil, -1, 0, 1,
> 2) [iii]"
> > + | index |
> > + index := #(true false nil -1 0 1 2) indexOf: aLiteral.
> > + index = 0 ifTrue:
> > + [^self error: 'push special literal: ', aLiteral printString,
> ' is not one of true false nil -1 0 1 2'].
> > + stream nextPut: index + 112!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genPushTemp: (in category 'bytecode
> generation') -----
> > + genPushTemp: tempIndex
> > + "See BlueBook page 596"
> > + tempIndex < 0 ifTrue:
> > + [^self outOfRangeError: 'index' index: tempIndex range: 0 to:
> 63].
> > + tempIndex < 16 ifTrue:
> > + ["16-31 0001iiii Push Temporary Location #iiii"
> > + stream nextPut: 16 + tempIndex.
> > + ^self].
> > + tempIndex < 64 ifTrue:
> > + ["128 10000000 jjkkkkkk Push (Receiver Variable,
> Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 128;
> > + nextPut: 64 + tempIndex.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genPushTempLong: (in category 'bytecode
> generation') -----
> > + genPushTempLong: tempIndex
> > + "See BlueBook page 596"
> > + (tempIndex >= 0 and: [tempIndex < 64]) ifTrue:
> > + ["128 10000000 jjkkkkkk Push (Receiver Variable,
> Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 128;
> > + nextPut: 64 + tempIndex.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genPushThisContext (in category 'bytecode
> generation') -----
> > + genPushThisContext
> > + "See BlueBook page 596"
> > + "137 10001001 Push Active Context"
> > + stream nextPut: 137!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genReturnReceiver (in category 'bytecode
> generation') -----
> > + genReturnReceiver
> > + "See BlueBook page 596"
> > + "120-123 011110ii Return (receiver, true, false, nil) [ii]
> From Message"
> > + stream nextPut: 120!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genReturnSpecialLiteral: (in category
> 'bytecode generation') -----
> > + genReturnSpecialLiteral: aLiteral
> > + "120-123 011110ii Return (receiver, true, false, nil) [ii]
> From Message"
> > + | index |
> > + index := #(true false nil) indexOf: aLiteral.
> > + index = 0 ifTrue:
> > + [^self error: 'return special literal: ', aLiteral
> printString, ' is not one of true false nil'].
> > + stream nextPut: 120 + index!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genReturnTop (in category 'bytecode
> generation') -----
> > + genReturnTop
> > + "See BlueBook page 596"
> > + "124-125 0111110i Return Stack Top From (Message, Block) [i]"
> > + stream nextPut: 124!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genReturnTopToCaller (in category
> 'bytecode generation') -----
> > + genReturnTopToCaller
> > + "See BlueBook page 596"
> > + "124-125 0111110i Return Stack Top From (Message, Block) [i]"
> > + stream nextPut: 125!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genSend:numArgs: (in category 'bytecode
> generation') -----
> > + genSend: selectorLiteralIndex numArgs: nArgs
> > + "See BlueBook page 596 (with exceptions for 132 & 134)"
> > + nArgs < 0 ifTrue:
> > + [^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31
> "!!!!"].
> > + selectorLiteralIndex < 0 ifTrue:
> > + ["Special selector sends.
> > + 176-191 1011iiii Send Arithmetic Message #iiii
> > + 192-207 1100iiii Send Special Message #iiii"
> > + self flag: #yuck.
> > + (selectorLiteralIndex negated between: 176 and: 207) ifFalse:
> > + [^self outOfRangeError: 'special selector code' index:
> selectorLiteralIndex negated range: 176 to: 207].
> > + stream nextPut: selectorLiteralIndex negated.
> > + ^self].
> > + (selectorLiteralIndex < 16 and: [nArgs < 3]) ifTrue:
> > + [" 208-223 1101iiii Send Literal Selector #iiii With
> No Arguments
> > + 224-239 1110iiii Send Literal Selector #iiii With 1
> Argument
> > + 240-255 1111iiii Send Literal Selector #iiii With 2
> Arguments"
> > + stream nextPut: 208 + (nArgs * 16) + selectorLiteralIndex.
> > + ^self].
> > + (selectorLiteralIndex < 32 and: [nArgs < 8]) ifTrue:
> > + [" 131 10000011 jjjkkkkk Send Literal Selector #kkkkk
> With jjj Arguments"
> > + stream
> > + nextPut: 131;
> > + nextPut: ((nArgs bitShift: 5) + selectorLiteralIndex).
> > + ^self].
> > + (selectorLiteralIndex < 64 and: [nArgs < 4]) ifTrue:
> > + ["In Squeak V3
> > + 134 10000110 jjjjjjjj kkkkkkkk Send Literal Selector
> #kkkkkkkk To Superclass With jjjjjjjj Arguments
> > + is replaced by
> > + 134 10000110 jjkkkkkk Send Literal Selector #kkkkkk
> With jj Arguments"
> > + stream
> > + nextPut: 134;
> > + nextPut: ((nArgs bitShift: 6) + selectorLiteralIndex).
> > + ^self].
> > + (selectorLiteralIndex < 256 and: [nArgs < 32]) ifTrue:
> > + ["In Squeak V3
> > + 132 10000100 jjjjjjjj kkkkkkkk Send Literal Selector
> #kkkkkkkk With jjjjjjjj Arguments
> > + is replaced by
> > + 132 10000100 ooojjjjj kkkkkkkk
> > + ooo = 0 => Send Literal Selector #kkkkkkkk With jjjjj
> Arguments
> > + ooo = 1 => Send Literal Selector #kkkkkkkk To
> Superclass With jjjjj Arguments"
> > + stream
> > + nextPut: 132;
> > + nextPut: nArgs;
> > + nextPut: selectorLiteralIndex.
> > + ^self].
> > + nArgs >= 32 ifTrue:
> > + [^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31].
> > + selectorLiteralIndex >= 256 ifTrue:
> > + [^self outOfRangeError: 'selector literal index' index:
> selectorLiteralIndex range: 0 to: 255]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genSendSpecial:numArgs: (in category
> 'bytecode generation') -----
> > + genSendSpecial: specialSelectorIndex numArgs: nArgs
> > + "See BlueBook page 596"
> > + self assert: (specialSelectorIndex between: 1 and: Smalltalk
> specialSelectorSize).
> > + self assert: nArgs = (Smalltalk specialNargsAt:
> specialSelectorIndex).
> > + "Special selector sends.
> > + 176-191 1011iiii Send Arithmetic Message #iiii
> > + 192-207 1100iiii Send Special Message #iiii"
> > + stream nextPut: specialSelectorIndex + 175!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genSendSuper:numArgs: (in category
> 'bytecode generation') -----
> > + genSendSuper: selectorLiteralIndex numArgs: nArgs
> > + "See BlueBook page 596 (with exceptions for 132 & 134)"
> > + nArgs < 0 ifTrue:
> > + [^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31
> "!!!!"].
> > + selectorLiteralIndex < 0 ifTrue:
> > + [^self outOfRangeError: 'selector literal index' index:
> selectorLiteralIndex range: 0 to: 255].
> > + (selectorLiteralIndex < 32 and: [nArgs < 8]) ifTrue:
> > + [" 133 10000011 jjjkkkkk Send Literal Selector #kkkkk
> To Superclass With jjj Arguments"
> > + stream
> > + nextPut: 133;
> > + nextPut: ((nArgs bitShift: 5) + selectorLiteralIndex).
> > + ^self].
> > + (selectorLiteralIndex < 256 and: [nArgs < 32]) ifTrue:
> > + ["In Squeak V3
> > + 132 10000100 jjjjjjjj kkkkkkkk Send Literal Selector
> #kkkkkkkk With jjjjjjjj Arguments
> > + is replaced by
> > + 132 10000100 ooojjjjj kkkkkkkk
> > + ooo = 0 => Send Literal Selector #kkkkkkkk With jjjjj
> Arguments
> > + ooo = 1 => Send Literal Selector #kkkkkkkk To
> Superclass With jjjjj Arguments"
> > + stream
> > + nextPut: 132;
> > + nextPut: 32 + nArgs;
> > + nextPut: selectorLiteralIndex.
> > + ^self].
> > + nArgs >= 32 ifTrue:
> > + [^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31].
> > + selectorLiteralIndex >= 256 ifTrue:
> > + [^self outOfRangeError: 'selector literal index' index:
> selectorLiteralIndex range: 0 to: 255]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genStoreInstVar: (in category 'bytecode
> generation') -----
> > + genStoreInstVar: instVarIndex
> > + "See BlueBook page 596"
> > + (instVarIndex >= 0 and: [instVarIndex < 64]) ifTrue:
> > + ["129 10000001 jjkkkkkk Store (Receiver Variable,
> Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 129;
> > + nextPut: instVarIndex.
> > + ^self].
> > + self genStoreInstVarLong: instVarIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genStoreInstVarLong: (in category
> 'bytecode generation') -----
> > + genStoreInstVarLong: instVarIndex
> > + "See BlueBook page 596"
> > + "See also MaybeContextInstanceVariableNode"
> > + (instVarIndex >= 0 and: [instVarIndex < 256]) ifTrue:
> > + ["132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push
> Receiver Variable, Push Literal Constant, Push Literal Variable, Store
> Receiver Variable, Store-Pop Receiver Variable, Store Literal
> Variable)[iii] #kkkkkkkk jjjjj"
> > + stream
> > + nextPut: 132;
> > + nextPut: 160;
> > + nextPut: instVarIndex.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 255!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genStoreLiteralVar: (in category 'bytecode
> generation') -----
> > + genStoreLiteralVar: literalIndex
> > + "See BlueBook page 596"
> > + literalIndex < 0 ifTrue:
> > + [^self outOfRangeError: 'index' index: literalIndex range: 0
> to: 255].
> > + literalIndex < 64 ifTrue:
> > + ["129 10000001 jjkkkkkk Store (Receiver Variable,
> Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 129;
> > + nextPut: 192 + literalIndex.
> > + ^self].
> > + literalIndex < 256 ifTrue:
> > + ["132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push
> Receiver Variable, Push Literal Constant, Push Literal Variable, Store
> Receiver Variable, Store-Pop Receiver Variable, Store Literal
> Variable)[iii] #kkkkkkkk jjjjj"
> > + stream
> > + nextPut: 132;
> > + nextPut: 224;
> > + nextPut: literalIndex.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genStorePopInstVar: (in category 'bytecode
> generation') -----
> > + genStorePopInstVar: instVarIndex
> > + "See BlueBook page 596"
> > + instVarIndex >= 0 ifTrue:
> > + [instVarIndex < 8 ifTrue:
> > + ["96-103 01100iii Pop and Store Receiver Variable
> #iii"
> > + stream nextPut: 96 + instVarIndex.
> > + ^self].
> > + instVarIndex < 64 ifTrue:
> > + ["130 10000010 jjkkkkkk Pop and Store (Receiver
> Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 130;
> > + nextPut: instVarIndex.
> > + ^self]].
> > + self genStorePopInstVarLong: instVarIndex!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genStorePopInstVarLong: (in category
> 'bytecode generation') -----
> > + genStorePopInstVarLong: instVarIndex
> > + "See BlueBook page 596"
> > + "See also MaybeContextInstanceVariableNode"
> > + (instVarIndex >= 0 and: [instVarIndex < 256]) ifTrue:
> > + ["132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push
> Receiver Variable, Push Literal Constant, Push Literal Variable, Store
> Receiver Variable, Store-Pop Receiver Variable, Store Literal
> Variable)[iii] #kkkkkkkk jjjjj"
> > + stream
> > + nextPut: 132;
> > + nextPut: 192;
> > + nextPut: instVarIndex.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 255!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genStorePopLiteralVar: (in category
> 'bytecode generation') -----
> > + genStorePopLiteralVar: literalIndex
> > + "See BlueBook page 596"
> > + literalIndex < 0 ifTrue:
> > + [^self outOfRangeError: 'index' index: literalIndex range: 0
> to: 255].
> > + literalIndex < 64 ifTrue:
> > + ["130 10000010 jjkkkkkk Pop and Store (Receiver Variable,
> Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 130;
> > + nextPut: 192 + literalIndex.
> > + ^self].
> > + literalIndex < 256 ifTrue:
> > + ["132 10000100 iiijjjjj kkkkkkkk (Send, Send Super, Push
> Receiver Variable, Push Literal Constant, Push Literal Variable, Store
> Receiver Variable, Store-Pop Receiver Variable, Store Literal
> Variable)[iii] #kkkkkkkk jjjjj"
> > + stream
> > + nextPut: 132;
> > + nextPut: 224;
> > + nextPut: literalIndex.
> > + self genPop.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genStorePopTemp: (in category 'bytecode
> generation') -----
> > + genStorePopTemp: tempIndex
> > + "See BlueBook page 596"
> > + tempIndex < 0 ifTrue:
> > + [^self outOfRangeError: 'index' index: tempIndex range: 0 to:
> 63].
> > + tempIndex < 8 ifTrue:
> > + ["104-111 01101iii Pop and Store Temporary Location #iii"
> > + stream nextPut: 104 + tempIndex.
> > + ^self].
> > + tempIndex < 64 ifTrue:
> > + ["130 10000010 jjkkkkkk Pop and Store (Receiver Variable,
> Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 130;
> > + nextPut: 64 + tempIndex.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>genStoreTemp: (in category 'bytecode
> generation') -----
> > + genStoreTemp: tempIndex
> > + "See BlueBook page 596"
> > + tempIndex < 0 ifTrue:
> > + [^self outOfRangeError: 'index' index: tempIndex range: 0 to:
> 63].
> > + tempIndex < 64 ifTrue:
> > + ["129 10000001 jjkkkkkk Store (Receiver Variable,
> Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
> > + stream
> > + nextPut: 129;
> > + nextPut: 64 + tempIndex.
> > + ^self].
> > + ^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>if:isSpecialLiteralForPush: (in category
> 'special literal encodings') -----
> > + if: code isSpecialLiteralForPush: aBlock
> > + "If code is that of a special literal for push then evaluate aBlock
> with the special literal
> > + The special literals for push are nil true false -1 0 1 & 2 which
> have special encodings
> > + in the blue book bytecode set. Answer whether it was a special
> literal."
> > + ^(code between: LdTrue and: LdNil + 4)
> > + and: [aBlock value: (#(true false nil -1 0 1 2) at: code -
> LdSelf).
> > + true]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>if:isSpecialLiteralForReturn: (in category
> 'special literal encodings') -----
> > + if: code isSpecialLiteralForReturn: aBlock
> > + "If code is that of a special literal for return then evaluate
> aBlock with the special literal.
> > + The special literals for return are nil true false which have
> special encodings
> > + in the blue book bytecode set. Answer whether it was a special
> literal."
> > + ^(code between: LdTrue and: LdNil)
> > + and: [aBlock value: (#(true false nil) at: code - LdSelf).
> > + true]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>isSpecialLiteralForPush: (in category
> 'special literal encodings') -----
> > + isSpecialLiteralForPush: literal
> > + ^literal isInteger
> > + ifFalse:
> > + [false == literal
> > + or: [true == literal
> > + or: [nil == literal]]]
> > + ifTrue: [literal between: -1 and: 2]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>isSpecialLiteralForReturn: (in category
> 'special literal encodings') -----
> > + isSpecialLiteralForReturn: literal
> > + ^literal == false
> > + or: [literal == true
> > + or: [literal == nil]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>maxIndexableLiterals (in category
> 'bytecode generation') -----
> > + maxIndexableLiterals
> > + "This bytecode set can index up to 256 literals."
> > + ^256!
> >
> > Item was added:
> > + ----- Method: EncoderForV3>>supportsFullBlocks (in category 'testing')
> -----
> > + supportsFullBlocks
> > + "Answer if the instruction set supports full closures (closure
> creation from
> > + specfic methods instead of bytecodes embedded in an outer home
> method)."
> > +
> > + ^false!
> >
> > Item was added:
> > + EncoderForV3 subclass: #EncoderForV3PlusClosures
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> > +
> > + !EncoderForV3PlusClosures commentStamp: 'eem 2/29/2016 00:07' prior: 0!
> > + An encoder for the V3 bytecode set augmented with the following
> bytecodes that are part of the full closure implementation.
> > + 138 10001010 jkkkkkkk Push (Array new: kkkkkkk) (j = 0)
> > + or Pop kkkkkkk elements into: (Array
> new: kkkkkkk) (j = 1)
> > + 139 10001011 kkkkkkkk jjjjjjjj Invoke primitive number
> jjjjjjjjkkkkkkkk
> > + 140 10001100 kkkkkkkk jjjjjjjj Push Temp At kkkkkkkk In Temp
> Vector At: jjjjjjjj
> > + 141 10001101 kkkkkkkk jjjjjjjj Store Temp At kkkkkkkk In Temp
> Vector At: jjjjjjjj
> > + 142 10001110 kkkkkkkk jjjjjjjj Pop and Store Temp At kkkkkkkk
> In Temp Vector At: jjjjjjjj
> > + 143 10001111 llllkkkk jjjjjjjj iiiiiiii Push Closure Num
> Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii
> > + This is an exact duplicate of EncoderForLongFormV3PlusClosures.
> > + Could be a trait (or in Newspeak, a Mixin).
> > + For now we impose upon you to synchronise any and all changes between
> these two classes.!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures class>>bytecodeSize: (in
> category 'instruction stream support') -----
> > + bytecodeSize: bytecode
> > + "Answer the number of bytes in the bytecode."
> > + bytecode <= 125 ifTrue:
> > + [^1].
> > + bytecode >= 176 ifTrue:
> > + [^1].
> > + bytecode >= 160 ifTrue: "long jumps"
> > + [^2].
> > + bytecode >= 144 ifTrue: "short jumps"
> > + [^1].
> > + "extensions"
> > + bytecode >= 128 ifTrue:
> > + [^#(2 2 2 2 3 2 2 1 1 1 2 3 3 3 3 4) at: bytecode - 127].
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures class>>callPrimitiveCode (in
> category 'bytecode decoding') -----
> > + callPrimitiveCode
> > + "139 11101111 iiiiiiii jjjjjjjj Call Primitive #iiiiiiii +
> (jjjjjjjj * 256)"
> > + ^139!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures class>>createClosureCode (in
> category 'bytecode decoding') -----
> > + createClosureCode
> > + "Answer the create closure bytecode, if it exists in the encoder's
> bytecode set, or nil if not.
> > + Actually this code is that for a closure whose bytecodes are
> nested within its home method's."
> > + ^143!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures class>>createClosureScanBlock
> (in category 'compiled method support') -----
> > + createClosureScanBlock
> > + "Answer a block argument for InstructionStream>>scanFor: that
> answers true
> > + for block closure creation bytecodes."
> > + ^[ :bc | bc = 143]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures
> class>>interpretNextInstructionFor:in: (in category 'instruction stream
> support') -----
> > + interpretNextInstructionFor: aClient in: anInstructionStream
> > + "Double-dispatch through the encoder to select the correct
> instruction set decoder."
> > + ^anInstructionStream interpretNextV3ClosuresInstructionFor: aClient!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures class>>isStoreAt:in: (in
> category 'instruction stream support') -----
> > + isStoreAt: pc in: method
> > + "Answer whether the bytecode at pc is a store or store-pop."
> > +
> > + | byte |
> > + byte := method at: pc.
> > + ^(byte between: 96 and: 142)
> > + and: [byte <= 111 "96 103
> storeAndPopReceiverVariableBytecode"
> > + "104 111
> storeAndPopTemporaryVariableBytecode"
> > + or: [byte >= 129 "129
> extendedStoreBytecode"
> > + and: [byte <= 130 "130
> extendedStoreAndPopBytecode"
> > + or: [(byte = 132 "132
> doubleExtendedDoAnythingBytecode"
> > + and: [(method at: pc+1) >= 160])
> > + or: [byte = 141 "141
> storeRemoteTempLongBytecode"
> > + or: [byte = 142 "142
> storeAndPopRemoteTempLongBytecode"]]]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures class>>isStorePopAt:in: (in
> category 'instruction stream support') -----
> > + isStorePopAt: pc in: method
> > + "Answer whether the bytecode at pc is a store-pop."
> > +
> > + | byte |
> > + byte := method at: pc.
> > + ^(byte between: 96 and: 111) "96 103
> storeAndPopReceiverVariableBytecode"
> > + "104 111
> storeAndPopTemporaryVariableBytecode"
> > + or: [byte = 130 "130
> extendedStoreAndPopBytecode"
> > + or: [byte = 142]] "142
> storeAndPopRemoteTempLongBytecode"!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures
> class>>isSyntheticStoreAt:in:for: (in category 'instruction stream
> support') -----
> > + isSyntheticStoreAt: pc in: method for: anInstructionStream
> > + "Answer whether the bytecode at pc is a store or store-pop of an
> indirect temp vector,
> > + which implement mutable closed-over variables in the the closure
> implementation.
> > + Stores into temp vectors are not real stores. N.B.
> pcPreviousTo:in:for: is slow, so filter
> > + out any preceding bytecodes other than what looks like a
> pushNewArrayCode. But the
> > + pcPreviousTo:in:for: is still necessary, since the presence of a
> pcPreviousTo:in:for: in the
> > + right place is potentially ambiguous, possibly part of a different
> bytecode seqence."
> > +
> > + ^(self isTempStoreAt: pc in: method)
> > + and: [pc - 2 >= method initialPC
> > + and: [(method at: pc - 2) = self pushNewArrayCode
> > + and: [(method at: pc - 1) <= 127
> > + and: [pc - 2 = (self pcPreviousTo: pc in: method for:
> anInstructionStream)]]]]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures class>>pcFollowingBlockAt:in:
> (in category 'bytecode decoding') -----
> > + pcFollowingBlockAt: pc in: method
> > + "Assuming the pc is that of a block creation bytecode, answer the
> pc immediately following the block,
> > + i.e. the next pc after the block creation."
> > + self assert: (method at: pc) = self createClosureCode.
> > + ^(method at: pc + 2) * 256 + (method at: pc + 3) + pc + 4!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures
> class>>pcOfBlockCreationBytecodeForBlockStartingAt:in: (in category
> 'bytecode decoding') -----
> > + pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method
> > + "Answer the pc of the push closure bytecode whose block starts at
> startpc in method.
> > + 143 10001111 llllkkkk jjjjjjjj iiiiiiii Push Closure Num
> Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii"
> > + ^startpc - 4!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures class>>pushClosureBytecodeSize
> (in category 'bytecode decoding') -----
> > + pushClosureBytecodeSize
> > + "Answer the size of the push closure bytecode.
> > + 143 10001111 llllkkkk jjjjjjjj iiiiiiii Push Closure Num
> Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii"
> > + ^4!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures class>>pushNewArrayCode (in
> category 'bytecode decoding') -----
> > + pushNewArrayCode
> > + "138 10001010 jkkkkkkk Push (Array new: kkkkkkk) (j = 0)
> > + or Pop kkkkkkk elements into: (Array
> new: kkkkkkk) (j = 1)"
> > + ^138!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures class>>supportsClosures (in
> category 'compiled method support') -----
> > + supportsClosures
> > + "Answer if the instruction set supports closures (contains
> > + closure creation and indirect temp access bytecodes)."
> > +
> > + ^true!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures>>genCallPrimitive: (in category
> 'bytecode generation') -----
> > + genCallPrimitive: primitiveIndex
> > + "139 11101111 iiiiiiii jjjjjjjj Call Primitive #iiiiiiii +
> (jjjjjjjj * 256)"
> > + (primitiveIndex < 1 or: [primitiveIndex > 65535]) ifTrue:
> > + [self outOfRangeError: 'primitive index' index: primitiveIndex
> range: 1 to: 65535].
> > + stream
> > + nextPut: 139;
> > + nextPut: (primitiveIndex bitAnd: 255);
> > + nextPut: (primitiveIndex bitShift: -8)!
> >
> > Item was added:
> > + ----- Method:
> EncoderForV3PlusClosures>>genPushClosureCopyNumCopiedValues:numArgs:jumpSize:
> (in category 'bytecode generation') -----
> > + genPushClosureCopyNumCopiedValues: numCopied numArgs: numArgs
> jumpSize: jumpSize
> > + "143 10001111 llllkkkk jjjjjjjj iiiiiiii Push Closure Num
> Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii"
> > + (jumpSize < 0 or: [jumpSize > 65535]) ifTrue:
> > + [^self outOfRangeError: 'block size' index: jumpSize range: 0
> to: 65535].
> > + (numCopied < 0 or: [numCopied > 15]) ifTrue:
> > + [^self outOfRangeError: 'num copied' index: numCopied range: 0
> to: 15].
> > + (numArgs < 0 or: [numArgs > 15]) ifTrue:
> > + [^self outOfRangeError: 'num args' index: numArgs range: 0 to:
> 15].
> > + stream
> > + nextPut: 143;
> > + nextPut: numArgs + (numCopied bitShift: 4);
> > + nextPut: (jumpSize bitShift: -8);
> > + nextPut: (jumpSize bitAnd: 16rFF)!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures>>genPushConsArray: (in category
> 'bytecode generation') -----
> > + genPushConsArray: size
> > + (size < 0 or: [size > 127]) ifTrue:
> > + [^self outOfRangeError: 'numElements' index: size range: 0 to:
> 127].
> > + "138 10001010 1kkkkkkk Push (Array new: kkkkkkk)"
> > + stream
> > + nextPut: 138;
> > + nextPut: size + 128!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures>>genPushNewArray: (in category
> 'bytecode generation') -----
> > + genPushNewArray: size
> > + (size < 0 or: [size > 127]) ifTrue:
> > + [^self outOfRangeError: 'numElements' index: size range: 0 to:
> 127].
> > + "138 10001010 0kkkkkkk Pop kkkkkkk into: (Array new: kkkkkkk)"
> > + stream
> > + nextPut: 138;
> > + nextPut: size!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures>>genPushRemoteTemp:inVectorAt:
> (in category 'bytecode generation') -----
> > + genPushRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> > + (tempIndex >= 0 and: [tempIndex < 256
> > + and: [tempVectorIndex >= 0 and: [tempVectorIndex < 256]]]) ifTrue:
> > + ["140 10001100 kkkkkkkk jjjjjjjj Push Temp At kkkkkkkk In
> Temp Vector At: jjjjjjjj"
> > + stream
> > + nextPut: 140;
> > + nextPut: tempIndex;
> > + nextPut: tempVectorIndex.
> > + ^self].
> > + tempIndex >= 256 ifTrue:
> > + [^self outOfRangeError: 'remoteTempIndex' index: tempIndex
> range: 0 to: 255].
> > + tempVectorIndex >= 256 ifTrue:
> > + [^self outOfRangeError: 'tempVectorIndex' index:
> tempVectorIndex range: 0 to: 255]!
> >
> > Item was added:
> > + ----- Method:
> EncoderForV3PlusClosures>>genStorePopRemoteTemp:inVectorAt: (in category
> 'bytecode generation') -----
> > + genStorePopRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> > + "142 10001110 kkkkkkkk jjjjjjjj Pop and Store Temp At
> kkkkkkkk In Temp Vector At: jjjjjjjj"
> > + (tempIndex >= 0 and: [tempIndex < 256
> > + and: [tempVectorIndex >= 0 and: [tempVectorIndex < 256]]]) ifTrue:
> > + [stream
> > + nextPut: 142;
> > + nextPut: tempIndex;
> > + nextPut: tempVectorIndex.
> > + ^self].
> > + tempIndex >= 256 ifTrue:
> > + [^self outOfRangeError: 'remoteTempIndex' index: tempIndex
> range: 0 to: 255].
> > + tempVectorIndex >= 256 ifTrue:
> > + [^self outOfRangeError: 'tempVectorIndex' index:
> tempVectorIndex range: 0 to: 255]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures>>genStoreRemoteTemp:inVectorAt:
> (in category 'bytecode generation') -----
> > + genStoreRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> > + "141 10001101 kkkkkkkk jjjjjjjj Store Temp At kkkkkkkk In
> Temp Vector At: jjjjjjjj"
> > + (tempIndex >= 0 and: [tempIndex < 256
> > + and: [tempVectorIndex >= 0 and: [tempVectorIndex < 256]]]) ifTrue:
> > + [stream
> > + nextPut: 141;
> > + nextPut: tempIndex;
> > + nextPut: tempVectorIndex.
> > + ^self].
> > + tempIndex >= 256 ifTrue:
> > + [^self outOfRangeError: 'remoteTempIndex' index: tempIndex
> range: 0 to: 255].
> > + tempVectorIndex >= 256 ifTrue:
> > + [^self outOfRangeError: 'tempVectorIndex' index:
> tempVectorIndex range: 0 to: 255]!
> >
> > Item was added:
> > + ----- Method: EncoderForV3PlusClosures>>supportsClosureOpcodes (in
> category 'testing') -----
> > + supportsClosureOpcodes
> > + ^true!
> >
> > Item was added:
> > + VariableNode subclass: #FieldNode
> > + instanceVariableNames: 'fieldDef rcvrNode readNode writeNode'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !FieldNode commentStamp: 'eem 5/24/2017 10:26' prior: 0!
> > + FieldNode handles field access in Tweak, e.g. self fieldName := foo =>
> self fieldName: foo.!
> >
> > Item was added:
> > + ----- Method: FieldNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitFieldNode: self!
> >
> > Item was added:
> > + ----- Method: FieldNode>>assignmentCheck:at: (in category 'testing')
> -----
> > + assignmentCheck: encoder at: location
> > + (encoder cantStoreInto: name) ifTrue: [^location].
> > + fieldDef toSet ifNil:[
> > + encoder interactive ifTrue:[^location].
> > + fieldDef := fieldDef shallowCopy assignDefaultSetter.
> > + ].
> > + ^-1!
> >
> > Item was added:
> > + ----- Method: FieldNode>>emitCodeForEffect:encoder: (in category 'code
> generation') -----
> > + emitCodeForEffect: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: FieldNode>>emitCodeForLoad:forValue:encoder: (in
> category 'code generation') -----
> > + emitCodeForLoad: stack forValue: forValue encoder: encoder
> > + rcvrNode emitCodeForValue: stack encoder: encoder.
> > + fieldDef accessKey ifNotNil:
> > + [super emitCodeForValue: stack encoder: encoder]!
> >
> > Item was added:
> > + ----- Method: FieldNode>>emitCodeForStore:encoder: (in category 'code
> generation') -----
> > + emitCodeForStore: stack encoder: encoder
> > + fieldDef accessKey ifNil:[
> > + writeNode emitCode: stack args: 1 encoder: encoder super: false.
> > + ] ifNotNil:[
> > + writeNode emitCode: stack args: 2 encoder: encoder super: false.
> > + ].!
> >
> > Item was added:
> > + ----- Method: FieldNode>>emitCodeForStorePop:encoder: (in category
> 'code generation') -----
> > + emitCodeForStorePop: stack encoder: encoder
> > + self emitCodeForStore: stack encoder: encoder.
> > + encoder genPop.
> > + stack pop: 1.!
> >
> > Item was added:
> > + ----- Method: FieldNode>>emitCodeForValue:encoder: (in category 'code
> generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + fieldDef accessKey ifNil:[
> > + rcvrNode emitCodeForValue: stack encoder: encoder.
> > + readNode emitCode: stack args: 0 encoder: encoder super: false.
> > + ] ifNotNil:[
> > + rcvrNode emitCodeForValue: stack encoder: encoder.
> > + super emitCodeForValue: stack encoder: encoder.
> > + readNode emitCode: stack args: 1 encoder: encoder super: false.
> > + ].!
> >
> > Item was added:
> > + ----- Method: FieldNode>>encodeReceiverOn: (in category 'code
> generation') -----
> > + encodeReceiverOn: encoder
> > + "encode the receiver node"
> > + rcvrNode := encoder encodeVariable: 'self'.!
> >
> > Item was added:
> > + ----- Method: FieldNode>>fieldDef (in category 'accessing') -----
> > + fieldDef
> > + ^fieldDef!
> >
> > Item was added:
> > + ----- Method: FieldNode>>fieldDefinition: (in category
> 'initialize-release') -----
> > + fieldDefinition: fieldDefinition
> > + self name: fieldDefinition name key: fieldDefinition index: nil
> type: LdLitType!
> >
> > Item was added:
> > + ----- Method: FieldNode>>name:key:index:type: (in category
> 'initialize-release') -----
> > + name: varName key: objRef index: i type: type
> > + fieldDef := objRef.
> > + ^super name: varName key: objRef key index: nil type: LdLitType!
> >
> > Item was added:
> > + ----- Method: FieldNode>>resetFromCopy: (in category 'code
> generation') -----
> > + resetFromCopy: aFieldNode
> > + "Reset the state of the recever to match that of the argument.
> > + This is used to reset nodes that may have been repurposed
> > + while generatig the compiled method for a full block."
> > +
> > + self assert: (fieldDef == aFieldNode fieldDef
> > + and: [rcvrNode == (aFieldNode instVarNamed: 'rcvrNode')
> > + and: [readNode == (aFieldNode instVarNamed: 'readNode')
> > + and: [writeNode == (aFieldNode instVarNamed:
> 'writeNode')]]]).
> > + super resetFromCopy: aFieldNode!
> >
> > Item was added:
> > + ----- Method: FieldNode>>sizeCodeForEffect: (in category 'code
> generation') -----
> > + sizeCodeForEffect: encoder
> > + ^0!
> >
> > Item was added:
> > + ----- Method: FieldNode>>sizeCodeForStore: (in category 'code
> generation') -----
> > + sizeCodeForStore: encoder
> > + rcvrNode ifNil:[self encodeReceiverOn: encoder].
> > + fieldDef accessKey ifNil:[
> > + writeNode ifNil:[writeNode := encoder encodeSelector: fieldDef
> toSet].
> > + ^(rcvrNode sizeCodeForValue: encoder) +
> > + (writeNode sizeCode: encoder args: 1 super: false)
> > + ].
> > + writeNode ifNil:[writeNode := encoder encodeSelector: #set:to:].
> > + ^(rcvrNode sizeCodeForValue: encoder) +
> > + (super sizeCodeForValue: encoder) +
> > + (writeNode sizeCode: encoder args: 2 super: false)!
> >
> > Item was added:
> > + ----- Method: FieldNode>>sizeCodeForStorePop: (in category 'code
> generation') -----
> > + sizeCodeForStorePop: encoder
> > + ^(self sizeCodeForStore: encoder) + encoder sizePop!
> >
> > Item was added:
> > + ----- Method: FieldNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + rcvrNode ifNil:[self encodeReceiverOn: encoder].
> > + fieldDef accessKey ifNil:[
> > + readNode ifNil:[readNode := encoder encodeSelector: fieldDef
> toGet].
> > + ^(rcvrNode sizeCodeForValue: encoder) +
> > + (readNode sizeCode: encoder args: 0 super: false)
> > + ].
> > + readNode ifNil:[readNode := encoder encodeSelector: #get:].
> > + ^(rcvrNode sizeCodeForValue: encoder) +
> > + (super sizeCodeForValue: encoder) +
> > + (readNode sizeCode: encoder args: 1 super: false)!
> >
> > Item was added:
> > + ParseNode subclass: #FutureNode
> > + instanceVariableNames: 'receiver originalSelector futureSelector
> futureDelta futureArgs effectNode valueNode'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !FutureNode commentStamp: 'jcg 12/17/2009 02:03' prior: 0!
> > + Compile-time transformation of #future and #future: messages. Use is
> best described through examples:
> > +
> > + receiver future doSomething: arg1 withArgs: arg2.
> > + (receiver future: 2000) doSomethingElse
> > +
> > + The first means to immediately schedule #doSomething:withArgs: for
> asyncronous evaluation. The second means to wait 2000 milliseconds before
> scheduling #doSomethingElse for asynchronous evaluation.
> > +
> > + These are transformed into either #futureDo:at:args: or
> #futureSend:at:args:, depending on whether the result is used. Let's look
> at a few examples.
> > +
> > + [receiver future foo. 2+2] value.
> > + true ifTrue: [^receiver future foo].
> > + arraySize := receiver future getArray wait size.
> > +
> > + In the first case, the result is never used, so the message
> #futureDo:at:args: is generated. In the second case, the result is
> answered from the current method. Since we don't do any cross-method
> analysis, we have to assume that the result is needed for a later
> computation. The result is provided in the form of a Promise, which will
> resolve to a value when the asynchronous evaluation has completed.
> Creating and resolving this Promise is the responsibility of
> #futureSend:at:args:, which is generated instead of #futureDo:at:args: when
> code-analysis indicates that the result of the message might be used. The
> third example is another one where #futureSend:at:args: is generated.
> > +
> > + See the default implementations of #futureDo:at:args: and
> #futureSend:at:args: in Object. Subclasses are free to override the
> default implementations to achieve specific effects. For example, this
> functionality originated in the Croquet class TFarRef. If you have a
> TFarRef to a replicated object, then sending 'aTFarRef future foo' results
> in a message being sent over the network to each replica of the object
> referenced by aTFarRef. We might also use far-refs, for example, to send a
> message to an object in another Hydra object-memory.!
> >
> > Item was added:
> > + ----- Method: FutureNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitFutureNode: self!
> >
> > Item was added:
> > + ----- Method: FutureNode>>analyseTempsWithin:rootNode:assignmentPools:
> (in category 'closure analysis') -----
> > + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode
> "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + { receiver. futureDelta }, (futureArgs ifNil: [#()]) do:
> > + [:node|
> > + node == nil ifFalse:
> > + [node analyseTempsWithin: scopeBlock rootNode: rootNode
> assignmentPools: assignmentPools]]!
> >
> > Item was added:
> > + ----- Method: FutureNode>>emitCodeForBlockValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForBlockValue: stack encoder: encoder
> > + "Generate code for evaluating the last statement in a block."
> > + ^effectNode emitCodeForValue: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: FutureNode>>emitCodeForEffect:encoder: (in category
> 'code generation') -----
> > + emitCodeForEffect: stack encoder: encoder
> > + ^effectNode emitCodeForEffect: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: FutureNode>>emitCodeForValue:encoder: (in category 'code
> generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + ^valueNode emitCodeForValue: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: FutureNode>>futureMessage:arguments:from:sourceRange:
> (in category 'initialize-release') -----
> > + futureMessage: selName arguments: args from: encoder sourceRange:
> range
> > + futureSelector := selName.
> > + futureArgs := args.
> > + ^self!
> >
> > Item was added:
> > + ----- Method: FutureNode>>futureSelector (in category 'accessing')
> -----
> > + futureSelector
> > + ^futureSelector!
> >
> > Item was added:
> > + ----- Method: FutureNode>>isFutureNode (in category 'testing') -----
> > + isFutureNode
> > + ^true!
> >
> > Item was added:
> > + ----- Method: FutureNode>>originalSelector (in category 'accessing')
> -----
> > + originalSelector
> > + ^originalSelector!
> >
> > Item was added:
> > + ----- Method: FutureNode>>receiver (in category 'accessing') -----
> > + receiver
> > + ^receiver!
> >
> > Item was added:
> > + ----- Method:
> FutureNode>>receiver:selector:arguments:precedence:from:sourceRange: (in
> category 'initialize-release') -----
> > + receiver: rcvr selector: selector arguments: args precedence: p from:
> encoder sourceRange: range
> > + receiver := rcvr.
> > + originalSelector := selector.
> > + originalSelector == #future: ifTrue:[futureDelta := args first].
> > + encoder noteSourceRange: range forNode: self.!
> >
> > Item was added:
> > + ----- Method: FutureNode>>sizeCodeForBlockValue: (in category 'code
> generation') -----
> > + sizeCodeForBlockValue: encoder
> > + receiver == NodeSuper ifTrue: [^self error: 'Futures cannot send to
> future'].
> > + (futureArgs isNil or: [futureSelector isNil]) ifTrue:
> > + [^self error: 'Futures must be sent messages'].
> > + encoder sharableLitIndex: originalSelector. "to find its senders"
> > + futureDelta ifNil:[futureDelta := encoder encodeLiteral: 0].
> > + effectNode := MessageNode new
> > + receiver: receiver
> > + selector: #futureDo:at:args:
> > + arguments: (Array
> > + with: (encoder encodeLiteral: futureSelector)
> > + with: futureDelta
> > + with: (BraceNode new elements: futureArgs))
> > + precedence: 3
> > + from: encoder.
> > + ^effectNode sizeCodeForValue: encoder!
> >
> > Item was added:
> > + ----- Method: FutureNode>>sizeCodeForEffect: (in category 'code
> generation') -----
> > + sizeCodeForEffect: encoder
> > + receiver == NodeSuper ifTrue: [^self error: 'Futures cannot send to
> future'].
> > + (futureArgs isNil or: [futureSelector isNil]) ifTrue:
> > + [^self error: 'Futures must be sent messages'].
> > + encoder sharableLitIndex: originalSelector. "to find its senders"
> > + futureDelta ifNil:[futureDelta := encoder encodeLiteral: 0].
> > + effectNode := MessageNode new
> > + receiver: receiver
> > + selector: #futureDo:at:args:
> > + arguments: (Array
> > + with: (encoder encodeLiteral: futureSelector)
> > + with: futureDelta
> > + with: (BraceNode new elements: futureArgs))
> > + precedence: 3
> > + from: encoder.
> > + ^effectNode sizeCodeForEffect: encoder!
> >
> > Item was added:
> > + ----- Method: FutureNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + receiver == NodeSuper ifTrue: [^self error: 'Futures cannot send to
> future'].
> > + (futureArgs isNil or: [futureSelector isNil]) ifTrue:
> > + [^self error: 'Futures must be sent messages'].
> > + encoder sharableLitIndex: originalSelector. "to find its senders"
> > + futureDelta ifNil:[futureDelta := encoder encodeLiteral: 0].
> > + valueNode := MessageNode new
> > + receiver: receiver
> > + selector: #futureSend:at:args:
> > + arguments: (Array
> > + with: (encoder encodeLiteral: futureSelector)
> > + with: futureDelta
> > + with: (BraceNode new elements: futureArgs))
> > + precedence: 3
> > + from: encoder.
> > + ^valueNode sizeCodeForValue: encoder!
> >
> > Item was added:
> > + VariableNode subclass: #InstanceVariableNode
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> >
> > Item was added:
> > + ----- Method: InstanceVariableNode>>accept: (in category 'visiting')
> -----
> > + accept: aVisitor
> > + ^aVisitor visitInstanceVariableNode: self!
> >
> > Item was added:
> > + ----- Method: InstanceVariableNode>>emitCodeForStore:encoder: (in
> category 'code generation') -----
> > + emitCodeForStore: stack encoder: encoder
> > + encoder genStoreInstVar: index!
> >
> > Item was added:
> > + ----- Method: InstanceVariableNode>>emitCodeForStorePop:encoder: (in
> category 'code generation') -----
> > + emitCodeForStorePop: stack encoder: encoder
> > + encoder genStorePopInstVar: index.
> > + stack pop: 1!
> >
> > Item was added:
> > + ----- Method: InstanceVariableNode>>emitCodeForValue:encoder: (in
> category 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + stack push: 1.
> > + ^encoder genPushInstVar: index!
> >
> > Item was added:
> > + ----- Method: InstanceVariableNode>>name:index: (in category
> 'initialize-release') -----
> > + name: varName index: varIndex
> > + ^self name: varName index: varIndex-1 type: LdInstType!
> >
> > Item was added:
> > + ----- Method: InstanceVariableNode>>sizeCodeForStore: (in category
> 'code generation') -----
> > + sizeCodeForStore: encoder
> > + ^encoder sizeStoreInstVar: index!
> >
> > Item was added:
> > + ----- Method: InstanceVariableNode>>sizeCodeForStorePop: (in category
> 'code generation') -----
> > + sizeCodeForStorePop: encoder
> > + ^encoder sizeStorePopInstVar: index!
> >
> > Item was added:
> > + ----- Method: InstanceVariableNode>>sizeCodeForValue: (in category
> 'code generation') -----
> > + sizeCodeForValue: encoder
> > + ^encoder sizePushInstVar: index!
> >
> > Item was added:
> > + SelectorNode subclass: #KeyWordNode
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Syntax'!
> > +
> > + !KeyWordNode commentStamp: '<historical>' prior: 0!
> > + I am a part of a selector. #at:put: is owned by a SelectorNode, and
> #put: within it is owned by a KeyWordNode.!
> >
> > Item was added:
> > + ParseNode subclass: #LeafNode
> > + instanceVariableNames: 'key code index'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !LeafNode commentStamp: '<historical>' prior: 0!
> > + I represent a leaf node of the compiler parse tree. I am abstract.
> > +
> > + Types (defined in class ParseNode):
> > + 1 LdInstType (which uses class VariableNode)
> > + 2 LdTempType (which uses class VariableNode)
> > + 3 LdLitType (which uses class LiteralNode)
> > + 4 LdLitIndType (which uses class VariableNode)
> > + 5 SendType (which uses class SelectorNode).
> > +
> > + Note that Squeak departs slightly from the Blue Book bytecode spec.
> > +
> > + In order to allow access to more than 63 literals and instance
> variables,
> > + bytecode 132 has been redefined as DoubleExtendedDoAnything:
> > + byte2 byte3 Operation
> > + (hi 3 bits) (lo 5 bits)
> > + 0 nargs lit index Send Literal Message
> 0-255
> > + 1 nargs lit index Super-Send Lit Msg
> 0-255
> > + 2 ignored rcvr index Push Receiver
> Variable 0-255
> > + 3 ignored lit index Push Literal
> Constant 0-255
> > + 4 ignored lit index Push Literal
> Variable 0-255
> > + 5 ignored rcvr index Store Receiver
> Variable 0-255
> > + 6 ignored rcvr index Store-pop Receiver
> Variable 0-255
> > + 7 ignored lit index Store Literal
> Variable 0-255
> > +
> > + This has allowed bytecode 134 also to be redefined as a second
> extended send
> > + that can access literals up to 64 for nargs up to 3 without needing
> three bytes.
> > + It is just like 131, except that the extension byte is aallllll
> instead of aaalllll,
> > + where aaa are bits of argument count, and lll are bits of literal
> index.!
> >
> > Item was added:
> > + ----- Method: LeafNode>>analyseTempsWithin:rootNode:assignmentPools:
> (in category 'closure analysis') -----
> > + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode
> "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + "This is a no-op except in TempVariableNode"
> > + ^self!
> >
> > Item was added:
> > + ----- Method: LeafNode>>code (in category 'code generation') -----
> > + code
> > +
> > + ^ code!
> >
> > Item was added:
> > + ----- Method: LeafNode>>code:type: (in category 'private') -----
> > + code: index type: type
> > +
> > + index isNil
> > + ifTrue: [^type negated].
> > + (CodeLimits at: type) > index
> > + ifTrue: [^(CodeBases at: type) + index].
> > + ^type * 256 + index!
> >
> > Item was added:
> > + ----- Method: LeafNode>>emitCodeForEffect:encoder: (in category 'code
> generation') -----
> > + emitCodeForEffect: stack encoder: encoder
> > +
> > + ^self!
> >
> > Item was added:
> > + ----- Method: LeafNode>>emitCodeForLoad:forValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForLoad: stack forValue: forValue encoder: encoder
> > + "Default is to do nothing.
> > + Subclasses may need to override."!
> >
> > Item was added:
> > + ----- Method: LeafNode>>index (in category 'accessing') -----
> > + index
> > + "Answer the index of the receiver, which has various uses depending
> on the class of the receiver."
> > +
> > + ^index!
> >
> > Item was added:
> > + ----- Method: LeafNode>>key (in category 'accessing') -----
> > + key
> > +
> > + ^key!
> >
> > Item was added:
> > + ----- Method: LeafNode>>key:code: (in category 'initialize-release')
> -----
> > + key: object code: byte
> > +
> > + key := object.
> > + code := byte!
> >
> > Item was added:
> > + ----- Method: LeafNode>>key:index:type: (in category
> 'initialize-release') -----
> > + key: object index: i type: type
> > +
> > + key := object.
> > + code := (self code: i type: type).
> > + index := i!
> >
> > Item was added:
> > + ----- Method: LeafNode>>name:key:code: (in category
> 'initialize-release') -----
> > + name: ignored key: object code: byte
> > +
> > + key := object.
> > + code := byte!
> >
> > Item was added:
> > + ----- Method: LeafNode>>reserve: (in category 'code generation') -----
> > + reserve: encoder
> > + "If this is a yet unused literal of type -code, reserve it."
> > +
> > + code < 0 ifTrue: [code := self code: (index := encoder litIndex:
> key) type: 0 - code]!
> >
> > Item was added:
> > + ----- Method: LeafNode>>resetFromCopy: (in category 'code generation')
> -----
> > + resetFromCopy: aLeafNode
> > + "Reset the state of the recever to match that of the argument.
> > + This is used to reset nodes that may have been repurposed
> > + while generatig the compiled method for a full block."
> > +
> > + self assert: key == aLeafNode key.
> > + code := aLeafNode code.
> > + index := aLeafNode index!
> >
> > Item was added:
> > + ----- Method: LeafNode>>sizeCodeForEffect: (in category 'code
> generation') -----
> > + sizeCodeForEffect: encoder
> > +
> > + ^0!
> >
> > Item was added:
> > + ----- Method: LeafNode>>sizeCodeForLoad:forValue: (in category 'code
> generation') -----
> > + sizeCodeForLoad: encoder forValue: forValue
> > + "Default is to do nothing.
> > + Subclasses may need to override."
> > + ^0!
> >
> > Item was added:
> > + ----- Method: LeafNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: LeafNode>>veryDeepFixupWith: (in category 'copying')
> -----
> > + veryDeepFixupWith: deepCopier
> > + "If fields were weakly copied, fix them here. If they were in the
> tree being copied, fix them up, otherwise point to the originals!!!!"
> > +
> > + super veryDeepFixupWith: deepCopier.
> > + key := (deepCopier references at: key ifAbsent: [key]).
> > + !
> >
> > Item was added:
> > + ----- Method: LeafNode>>veryDeepInner: (in category 'copying') -----
> > + veryDeepInner: deepCopier
> > + "Copy all of my instance variables. Some need to be not copied at
> all, but shared. Warning!!!! Every instance variable defined in this
> class must be handled. We must also implement veryDeepFixupWith:. See
> DeepCopier class comment."
> > +
> > + super veryDeepInner: deepCopier.
> > + "key := key. Weakly copied"
> > + code := code veryDeepCopyWith: deepCopier.
> > + index := index veryDeepCopyWith: deepCopier.
> > + !
> >
> > Item was added:
> > + LeafNode subclass: #LiteralNode
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !LiteralNode commentStamp: '<historical>' prior: 0!
> > + I am a parse tree leaf representing a literal string or number.!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitLiteralNode: self!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>emitCodeForValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + stack push: 1.
> > + (encoder isSpecialLiteralForPush: key)
> > + ifTrue: [encoder genPushSpecialLiteral: key]
> > + ifFalse: [encoder genPushLiteral: index]!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>eval (in category 'evaluation') -----
> > + eval
> > + "When everything in me is a constant, I can produce a value. This
> is only used by the Scripting system (TilePadMorph tilesFrom:in:)"
> > +
> > + ^ key!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>isConstantNumber (in category 'testing')
> -----
> > + isConstantNumber
> > + ^ key isNumber!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>isLiteralNode (in category 'testing') -----
> > + isLiteralNode
> > +
> > + ^ true!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>isSpecialConstant (in category 'testing')
> -----
> > + isSpecialConstant
> > + ^ code between: LdTrue and: LdMinus1+3!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>literalValue (in category 'testing') -----
> > + literalValue
> > +
> > + ^key!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>name:key:index:type: (in category
> 'initialize-release') -----
> > + name: literal key: object index: i type: type
> > + "For compatibility with Encoder>>name:key:class:type:set:"
> > + ^self key: object index: i type: type!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>printOn:indent: (in category 'printing')
> -----
> > + printOn: aStream indent: level
> > +
> > + key isVariableBinding ifTrue:
> > + [key key isNil
> > + ifTrue:
> > + [aStream nextPutAll: '###'; nextPutAll: key value
> soleInstance name]
> > + ifFalse:
> > + [aStream nextPutAll: '##'; nextPutAll: key key].
> > + ^self].
> > + key isLiteral ifTrue:
> > + [key printAsLiteralOn: aStream.
> > + ^self].
> > + (key isCompiledCode and: [key isCompiledBlock]) ifTrue:
> > + [key printOn: aStream.
> > + ^self].
> > + key storeOn: aStream!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level
> > +
> > + key isVariableBinding
> > + ifTrue:
> > + [key key isNil
> > + ifTrue:
> > + [aStream nextPutAll: '###'; nextPutAll: key value
> soleInstance name]
> > + ifFalse:
> > + [aStream nextPutAll: '##'; nextPutAll: key key]]
> > + ifFalse:
> > + [key storeOn: aStream]!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>reserve: (in category 'code generation')
> -----
> > + reserve: encoder
> > + "If this is a yet unused literal of type -code, reserve it."
> > +
> > + code < 0 ifTrue:
> > + [index := key isVariableBinding "true if sending value[:] to a
> special binding"
> > + ifTrue: [encoder sharableLitIndex: key]
> > + ifFalse: [encoder litIndex: key].
> > + code := self code: index type: 0 - code]!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>resetForBlockGeneration (in category 'code
> generation') -----
> > + resetForBlockGeneration
> > + "Reset the receiver to an unassigned state such that its index
> > + in the encoder's literalStream is as yet to be determined."
> > + code := LdLitType negated.
> > + index := nil!
> >
> > Item was added:
> > + ----- Method: LiteralNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + self reserve: encoder.
> > + ^(encoder isSpecialLiteralForPush: key)
> > + ifTrue: [encoder sizePushSpecialLiteral: key]
> > + ifFalse: [encoder sizePushLiteral: index]!
> >
> > Item was added:
> > + VariableNode subclass: #LiteralVariableNode
> > + instanceVariableNames: 'readNode writeNode'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>accept: (in category 'visiting')
> -----
> > + accept: aVisitor
> > + ^aVisitor visitLiteralVariableNode: self!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>assignmentCheck:at: (in category
> 'testing') -----
> > + assignmentCheck: encoder at: location
> > + ^(key isVariableBinding and: [key canAssign not])
> > + ifTrue: [location]
> > + ifFalse: [-1]!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>emitCodeForLoad:forValue:encoder:
> (in category 'code generation') -----
> > + emitCodeForLoad: stack forValue: forValue encoder: encoder
> > + "If a normal literal variable (not sending value:), do nothing.
> > + If for value (e.g. v := Binding := expr) do nothing; the work will
> be done in emitCodeForStore:encoder:.
> > + If not for value then indeed load. The rest of the work will be
> done in emitCodeForStorePop:encoder:."
> > + (writeNode isNil or: [forValue]) ifTrue: [^self].
> > + encoder genPushLiteral: index.
> > + stack push: 1!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>emitCodeForStore:encoder: (in
> category 'code generation') -----
> > + emitCodeForStore: stack encoder: encoder
> > + | exprOffset |
> > + writeNode ifNil: [^encoder genStoreLiteralVar: index].
> > + "On entry the stack has only the expression. Push the binding,
> > + duplicate the expression, send #value: and pop.
> > + The various value: methods on Association ReadOnlyVariableBinding
> > + etc _do not_ return the value assigned; they return the receiver.
> If they
> > + did we could generate much simpler code, e.g.
> > + encoder genPushLiteral: index.
> > + stack push: 1.
> > + writeNode emitCode: stack args: 1 encoder: encoder super: false"
> > + exprOffset := stack position - 1.
> > + encoder genPushLiteral: index.
> > + stack push: 1.
> > + encoder genPushTempLong: exprOffset.
> > + stack push: 1.
> > + writeNode
> > + emitCode: stack
> > + args: 1
> > + encoder: encoder
> > + super: false.
> > + stack pop: 1.
> > + encoder genPop!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>emitCodeForStorePop:encoder: (in
> category 'code generation') -----
> > + emitCodeForStorePop: stack encoder: encoder
> > + writeNode ifNil:
> > + [stack pop: 1.
> > + ^encoder genStorePopLiteralVar: index].
> > + writeNode
> > + emitCode: stack
> > + args: 1
> > + encoder: encoder
> > + super: false.
> > + stack pop: 1.
> > + encoder genPop!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>emitCodeForValue:encoder: (in
> category 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + ^readNode
> > + ifNil: [stack push: 1.
> > + encoder genPushLiteralVar: index]
> > + ifNotNil: [readNode emitCodeForValue: stack encoder: encoder]!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>resetForBlockGeneration (in
> category 'code generation') -----
> > + resetForBlockGeneration
> > + "Reset the receiver to an unassigned state such that its index
> > + in the encoder's literalStream is as yet to be determined."
> > + code := LdLitIndType negated.
> > + index := nil!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>resetFromCopy: (in category 'code
> generation') -----
> > + resetFromCopy: aLiteralVariableNode
> > + "Reset the state of the recever to match that of the argument.
> > + This is used to reset nodes that may have been repurposed
> > + while generatig the compiled method for a full block."
> > +
> > + self assert: (readNode == (aLiteralVariableNode instVarNamed:
> 'readNode')
> > + and: [writeNode == (aLiteralVariableNode instVarNamed:
> 'writeNode')]).
> > + super resetFromCopy: aLiteralVariableNode!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>sizeCodeForLoad:forValue: (in
> category 'code generation') -----
> > + sizeCodeForLoad: encoder forValue: forValue
> > + self reserve: encoder.
> > + ^(key isVariableBinding and: [key isSpecialWriteBinding and:
> [forValue not]])
> > + ifTrue: [encoder sizePushLiteral: index]
> > + ifFalse: [0]!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>sizeCodeForStore: (in category
> 'code generation') -----
> > + sizeCodeForStore: encoder
> > + self reserve: encoder.
> > + (key isVariableBinding and: [key isSpecialWriteBinding]) ifFalse:
> > + [^encoder sizeStoreLiteralVar: index].
> > + writeNode := encoder encodeSelector: #value:.
> > + "On entry the stack has only the expression. Push the binding,
> > + duplicate the expression, send #value: and pop."
> > + ^(encoder sizePushLiteral: index)
> > + + (encoder sizePushTempLong: 0) "we don't know yet, hence long,
> sigh..."
> > + + (writeNode sizeCode: encoder args: 1 super: false)
> > + + encoder sizePop!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>sizeCodeForStorePop: (in category
> 'code generation') -----
> > + sizeCodeForStorePop: encoder
> > + self reserve: encoder.
> > + ^(key isVariableBinding and: [key isSpecialWriteBinding])
> > + ifTrue: [ writeNode := encoder encodeSelector: #value:.
> > + ^ (writeNode sizeCode: encoder args: 1 super: false)
> > + + encoder sizePop]
> > + ifFalse: [encoder sizeStorePopLiteralVar: index]!
> >
> > Item was added:
> > + ----- Method: LiteralVariableNode>>sizeCodeForValue: (in category
> 'code generation') -----
> > + sizeCodeForValue: encoder
> > + self reserve: encoder.
> > + (key isVariableBinding and: [key isSpecialReadBinding])
> > + ifFalse:
> > + [^encoder sizePushLiteralVar: index].
> > + readNode := MessageNode new
> > + receiver: (encoder encodeLiteral: key)
> > + selector: (encoder encodeSelector: #value)
> > + arguments: #()
> > + precedence: #value precedence.
> > + ^readNode sizeCodeForValue: encoder!
> >
> > Item was added:
> > + InstanceVariableNode subclass: #MaybeContextInstanceVariableNode
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !MaybeContextInstanceVariableNode commentStamp: '<historical>' prior:
> 0!
> > + This class conspires to arrange that inst var access for contexts is
> done exclusively using the long-form instance variabl;e access bytecodes.
> See InstructionStream class>>variablesAndOffsetsDo:.
> > +
> > + A virtual machine can benefit in performance by organizing method and
> block activations using a more conventional stack organization than by
> using first-class activation records (contexts). But such a virtual
> machine is also cabable of hiding the stack and making it appear as if
> contexts are still used. This means the system has better performance but
> still has all the benefits of first-class activation records. To pull this
> off the VM needs to intercept any and all accesses to context objects so
> that it can make contexts function as proxy objects for stack frames.
> > +
> > + Without help from the image such a virtual machine based on an
> interpreter would have to perform an expensive check on all instance
> variable accesses to determine if the instance variable was that of a
> context serving as a proxy for a stack frame. A simple hack is to take
> advantage of the short and long forms of instance variable access
> bytecodes. The BlueBook instruction set (and likely any bytecode set
> evolved from it) has short form bytecodes for fetching and storing the
> first few bytecodes (BlueBook fetch first 16, store first 8). Contexts
> typically have at most 6 instance variables. If we arrange to use the
> long-form bytecodes for all context inst var accesses then we only have to
> check for context inst var access in long-form bytecodes, and then only if
> the index is within the context inst var range. This effectively makes the
> check free because on modern processors checking an index fetched from
> memory into a register against a constant costs far less than the memry rea
> > d to fetch the index.!
> >
> > Item was added:
> > + ----- Method: MaybeContextInstanceVariableNode>>code (in category
> 'accessing') -----
> > + code
> > + "Answer a bogus code to avoid creating quick methods.
> > + See MethodNode>>generate:ifQuick:"
> > + ^LoadLong!
> >
> > Item was added:
> > + ----- Method:
> MaybeContextInstanceVariableNode>>emitCodeForStore:encoder: (in category
> 'code generation') -----
> > + emitCodeForStore: stack encoder: encoder
> > + encoder genStoreInstVarLong: index!
> >
> > Item was added:
> > + ----- Method:
> MaybeContextInstanceVariableNode>>emitCodeForStorePop:encoder: (in category
> 'code generation') -----
> > + emitCodeForStorePop: stack encoder: encoder
> > + encoder genStorePopInstVarLong: index.
> > + stack pop: 1!
> >
> > Item was added:
> > + ----- Method:
> MaybeContextInstanceVariableNode>>emitCodeForValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + stack push: 1.
> > + ^encoder genPushInstVarLong: index!
> >
> > Item was added:
> > + ----- Method: MaybeContextInstanceVariableNode>>sizeCodeForStore: (in
> category 'code generation') -----
> > + sizeCodeForStore: encoder
> > + ^encoder sizeStoreInstVarLong: index!
> >
> > Item was added:
> > + ----- Method: MaybeContextInstanceVariableNode>>sizeCodeForStorePop:
> (in category 'code generation') -----
> > + sizeCodeForStorePop: encoder
> > + ^encoder sizeStorePopInstVarLong: index!
> >
> > Item was added:
> > + ----- Method: MaybeContextInstanceVariableNode>>sizeCodeForValue: (in
> category 'code generation') -----
> > + sizeCodeForValue: encoder
> > + ^encoder sizePushInstVarLong: index!
> >
> > Item was added:
> > + MessageNode subclass: #MessageAsTempNode
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !MessageAsTempNode commentStamp: '<historical>' prior: 0!
> > + This node represents accesses to temporary variables for do-its in the
> debugger. Since they execute in another context, they must send a message
> to the original context to access the value of the temporary variable in
> that context.!
> >
> > Item was added:
> > + ----- Method: MessageAsTempNode>>asStorableNode: (in category 'access
> to remote temps') -----
> > + asStorableNode: encoder
> > + "This node is a message masquerading as a temporary variable.
> > + It currently has the form {homeContext tempAt: offset}.
> > + We need to generate code for {expr storeAt: offset inTempFrame:
> homeContext},
> > + where the expr, the block argument, is already on the stack.
> > + This, in turn will get turned into {homeContext tempAt: offset put:
> expr}
> > + at runtime if nobody disturbs storeAt:inTempFrame: in Object (not
> clean)"
> > + ^ MessageAsTempNode new
> > + receiver: nil "suppress code generation for reciever already
> on stack"
> > + selector: #storeAt:inTempFrame:
> > + arguments: (arguments copyWith: receiver)
> > + precedence: precedence
> > + from: encoder!
> >
> > Item was added:
> > + ----- Method: MessageAsTempNode>>code (in category 'access to remote
> temps') -----
> > + code
> > + "Allow synthetic temp nodes to be sorted by code"
> > + ^ arguments first literalValue!
> >
> > Item was added:
> > + ----- Method: MessageAsTempNode>>emitCodeForStorePop:encoder: (in
> category 'code generation') -----
> > + emitCodeForStorePop: stack encoder: encoder
> > + "This node has the form {expr storeAt: offset inTempFrame:
> homeContext},
> > + where the expr, the block argument, is already on the stack."
> > + ^self emitCodeForEffect: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: MessageAsTempNode>>sizeCodeForStorePop: (in category
> 'code generation') -----
> > + sizeCodeForStorePop: encoder
> > + "This node has the form {expr storeAt: offset inTempFrame:
> homeContext},
> > + where the expr, the block argument, is already on the stack."
> > + ^self sizeCodeForEffect: encoder!
> >
> > Item was added:
> > + ----- Method: MessageAsTempNode>>store:from: (in category 'access to
> remote temps') -----
> > + store: expr from: encoder
> > + "ctxt tempAt: n -> ctxt tempAt: n put: expr (see Assignment).
> > + For assigning into temps of a context being debugged."
> > +
> > + selector key ~= #namedTempAt:
> > + ifTrue: [^self error: 'cant transform this message'].
> > + ^ MessageAsTempNode new
> > + receiver: receiver
> > + selector: #namedTempAt:put:
> > + arguments: (arguments copyWith: expr)
> > + precedence: precedence
> > + from: encoder!
> >
> > Item was added:
> > + ParseNode subclass: #MessageNode
> > + instanceVariableNames: 'receiver selector precedence special
> arguments sizes equalNode caseErrorNode originalReceiver originalSelector
> originalArguments'
> > + classVariableNames: 'MacroEmitters MacroPrinters MacroSelectors
> MacroSizers MacroTransformers StdTypers ThenFlag'
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !MessageNode commentStamp: '<historical>' prior: 0!
> > + I represent a receiver and its message.
> > +
> > + Precedence codes:
> > + 1 unary
> > + 2 binary
> > + 3 keyword
> > + 4 other
> > +
> > + If special>0, I compile special code in-line instead of sending
> messages with literal methods as remotely copied contexts.!
> >
> > Item was added:
> > + ----- Method: MessageNode class>>initialize (in category 'class
> initialization') -----
> > + initialize
> > + "MessageNode initialize"
> > + MacroSelectors :=
> > + #( ifTrue: ifFalse: ifTrue:ifFalse: ifFalse:ifTrue:
> > + and: or:
> > + whileFalse: whileTrue: whileFalse whileTrue
> > + to:do: to:by:do:
> > + caseOf: caseOf:otherwise:
> > + ifNil: ifNotNil: ifNil:ifNotNil: ifNotNil:ifNil:
> > + repeat ).
> > + MacroTransformers :=
> > + #( transformIfTrue: transformIfFalse:
> transformIfTrueIfFalse: transformIfFalseIfTrue:
> > + transformAnd: transformOr:
> > + transformWhile: transformWhile: transformWhile:
> transformWhile:
> > + transformToDo: transformToDo:
> > + transformCase: transformCase:
> > + transformIfNil: transformIfNil: transformIfNilIfNotNil:
> transformIfNotNilIfNil:
> > + transformRepeat: ).
> > + MacroEmitters :=
> > + #( emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
> > + emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
> > + emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
> > + emitCodeForWhile:encoder:value:
> emitCodeForWhile:encoder:value:
> > + emitCodeForWhile:encoder:value:
> emitCodeForWhile:encoder:value:
> > + emitCodeForToDo:encoder:value:
> emitCodeForToDo:encoder:value:
> > + emitCodeForCase:encoder:value:
> emitCodeForCase:encoder:value:
> > + emitCodeForIfNil:encoder:value:
> emitCodeForIfNil:encoder:value:
> > + emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
> > + emitCodeForRepeat:encoder:value:).
> > + MacroSizers :=
> > + #( sizeCodeForIf:value: sizeCodeForIf:value:
> sizeCodeForIf:value: sizeCodeForIf:value:
> > + sizeCodeForIf:value: sizeCodeForIf:value:
> > + sizeCodeForWhile:value: sizeCodeForWhile:value:
> sizeCodeForWhile:value: sizeCodeForWhile:value:
> > + sizeCodeForToDo:value: sizeCodeForToDo:value:
> > + sizeCodeForCase:value: sizeCodeForCase:value:
> > + sizeCodeForIfNil:value: sizeCodeForIfNil:value:
> sizeCodeForIf:value: sizeCodeForIf:value:
> > + sizeCodeForRepeat:value:).
> > + MacroPrinters :=
> > + #( printIfOn:indent: printIfOn:indent: printIfOn:indent:
> printIfOn:indent:
> > + printIfOn:indent: printIfOn:indent:
> > + printWhileOn:indent: printWhileOn:indent:
> printWhileOn:indent: printWhileOn:indent:
> > + printToDoOn:indent: printToDoOn:indent:
> > + printCaseOn:indent: printCaseOn:indent:
> > + printIfNil:indent: printIfNil:indent:
> printIfNilNotNil:indent: printIfNilNotNil:indent:
> > + printRepeatOn:indent:)!
> >
> > Item was added:
> > + ----- Method: MessageNode class>>isMacroEmitter: (in category
> 'browsing support') -----
> > + isMacroEmitter: aLiteral
> > + "Let our macro methods be found when browsing senders"
> > + ^aLiteral isSymbol
> > + and: [MacroEmitters includes: aLiteral]!
> >
> > Item was added:
> > + ----- Method: MessageNode class>>isMacroPrinter: (in category
> 'browsing support') -----
> > + isMacroPrinter: aLiteral
> > + "Let our macro methods be found when browsing senders"
> > + ^aLiteral isSymbol
> > + and: [MacroPrinters includes: aLiteral]
> > + !
> >
> > Item was added:
> > + ----- Method: MessageNode class>>isMacroSizer: (in category 'browsing
> support') -----
> > + isMacroSizer: aLiteral
> > + "Let our macro methods be found when browsing senders"
> > + ^aLiteral isSymbol
> > + and: [MacroSizers includes: aLiteral]
> > + !
> >
> > Item was added:
> > + ----- Method: MessageNode class>>isMacroTransformer: (in category
> 'browsing support') -----
> > + isMacroTransformer: aLiteral
> > + "Let our macro methods be found when browsing senders"
> > + ^aLiteral isSymbol
> > + and: [MacroTransformers includes: aLiteral]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitMessageNode: self!
> >
> > Item was added:
> > + ----- Method:
> MessageNode>>analyseTempsWithin:rootNode:assignmentPools: (in category
> 'closure analysis') -----
> > + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode
> "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + "Assignments within optimized loops are tricky. Because a loop
> repeats a
> > + write to a temporary in an optimized loop effectively occurs after
> the loop.
> > + To handle this collect the set of temps assigned to in optimized
> loops and
> > + add extra writes after traversing the optimized loop constituents."
> > + | writtenToTemps |
> > + self isOptimizedLoop ifTrue:
> > + [{ receiver }, arguments do:
> > + [:node|
> > + (node notNil and: [node isBlockNode and: [node optimized]])
> ifTrue:
> > + [assignmentPools at: node put: Set new]]].
> > + "receiver is nil in cascades"
> > + receiver == nil ifFalse:
> > + [receiver analyseTempsWithin: scopeBlock rootNode: rootNode
> assignmentPools: assignmentPools].
> > + arguments do:
> > + [:node|
> > + node == nil ifFalse: "last argument of optimized to:do: can be
> nil"
> > + [node analyseTempsWithin: scopeBlock rootNode: rootNode
> assignmentPools: assignmentPools]].
> > + "Add assignments representing subsequent iterations
> > + and redo the closure analysis for the written-to temps."
> > + self isOptimizedLoop ifTrue:
> > + [writtenToTemps := Set new.
> > + { receiver }, arguments do:
> > + [:node|
> > + (node notNil and: [node isBlockNode and: [node optimized]])
> ifTrue:
> > + [(assignmentPools removeKey: node) do:
> > + [:temp|
> > + temp isBlockArg ifFalse: "ignore added assignments
> to to:do: loop args"
> > + [writtenToTemps add: temp.
> > + temp addWriteWithin: node at: rootNode
> locationCounter]]]].
> > + writtenToTemps isEmpty ifFalse:
> > + [(writtenToTemps sorted: ParseNode tempSortBlock) do:
> > + [:each| each analyseClosure: rootNode].
> > + (writtenToTemps collect: [:each| each definingScope]) do:
> > + [:blockNode|
> > + blockNode
> ifHasRemoteTempNodeEnsureInitializationStatementExists: rootNode]]]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>arguments (in category 'equation
> translation') -----
> > + arguments
> > + ^arguments!
> >
> > Item was added:
> > + ----- Method: MessageNode>>arguments: (in category 'equation
> translation') -----
> > + arguments: list
> > + arguments := list!
> >
> > Item was added:
> > + ----- Method: MessageNode>>argumentsInEvaluationOrder (in category
> 'visiting') -----
> > + argumentsInEvaluationOrder
> > + "Answer the receiver's arguments in evaluation order.
> > + If the receiver is a transformed to:do: node this will undo the
> misordering done by the transformation."
> > + ^(special > 0
> > + and: [(MacroTransformers at: special) == #transformToDo:
> > + and: [arguments size >= 7]])
> > + "arguments are in a weird order and may be nil in a transformed
> to:do: loop. sigh...
> > + c.f. emitCodeForToDo:encoder:value:"
> > + ifTrue:
> > + [(arguments at: 7) "limitInit"
> > + ifNil: [{ arguments at: 4. "initStmt"
> > + arguments at: 5. "test"
> > + arguments at: 3. "block"
> > + arguments at: 6 "incStmt" }]
> > + ifNotNil: [:limitInit|
> > + { limitInit.
> > + arguments at: 4. "initStmt"
> > + arguments at: 5. "test"
> > + arguments at: 3. "block"
> > + arguments at: 6 "incStmt" }]]
> > + ifFalse:
> > + [arguments]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>asMorphicCaseOn:indent: (in category
> 'printing') -----
> > + asMorphicCaseOn: parent indent: ignored
> > + "receiver caseOf: {[key]->[value]. ...} otherwise: [otherwise]"
> > +
> > + | braceNode otherwise |
> > +
> > + braceNode := arguments first.
> > + otherwise := arguments last.
> > + ((arguments size = 1) or: [otherwise isJustCaseError]) ifTrue: [
> > + self morphFromKeywords: #caseOf: arguments: {braceNode} on:
> parent indent: nil.
> > + ^parent
> > + ].
> > + self morphFromKeywords: #caseOf:otherwise: arguments: arguments on:
> parent indent: nil.
> > + ^parent
> > + !
> >
> > Item was added:
> > + ----- Method: MessageNode>>canCascade (in category 'testing') -----
> > + canCascade
> > +
> > + ^receiver ~~ NodeSuper!
> >
> > Item was added:
> > + ----- Method: MessageNode>>cascadeReceiver (in category 'cascading')
> -----
> > + cascadeReceiver
> > + "Nil out rcvr (to indicate cascade) and return what it had been."
> > +
> > + | rcvr |
> > + rcvr := receiver.
> > + receiver := nil.
> > + ^rcvr!
> >
> > Item was added:
> > + ----- Method: MessageNode>>checkBlock:as:from:maxArgs: (in category
> 'private') -----
> > + checkBlock: node as: nodeName from: encoder maxArgs: maxArgs
> > + "Answer true if node is a BlockNode with at most maxArgs arguments.
> > + This check is required in order to inline some special messages.
> > + Notify some undue usage of these special messages."
> > +
> > + node isBlockNode ifFalse: [ ^false ].
> > + node numberOfArguments <= maxArgs ifTrue: [ ^true ].
> > + ^encoder notify: '<- ', nodeName , ' of ' , (MacroSelectors at:
> special) , ' has too many arguments'!
> >
> > Item was added:
> > + ----- Method: MessageNode>>emitCodeForCase:encoder:value: (in category
> 'code generation') -----
> > + emitCodeForCase: stack encoder: encoder value: forValue
> > +
> > + | braceNode sizeStream allReturn |
> > + forValue ifFalse:
> > + [^super emitCodeForEffect: stack encoder: encoder].
> > + braceNode := arguments first.
> > + sizeStream := ReadStream on: sizes.
> > + receiver emitCodeForValue: stack encoder: encoder.
> > + "There must be at least one branch around the otherwise/caseError
> > + so the decompiler can identify the end of the
> otherwise/caseError."
> > + allReturn := true. "assume every case ends with a return"
> > + braceNode casesForwardDo:
> > + [:keyNode :valueNode :last |
> > + | thenSize elseSize dropReceiver |
> > + dropReceiver := last and: [arguments size >= 2].
> > + thenSize := sizeStream next.
> > + elseSize := sizeStream next.
> > + dropReceiver ifFalse: [encoder genDup. stack push: 1].
> > + keyNode emitCodeForEvaluatedValue: stack encoder: encoder.
> > + keyNode pc: encoder nextPC.
> > + equalNode emitCode: stack args: 1 encoder: encoder.
> > + self emitCodeForBranchOn: false dist: thenSize pop: stack
> encoder: encoder.
> > + dropReceiver ifFalse: [encoder genPop. stack pop: 1].
> > + valueNode emitCodeForEvaluatedValue: stack encoder: encoder.
> > + dropReceiver ifTrue: [stack pop: 1].
> > + valueNode returns ifFalse:
> > + [self emitCodeForJump: elseSize encoder: encoder.
> > + allReturn := false].
> > + (last and: [allReturn]) ifTrue:
> > + [self emitCodeForJump: elseSize encoder: encoder]].
> > + arguments size = 2
> > + ifTrue:
> > + [arguments last emitCodeForEvaluatedValue: stack encoder:
> encoder] "otherwise: [...]"
> > + ifFalse:
> > + ["the receiver of caseOf: has been previously dup, just
> send"
> > + caseErrorNode emitCode: stack args: 0 encoder: encoder]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>emitCodeForEffect:encoder: (in category
> 'code generation') -----
> > + emitCodeForEffect: stack encoder: encoder
> > + "For #ifTrue:ifFalse: and #whileTrue: / #whileFalse: style
> messages, the pc is set to the jump instruction, so that mustBeBoolean
> exceptions can be shown correctly."
> > + <hasLiteralTest: #isMacroEmitter:>
> > + special > 0
> > + ifTrue:
> > + [pc := 0.
> > + self perform: (MacroEmitters at: special) with: stack with:
> encoder with: false]
> > + ifFalse:
> > + [super emitCodeForEffect: stack encoder: encoder]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>emitCodeForIf:encoder:value: (in category
> 'code generation') -----
> > + emitCodeForIf: stack encoder: encoder value: forValue
> > + | thenExpr thenSize elseExpr elseSize |
> > + thenSize := sizes at: 1.
> > + elseSize := sizes at: 2.
> > + thenExpr := arguments at: 1.
> > + elseExpr := arguments at: 2.
> > + receiver emitCodeForValue: stack encoder: encoder.
> > + pc := encoder nextPC.
> > + elseSize * thenSize > 0
> > + ifTrue: "Code for two-armed"
> > + [self emitCodeForBranchOn: false dist: thenSize pop: stack
> encoder: encoder.
> > + thenExpr emitCodeForEvaluatedValue: stack encoder: encoder.
> > + stack pop: 1. "then and else alternate; they don't
> accumulate"
> > + thenExpr returns ifFalse: "Elide jump over else after a
> return"
> > + [self emitCodeForJump: elseSize encoder: encoder].
> > + elseExpr emitCodeForEvaluatedValue: stack encoder: encoder.
> > + forValue ifFalse: "Two-armed IFs forEffect share a single
> pop - except if both return"
> > + [(arguments allSatisfy: #returns) ifFalse: [encoder
> genPop].
> > + stack pop: 1]]
> > + ifFalse: "One arm is empty here (this can only ever be for
> effect)"
> > + [thenSize > 0
> > + ifTrue:
> > + [self emitCodeForBranchOn: false dist: thenSize
> pop: stack encoder: encoder.
> > + thenExpr emitCodeForEvaluatedEffect: stack encoder:
> encoder]
> > + ifFalse:
> > + [self emitCodeForBranchOn: true dist: elseSize pop:
> stack encoder: encoder.
> > + elseExpr emitCodeForEvaluatedEffect: stack encoder:
> encoder]]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>emitCodeForIfNil:encoder:value: (in
> category 'code generation') -----
> > + emitCodeForIfNil: stack encoder: encoder value: forValue
> > +
> > + | theNode theSize ifNotNilSelector |
> > + theNode := arguments first.
> > + theSize := sizes at: 1.
> > + ifNotNilSelector := #ifNotNil:.
> > + receiver emitCodeForValue: stack encoder: encoder.
> > + forValue ifTrue: [encoder genDup. stack push: 1].
> > + encoder genPushSpecialLiteral: nil. stack push: 1.
> > + equalNode emitCode: stack args: 1 encoder: encoder.
> > + pc := encoder nextPC.
> > + self
> > + emitCodeForBranchOn: (selector key == ifNotNilSelector)
> > + dist: theSize
> > + pop: stack
> > + encoder: encoder.
> > + forValue
> > + ifTrue:
> > + [encoder genPop. stack pop: 1.
> > + theNode emitCodeForEvaluatedValue: stack encoder: encoder]
>
> > + ifFalse: [theNode emitCodeForEvaluatedEffect: stack encoder:
> encoder]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>emitCodeForRepeat:encoder:value: (in
> category 'code generation') -----
> > + emitCodeForRepeat: stack encoder: encoder value: forValue
> > + " L1: ... Jmp(L1)"
> > + | loopSize |
> > + loopSize := sizes at: 1.
> > + receiver emitCodeForEvaluatedEffect: stack encoder: encoder.
> > + self emitCodeForJump: 0 - loopSize encoder: encoder.
> > + forValue ifTrue: [encoder genPushSpecialLiteral: nil. stack push:
> 1]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>emitCodeForToDo:encoder:value: (in category
> 'code generation') -----
> > + emitCodeForToDo: stack encoder: encoder value: forValue
> > + " var := rcvr. L1: [var <= arg1] Bfp(L2) [block body. var := var +
> inc] Jmp(L1) L2: "
> > + | loopSize initStmt limitInit test block incStmt blockSize |
> > + initStmt := arguments at: 4.
> > + limitInit := arguments at: 7.
> > + test := arguments at: 5.
> > + block := arguments at: 3.
> > + incStmt := arguments at: 6.
> > + blockSize := sizes at: 1.
> > + loopSize := sizes at: 2.
> > +
> > + "This will return the receiver of to:do: which is the initial value
> of the loop"
> > + forValue
> > + ifTrue: [initStmt emitCodeForValue: stack encoder: encoder]
> > + ifFalse: [initStmt emitCodeForEffect: stack encoder: encoder].
> > + limitInit ifNotNil:
> > + [limitInit emitCodeForEffect: stack encoder: encoder].
> > + test emitCodeForValue: stack encoder: encoder.
> > + pc := encoder nextPC.
> > + self emitCodeForBranchOn: false dist: blockSize pop: stack encoder:
> encoder.
> > + block emitCodeForEvaluatedEffect: stack encoder: encoder.
> > + incStmt emitCodeForEffect: stack encoder: encoder.
> > + self emitCodeForJump: 0 - loopSize encoder: encoder!
> >
> > Item was added:
> > + ----- Method: MessageNode>>emitCodeForValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + "For #ifTrue:ifFalse: and #whileTrue: / #whileFalse: style
> messages, the pc is set to the jump instruction, so that mustBeBoolean
> exceptions can be shown correctly."
> > + <hasLiteralTest: #isMacroEmitter:>
> > + special > 0
> > + ifTrue:
> > + [pc := 0.
> > + self perform: (MacroEmitters at: special) with: stack with:
> encoder with: true]
> > + ifFalse:
> > + [receiver ~~ nil ifTrue: [receiver emitCodeForValue: stack
> encoder: encoder].
> > + arguments do: [:argument | argument emitCodeForValue: stack
> encoder: encoder].
> > + pc := encoder nextPC. "debug pc is first byte of the send,
> i.e. the next byte".
> > + selector
> > + emitCode: stack
> > + args: arguments size
> > + encoder: encoder
> > + super: receiver == NodeSuper]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>emitCodeForWhile:encoder:value: (in
> category 'code generation') -----
> > + emitCodeForWhile: stack encoder: encoder value: forValue
> > + "L1: ... Bfp(L2)|Btp(L2) ... Jmp(L1) L2: "
> > + | cond stmt stmtSize loopSize |
> > + cond := receiver.
> > + stmt := arguments at: 1.
> > + stmtSize := sizes at: 1.
> > + loopSize := sizes at: 2.
> > + cond emitCodeForEvaluatedValue: stack encoder: encoder.
> > + pc := encoder nextPC.
> > + self emitCodeForBranchOn: (selector key == #whileFalse:) "Bfp for
> whileTrue"
> > + dist: stmtSize pop: stack encoder: encoder. "Btp
> for whileFalse"
> > + stmt emitCodeForEvaluatedEffect: stack encoder: encoder.
> > + self emitCodeForJump: 0 - loopSize encoder: encoder.
> > + forValue ifTrue: [encoder genPushSpecialLiteral: nil. stack push:
> 1]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>ensureCanCascade: (in category 'cascading')
> -----
> > + ensureCanCascade: encoder
> > + special > 0 ifTrue:
> > + [special := 0.
> > + receiver := originalReceiver.
> > + selector := encoder encodeSelector: originalSelector.
> > + arguments := originalArguments.
> > + receiver isBlockNode ifTrue: [receiver deoptimize].
> > + arguments do:
> > + [:each|
> > + (each isBlockNode or: [each isBraceNode]) ifTrue:
> > + [each deoptimize]]]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>eval (in category 'equation translation')
> -----
> > + eval
> > + "When everything in me is a constant, I can produce a value. This
> is only used by the Scripting system (TilePadMorph tilesFrom:in:)"
> > +
> > + | rec args |
> > + receiver isVariableNode ifFalse: [^ #illegal].
> > + rec := receiver key value.
> > + args := arguments collect: [:each | each eval].
> > + ^ rec perform: selector key withArguments: args!
> >
> > Item was added:
> > + ----- Method: MessageNode>>ifNilReceiver (in category 'private') -----
> > + ifNilReceiver
> > +
> > + ^receiver!
> >
> > Item was added:
> > + ----- Method: MessageNode>>ifNilTemporary (in category 'private') -----
> > + ifNilTemporary
> > +
> > + ^ self ifNilReceiver ifNilTemporary!
> >
> > Item was added:
> > + ----- Method: MessageNode>>isComplex (in category 'testing') -----
> > + isComplex
> > +
> > + ^(special between: 1 and: 10) or: [arguments size > 2 or: [receiver
> isComplex]]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>isMessage (in category 'testing') -----
> > + isMessage
> > + ^true!
> >
> > Item was added:
> > + ----- Method: MessageNode>>isMessage:receiver:arguments: (in category
> 'testing') -----
> > + isMessage: selSymbol receiver: rcvrPred arguments: argsPred
> > + "Answer whether selector is selSymbol, and the predicates rcvrPred
> and argsPred
> > + evaluate to true with respect to receiver and the list of
> arguments. If selSymbol or
> > + either predicate is nil, it means 'don't care'. Note that
> argsPred takes numArgs
> > + arguments. All block arguments are ParseNodes."
> > +
> > + ^(selSymbol isNil or: [selSymbol==selector key]) and:
> > + [(rcvrPred isNil or: [rcvrPred value: receiver]) and:
> > + [(argsPred isNil or: [argsPred valueWithArguments:
> arguments])]]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>isMessageNode (in category 'testing') -----
> > + isMessageNode
> > + ^true!
> >
> > Item was added:
> > + ----- Method: MessageNode>>isNilIf (in category 'testing') -----
> > + isNilIf
> > +
> > + ^(special between: 3 and: 4)
> > + and: [(arguments first returns or: [arguments first isJust:
> NodeNil])
> > + and: [(arguments last returns or: [arguments last isJust:
> NodeNil])]]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>isOptimized (in category 'testing') -----
> > + isOptimized
> > + ^special > 0!
> >
> > Item was added:
> > + ----- Method: MessageNode>>isOptimizedLoop (in category 'testing')
> -----
> > + isOptimizedLoop
> > + ^special > 0
> > + and: [#(transformWhile: transformToDo: transformRepeat:)
> includes: (MacroTransformers at: special)]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>isOptimizedWhileLoop (in category
> 'testing') -----
> > + isOptimizedWhileLoop
> > + ^special > 0
> > + and: [#(transformWhile: transformRepeat:) includes:
> (MacroTransformers at: special)]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>isReturningIf (in category 'testing') -----
> > + isReturningIf
> > +
> > + ^((special between: 3 and: 4) "ifTrue:ifFalse:/ifFalse:ifTrue:"
> > + or: [special between: 17 and: 18])
> "ifNil:ifNotNil:/ifNotNil:ifNil:"
> > + and: [arguments first returns and: [arguments last returns]]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>macroPrinter (in category 'printing') -----
> > + macroPrinter
> > +
> > + special > 0 ifTrue: [^MacroPrinters at: special].
> > + ^nil
> > + !
> >
> > Item was added:
> > + ----- Method: MessageNode>>noteSpecialSelector: (in category 'macro
> transformations') -----
> > + noteSpecialSelector: selectorSymbol
> > + "special > 0 denotes specially treated (potentially inlined)
> messages. "
> > +
> > + special := MacroSelectors indexOf: selectorSymbol.
> > + !
> >
> > Item was added:
> > + ----- Method: MessageNode>>precedence (in category 'printing') -----
> > + precedence
> > +
> > + ^precedence!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printCaseOn:indent: (in category
> 'printing') -----
> > + printCaseOn: aStream indent: level
> > + "receiver caseOf: {[key]->[value]. ...} otherwise: [otherwise]"
> > + | braceNode otherwise extra |
> > + braceNode := arguments first.
> > + otherwise := arguments last.
> > + (arguments size = 1 or: [otherwise isJustCaseError]) ifTrue:
> > + [otherwise := nil].
> > + receiver
> > + printOn: aStream
> > + indent: level
> > + precedence: 3.
> > + aStream nextPutAll: ' caseOf: '.
> > + braceNode isVariableReference
> > + ifTrue: [braceNode printOn: aStream indent: level]
> > + ifFalse:
> > + [aStream nextPutAll: '{'; crtab: level + 1.
> > + braceNode casesForwardDo:
> > + [:keyNode :valueNode :last |
> > + keyNode printOn: aStream indent: level + 1.
> > + aStream nextPutAll: ' -> '.
> > + valueNode isComplex
> > + ifTrue:
> > + [aStream crtab: level + 2.
> > + extra := 1]
> > + ifFalse: [extra := 0].
> > + valueNode printOn: aStream indent: level + 1 + extra.
> > + last ifTrue: [aStream nextPut: $}]
> > + ifFalse: [aStream nextPut: $.;
> > + crtab: level + 1]]].
> > + otherwise notNil ifTrue:
> > + [aStream crtab: level + 1; nextPutAll: ' otherwise: '.
> > + extra := otherwise isComplex
> > + ifTrue:
> > + [aStream crtab: level + 2.
> > + 1]
> > + ifFalse: [0].
> > + otherwise printOn: aStream indent: level + 1 + extra]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printIfNil:indent: (in category 'printing')
> -----
> > + printIfNil: aStream indent: level
> > +
> > + self printReceiver: receiver on: aStream indent: level.
> > +
> > + ^self printKeywords: selector key
> > + arguments: (Array with: arguments first)
> > + on: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printIfNilNotNil:indent: (in category
> 'printing') -----
> > + printIfNilNotNil: aStream indent: level
> > +
> > + (arguments first isJust: NodeNil) ifTrue:
> > + [self printReceiver: receiver ifNilReceiver ifNilValue on:
> aStream indent: level.
> > + ^ self
> > + printKeywords: #ifNotNil:
> > + arguments: { arguments second }
> > + on: aStream indent: level].
> > +
> > + (arguments second isJust: NodeNil) ifTrue:
> > + [self printReceiver: receiver ifNilReceiver on: aStream indent:
> level.
> > + ^ self
> > + printKeywords: #ifNil:
> > + arguments: { arguments first }
> > + on: aStream indent: level].
> > +
> > + self printReceiver: receiver ifNilReceiver ifNilValue on: aStream
> indent: level.
> > + ^ self
> > + printKeywords: #ifNil:ifNotNil:
> > + arguments: arguments
> > + on: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printIfOn:indent: (in category 'printing')
> -----
> > + printIfOn: aStream indent: level
> > +
> > + receiver ifNotNil:
> > + [receiver printOn: aStream indent: level + 1 precedence:
> precedence].
> > + (arguments last isJust: NodeNil) ifTrue:
> > + [^self printKeywords: #ifTrue: arguments: (Array with:
> arguments first)
> > + on: aStream indent: level].
> > + (arguments last isJust: NodeFalse) ifTrue:
> > + [^self printKeywords: #and: arguments: (Array with: arguments
> first)
> > + on: aStream indent: level].
> > + (arguments first isJust: NodeNil) ifTrue:
> > + [^self printKeywords: #ifFalse: arguments: (Array with:
> arguments last)
> > + on: aStream indent: level].
> > + (arguments first isJust: NodeTrue) ifTrue:
> > + [^self printKeywords: #or: arguments: (Array with: arguments
> last)
> > + on: aStream indent: level].
> > + self printKeywords: #ifTrue:ifFalse: arguments: arguments
> > + on: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printKeywords:arguments:on:indent: (in
> category 'printing') -----
> > + printKeywords: key arguments: args on: aStream indent: level
> > + | keywords indent arg kwd doCrTab |
> > + args size = 0 ifTrue:
> > + [aStream space; nextPutAll: key.
> > + ^self].
> > + keywords := key asString keywords.
> > + doCrTab := args size > 2
> > + or: [{receiver} , args anySatisfy:
> > + [:thisArg |
> > + thisArg notNil
> > + and: [thisArg isBlockNode
> > + or: [thisArg isMessageNode and: [thisArg
> precedence >= 3]]]]].
> > + 1 to: (args size min: keywords size) do:
> > + [:i |
> > + arg := args at: i.
> > + kwd := keywords at: i.
> > + doCrTab
> > + ifTrue: [aStream crtab: level+1. indent := 1] "newline
> after big args"
> > + ifFalse: [aStream space. indent := 0].
> > + aStream nextPutAll: kwd; space.
> > + arg printOn: aStream
> > + indent: level + 1 + indent
> > + precedence: (precedence = 2 ifTrue: [1] ifFalse:
> [precedence])]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printOn:indent: (in category 'printing')
> -----
> > + printOn: aStream indent: level
> > + "may not need this check anymore - may be fixed by the #receiver:
> change"
> > + <hasLiteralTest: #isMacroPrinter:>
> > +
> > + special ifNil: [^aStream nextPutAll: '** MessageNode with nil
> special **'].
> > +
> > + special > 0 ifTrue:
> > + [^self perform: self macroPrinter with: aStream with: level].
> > +
> > + self printReceiver: receiver on: aStream indent: level.
> > + selector isForFFICall
> > + ifTrue:
> > + [aStream space.
> > + selector
> > + printAsFFICallWithArguments: arguments
> > + on: aStream
> > + indent: 0]
> > + ifFalse:
> > + [self printKeywords: selector key
> > + arguments: arguments
> > + on: aStream
> > + indent: level]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printOn:indent:precedence: (in category
> 'printing') -----
> > + printOn: strm indent: level precedence: outerPrecedence
> > +
> > + | parenthesize |
> > + parenthesize := precedence > outerPrecedence
> > + or: [outerPrecedence = 3 and: [precedence = 3 "both keywords"]].
> > + parenthesize
> > + ifTrue: [strm nextPutAll: '('.
> > + self printOn: strm indent: level.
> > + strm nextPutAll: ')']
> > + ifFalse: [self printOn: strm indent: level]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printParenReceiver:on:indent: (in category
> 'printing') -----
> > + printParenReceiver: rcvr on: aStream indent: level
> > +
> > + rcvr isBlockNode ifTrue:
> > + [^rcvr printOn: aStream indent: level].
> > + aStream nextPut: $(.
> > + rcvr printOn: aStream indent: level.
> > + aStream nextPut: $)
> > + !
> >
> > Item was added:
> > + ----- Method: MessageNode>>printReceiver:on:indent: (in category
> 'printing') -----
> > + printReceiver: rcvr on: aStream indent: level
> > +
> > + rcvr ifNil: [^ self].
> > +
> > + "Force parens around keyword receiver of kwd message"
> > + rcvr printOn: aStream indent: level precedence: precedence!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printRepeatOn:indent: (in category
> 'printing') -----
> > + printRepeatOn: aStream indent: level
> > +
> > + self printReceiver: receiver on: aStream indent: level.
> > +
> > + ^self printKeywords: selector key
> > + arguments: (Array new)
> > + on: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printToDoOn:indent: (in category
> 'printing') -----
> > + printToDoOn: aStream indent: level
> > +
> > + | limitNode |
> > + self printReceiver: receiver on: aStream indent: level.
> > +
> > + (arguments last == nil or: [(arguments last isMemberOf:
> AssignmentNode) not])
> > + ifTrue: [limitNode := arguments first]
> > + ifFalse: [limitNode := arguments last value].
> > + (selector key = #to:by:do:
> > + and: [(arguments at: 2) isConstantNumber
> > + and: [(arguments at: 2) key = 1]])
> > + ifTrue: [self printKeywords: #to:do:
> > + arguments: (Array with: limitNode with: (arguments
> at: 3))
> > + on: aStream indent: level]
> > + ifFalse: [self printKeywords: selector key
> > + arguments: (Array with: limitNode) , arguments
> allButFirst
> > + on: aStream indent: level]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printWhileOn:indent: (in category
> 'printing') -----
> > + printWhileOn: aStream indent: level
> > + self printReceiver: receiver on: aStream indent: level.
> > + self
> > + printKeywords: originalSelector
> > + arguments: originalArguments
> > + on: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printWithClosureAnalysisCaseOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisCaseOn: aStream indent: level
> > + "receiver caseOf: {[key]->[value]. ...} otherwise: [otherwise]"
> > + | braceNode otherwise extra |
> > + braceNode := arguments first.
> > + otherwise := arguments last.
> > + (arguments size = 1 or: [otherwise isJustCaseError]) ifTrue:
> > + [otherwise := nil].
> > + receiver
> > + printWithClosureAnalysisOn: aStream
> > + indent: level
> > + precedence: 3.
> > + aStream nextPutAll: ' caseOf: '.
> > + braceNode isVariableReference
> > + ifTrue: [braceNode printWithClosureAnalysisOn: aStream indent:
> level]
> > + ifFalse:
> > + [aStream nextPutAll: '{'; crtab: level + 1.
> > + braceNode casesForwardDo:
> > + [:keyNode :valueNode :last |
> > + keyNode printWithClosureAnalysisOn: aStream indent:
> level + 1.
> > + aStream nextPutAll: ' -> '.
> > + valueNode isComplex
> > + ifTrue:
> > + [aStream crtab: level + 2.
> > + extra := 1]
> > + ifFalse: [extra := 0].
> > + valueNode printWithClosureAnalysisOn: aStream indent:
> level + 1 + extra.
> > + last ifTrue: [aStream nextPut: $}]
> > + ifFalse: [aStream nextPut: $.;
> > + crtab: level + 1]]].
> > + otherwise notNil ifTrue:
> > + [aStream crtab: level + 1; nextPutAll: ' otherwise: '.
> > + extra := otherwise isComplex
> > + ifTrue:
> > + [aStream crtab: level + 2.
> > + 1]
> > + ifFalse: [0].
> > + otherwise printWithClosureAnalysisOn: aStream indent: level +
> 1 + extra]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printWithClosureAnalysisIfNil:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisIfNil: aStream indent: level
> > +
> > + self printWithClosureAnalysisReceiver: receiver on: aStream indent:
> level.
> > +
> > + ^self printWithClosureAnalysisKeywords: selector key
> > + arguments: (Array with: arguments first)
> > + on: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printWithClosureAnalysisIfNilNotNil:indent:
> (in category 'printing') -----
> > + printWithClosureAnalysisIfNilNotNil: aStream indent: level
> > +
> > + (arguments first isJust: NodeNil) ifTrue:
> > + [self printWithClosureAnalysisReceiver: receiver ifNilReceiver
> ifNilValue on: aStream indent: level.
> > + ^ self
> > + printWithClosureAnalysisKeywords: #ifNotNil:
> > + arguments: { arguments second }
> > + on: aStream indent: level].
> > +
> > + (arguments second isJust: NodeNil) ifTrue:
> > + [self printWithClosureAnalysisReceiver: receiver ifNilReceiver
> on: aStream indent: level.
> > + ^ self
> > + printWithClosureAnalysisKeywords: #ifNil:
> > + arguments: { arguments first }
> > + on: aStream indent: level].
> > +
> > + self printWithClosureAnalysisReceiver: receiver ifNilReceiver
> ifNilValue on: aStream indent: level.
> > + ^ self
> > + printWithClosureAnalysisKeywords: #ifNil:ifNotNil:
> > + arguments: arguments
> > + on: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printWithClosureAnalysisIfOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisIfOn: aStream indent: level
> > +
> > + receiver ifNotNil:
> > + [receiver printWithClosureAnalysisOn: aStream indent: level + 1
> precedence: precedence].
> > + (arguments last isJust: NodeNil) ifTrue:
> > + [^self printWithClosureAnalysisKeywords: #ifTrue: arguments:
> (Array with: arguments first)
> > + on: aStream indent: level].
> > + (arguments last isJust: NodeFalse) ifTrue:
> > + [^self printWithClosureAnalysisKeywords: #and: arguments:
> (Array with: arguments first)
> > + on: aStream indent: level].
> > + (arguments first isJust: NodeNil) ifTrue:
> > + [^self printWithClosureAnalysisKeywords: #ifFalse: arguments:
> (Array with: arguments last)
> > + on: aStream indent: level].
> > + (arguments first isJust: NodeTrue) ifTrue:
> > + [^self printWithClosureAnalysisKeywords: #or: arguments: (Array
> with: arguments last)
> > + on: aStream indent: level].
> > + self printWithClosureAnalysisKeywords: #ifTrue:ifFalse: arguments:
> arguments
> > + on: aStream indent: level!
> >
> > Item was added:
> > + ----- Method:
> MessageNode>>printWithClosureAnalysisKeywords:arguments:on:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisKeywords: key arguments: args on: aStream
> indent: level
> > + | keywords indent arg kwd doCrTab |
> > + args size = 0 ifTrue: [aStream space; nextPutAll: key. ^self].
> > + keywords := key keywords.
> > + doCrTab := args size > 2
> > + or: [{receiver} , args anySatisfy:
> > + [:thisArg |
> > + thisArg isBlockNode
> > + or: [thisArg isMessageNode and: [thisArg
> precedence >= 3]]]].
> > + 1 to: (args size min: keywords size) do:
> > + [:i |
> > + arg := args at: i.
> > + kwd := keywords at: i.
> > + doCrTab
> > + ifTrue: [aStream crtab: level+1. indent := 1] "newline
> after big args"
> > + ifFalse: [aStream space. indent := 0].
> > + aStream nextPutAll: kwd; space.
> > + arg printWithClosureAnalysisOn: aStream
> > + indent: level + 1 + indent
> > + precedence: (precedence = 2 ifTrue: [1] ifFalse:
> [precedence])]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level
> > + "may not need this check anymore - may be fixed by the #receiver:
> change"
> > + <hasLiteralTest: #isMacroPrinter:>
> > +
> > + special ifNil: [^aStream nextPutAll: '** MessageNode with nil
> special **'].
> > +
> > + special > 0 ifTrue:
> > + [^self perform: self macroPrinter with: aStream with: level].
> > +
> > + self printWithClosureAnalysisReceiver: receiver on: aStream indent:
> level.
> > + self printWithClosureAnalysisKeywords: selector key
> > + arguments: arguments
> > + on: aStream
> > + indent: level!
> >
> > Item was added:
> > + ----- Method:
> MessageNode>>printWithClosureAnalysisOn:indent:precedence: (in category
> 'printing') -----
> > + printWithClosureAnalysisOn: strm indent: level precedence:
> outerPrecedence
> > +
> > + | parenthesize |
> > + parenthesize := precedence > outerPrecedence
> > + or: [outerPrecedence = 3 and: [precedence = 3 "both keywords"]].
> > + parenthesize
> > + ifTrue: [strm nextPutAll: '('.
> > + self printWithClosureAnalysisOn: strm indent: level.
> > + strm nextPutAll: ')']
> > + ifFalse: [self printWithClosureAnalysisOn: strm indent: level]!
> >
> > Item was added:
> > + ----- Method:
> MessageNode>>printWithClosureAnalysisParenReceiver:on:indent: (in category
> 'printing') -----
> > + printWithClosureAnalysisParenReceiver: rcvr on: aStream indent: level
> > +
> > + rcvr isBlockNode ifTrue:
> > + [^rcvr printWithClosureAnalysisOn: aStream indent: level].
> > + aStream nextPut: $(.
> > + rcvr printWithClosureAnalysisOn: aStream indent: level.
> > + aStream nextPut: $)!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printWithClosureAnalysisReceiver:on:indent:
> (in category 'printing') -----
> > + printWithClosureAnalysisReceiver: rcvr on: aStream indent: level
> > +
> > + rcvr ifNil: [^self].
> > +
> > + "Force parens around keyword receiver of kwd message"
> > + rcvr printWithClosureAnalysisOn: aStream indent: level precedence:
> precedence!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printWithClosureAnalysisToDoOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisToDoOn: aStream indent: level
> > +
> > + | limitNode |
> > + self printWithClosureAnalysisReceiver: receiver on: aStream indent:
> level.
> > +
> > + limitNode := (arguments last == nil
> > + or: [arguments last isAssignmentNode not])
> > + ifTrue: [arguments first]
> > + ifFalse: [arguments last value].
> > + (selector key = #to:by:do:
> > + and: [(arguments at: 2) isConstantNumber
> > + and: [(arguments at: 2) key = 1]])
> > + ifTrue: [self printWithClosureAnalysisKeywords: #to:do:
> > + arguments: (Array with: limitNode with: (arguments
> at: 3))
> > + on: aStream indent: level]
> > + ifFalse: [self printWithClosureAnalysisKeywords: selector key
> > + arguments: (Array with: limitNode) , arguments
> allButFirst
> > + on: aStream indent: level]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>printWithClosureAnalysisWhileOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisWhileOn: aStream indent: level
> > +
> > + self printWithClosureAnalysisReceiver: receiver on: aStream indent:
> level.
> > + (arguments isEmpty not
> > + and: [arguments first isJust: NodeNil]) ifTrue:
> > + [selector := SelectorNode new
> > + key:
> > + (selector key == #whileTrue:
> > + ifTrue: [#whileTrue]
> > + ifFalse: [#whileFalse])
> > + code: #macro.
> > + arguments := Array new].
> > + self printWithClosureAnalysisKeywords: selector key arguments:
> arguments
> > + on: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: MessageNode>>pvtCheckForPvtSelector: (in category
> 'private') -----
> > + pvtCheckForPvtSelector: encoder
> > + "If the code being compiled is trying to send a private message
> (e.g. 'pvtCheckForPvtSelector:') to anyone other than self, then complain
> to encoder."
> > +
> > + selector isPvtSelector ifTrue:
> > + [receiver isSelfPseudoVariable ifFalse:
> > + [encoder notify: 'Private messages may only be sent to
> self']].!
> >
> > Item was added:
> > + ----- Method: MessageNode>>receiver (in category 'equation
> translation') -----
> > + receiver
> > + ^receiver!
> >
> > Item was added:
> > + ----- Method: MessageNode>>receiver: (in category 'equation
> translation') -----
> > + receiver: val
> > + "14 feb 2001 - removed return arrow"
> > +
> > + receiver := val!
> >
> > Item was added:
> > + ----- Method: MessageNode>>receiver:arguments:precedence: (in category
> 'private') -----
> > + receiver: rcvr arguments: args precedence: p
> > +
> > + receiver := rcvr.
> > + originalReceiver := rcvr.
> > + arguments := args.
> > + originalArguments := arguments copy.
> > + sizes := Array new: arguments size.
> > + precedence := p!
> >
> > Item was added:
> > + ----- Method: MessageNode>>receiver:selector:arguments:precedence: (in
> category 'initialize-release') -----
> > + receiver: rcvr selector: selNode arguments: args precedence: p
> > + "Decompile."
> > +
> > + self receiver: rcvr
> > + arguments: args
> > + precedence: p.
> > + originalSelector := selNode key.
> > + selNode code == #macro
> > + ifTrue: [self noteSpecialSelector: selNode key]
> > + ifFalse: [special := 0].
> > + selector := selNode.
> > + "self pvtCheckForPvtSelector: encoder"
> > + "We could test code being decompiled, but the compiler should've
> checked already. And where to send the complaint?"!
> >
> > Item was added:
> > + ----- Method:
> MessageNode>>receiver:selector:arguments:precedence:from: (in category
> 'initialize-release') -----
> > + receiver: rcvr selector: aSelector arguments: args precedence: p from:
> encoder
> > + "Compile."
> > +
> > + self receiver: rcvr
> > + arguments: args
> > + precedence: p.
> > + originalSelector := aSelector.
> > + self noteSpecialSelector: aSelector.
> > + (self transform: encoder)
> > + ifTrue:
> > + [selector isNil ifTrue:
> > + [selector := SelectorNode new
> > + key: (MacroSelectors at: special)
> > + code: #macro]]
> > + ifFalse:
> > + [selector := encoder encodeSelector: aSelector.
> > + rcvr == NodeSuper ifTrue: [encoder noteSuper]].
> > + self pvtCheckForPvtSelector: encoder!
> >
> > Item was added:
> > + ----- Method:
> MessageNode>>receiver:selector:arguments:precedence:from:sourceRange: (in
> category 'initialize-release') -----
> > + receiver: rcvr selector: selName arguments: args precedence: p from:
> encoder sourceRange: range
> > + "Compile."
> > + ((selName == #future) or:[selName == #future:]) ifTrue:
> > + [Smalltalk at: #FutureNode ifPresent:
> > + [:futureNode|
> > + ^futureNode new
> > + receiver: rcvr
> > + selector: selName
> > + arguments: args
> > + precedence: p
> > + from: encoder
> > + sourceRange: range]].
> > + (rcvr isFutureNode
> > + and: [rcvr futureSelector == nil]) ifTrue:
> > + "Transform regular message into future"
> > + [^rcvr futureMessage: selName
> > + arguments: args
> > + from: encoder
> > + sourceRange: range].
> > +
> > + encoder noteSourceRange: range forNode: self.
> > + ^self
> > + receiver: rcvr
> > + selector: selName
> > + arguments: args
> > + precedence: p
> > + from: encoder!
> >
> > Item was added:
> > + ----- Method: MessageNode>>selector (in category 'equation
> translation') -----
> > + selector
> > + ^selector!
> >
> > Item was added:
> > + ----- Method: MessageNode>>selector: (in category
> 'initialize-release') -----
> > + selector: sel
> > + selector := sel!
> >
> > Item was added:
> > + ----- Method: MessageNode>>sizeCodeForCase:value: (in category 'code
> generation') -----
> > + sizeCodeForCase: encoder value: forValue
> > +
> > + | braceNode sizeIndex elseSize allReturn |
> > + forValue not ifTrue:
> > + [^super sizeCodeForEffect: encoder].
> > + equalNode := encoder encodeSelector: #=.
> > + braceNode := arguments first.
> > + sizes := Array new: 2 * braceNode numElements.
> > + sizeIndex := sizes size.
> > + elseSize := arguments size = 2
> > + ifTrue:
> > + [arguments last sizeCodeForEvaluatedValue: encoder]
> "otherwise: [...]"
> > + ifFalse:
> > + [caseErrorNode := encoder encodeSelector: #caseError.
> > + "Assume that the receiver of caseOf: has been dup"
> > + (caseErrorNode sizeCode: encoder args: 0 super: false)].
> "self caseError"
> > + "There must be at least one branch around the otherwise/caseError
> > + so the decompiler can identify the end of the
> otherwise/caseError."
> > + allReturn := true. "assume every case ends with a return"
> > + braceNode casesForwardDo:
> > + [:keyNode :valueNode :last |
> > + valueNode returns ifFalse: [allReturn := false]].
> > + braceNode casesReverseDo:
> > + [:keyNode :valueNode :last |
> > + | thenSize dropReceiver |
> > + dropReceiver := last and: [arguments size >= 2].
> > + sizes at: sizeIndex put: elseSize.
> > + thenSize := valueNode sizeCodeForEvaluatedValue: encoder.
> > + dropReceiver ifFalse: [thenSize := thenSize + encoder sizePop].
> > + valueNode returns ifFalse: [thenSize := thenSize + (self
> sizeCode: encoder forJump: elseSize)].
> > + (last and: [allReturn]) ifTrue: [thenSize := thenSize + (self
> sizeCode: encoder forJump: elseSize)].
> > + sizes at: sizeIndex-1 put: thenSize.
> > + dropReceiver ifFalse: [elseSize := elseSize + encoder sizeDup].
> > + elseSize := elseSize
> > + + (keyNode sizeCodeForEvaluatedValue: encoder)
> > + + (equalNode sizeCode: encoder args: 1 super: false)
> > + + (self sizeCode: encoder forBranchOn: false dist:
> thenSize)
> > + + thenSize.
> > + sizeIndex := sizeIndex - 2].
> > + ^(receiver sizeCodeForValue: encoder) + elseSize!
> >
> > Item was added:
> > + ----- Method: MessageNode>>sizeCodeForEffect: (in category 'code
> generation') -----
> > + sizeCodeForEffect: encoder
> > + <hasLiteralTest: #isMacroSizer:>
> > +
> > + special > 0
> > + ifTrue:
> > + [encoder noteOptimizedSelector: originalSelector.
> > + ^self perform: (MacroSizers at: special) with: encoder
> with: false].
> > + ^super sizeCodeForEffect: encoder!
> >
> > Item was added:
> > + ----- Method: MessageNode>>sizeCodeForIf:value: (in category 'code
> generation') -----
> > + sizeCodeForIf: encoder value: forValue
> > + | thenExpr elseExpr branchSize thenSize elseSize popSize
> requireTwoArms |
> > + thenExpr := arguments at: 1.
> > + elseExpr := arguments at: 2.
> > + popSize := 0.
> > + requireTwoArms := forValue or: [ "Code all forValue as two-armed"
> > + arguments noneSatisfy: [:expr | expr isJust: NodeNil]].
> > + requireTwoArms
> > + ifTrue:
> > + [elseSize := elseExpr sizeCodeForEvaluatedValue: encoder.
> > + thenSize := (thenExpr sizeCodeForEvaluatedValue: encoder)
> > + + (thenExpr returns
> > + ifTrue: [0] "Elide jump over else after a
> return"
> > + ifFalse: [self sizeCode: encoder forJump:
> elseSize]).
> > + branchSize := self sizeCode: encoder forBranchOn: false
> dist: thenSize.
> > + "Two-armed IFs forEffect share a single pop - except if
> both branches return"
> > + forValue ifFalse: [(arguments allSatisfy: #returns)
> ifFalse: [popSize := encoder sizePop]]]
> > + ifFalse: "One arm is empty here (two-arms code forValue)"
> > + [(elseExpr isJust: NodeNil)
> > + ifTrue:
> > + [elseSize := 0.
> > + thenSize := thenExpr sizeCodeForEvaluatedEffect:
> encoder.
> > + branchSize := self sizeCode: encoder forBranchOn:
> false dist: thenSize]
> > + ifFalse:
> > + [thenSize := 0.
> > + elseSize := elseExpr sizeCodeForEvaluatedEffect:
> encoder.
> > + branchSize := self sizeCode: encoder forBranchOn:
> true dist: elseSize]].
> > + sizes := Array with: thenSize with: elseSize.
> > + ^(receiver sizeCodeForValue: encoder)
> > + + branchSize + thenSize + elseSize + popSize!
> >
> > Item was added:
> > + ----- Method: MessageNode>>sizeCodeForIfNil:value: (in category 'code
> generation') -----
> > + sizeCodeForIfNil: encoder value: forValue
> > +
> > + | theNode theSize theSelector |
> > + equalNode := encoder encodeSelector: #==.
> > + sizes := Array new: 1.
> > + theNode := arguments first.
> > + theSelector := #ifNotNil:.
> > + forValue
> > + ifTrue:
> > + [sizes at: 1 put: (theSize := (encoder sizePop + (theNode
> sizeCodeForEvaluatedValue: encoder))).
> > + ^(receiver sizeCodeForValue: encoder)
> > + + encoder sizeDup
> > + + (encoder sizePushSpecialLiteral: nil)
> > + + (equalNode sizeCode: encoder args: 1 super: false)
> > + + (self
> > + sizeCode: encoder forBranchOn: selector key ==
> theSelector
> > + dist: theSize)
> > + + theSize]
> > + ifFalse:
> > + [sizes at: 1 put: (theSize := (theNode
> sizeCodeForEvaluatedEffect: encoder)).
> > + ^(receiver sizeCodeForValue: encoder)
> > + + (encoder sizePushSpecialLiteral: nil)
> > + + (equalNode sizeCode: encoder args: 1 super: false)
> > + + (self
> > + sizeCode: encoder
> > + forBranchOn: selector key == theSelector
> > + dist: theSize)
> > + + theSize]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>sizeCodeForRepeat:value: (in category 'code
> generation') -----
> > + sizeCodeForRepeat: encoder value: forValue
> > + "L1: ... Jmp(L1) nil (nil for value only);"
> > + | loopSize |
> > + "We assume long backward branches are always maximal size branches."
> > + loopSize := (receiver sizeCodeForEvaluatedEffect: encoder) +
> (encoder sizeJumpLong: -1).
> > + sizes := Array with: loopSize.
> > + ^loopSize + (forValue ifTrue: [encoder sizePushSpecialLiteral: nil]
> ifFalse: [0])!
> >
> > Item was added:
> > + ----- Method: MessageNode>>sizeCodeForToDo:value: (in category 'code
> generation') -----
> > + sizeCodeForToDo: encoder value: forValue
> > + " var := rcvr. L1: [var <= arg1] Bfp(L2) [block body. var := var +
> inc] Jmp(L1) L2: "
> > + | loopSize initStmt test block incStmt blockSize initSize limitInit
> |
> > + block := arguments at: 3.
> > + initStmt := arguments at: 4.
> > + test := arguments at: 5.
> > + incStmt := arguments at: 6.
> > + limitInit := arguments at: 7.
> > + initSize := forValue
> > + ifTrue: [initStmt sizeCodeForValue: encoder.]
> > + ifFalse: [initStmt sizeCodeForEffect: encoder].
> > + limitInit == nil ifFalse:
> > + [initSize := initSize + (limitInit sizeCodeForEffect: encoder)].
> > + blockSize := (block sizeCodeForEvaluatedEffect: encoder)
> > + + (incStmt sizeCodeForEffect: encoder)
> > + + (encoder sizeJumpLong: -1).
> > + loopSize := (test sizeCodeForValue: encoder)
> > + + (self sizeCode: encoder forBranchOn: false dist:
> blockSize)
> > + + blockSize.
> > + sizes := Array with: blockSize with: loopSize.
> > + ^initSize
> > + + loopSize!
> >
> > Item was added:
> > + ----- Method: MessageNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + <hasLiteralTest: #isMacroSizer:>
> > + | total |
> > + special > 0 ifTrue:
> > + [encoder noteOptimizedSelector: originalSelector.
> > + ^self perform: (MacroSizers at: special) with: encoder with:
> true].
> > + receiver == NodeSuper ifTrue:
> > + [selector := selector forSuperSend "only necessary for special
> selectors"].
> > + total := selector sizeCode: encoder args: arguments size super:
> receiver == NodeSuper.
> > + receiver ifNotNil:
> > + [total := total + (receiver sizeCodeForValue: encoder)].
> > + sizes := arguments collect:
> > + [:arg | | argSize |
> > + argSize := arg sizeCodeForValue: encoder.
> > + total := total + argSize.
> > + argSize].
> > + ^total!
> >
> > Item was added:
> > + ----- Method: MessageNode>>sizeCodeForWhile:value: (in category 'code
> generation') -----
> > + sizeCodeForWhile: encoder value: forValue
> > + "L1: ... Bfp(L2) ... Jmp(L1) L2: nil (nil for value only);
> > + justStmt, wholeLoop, justJump."
> > + | cond stmt stmtSize loopSize branchSize |
> > + cond := receiver.
> > + stmt := arguments at: 1.
> > + "We assume long backward branches are always maximal size branches."
> > + stmtSize := (stmt sizeCodeForEvaluatedEffect: encoder) + (encoder
> sizeJumpLong: -1).
> > + branchSize := self
> > + sizeCode: encoder
> > + forBranchOn: selector key == #whileFalse: "Btp for
> whileFalse"
> > + dist: stmtSize.
> > + loopSize := (cond sizeCodeForEvaluatedValue: encoder) + branchSize
> + stmtSize.
> > + sizes := Array with: stmtSize with: loopSize.
> > + ^loopSize + (forValue ifTrue: [encoder sizePushSpecialLiteral: nil]
> ifFalse: [0])!
> >
> > Item was added:
> > + ----- Method: MessageNode>>test (in category 'printing') -----
> > + test
> > +
> > + 3 > 4 ifTrue: [4+5 between: 6 and: 7]
> > + ifFalse: [4 between: 6+5 and: 7-2]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>toDoFromWhileWithCounts:init:limit: (in
> category 'decompiling') -----
> > + toDoFromWhileWithCounts: blockBodyTempCounts init: incrInit limit:
> limitInitOrNil
> > + "If the receiver, a whileTrue: loop, represents a to:[by:]do: loop
> > + then answer the replacement to:[by:]do:, otherwise answer nil."
> > + | variable increment limit toDoBlock body test |
> > + self assert: (selector key == #whileTrue:
> > + and: [incrInit isAssignmentNode]).
> > + (limitInitOrNil notNil "limit should not be referenced within the
> loop"
> > + and: [(blockBodyTempCounts at: limitInitOrNil variable ifAbsent:
> [0]) ~= 1]) ifTrue:
> > + [^nil].
> > + body := arguments last statements.
> > + (variable := incrInit variable) isTemp ifFalse:
> > + [^nil].
> > + (increment := body last toDoIncrement: variable) ifNil:
> > + [^nil].
> > + receiver statements size ~= 1 ifTrue:
> > + [^nil].
> > + test := receiver statements first.
> > + "Note: test should really be checked that <= or >= comparison
> > + jibes with the sign of the (constant) increment"
> > + (test isMessageNode
> > + and: [(limit := test toDoLimit: variable) notNil]) ifFalse:
> > + [^nil].
> > + "The block must not overwrite the limit"
> > + (limit isVariableNode and: [body anySatisfy: [:e | e
> isAssignmentNode and: [e variable = limit]]]) ifTrue:
> > + [^nil].
> > + toDoBlock := BlockNode statements: body allButLast returns: false.
> > + toDoBlock arguments: {variable}.
> > + ^MessageNode new
> > + receiver: incrInit value
> > + selector: (SelectorNode new key: #to:by:do: code: #macro)
> > + arguments: (Array with: limit with: increment with: toDoBlock)
> > + precedence: precedence!
> >
> > Item was added:
> > + ----- Method: MessageNode>>toDoFromWhileWithInit:withLimit: (in
> category 'decompiling') -----
> > + toDoFromWhileWithInit: incrInit withLimit: limitInitOrNil
> > + "If the receiver, a whileTrue: loop, represents a to:[by:]do: loop
> > + then answer the replacement to:[by:]do:, otherwise answer nil."
> > + | variable increment limit toDoBlock body test |
> > + self assert: (selector key == #whileTrue:
> > + and: [incrInit isAssignmentNode]).
> > + body := arguments last statements.
> > + (variable := incrInit variable) isTemp ifFalse:
> > + [^nil].
> > + (increment := body last toDoIncrement: variable) ifNil:
> > + [^nil].
> > + receiver statements size ~= 1 ifTrue:
> > + [^nil].
> > + test := receiver statements first.
> > + "Note: test should really be checked that <= or >= comparison
> > + jibes with the sign of the (constant) increment"
> > + (test isMessageNode
> > + and: [(limit := test toDoLimit: variable) notNil]) ifFalse:
> > + [^nil].
> > + "The block must not overwrite the limit"
> > + (limit isVariableNode and: [body anySatisfy: [:e | e
> isAssignmentNode and: [e variable = limit]]]) ifTrue:
> > + [^nil].
> > + toDoBlock := BlockNode statements: body allButLast returns: false.
> > + toDoBlock arguments: {variable}.
> > + ^MessageNode new
> > + receiver: incrInit value
> > + selector: (SelectorNode new key: #to:by:do: code: #macro)
> > + arguments: (Array with: limit with: increment with: toDoBlock)
> > + precedence: precedence!
> >
> > Item was added:
> > + ----- Method: MessageNode>>toDoIncrement: (in category 'testing') -----
> > + toDoIncrement: variable
> > + ^(receiver = variable
> > + and: [selector key = #+
> > + and: [arguments first isConstantNumber]]) ifTrue:
> > + [arguments first]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>toDoLimit: (in category 'testing') -----
> > + toDoLimit: variable
> > + ^(receiver = variable
> > + and: [selector key = #<= or: [selector key = #>=]]) ifTrue:
> > + [arguments first]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transform: (in category 'macro
> transformations') -----
> > + transform: encoder
> > + <hasLiteralTest: #isMacroTransformer:>
> > +
> > + special = 0 ifTrue: [^false].
> > + (self perform: (MacroTransformers at: special) with: encoder)
> > + ifTrue:
> > + [^true]
> > + ifFalse:
> > + [special := 0. ^false]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformAnd: (in category 'macro
> transformations') -----
> > + transformAnd: encoder
> > + (self transformBoolean: encoder)
> > + ifTrue:
> > + [arguments :=
> > + Array
> > + with: ((arguments at: 1) noteOptimizedIn: self)
> > + with: ((BlockNode withJust: NodeFalse)
> noteOptimizedIn: self).
> > + ^true]
> > + ifFalse:
> > + [^false]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformBoolean: (in category 'macro
> transformations') -----
> > + transformBoolean: encoder
> > + ^self
> > + checkBlock: (arguments at: 1)
> > + as: 'argument'
> > + from: encoder
> > + maxArgs: 0!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformCase: (in category 'macro
> transformations') -----
> > + transformCase: encoder
> > +
> > + | caseNode |
> > + caseNode := arguments first.
> > + (caseNode isMemberOf: BraceNode) ifFalse: [^false].
> > + (caseNode blockAssociationCheck: encoder) ifFalse: [^false].
> > + (arguments size = 1
> > + or: [self checkBlock: arguments last as: 'otherwise arg' from:
> encoder maxArgs: 1]) ifFalse:
> > + [^false].
> > + caseNode elements do:
> > + [:messageNode |
> > + messageNode receiver noteOptimizedIn: self.
> > + messageNode arguments first noteOptimizedIn: self].
> > + arguments size = 2 ifTrue:
> > + [| otherwiseBlock |
> > + otherwiseBlock := arguments last noteOptimizedIn: self.
> > + otherwiseBlock numberOfArguments = 1 ifTrue:
> > + [receiver := AssignmentNode new
> > + variable: otherwiseBlock firstArgument
> > + value: receiver.
> > + encoder noteSourceRange: (encoder sourceRangeFor: self)
> forNode: receiver]].
> > + ^true!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformIfFalse: (in category 'macro
> transformations') -----
> > + transformIfFalse: encoder
> > + (self transformBoolean: encoder)
> > + ifTrue:
> > + [arguments :=
> > + Array
> > + with: ((BlockNode withJust: NodeNil)
> noteOptimizedIn: self)
> > + with: ((arguments at: 1) noteOptimizedIn: self).
> > + ^true]
> > + ifFalse:
> > + [^false]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformIfFalseIfTrue: (in category 'macro
> transformations') -----
> > + transformIfFalseIfTrue: encoder
> > + ^(self checkBlock: (arguments at: 1) as: 'False arg' from: encoder
> maxArgs: 0)
> > + and: [(self checkBlock: (arguments at: 2) as: 'True arg' from:
> encoder maxArgs: 0)
> > + and: [selector := SelectorNode new key: #ifTrue:ifFalse: code:
> #macro.
> > + arguments swap: 1 with: 2.
> > + arguments do: [:arg| arg noteOptimizedIn: self].
> > + true]]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformIfNil: (in category 'macro
> transformations') -----
> > + transformIfNil: encoder
> > +
> > + "vb: Removed the original transformBoolean: which amounds to a test
> we perform in each of the branches below."
> > + (MacroSelectors at: special) = #ifNotNil: ifTrue:
> > + [(self checkBlock: arguments first as: 'ifNotNil arg' from:
> encoder maxArgs: 1) ifFalse:
> > + [^false].
> > +
> > + "Transform 'ifNotNil: [stuff]' to 'ifNil: [nil] ifNotNil:
> [stuff]'.
> > + Slightly better code and more consistent with decompilation."
> > + self noteSpecialSelector: #ifNil:ifNotNil:.
> > + selector := SelectorNode new key: (MacroSelectors at: special)
> code: #macro.
> > + arguments := Array
> > + with: ((BlockNode withJust: NodeNil)
> noteOptimizedIn: self)
> > + with: (arguments first noteOptimizedIn: self).
> > + (self transform: encoder) ifFalse:
> > + [self error: 'compiler logic error'].
> > + ^true].
> > + (self checkBlock: arguments first as: 'ifNil arg' from: encoder
> maxArgs: 0) ifFalse:
> > + [^false].
> > + arguments first noteOptimizedIn: self.
> > + ^true!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformIfNilIfNotNil: (in category 'macro
> transformations') -----
> > + transformIfNilIfNotNil: encoder
> > + "vb: Changed to support one-argument ifNotNil: branch. In the 1-arg
> case we
> > + transform the receiver to
> > + (var := receiver)
> > + which is further transformed to
> > + (var := receiver) == nil ifTrue: .... ifFalse: ...
> > + This does not allow the block variable to shadow an existing temp,
> but it's no different
> > + from how to:do: is done."
> > + | ifNotNilArg |
> > + ifNotNilArg := arguments at: 2.
> > + ((self checkBlock: (arguments at: 1) as: 'Nil arg' from: encoder
> maxArgs: 0)
> > + and: [self checkBlock: ifNotNilArg as: 'NotNil arg' from: encoder
> maxArgs: 1]) ifFalse:
> > + [^false].
> > +
> > + ifNotNilArg numberOfArguments = 1 ifTrue:
> > + [receiver := AssignmentNode new
> > + variable: ifNotNilArg firstArgument
> > + value: receiver.
> > + encoder noteSourceRange: (encoder sourceRangeFor: self)
> forNode: receiver].
> > +
> > + selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro.
> > + receiver := MessageNode new
> > + receiver: receiver
> > + selector: #==
> > + arguments: (Array with: NodeNil)
> > + precedence: 2
> > + from: encoder.
> > + encoder noteSourceRange: (encoder sourceRangeFor: self) forNode:
> receiver.
> > + arguments do: [:arg| arg noteOptimizedIn: self].
> > + ^true!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformIfNotNilIfNil: (in category 'macro
> transformations') -----
> > + transformIfNotNilIfNil: encoder
> > + "vb: Changed to support one-argument ifNotNil: branch. In the 1-arg
> case we
> > + transform the receiver to
> > + (var := receiver)
> > + which is further transformed to
> > + (var := receiver) == nil ifTrue: .... ifFalse: ...
> > + This does not allow the block variable to shadow an existing temp,
> but it's no different
> > + from how to:do: is done."
> > + | ifNotNilArg |
> > + ifNotNilArg := arguments at: 1.
> > + ((self checkBlock: ifNotNilArg as: 'NotNil arg' from: encoder
> maxArgs: 1)
> > + and: [self checkBlock: (arguments at: 2) as: 'Nil arg' from:
> encoder maxArgs: 0]) ifFalse:
> > + [^false].
> > +
> > + ifNotNilArg numberOfArguments = 1 ifTrue:
> > + [receiver := AssignmentNode new
> > + variable: ifNotNilArg firstArgument
> > + value: receiver.
> > + encoder noteSourceRange: (encoder sourceRangeFor: self)
> forNode: receiver].
> > +
> > + selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro.
> > + receiver := MessageNode new
> > + receiver: receiver
> > + selector: #==
> > + arguments: (Array with: NodeNil)
> > + precedence: 2
> > + from: encoder.
> > + encoder noteSourceRange: (encoder sourceRangeFor: self) forNode:
> receiver.
> > + arguments swap: 1 with: 2.
> > + arguments do: [:arg| arg noteOptimizedIn: self].
> > + ^true!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformIfTrue: (in category 'macro
> transformations') -----
> > + transformIfTrue: encoder
> > + (self transformBoolean: encoder)
> > + ifTrue:
> > + [arguments :=
> > + Array
> > + with: ((arguments at: 1) noteOptimizedIn: self)
> > + with: ((BlockNode withJust: NodeNil)
> noteOptimizedIn: self).
> > + ^true]
> > + ifFalse:
> > + [^false]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformIfTrueIfFalse: (in category 'macro
> transformations') -----
> > + transformIfTrueIfFalse: encoder
> > + ^(self checkBlock: (arguments at: 1) as: 'True arg' from: encoder
> maxArgs: 0)
> > + and: [(self checkBlock: (arguments at: 2) as: 'False arg' from:
> encoder maxArgs: 0)
> > + and: [arguments do: [:arg| arg noteOptimizedIn: self].
> > + true]]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformOr: (in category 'macro
> transformations') -----
> > + transformOr: encoder
> > + (self transformBoolean: encoder)
> > + ifTrue:
> > + [arguments :=
> > + Array
> > + with: ((BlockNode withJust: NodeTrue)
> noteOptimizedIn: self)
> > + with: ((arguments at: 1) noteOptimizedIn: self).
> > + ^true]
> > + ifFalse:
> > + [^false]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformRepeat: (in category 'macro
> transformations') -----
> > + transformRepeat: encoder
> > + "answer true if this #repeat message can be optimized"
> > +
> > + ^(self checkBlock: receiver as: 'receiver' from: encoder maxArgs: 0)
> > + and: [receiver noteOptimizedIn: self.
> > + true]!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformToDo: (in category 'macro
> transformations') -----
> > + transformToDo: encoder
> > + " var := rcvr. L1: [var <= arg1] Bfp(L2) [block body. var := var +
> inc] Jmp(L1) L2: "
> > + | limit increment block initStmt test incStmt limitInit blockVar
> myRange blockRange |
> > + block := arguments last.
> > + "First check for valid arguments"
> > + (block notNil
> > + and: [block isBlockNode
> > + and: [block numberOfArguments = 1
> > + and: [block firstArgument isVariableReference "As with debugger
> remote vars"]]]) ifFalse:
> > + [^false].
> > + arguments size = 3
> > + ifTrue: [increment := arguments at: 2.
> > + (increment isConstantNumber
> > + and: [increment literalValue ~= 0]) ifFalse: [^false]]
> > + ifFalse: [increment := encoder encodeLiteral: 1].
> > + (limit := arguments at: 1) isVariableReference ifTrue:
> > + [| shouldScanForAssignment |
> > + shouldScanForAssignment := limit isArg not
> > + or: [limit isBlockArg and:
> [Scanner allowBlockArgumentAssignment]].
> > + shouldScanForAssignment ifTrue:
> > + [block nodesDo:
> > + [:node|
> > + (node isAssignmentNode and: [node variable = limit])
> ifTrue:
> > + [^false]]]].
> > + arguments size < 3 ifTrue: "transform to full form"
> > + [selector := SelectorNode new key: #to:by:do: code: #macro].
> > +
> > + "Now generate auxiliary structures"
> > + myRange := encoder rawSourceRanges at: self ifAbsent: [1 to: 0].
> > + blockRange := encoder rawSourceRanges at: block ifAbsent: [1 to: 0].
> > + blockVar := block firstArgument.
> > + initStmt := AssignmentNode new variable: blockVar value: receiver.
> > + (limit isVariableReference or: [limit isConstantNumber])
> > + ifTrue: [limitInit := nil]
> > + ifFalse: "Need to store limit in a var"
> > + [limit := encoder bindBlockArg: blockVar key, 'LimiT'
> within: block.
> > + limit scope: -2. "Already done parsing block; flag so it
> won't print"
> > + block addArgument: limit.
> > + limitInit := AssignmentNode new
> > + variable: limit
> > + value: arguments first].
> > + test := MessageNode new
> > + receiver: blockVar
> > + selector: (increment key > 0 ifTrue: [#<=] ifFalse:
> [#>=])
> > + arguments: {limit}
> > + precedence: precedence
> > + from: encoder
> > + sourceRange: (myRange first to: blockRange first).
> > + incStmt := AssignmentNode new
> > + variable: blockVar
> > + value: (MessageNode new
> > + receiver: blockVar selector: #+
> > + arguments: {increment}
> > + precedence: precedence
> > + from: encoder
> > + sourceRange: (myRange last to: (myRange
> last max: blockRange last)))
> > + from: encoder
> > + sourceRange: (myRange last to: (myRange last max:
> blockRange last)).
> > + arguments := {limit. increment. block. initStmt. test. incStmt.
> limitInit}.
> > + block noteOptimizedIn: self.
> > + ^true!
> >
> > Item was added:
> > + ----- Method: MessageNode>>transformWhile: (in category 'macro
> transformations') -----
> > + transformWhile: encoder
> > + (self checkBlock: receiver as: 'receiver' from: encoder maxArgs: 0)
> ifFalse:
> > + [^false].
> > + arguments size = 0 ifTrue: "transform bodyless form to body form"
> > + [selector := SelectorNode new
> > + key: (special = 10 ifTrue: [#whileTrue:]
> ifFalse: [#whileFalse:])
> > + code: #macro.
> > + arguments := Array with: ((BlockNode withJust: NodeNil)
> noteOptimizedIn: self).
> > + receiver noteOptimizedIn: self.
> > + ^true].
> > + ^(self transformBoolean: encoder)
> > + and: [receiver noteOptimizedIn: self.
> > + arguments first noteOptimizedIn: self.
> > + true]!
> >
> > Item was added:
> > + ParseNode subclass: #MethodNode
> > + instanceVariableNames: 'selectorOrFalse precedence arguments block
> primitive encoder temporaries properties sourceText locationCounter
> localsPool'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !MethodNode commentStamp: 'eem 8/15/2010 10:49' prior: 0!
> > + I am the root of the parse tree..
> > +
> > + Instance Variables
> > + arguments: <SequenceableCollection>
> > + block: <BlockNode>
> > + encoder: <BytecodeEncoder>
> > + localsPool: <IdentitySet>
> > + locationCounter: <Integer>
> > + precedence: <Integer>
> > + primitive: <Integer>
> > + properties: <AdditionalMethodState|nil>
> > + selectorOrFalse: <Object>
> > + sourceText: <String|Text>
> > + temporaries: <SequenceableCollection>
> > +
> > + arguments
> > + - the collection of parsed or decompiled method arguments
> > +
> > + block
> > + - the BlockNode holding the method's statements
> > +
> > + encoder
> > + - the object that comprises the copiler's scope table, literal pool
> and back-end bytecode generator
> > +
> > + localsPool
> > + - a set used to determine the set of copied values for each block
> in the method
> > +
> > + locationCounter
> > + - an integer used to mark block scopes for the purposes of the
> closure transformation. See
> BlockNode>>#analyseArguments:temporaries:rootNode:
> > +
> > + precedence
> > + - the precedence of the method's selector (see Symbol>>precedence)
> > +
> > + primitive
> > + - if non-zero this is the integer code of the method's primitive
> > +
> > + properties
> > + - the object used to accumulate method properties (a.k.a. pragmas)
> > +
> > + selectorOrFalse
> > + - the method's selector or false if this is a doit
> > +
> > + sourceText
> > + - the source test from which the method was compiled
> > +
> > + temporaries
> > + - the collection of parsed or decompiled method temporaries
> > + !
> >
> > Item was added:
> > + ----- Method: MethodNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitMethodNode: self!
> >
> > Item was added:
> > + ----- Method: MethodNode>>addLocalsToPool: (in category 'closure
> analysis') -----
> > + addLocalsToPool: locals "<Set of: TempVariableNode>"
> > + localsPool isNil ifTrue:
> > + [localsPool := IdentitySet new].
> > + localsPool addAll: locals!
> >
> > Item was added:
> > + ----- Method: MethodNode>>arguments (in category 'accessing') -----
> > + arguments
> > + "For transformations etc, not used in compilation"
> > + ^arguments!
> >
> > Item was added:
> > + ----- Method: MethodNode>>arguments: (in category 'accessing') -----
> > + arguments: aSequence
> > + "For transformations etc, not used in compilation"
> > + arguments := aSequence!
> >
> > Item was added:
> > + ----- Method: MethodNode>>asColorizedSmalltalk80Text (in category
> 'converting') -----
> > + asColorizedSmalltalk80Text
> > + "Answer a colorized Smalltalk-80-syntax string description of the
> parse tree whose root is the receiver."
> > +
> > + | printText |
> > + printText := self printString asText.
> > + ^(TextStyler for: #Smalltalk)
> > + ifNotNil: [:stylerClass| stylerClass new styledTextFor:
> printText]
> > + ifNil: [printText]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>block (in category 'initialize-release')
> -----
> > + block
> > + ^ block!
> >
> > Item was added:
> > + ----- Method: MethodNode>>blockExtentsToTempsMap (in category
> 'debugger support') -----
> > + blockExtentsToTempsMap
> > + "Answer a Dictionary of blockExtent to temp locations for the
> current method.
> > + This is used by the debugger to locate temp vars in contexts. A
> temp map
> > + entry is a pair of the temp's name and its index, where an index
> is either an
> > + integer for a normal temp or a pair of the index of the indirect
> temp vector
> > + containing the temp and the index of the temp in its indirect
> temp vector."
> > +
> > + ^encoder blockExtentsToTempsMap ifNil:
> > + [| methNode |
> > + methNode := encoder classEncoding newParser
> > + encoderClass: encoder class;
> > + parse: (sourceText ifNil: [self
> decompileString])
> > + class: self methodClass.
> > + "As a side effect generate: creates data needed for the map."
> > + methNode generate.
> > + methNode encoder blockExtentsToTempsMap]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>body (in category 'accessing') -----
> > + body
> > + ^block!
> >
> > Item was added:
> > + ----- Method: MethodNode>>decompileString (in category 'converting')
> -----
> > + decompileString
> > + "Answer a string description of the parse tree whose root is the
> receiver."
> > +
> > + ^self fullPrintString
> > + !
> >
> > Item was added:
> > + ----- Method: MethodNode>>decompileText (in category 'converting')
> -----
> > + decompileText
> > + "Answer a string description of the parse tree whose root is the
> receiver."
> > +
> > + ^self asColorizedSmalltalk80Text!
> >
> > Item was added:
> > + ----- Method: MethodNode>>encoder (in category 'code generation') -----
> > + encoder
> > + ^ encoder!
> >
> > Item was added:
> > + ----- Method: MethodNode>>ensureClosureAnalysisDone (in category
> 'closure analysis') -----
> > + ensureClosureAnalysisDone
> > + block blockExtent ifNil:
> > + [temporaries := block analyseArguments: arguments temporaries:
> temporaries rootNode: self]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>ensureNotQuick (in category 'converting')
> -----
> > + ensureNotQuick
> > + "If the receiver is quick (can be generated as a Quick method,
> ^self,^inst var or ^ special constant)
> > + make it not so. This is used to create break-pointable versions
> of quick methods. Answer if the
> > + receiver was quick."
> > + ^block ensureNotQuick: encoder!
> >
> > Item was added:
> > + ----- Method: MethodNode>>generate (in category 'code generation')
> -----
> > + generate
> > + "The receiver is the root of a parse tree. Answer a CompiledMethod.
> The
> > + argument, trailer, is the references to the source code that is
> stored with
> > + every CompiledMethod."
> > +
> > + ^self generate: CompiledMethodTrailer empty using: CompiledMethod!
> >
> > Item was added:
> > + ----- Method: MethodNode>>generate: (in category 'code generation')
> -----
> > + generate: trailer
> > + "The receiver is the root of a parse tree. Answer a CompiledMethod.
> > + The argument, trailer, is arbitrary but is typically either the
> reference
> > + to the source code that is stored with every CompiledMethod, or an
> > + encoding of the method's temporary names."
> > +
> > + ^self generate: trailer using: CompiledMethod!
> >
> > Item was added:
> > + ----- Method: MethodNode>>generate:ifQuick: (in category 'code
> generation') -----
> > + generate: trailer ifQuick: methodBlock
> > + ^self generate: trailer using: CompiledMethod ifQuick: methodBlock!
> >
> > Item was added:
> > + ----- Method: MethodNode>>generate:using: (in category 'code
> generation') -----
> > + generate: trailer using: aCompiledMethodClass
> > + "The receiver is the root of a parse tree. Answer an instance of
> aCompiledMethodClass.
> > + The argument, trailer, is arbitrary but is typically either the
> reference to the source code
> > + that is stored with every CompiledMethod, or an encoding of the
> method's temporary names."
> > +
> > + | method |
> > + self generate: trailer
> > + using: aCompiledMethodClass
> > + ifQuick:
> > + [:m |
> > + m literalAt: 2 put: encoder associationForClass;
> > + properties: properties.
> > + ^m].
> > + method := encoder generateMethodOfClass: aCompiledMethodClass
> trailer: trailer from: self.
> > + method properties: properties.
> > + ^method!
> >
> > Item was added:
> > + ----- Method: MethodNode>>generate:using:ifQuick: (in category 'code
> generation') -----
> > + generate: trailer using: aCompiledMethodClass ifQuick: methodBlock
> > + | v |
> > + (primitive = 0 and: [arguments size = 0 and: [block isQuick]])
> ifFalse:
> > + [^self].
> > + v := block code.
> > + v < 0 ifTrue:
> > + [^self].
> > + v = LdSelf ifTrue:
> > + [^methodBlock value: (aCompiledMethodClass
> toReturnSelfTrailerBytes: trailer)].
> > + (v between: LdTrue and: LdMinus1 + 3) ifTrue:
> > + [^methodBlock value: (aCompiledMethodClass toReturnConstant: v
> - LdSelf trailerBytes: trailer)].
> > + v < ((CodeBases at: LdInstType) + (CodeLimits at: LdInstType))
> ifTrue:
> > + [^methodBlock value: (aCompiledMethodClass toReturnField: v
> trailerBytes: trailer)].
> > + v // 256 = 1 ifTrue:
> > + [^methodBlock value: (aCompiledMethodClass toReturnField: v \\
> 256 trailerBytes: trailer)]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>generateWithTempNames (in category 'code
> generation') -----
> > + generateWithTempNames
> > + "Answer a CompiledMethod with temps names encoded in its trailer."
> > + | methodSansTempNames |
> > + "The encoder computes the schematic temp names during generation,
> so
> > + generate a method without temp names first. If the method is
> quick there are
> > + no temps and hence no temp names."
> > + methodSansTempNames := self
> > + generate: CompiledMethodTrailer
> empty
> > + using: CompiledMethod.
> > + ^methodSansTempNames
> > + copyWithTrailerBytes:
> > + ((CompiledMethodTrailer new tempNames:
> > + (methodSansTempNames isQuick
> > + ifTrue: ['']
> > + ifFalse: [encoder schematicTempNamesString])))!
> >
> > Item was added:
> > + ----- Method: MethodNode>>hasGeneratedMethod (in category 'debugger
> support') -----
> > + hasGeneratedMethod
> > + ^encoder hasGeneratedMethod!
> >
> > Item was added:
> > + ----- Method: MethodNode>>locationCounter (in category 'closure
> analysis') -----
> > + locationCounter
> > + ^locationCounter!
> >
> > Item was added:
> > + ----- Method: MethodNode>>methodClass (in category 'printing') -----
> > + methodClass
> > +
> > + ^ encoder classEncoding!
> >
> > Item was added:
> > + ----- Method: MethodNode>>noteBlockEntry: (in category 'closure
> analysis') -----
> > + noteBlockEntry: aBlock
> > + "Evaluate aBlock with the numbering for the block entry."
> > + locationCounter isNil ifTrue:
> > + [locationCounter := -1].
> > + aBlock value: locationCounter + 1.
> > + locationCounter := locationCounter + 2!
> >
> > Item was added:
> > + ----- Method: MethodNode>>noteBlockExit: (in category 'closure
> analysis') -----
> > + noteBlockExit: aBlock
> > + "Evaluate aBlock with the numbering for the block exit."
> > + aBlock value: locationCounter + 1.
> > + locationCounter := locationCounter + 2!
> >
> > Item was added:
> > + ----- Method: MethodNode>>parserClass (in category 'code generation')
> -----
> > + parserClass
> > + "Which parser produces this class of parse node"
> > +
> > + ^ Parser!
> >
> > Item was added:
> > + ----- Method: MethodNode>>preen (in category 'converting') -----
> > + preen
> > + "Preen for pretty-printing and/or decompilation.
> > + i.e. post-process to cover up for inadequacies in both algorithms.
> > +
> > + Currently two cases:
> > +
> > + preenLocalIfNotNilArg: blockNode
> > + hiding the assignment to the arg of an inlined block arg to
> ifNotNil:,
> > + (var := expr) ifNil: [...] ifNotNil: [...] => expr
> ifNil: [...] ifNotNil: [:var| ...].
> > +
> > + preenTempsConflictingWithBlockNode: temps
> > + hiding the declaration of a temp that is redeclared in some
> block"
> > +
> > + self preenableNodes keysAndValuesDo:
> > + [:nodeOrArray :selector |
> > + self perform: selector with: nodeOrArray]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>preenIfNotNilNode: (in category
> 'converting-private') -----
> > + preenIfNotNilNode: messageNode
> > + "Transform a (var := expr) ifNil: [...] ifNotNil: [...] where var
> is only used in the ifNotNil: block
> > + and convert it to expr ifNil: [...] ifNotNil: [:var| ...]. Deal
> both with the pretty-print case where
> > + the block already declares the variable and the decompile case
> where it does not."
> > +
> > + | variable |
> > + self assert: (messageNode isMessageNode
> > + and: [messageNode macroPrinter ==
> #printIfNilNotNil:indent:
> > + and: [messageNode receiver receiver isAssignmentNode]]).
> > + variable := messageNode receiver receiver variable.
> > + self assert: (variable isTemp and: [variable isRemote not]).
> > + messageNode arguments last arguments isEmpty
> > + ifTrue: [messageNode arguments last arguments: { variable }]
> > + ifFalse:
> > + [self assert: messageNode arguments last arguments asArray
> = { variable }.
> > + variable := nil].
> > + messageNode receiver receiver: messageNode receiver receiver value.
> > + variable ifNil: [^self].
> > + self nodesDo:
> > + [:node|
> > + ((node == self or: [node isBlockNode])
> > + and: [node temporaries includes: variable]) ifTrue:
> > + [node temporaries: (node temporaries copyWithout:
> variable)]]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>preenNilNodeFollowingNilIfNode: (in category
> 'converting-private') -----
> > + preenNilNodeFollowingNilIfNode: aNilIfMessageNode
> > + self nodesDo:
> > + [:node| | statements indices |
> > + (node isBlockNode
> > + and: [(statements := node statements) includes:
> aNilIfMessageNode]) ifTrue:
> > + [indices := (2 to: statements size) reject:
> > + [:i|
> > + (statements at: i) == NodeNil
> > + and: [(statements at: i - 1) isNilIf]].
> > + node statements: (({1}, indices) collect: [:i| statements
> at: i])]]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>preenTempsConflictingWithBlockNode: (in
> category 'converting-private') -----
> > + preenTempsConflictingWithBlockNode: temps
> > + "Push temps that conflict with other blocks down into their
> narrowest enclosing block scope."
> > + temps do:
> > + [:tempVar|
> > + (self accept: (NarrowerVariableScopeFinder new ofVariable:
> tempVar)) ifNotNil:
> > + [:enclosingScope |
> > + self assert: enclosingScope isBlockNode.
> > + self nodesDo:
> > + [:node|
> > + ((node == self or: [node isBlockNode])
> > + and: [node temporaries includes: tempVar]) ifTrue:
> > + [node temporaries: (node temporaries copyWithout:
> tempVar)]].
> > + enclosingScope temporaries: enclosingScope temporaries, {
> tempVar }]]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>preenableNodes (in category
> 'converting-private') -----
> > + preenableNodes
> > + "Answer a Dictionary from node or sequence of nodes to preen method
> selector for nodes
> > + in the tree that require post-processing after either a format or
> a decompile. Such issues
> > + are the variable for an ifNotNil: which is local to the ifNotNil:
> block but, due to the inlining
> > + of ifNotNil: appears to be declared at the outer level, and,
> similarly, a temporary variable
> > + that conflicts with one of the same name in a block when, were the
> variable declared
> > + local to some inlined block it would no longer conflict. The
> resulting dictionary is used to
> > + perform the value with the key (node or array) as argument to
> preen the tree."
> > +
> > + | preenableNodes priorBlocks priorVariables |
> > + preenableNodes := Dictionary new.
> > + priorBlocks := OrderedCollection new.
> > + priorVariables := Set new.
> > + self nodesWithPrecedingStatementsDo:
> > + [:node :precedingStatementOrNil| | variable temps |
> > + (node isMessageNode
> > + and: [node macroPrinter == #printIfNilNotNil:indent:
> > + and: [node receiver isMessageNode
> > + and: [node receiver selector key == #==
> > + and: [node receiver receiver isAssignmentNode
> > + and: [(variable := node receiver receiver variable) isTemp
> > + and: [variable isRemote not
> > + and: [variable isOnlySubnodeOf: node in: self]]]]]]]) ifTrue:
> > + [preenableNodes at: node put: #preenIfNotNilNode:.
> > + priorVariables add: variable].
> > + node isBlockNode ifTrue:
> > + [temps := OrderedCollection new.
> > + node temporaries do:
> > + [:temp|
> > + priorBlocks do:
> > + [:aBlock|
> > + aBlock temporaries do:
> > + [:priorTemp|
> > + (priorVariables includes: priorTemp) ifFalse:
> > + [priorTemp key = temp key ifTrue:
> > + [temps addLast: priorTemp]]]]].
> > + temps isEmpty ifFalse:
> > + [preenableNodes at: temps put:
> #preenTempsConflictingWithBlockNode:].
> > + priorBlocks addLast: node].
> > + (node == NodeNil
> > + and: [precedingStatementOrNil notNil
> > + and: [precedingStatementOrNil isMessageNode
> > + and: [precedingStatementOrNil isNilIf]]]) ifTrue:
> > + [preenableNodes at: precedingStatementOrNil put:
> #preenNilNodeFollowingNilIfNode:]].
> > + ^preenableNodes!
> >
> > Item was added:
> > + ----- Method: MethodNode>>primitive (in category 'accessing') -----
> > + primitive
> > + ^primitive!
> >
> > Item was added:
> > + ----- Method: MethodNode>>primitiveErrorVariableName (in category
> 'accessing') -----
> > + primitiveErrorVariableName
> > + "Answer the primitive error code temp name, or nil if none."
> > + (primitive isInteger and: [primitive > 0]) ifTrue:
> > + [properties pragmas do:
> > + [:pragma| | kwds ecIndex |
> > + ((kwds := pragma keyword keywords) first = 'primitive:'
> > + and: [(ecIndex := kwds indexOf: 'error:') > 0]) ifTrue:
> > + [^pragma argumentAt: ecIndex]]].
> > + ^nil
> > +
> > + "(Parser new parse: (MethodNode sourceCodeAt:
> #primitiveErrorVariableName) class: Parser) primitiveErrorVariableName"
> > +
> > + "(Parser new parse: 'foo <primitive: 111 error: ''foo''> self
> primitiveFailed' class: Object) primitiveErrorVariableName"
> > +
> > + "(Parser new parse: 'foo <primitive: 111 error: foo> self
> primitiveFailed' class: Object) primitiveErrorVariableName"
> > +
> > + "(Parser new parse: 'foo <primitive: 111> self primitiveFailed'
> class: Object) primitiveErrorVariableName"
> > +
> > + "(Parser new parse: 'foo <primitive: ''foo'' error: foo module:
> ''bar''> self primitiveFailed' class: Object) primitiveErrorVariableName"
> > +
> > + "(Parser new parse: 'foo <primitive: ''foo'' module: ''bar'' error:
> foo> self primitiveFailed' class: Object) primitiveErrorVariableName"
> > +
> > + "(Parser new parse: 'foo <primitive: 111 error: foo> self
> primitiveFailed' class: Object) generate"!
> >
> > Item was added:
> > + ----- Method: MethodNode>>printOn: (in category 'printing') -----
> > + printOn: aStream
> > + | selectorNode |
> > + selectorNode := self selectorNode.
> > + precedence = 1
> > + ifTrue:
> > + [selectorNode isForFFICall
> > + ifTrue: [selectorNode
> > + printAsFFICallWithArguments: arguments
> > + on: aStream
> > + indent: 0]
> > + ifFalse: [aStream nextPutAll: selectorNode key]]
> > + ifFalse:
> > + [selectorNode key keywords with: arguments do:
> > + [:kwd :arg |
> > + aStream nextPutAll: kwd; space; nextPutAll: arg key;
> space]].
> > + comment == nil ifFalse:
> > + [aStream crtab: 1.
> > + self printCommentOn: aStream indent: 1].
> > + block printTemporaries: temporaries on: aStream doPrior: [aStream
> crtab: 1].
> > + primitive > 0 ifTrue:
> > + [(primitive between: 255 and: 519) ifFalse: "Dont decompile
> quick prims e.g, ^ self or ^instVar"
> > + [aStream crtab: 1.
> > + self printPrimitiveOn: aStream]].
> > + self printPropertiesOn: aStream.
> > + self printPragmasOn: aStream.
> > + aStream crtab: 1.
> > + block printStatementsOn: aStream indent: 0!
> >
> > Item was added:
> > + ----- Method: MethodNode>>printPragmasOn: (in category 'printing')
> -----
> > + printPragmasOn: aStream
> > + properties ifNil: [^self].
> > + properties pragmas do:
> > + [:pragma|
> > + "Primitives are printed in printPrimitiveOn:; skip these"
> > + (Parser primitivePragmaSelectors includes: pragma keyword)
> ifFalse:
> > + [aStream crtab: 1; nextPut: $<; print: pragma message;
> nextPut: $>]]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>printPrimitiveOn: (in category 'printing')
> -----
> > + printPrimitiveOn: aStream
> > + "Print the primitive on aStream"
> > + | primDecl |
> > + primitive = 0 ifTrue:
> > + [^self].
> > + primitive = 120 ifTrue: "External call spec"
> > + [^aStream print: encoder literals first].
> > + aStream nextPutAll: '<primitive: '.
> > + primitive = 117
> > + ifTrue:
> > + [primDecl := encoder literals at: 1.
> > + (primDecl at: 2) asString printOn: aStream.
> > + (primDecl at: 1) ifNotNil:
> > + [:moduleName|
> > + aStream nextPutAll:' module: '.
> > + moduleName asString printOn: aStream]]
> > + ifFalse:
> > + [aStream print: primitive].
> > + self primitiveErrorVariableName ifNotNil:
> > + [:primitiveErrorVariableName|
> > + aStream nextPutAll: ' error: '; nextPutAll:
> primitiveErrorVariableName].
> > + aStream nextPut: $>.
> > + ((Smalltalk classNamed: #StackInterpreter) ifNil: [Smalltalk
> classNamed: #Interpreter]) ifNotNil:
> > + [:interpreterClass|
> > + aStream nextPutAll: ' "', (interpreterClass primitiveTable at:
> primitive + 1), '" ']!
> >
> > Item was added:
> > + ----- Method: MethodNode>>printPropertiesOn: (in category 'printing')
> -----
> > + printPropertiesOn: aStream
> > + properties ifNil: [^self].
> > + properties propertyKeysAndValuesDo:
> > + [:prop :val|
> > + aStream crtab; nextPut: $<.
> > + prop = #on:in:
> > + ifTrue:
> > + [prop keywords with: val do:
> > + [:k :v | aStream nextPutAll: k; space; nextPutAll:
> v; space]]
> > + ifFalse:
> > + [prop = #on
> > + ifTrue: [aStream nextPutAll: prop; nextPutAll:': ';
> nextPutAll: val]
> > + ifFalse: [aStream nextPutAll: prop; nextPutAll:':
> '; print: val]].
> > + aStream nextPut: $>]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>printWithClosureAnalysisOn: (in category
> 'printing') -----
> > + printWithClosureAnalysisOn: aStream
> > + self ensureClosureAnalysisDone.
> > + precedence = 1
> > + ifTrue:
> > + [(self selector includesSubstring: '()/')
> > + ifTrue: [aStream nextPutAll: (self selector copyUpTo:
> $)).
> > + arguments
> > + do: [:arg| aStream nextPutAll: arg key]
> > + separatedBy: [aStream nextPutAll: ', '].
> > + aStream nextPut: $)]
> > + ifFalse: [aStream nextPutAll: self selector]] "no node
> for method selector"
> > + ifFalse:
> > + [self selector keywords with: arguments do:
> > + [:kwd :arg |
> > + aStream nextPutAll: kwd; space.
> > + arg printDefinitionForClosureAnalysisOn: aStream.
> > + aStream space]].
> > + comment == nil ifFalse:
> > + [aStream crtab: 1.
> > + self printCommentOn: aStream indent: 1].
> > + temporaries size > 0 ifTrue:
> > + [aStream crtab: 1; nextPut: $|.
> > + temporaries do: [:temp |
> > + aStream space.
> > + temp printDefinitionForClosureAnalysisOn: aStream].
> > + aStream space; nextPut: $|].
> > + primitive > 0 ifTrue:
> > + [(primitive between: 255 and: 519) ifFalse: "Dont decompile
> quick prims e.g, ^ self or ^instVar"
> > + [aStream crtab: 1.
> > + self printPrimitiveOn: aStream]].
> > + self printPropertiesOn: aStream.
> > + self printPragmasOn: aStream.
> > + aStream crtab: 1.
> > + block printWithClosureAnalysisStatementsOn: aStream indent: 0!
> >
> > Item was added:
> > + ----- Method: MethodNode>>properties (in category 'code generation')
> -----
> > + properties
> > + ^properties!
> >
> > Item was added:
> > + ----- Method: MethodNode>>rawSourceRanges (in category 'source
> mapping') -----
> > + rawSourceRanges
> > +
> > + ^self rawSourceRangesAndMethodDo: [:rawSourceRanges :method|
> rawSourceRanges]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>rawSourceRangesAndMethodDo: (in category
> 'source mapping') -----
> > + rawSourceRangesAndMethodDo: aBinaryBlock
> > + "Evaluate aBinaryBlock with the rawSourceRanges and method
> generated from the receiver."
> > +
> > + | methNode method |
> > + methNode := encoder classEncoding newParser
> > + encoderClass: encoder class;
> > + parse: (sourceText "If no source, use decompile
> string as source to map from"
> > + ifNil: [self decompileString]
> > + ifNotNil: [sourceText])
> > + class: self methodClass.
> > + method := methNode generate. "set bytecodes to map to"
> > + ^aBinaryBlock
> > + value: methNode encoder rawSourceRanges
> > + value: method!
> >
> > Item was added:
> > + ----- Method: MethodNode>>referencedValuesWithinBlockExtent: (in
> category 'closure analysis') -----
> > + referencedValuesWithinBlockExtent: anInterval
> > + ^(localsPool select:
> > + [:temp|
> > + temp isReferencedWithinBlockExtent: anInterval]) collect:
> > + [:temp|
> > + temp isRemote ifTrue: [temp remoteNode] ifFalse: [temp]]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>removeAndRenameLastTempIfErrorCode (in
> category 'primitive error codes') -----
> > + removeAndRenameLastTempIfErrorCode
> > + self primitiveErrorVariableName ifNotNil:
> > + [:primitiveErrorVariableName|
> > + temporaries last
> > + name: primitiveErrorVariableName
> > + key: primitiveErrorVariableName
> > + code: temporaries last code.
> > + temporaries removeLast].!
> >
> > Item was added:
> > + ----- Method: MethodNode>>removeProperty: (in category 'accessing')
> -----
> > + removeProperty: aSymbol
> > + properties := properties copyWithout: (Association
> > + key: aSymbol
> > + value: (properties
> propertyValueAt: aSymbol))!
> >
> > Item was added:
> > + ----- Method: MethodNode>>schematicTempNamesString (in category
> 'debugger support') -----
> > + schematicTempNamesString
> > + "Answer the temp names for the current method node in a form that
> captures
> > + temp structure. The temps at each method and block scope level
> occur
> > + space-separated, with any indirect temps enclosed in parentheses.
> Each block
> > + level is enclosed in square brackets. e.g.
> > + 'method level temps (indirect temp)[block args and temps
> (indirect)]'
> > + This representation can be reconstituted into a
> blockExtentsToTempsMap
> > + by a CompiledMethod that has been copied with the
> schematicTempNamesString."
> > + encoder hasGeneratedMethod ifFalse:
> > + ["create the encoder's blockExtentsToLocals map, except if the
> method is quick
> > + in which case it has no temps."
> > + self generate isQuick ifTrue:
> > + [^'']].
> > + ^encoder schematicTempNamesString!
> >
> > Item was added:
> > + ----- Method: MethodNode>>selector (in category 'code generation')
> -----
> > + selector
> > + "Answer the message selector for the method represented by the
> receiver."
> > +
> > + (selectorOrFalse isSymbol)
> > + ifTrue: [^selectorOrFalse].
> > + ^selectorOrFalse key.
> > + !
> >
> > Item was added:
> > + ----- Method: MethodNode>>selector: (in category 'initialize-release')
> -----
> > + selector: symbol
> > +
> > + selectorOrFalse := symbol!
> >
> > Item was added:
> > + ----- Method:
> MethodNode>>selector:arguments:precedence:temporaries:block:encoder:primitive:
> (in category 'initialize-release') -----
> > + selector: selOrFalse arguments: args precedence: p temporaries: temps
> block: blk encoder: anEncoder primitive: prim
> > +
> > + self
> > + selector: selOrFalse
> > + arguments: args
> > + precedence: p
> > + temporaries: temps
> > + block: blk encoder:
> > + anEncoder
> > + primitive: prim
> > + properties: AdditionalMethodState new.!
> >
> > Item was added:
> > + ----- Method:
> MethodNode>>selector:arguments:precedence:temporaries:block:encoder:primitive:properties:
> (in category 'initialize-release') -----
> > + selector: selOrFalse arguments: args precedence: p temporaries: temps
> block: blk encoder: anEncoder primitive: prim properties: propDict
> > + "Initialize the receiver with respect to the arguments given."
> > +
> > + encoder := anEncoder.
> > + selectorOrFalse := selOrFalse.
> > + precedence := p.
> > + arguments := args.
> > + temporaries := temps.
> > + block := blk.
> > + primitive := prim.
> > + properties := propDict.!
> >
> > Item was added:
> > + ----- Method: MethodNode>>selectorNode (in category 'code generation')
> -----
> > + selectorNode
> > + "Answer a SelectorNode for the message selector of the method
> represented by the receiver."
> > +
> > + ^(selectorOrFalse isKindOf: SelectorNode)
> > + ifTrue: [selectorOrFalse]
> > + ifFalse: [SelectorNode new key: selectorOrFalse]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>sourceText (in category 'printing') -----
> > + sourceText
> > +
> > + ^ sourceText ifNil: [self printString]!
> >
> > Item was added:
> > + ----- Method: MethodNode>>sourceText: (in category
> 'initialize-release') -----
> > + sourceText: stringOrText
> > +
> > + sourceText := stringOrText!
> >
> > Item was added:
> > + ----- Method: MethodNode>>tempNames (in category 'printing') -----
> > + tempNames
> > + ^ encoder tempNames!
> >
> > Item was added:
> > + ----- Method: MethodNode>>temporaries (in category 'accessing') -----
> > + temporaries
> > + "For transformations etc, not used in compilation"
> > + ^temporaries!
> >
> > Item was added:
> > + ----- Method: MethodNode>>temporaries: (in category 'accessing') -----
> > + temporaries: aSequence
> > + "For transformations etc, not used in compilation"
> > + temporaries := aSequence!
> >
> > Item was added:
> > + ParseNode subclass: #MethodTempsNode
> > + instanceVariableNames: 'temporaries'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> >
> > Item was added:
> > + VariableScopeFinder subclass: #NarrowerVariableScopeFinder
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> > +
> > + !NarrowerVariableScopeFinder commentStamp: 'eem 4/3/2017 11:59' prior:
> 0!
> > + A NarrowerVariableScopeFinder is used to find a smaller scope for an
> already declared variable.!
> >
> > Item was added:
> > + ----- Method: NarrowerVariableScopeFinder>>visitTempVariableNode: (in
> category 'visiting') -----
> > + visitTempVariableNode: aVariableNode
> > + ^theVariable = aVariableNode ifTrue: [theVariable]!
> >
> > Item was added:
> > + ----- Method:
> NarrowerVariableScopeFinder>>visitUndeclaredVariableNode: (in category
> 'visiting') -----
> > + visitUndeclaredVariableNode: aVariableNode
> > + ^nil!
> >
> > Item was added:
> > + ParseNode subclass: #NewArrayNode
> > + instanceVariableNames: 'numElements'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !NewArrayNode commentStamp: '<historical>' prior: 0!
> > + I represent a node for the genPushNewArray: opcode.!
> >
> > Item was added:
> > + ----- Method: NewArrayNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitNewArrayNode: self!
> >
> > Item was added:
> > + ----- Method:
> NewArrayNode>>analyseTempsWithin:rootNode:assignmentPools: (in category
> 'closure analysis') -----
> > + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode
> "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + "This is a no-op except in TempVariableNode"
> > + ^self!
> >
> > Item was added:
> > + ----- Method: NewArrayNode>>emitCodeForValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + encoder genPushNewArray: numElements.
> > + stack push: 1!
> >
> > Item was added:
> > + ----- Method: NewArrayNode>>numElements (in category 'accessing') -----
> > + numElements
> > + ^numElements!
> >
> > Item was added:
> > + ----- Method: NewArrayNode>>numElements: (in category 'accessing')
> -----
> > + numElements: n
> > + numElements := n!
> >
> > Item was added:
> > + ----- Method: NewArrayNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + ^encoder sizePushNewArray: numElements!
> >
> > Item was added:
> > + ParseNodeVisitor subclass:
> #OptimizedBlockLocalTempReadBeforeWrittenVisitor
> > + instanceVariableNames: 'inOptimizedBlock readBeforeWritten written'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> > +
> > + !OptimizedBlockLocalTempReadBeforeWrittenVisitor commentStamp:
> '<historical>' prior: 0!
> > + Answer the set of temporary variables that are read before they are
> written in the visited parse tree. Used by the compiler to detect those
> block-local temporaries of blocks in optimized loops that require nilling
> to prevent a value from a previous iteration persisting into a subsequent
> one.!
> >
> > Item was added:
> > + ----- Method:
> OptimizedBlockLocalTempReadBeforeWrittenVisitor>>initialize (in category
> 'initialize-release') -----
> > + initialize
> > + inOptimizedBlock := false!
> >
> > Item was added:
> > + ----- Method:
> OptimizedBlockLocalTempReadBeforeWrittenVisitor>>readBeforeWritten (in
> category 'accessing') -----
> > + readBeforeWritten
> > + ^readBeforeWritten ifNil: [IdentitySet new]!
> >
> > Item was added:
> > + ----- Method:
> OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitAssignmentNode: (in
> category 'visiting') -----
> > + visitAssignmentNode: anAssignmentNode
> > + anAssignmentNode value accept: self.
> > + anAssignmentNode variable isTemp
> > + ifTrue:
> > + [written ifNil: [written := IdentitySet new].
> > + written add: anAssignmentNode variable]
> > + ifFalse:
> > + [anAssignmentNode variable accept: self]!
> >
> > Item was added:
> > + ----- Method:
> OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitBlockNode: (in
> category 'visiting') -----
> > + visitBlockNode: aBlockNode
> > + | savedWritten |
> > + "If we're in the optimized block in one side of an optimized
> ifTrue:ifFalse: et al
> > + leave it to the enclosing visitMessageNode: activation to handle
> merging written."
> > + inOptimizedBlock ifTrue:
> > + [^super visitBlockNode: aBlockNode].
> > + "If we're not then don't update written because without evaluating
> the guard(s)
> > + we can't tell if the block is evaluated or not, and we must avoid
> false positives."
> > + savedWritten := written copy.
> > + super visitBlockNode: aBlockNode.
> > + written := savedWritten!
> >
> > Item was added:
> > + ----- Method:
> OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitMessageNode: (in
> category 'visiting') -----
> > + visitMessageNode: aMessageNode
> > + | savedWritten writtenPostFirstArm |
> > + (aMessageNode isOptimized
> > + and: [#(ifTrue:ifFalse: ifFalse:ifTrue: ifNil:ifNotNil:
> ifNotNil:ifNil:) includes: aMessageNode selector key]) ifFalse:
> > + [^super visitMessageNode: aMessageNode].
> > + aMessageNode receiver accept: self.
> > + aMessageNode selector accept: self.
> > + savedWritten := written copy.
> > + aMessageNode argumentsInEvaluationOrder
> > + do: [:argument|
> > + argument isBlockNode
> > + ifTrue: [| savedIOB |
> > + savedIOB := inOptimizedBlock.
> > + inOptimizedBlock := true.
> > + [argument accept: self]
> > + ensure: [inOptimizedBlock := savedIOB]]
> > + ifFalse: [argument accept: self]]
> > + separatedBy:
> > + [writtenPostFirstArm := written.
> > + written := savedWritten].
> > + (written notNil
> > + and: [writtenPostFirstArm notNil]) ifTrue:
> > + [written := written intersection: writtenPostFirstArm]!
> >
> > Item was added:
> > + ----- Method:
> OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitTempVariableNode: (in
> category 'visiting') -----
> > + visitTempVariableNode: aTempVariableNode
> > + (aTempVariableNode isArg
> > + or: [written notNil
> > + and: [written includes: aTempVariableNode]]) ifTrue:
> > + [^self].
> > + readBeforeWritten ifNil:
> > + [readBeforeWritten := IdentitySet new].
> > + readBeforeWritten add: aTempVariableNode!
> >
> > Item was added:
> > + Notification subclass: #OutOfScopeNotification
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Exceptions'!
> >
> > Item was added:
> > + ----- Method: OutOfScopeNotification>>defaultAction (in category 'priv
> handling') -----
> > + defaultAction
> > +
> > + ^false!
> >
> > Item was added:
> > + Object subclass: #ParseNode
> > + instanceVariableNames: 'comment pc'
> > + classVariableNames: 'CodeBases CodeLimits LdFalse LdInstType
> LdLitIndType LdLitType LdMinus1 LdNil LdSelf LdSuper LdTempType
> LdThisContext LdTrue LoadLong NodeFalse NodeNil NodeSelf NodeSuper
> NodeThisContext NodeTrue Send SendPlus SendType StdLiterals StdSelectors
> StdVariables'
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !ParseNode commentStamp: '<historical>' prior: 0!
> > + This superclass of most compiler/decompiler classes declares common
> class variables, default messages, and the code emitters for jumps. Some of
> the class variables are initialized here; the rest are initialized in class
> VariableNode.!
> >
> > Item was added:
> > + ----- Method: ParseNode class>>initialize (in category 'class
> initialization') -----
> > + initialize
> > + "ParseNode initialize. VariableNode initialize"
> > + LdInstType := 1.
> > + LdTempType := 2.
> > + LdLitType := 3.
> > + LdLitIndType := 4.
> > + SendType := 5.
> > + "Back in the day the following constants corresponded to bytecodes.
> > + Now they're just unique values that need to be eliminated when and
> if
> > + things like code:type: are cleaned up."
> > + CodeBases := #(0 16 32 64 208 ).
> > + CodeLimits := #(16 16 32 32 16 ).
> > + LdSelf := 112.
> > + LdTrue := 113.
> > + LdFalse := 114.
> > + LdNil := 115.
> > + LdMinus1 := 116.
> > + LoadLong := 128.
> > + LdSuper := 133.
> > + LdThisContext := 137.
> > + SendPlus := 176.
> > + Send := 208
> > +
> > + "((ParseNode class >> #initialize) literals select: [:l| l
> isVariableBinding and: [(ParseNode classPool includesAssociation: l) and:
> [(self systemNavigation allCallsOn: l localTo: ParseNode) size = 1]]])
> sort: [:a :b| a key <= b key]"
> > +
> > + "ParseNode classPool associations select: [:a| (self
> systemNavigation allCallsOn: a localTo: ParseNode) isEmpty]"!
> >
> > Item was added:
> > + ----- Method: ParseNode class>>pushNilCode (in category 'accessing')
> -----
> > + pushNilCode
> > +
> > + ^LdNil!
> >
> > Item was added:
> > + ----- Method: ParseNode class>>tempSortBlock (in category 'accessing')
> -----
> > + tempSortBlock
> > + "Answer a block that can sort a set of temporaries into a stable
> > + order so that different compilations produce the same results."
> > + ^[:t1 :t2| | be1 be2 bs1 bs2 |
> > + t1 index < t2 index "simple sort by index."
> > + or: [t1 index = t2 index "complex tie break"
> > + and: [t1 isRemote ~= t2 isRemote
> > + ifTrue: [t2 isRemote] "put direct temps before indirect
> temps"
> > + ifFalse:
> > + [((be1 := t1 definingScope blockExtent) isNil
> > + or: [(be2 := t2 definingScope blockExtent) isNil])
> > + ifTrue: [t1 name < t2 name] "only have the name
> left to go on"
> > + ifFalse: "put temps from outer scopes before
> those from inner scopes"
> > + [(bs1 := be1 first) < (bs2 := be2 first)
> > + or: [bs1 = bs2 and: [t1 name < t2
> name]]]]]]] "only have the name left to go on"!
> >
> > Item was added:
> > + ----- Method: ParseNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + "Accept a visitor by double-dispatching to a type-specific method
> on the visitor, e.g. visitBlockNode:.
> > + All such implementations under ParseNode should answer the result
> of the dispatch, e.g.
> > + ^aVisitor visitBlockNode: self"
> > + ^self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: ParseNode>>asReturnNode (in category 'converting') -----
> > + asReturnNode
> > +
> > + ^ReturnNode new expr: self!
> >
> > Item was added:
> > + ----- Method: ParseNode>>assignmentCheck:at: (in category 'testing')
> -----
> > + assignmentCheck: encoder at: location
> > + "For messageNodes masquerading as variables for the debugger.
> > + For now we let this through - ie we allow stores ev
> > + into args. Should check against numArgs, though."
> > + ^ -1!
> >
> > Item was added:
> > + ----- Method: ParseNode>>canCascade (in category 'testing') -----
> > + canCascade
> > +
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>comment (in category 'comment') -----
> > + comment
> > +
> > + ^comment!
> >
> > Item was added:
> > + ----- Method: ParseNode>>comment: (in category 'comment') -----
> > + comment: newComment
> > +
> > + comment := newComment!
> >
> > Item was added:
> > + ----- Method: ParseNode>>emitCodeForBlockValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForBlockValue: stack encoder: encoder
> > + "Generate code for evaluating the last statement in a block"
> > + ^self emitCodeForValue: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: ParseNode>>emitCodeForBranchOn:dist:pop:encoder: (in
> category 'code generation') -----
> > + emitCodeForBranchOn: condition dist: dist pop: stack encoder: encoder
> > + stack pop: 1.
> > + dist = 0 ifTrue: [^encoder genPop].
> > + condition
> > + ifTrue: [encoder genBranchPopTrue: dist]
> > + ifFalse: [encoder genBranchPopFalse: dist]!
> >
> > Item was added:
> > + ----- Method: ParseNode>>emitCodeForEffect:encoder: (in category 'code
> generation') -----
> > + emitCodeForEffect: stack encoder: encoder
> > +
> > + self emitCodeForValue: stack encoder: encoder.
> > + encoder genPop.
> > + stack pop: 1!
> >
> > Item was added:
> > + ----- Method: ParseNode>>emitCodeForJump:encoder: (in category 'code
> generation') -----
> > + emitCodeForJump: dist encoder: encoder
> > +
> > + dist = 0 ifFalse: [encoder genJump: dist]!
> >
> > Item was added:
> > + ----- Method: ParseNode>>emitCodeForReturn:encoder: (in category 'code
> generation') -----
> > + emitCodeForReturn: stack encoder: encoder
> > +
> > + self emitCodeForValue: stack encoder: encoder.
> > + encoder genReturnTop!
> >
> > Item was added:
> > + ----- Method: ParseNode>>encodeSelector: (in category 'encoding') -----
> > + encodeSelector: selector
> > +
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: ParseNode>>ensureCanCascade: (in category 'testing')
> -----
> > + ensureCanCascade: encoder!
> >
> > Item was added:
> > + ----- Method: ParseNode>>ifNilReceiver (in category 'private') -----
> > + ifNilReceiver
> > + "assuming this object is the receiver of an ifNil:, what object is
> being asked about?"
> > + ^self!
> >
> > Item was added:
> > + ----- Method: ParseNode>>ifNilTemporary (in category 'private') -----
> > + ifNilTemporary
> > +
> > + ^ nil!
> >
> > Item was added:
> > + ----- Method: ParseNode>>ifNilValue (in category 'private') -----
> > + ifNilValue
> > +
> > + ^self!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isArg (in category 'testing') -----
> > + isArg
> > +
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isAssignmentNode (in category 'testing') -----
> > + isAssignmentNode
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isBlockNode (in category 'testing') -----
> > + isBlockNode
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isBraceNode (in category 'testing') -----
> > + isBraceNode
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isComplex (in category 'testing') -----
> > + isComplex
> > + "Used for pretty printing to determine whether to start a new line"
> > +
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isConstantNumber (in category 'testing') -----
> > + isConstantNumber "Overridden in LiteralNode"
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isDoIt (in category 'testing') -----
> > + isDoIt
> > + "polymorphic with RBNodes; called by debugger"
> > +
> > + ^ false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isFutureNode (in category 'testing') -----
> > + isFutureNode
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isJust: (in category 'testing') -----
> > + isJust: node
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isLiteralNode (in category 'testing') -----
> > + isLiteralNode
> > +
> > + ^ false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isMessage (in category 'testing') -----
> > + isMessage
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isMessage:receiver:arguments: (in category
> 'testing') -----
> > + isMessage: selSymbol receiver: rcvrPred arguments: argsPred
> > + "See comment in MessageNode."
> > +
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isMessageNode (in category 'testing') -----
> > + isMessageNode
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isOnlySubnodeOf:in: (in category 'testing')
> -----
> > + isOnlySubnodeOf: aSubtree "<ParseNode>" in: aParseTree "<ParseNode>"
> > + "Answer if the receiver only occurs within aSubtree of aParseTree,
> not in the rest of aParseTree.
> > + Assumes that aSubtree is in fact a subnode of aParseTree."
> > + | isSubnode |
> > + isSubnode := false.
> > + aSubtree accept: (ParseNodeEnumerator
> > + ofBlock: [:node| node == self ifTrue:
> [isSubnode := true]]).
> > + isSubnode ifFalse:
> > + [^false].
> > + aParseTree accept: (ParseNodeEnumerator
> > + ofBlock: [:node| node == self ifTrue:
> [^false]]
> > + select: [:node| node ~= aSubtree]).
> > + ^true!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isReturnSelf (in category 'testing') -----
> > + isReturnSelf
> > +
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isReturningIf (in category 'testing') -----
> > + isReturningIf
> > +
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isSelfPseudoVariable (in category 'testing')
> -----
> > + isSelfPseudoVariable
> > + "Overridden in VariableNode."
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isSpecialConstant (in category 'testing')
> -----
> > + isSpecialConstant
> > + ^ false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isTemp (in category 'testing') -----
> > + isTemp
> > + ^ false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isUndefTemp (in category 'testing') -----
> > + isUndefTemp
> > + ^ false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isUnusedTemp (in category 'testing') -----
> > + isUnusedTemp
> > + ^ false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isVariableNode (in category 'testing') -----
> > + isVariableNode
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>isVariableReference (in category 'testing')
> -----
> > + isVariableReference
> > +
> > + ^false!
> >
> > Item was added:
> > + ----- Method: ParseNode>>nextWordFrom:setCharacter: (in category
> 'private') -----
> > + nextWordFrom: aStream setCharacter: aBlock
> > + | outStream char |
> > + outStream := WriteStream on: (String new: 16).
> > + [(aStream peekFor: Character space)
> > + or: [aStream peekFor: Character tab]] whileTrue.
> > + [aStream atEnd
> > + or:
> > + [char := aStream next.
> > + char = Character cr or: [char = Character space]]]
> > + whileFalse: [outStream nextPut: char].
> > + aBlock value: char.
> > + ^ outStream contents!
> >
> > Item was added:
> > + ----- Method: ParseNode>>nodePrintOn:indent: (in category 'printing')
> -----
> > + nodePrintOn: aStrm indent: nn
> > + | var aaStrm myLine |
> > + "Show just the sub nodes and the code."
> > +
> > + (aaStrm := aStrm) ifNil: [aaStrm := WriteStream on: (String new:
> 500)].
> > + nn timesRepeat: [aaStrm tab].
> > + aaStrm nextPutAll: self class name; space.
> > + myLine := self printString copyWithout: Character cr.
> > + myLine := myLine copyFrom: 1 to: (myLine size min: 70).
> > + aaStrm nextPutAll: myLine; cr.
> > + 1 to: self class instSize do: [:ii |
> > + var := self instVarAt: ii.
> > + (var respondsTo: #asReturnNode) ifTrue: [var nodePrintOn:
> aaStrm indent: nn+1]].
> > + 1 to: self class instSize do: [:ii |
> > + var := self instVarAt: ii.
> > + (var isKindOf: SequenceableCollection) ifTrue: [
> > + var do: [:aNode |
> > + (aNode respondsTo: #asReturnNode) ifTrue: [
> > + aNode nodePrintOn: aaStrm indent: nn+1]]]].
> > + ^ aaStrm
> > + !
> >
> > Item was added:
> > + ----- Method: ParseNode>>nodesDo: (in category 'visiting') -----
> > + nodesDo: aBlock
> > + self accept: (ParseNodeEnumerator ofBlock: aBlock)!
> >
> > Item was added:
> > + ----- Method: ParseNode>>nodesWithPrecedingStatementsDo: (in category
> 'visiting') -----
> > + nodesWithPrecedingStatementsDo: aBinaryBlock
> > + self accept: (ParseNodeWithPrecedingStatementEnumerator ofBlock:
> aBinaryBlock)!
> >
> > Item was added:
> > + ----- Method: ParseNode>>nowHasDef (in category 'testing') -----
> > + nowHasDef "Ignored in all but VariableNode"!
> >
> > Item was added:
> > + ----- Method: ParseNode>>nowHasRef (in category 'testing') -----
> > + nowHasRef "Ignored in all but VariableNode"!
> >
> > Item was added:
> > + ----- Method: ParseNode>>pc (in category 'code generation') -----
> > + pc
> > + "Used by encoder source mapping."
> > +
> > + ^pc ifNil: [ 0 ]
> > + !
> >
> > Item was added:
> > + ----- Method: ParseNode>>pc: (in category 'code generation') -----
> > + pc: anInteger
> > + "Used by encoder source mapping."
> > +
> > + pc := anInteger!
> >
> > Item was added:
> > + ----- Method: ParseNode>>printCommentOn:indent: (in category
> 'printing') -----
> > + printCommentOn: aStream indent: indent
> > + | thisComment |
> > + self comment == nil ifTrue: [^ self].
> > + 1 to: self comment size
> > + do: [:index |
> > + index > 1 ifTrue: [aStream crtab: indent].
> > + aStream nextPut: $".
> > + thisComment := self comment at: index.
> > + self printSingleComment: thisComment
> > + on: aStream
> > + indent: indent.
> > + aStream nextPut: $"]!
> >
> > Item was added:
> > + ----- Method: ParseNode>>printOn: (in category 'printing') -----
> > + printOn: aStream
> > + "Refer to the comment in Object|printOn:."
> > +
> > + aStream nextPut: ${.
> > + self printOn: aStream indent: 0.
> > + aStream nextPut: $}.!
> >
> > Item was added:
> > + ----- Method: ParseNode>>printOn:indent: (in category 'printing') -----
> > + printOn: aStream indent: anInteger
> > + "If control gets here, avoid recursion loop."
> > +
> > + super printOn: aStream!
> >
> > Item was added:
> > + ----- Method: ParseNode>>printOn:indent:precedence: (in category
> 'printing') -----
> > + printOn: aStream indent: level precedence: p
> > +
> > + self printOn: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: ParseNode>>printSingleComment:on:indent: (in category
> 'private') -----
> > + printSingleComment: aString on: aStream indent: indent
> > + "Print the comment string, assuming it has been indented indent
> tabs.
> > + Break the string at word breaks, given the widths in the default
> > + font, at 450 points."
> > +
> > + | readStream word position lineBreak font wordWidth tabWidth
> spaceWidth lastChar |
> > + readStream := ReadStream on: aString.
> > + font := TextStyle default defaultFont.
> > + tabWidth := TextStyle default tabWidth.
> > + spaceWidth := font widthOf: Character space.
> > + position := indent * tabWidth.
> > + lineBreak := 450.
> > + [readStream atEnd]
> > + whileFalse:
> > + [word := self nextWordFrom: readStream setCharacter: [:lc |
> lastChar := lc].
> > + wordWidth := word inject: 0 into: [:width :char | width +
> (font widthOf: char)].
> > + position := position + wordWidth.
> > + position > lineBreak
> > + ifTrue:
> > + [aStream skip: -1; crtab: indent.
> > + position := indent * tabWidth + wordWidth +
> spaceWidth.
> > + lastChar = Character cr
> > + ifTrue: [[readStream peekFor: Character tab]
> whileTrue].
> > + word isEmpty ifFalse: [aStream nextPutAll: word;
> space]]
> > + ifFalse:
> > + [aStream nextPutAll: word.
> > + readStream atEnd
> > + ifFalse:
> > + [position := position + spaceWidth.
> > + aStream space].
> > + lastChar = Character cr
> > + ifTrue:
> > + [aStream skip: -1; crtab: indent.
> > + position := indent * tabWidth.
> > + [readStream peekFor: Character tab]
> whileTrue]]]!
> >
> > Item was added:
> > + ----- Method: ParseNode>>printWithClosureAnalysis (in category
> 'printing') -----
> > + printWithClosureAnalysis
> > +
> > + ^String streamContents: [:str| self printWithClosureAnalysisOn:
> str]!
> >
> > Item was added:
> > + ----- Method: ParseNode>>printWithClosureAnalysisOn: (in category
> 'printing') -----
> > + printWithClosureAnalysisOn: aStream
> > + "Refer to the comment in Object|printOn:."
> > +
> > + aStream nextPut: ${.
> > + self printWithClosureAnalysisOn: aStream indent: 0.
> > + aStream nextPut: $}.!
> >
> > Item was added:
> > + ----- Method: ParseNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: anInteger
> > + "If control gets here, avoid recursion loop."
> > +
> > + super printWithClosureAnalysisOn: aStream!
> >
> > Item was added:
> > + ----- Method: ParseNode>>printWithClosureAnalysisOn:indent:precedence:
> (in category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level precedence: p
> > +
> > + self printWithClosureAnalysisOn: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: ParseNode>>shortPrintOn: (in category 'printing') -----
> > + shortPrintOn: aStream
> > + self printOn: aStream indent: 0!
> >
> > Item was added:
> > + ----- Method: ParseNode>>sizeCode:forBranchOn:dist: (in category 'code
> generation') -----
> > + sizeCode: encoder forBranchOn: condition dist: dist
> > + dist = 0 ifTrue: [^encoder sizePop].
> > + ^condition
> > + ifTrue: [encoder sizeBranchPopTrue: dist]
> > + ifFalse: [encoder sizeBranchPopFalse: dist]!
> >
> > Item was added:
> > + ----- Method: ParseNode>>sizeCode:forJump: (in category 'code
> generation') -----
> > + sizeCode: encoder forJump: dist
> > +
> > + ^dist = 0 ifTrue: [0] ifFalse: [encoder sizeJump: dist]!
> >
> > Item was added:
> > + ----- Method: ParseNode>>sizeCodeForBlockValue: (in category 'code
> generation') -----
> > + sizeCodeForBlockValue: encoder
> > + "Answer the size for evaluating the last statement in a block"
> > + ^self sizeCodeForValue: encoder!
> >
> > Item was added:
> > + ----- Method: ParseNode>>sizeCodeForEffect: (in category 'code
> generation') -----
> > + sizeCodeForEffect: encoder
> > +
> > + ^(self sizeCodeForValue: encoder) + encoder sizePop!
> >
> > Item was added:
> > + ----- Method: ParseNode>>sizeCodeForReturn: (in category 'code
> generation') -----
> > + sizeCodeForReturn: encoder
> > +
> > + ^(self sizeCodeForValue: encoder) + encoder sizeReturnTop!
> >
> > Item was added:
> > + ----- Method: ParseNode>>toDoIncrement: (in category 'testing') -----
> > + toDoIncrement: ignored
> > + "Only meant for Messages or Assignments - else return nil"
> > + ^ nil!
> >
> > Item was added:
> > + ParseNodeVisitor subclass: #ParseNodeEnumerator
> > + instanceVariableNames: 'theBlock theSelectBlock'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> > +
> > + !ParseNodeEnumerator commentStamp: 'eem 3/19/2019 11:58' prior: 0!
> > + ParseNodeEnumerator implements ParseNode>>nodesDo:. It can be used to
> enumerate an entire tree via
> > + aParseNode accept: (ParseNodeEnumerator ofBlock: aBlock)
> > + or selectively, excluding the node and subnodes for which selectBlock
> answers false, via
> > + aParseNode accept: (ParseNodeEnumerator
> > + ofBlock: aBlock
> > + select: selectBlock)
> > + Instance Variables
> > + theBlock: <BlockClosure>
> > + theSelectBlock: <BlockClosure | nil>
> > +
> > + theBlock
> > + - the block that is evaluated with the parse nodes the receiver
> visits.
> > +
> > + theSelectBlock
> > + - an optional block used to select blocks to visit and descend into.
> > +
> > + Here's a doIt that generates and compiles the visiting methods:
> > +
> > + self superclass selectors do:
> > + [:s|
> > + self compile: (String streamContents:
> > + [:str| | arg |
> > + arg := 'a', (s allButFirst: 5) allButLast.
> > + str nextPutAll: s, ' ', arg; crtab;
> > + nextPutAll: '(theSelectBlock isNil or: [theSelectBlock
> value: '; nextPutAll: arg; nextPutAll: ']) ifFalse:'; crtab;
> > + tab: 2; nextPutAll: '[^nil].'; crtab;
> > + nextPutAll: 'theBlock value: '; nextPutAll: arg; nextPut:
> $.; crtab;
> > + nextPutAll: '^super '; nextPutAll: s, ' ', arg])]!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator class>>ofBlock: (in category
> 'instance creation') -----
> > + ofBlock: aBlock
> > + ^self new ofBlock: aBlock!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator class>>ofBlock:select: (in category
> 'instance creation') -----
> > + ofBlock: aBlock select: selectBlock
> > + ^self new ofBlock: aBlock select: selectBlock!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>ofBlock: (in category
> 'initialize-release') -----
> > + ofBlock: aBlock
> > + theBlock := aBlock!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>ofBlock:select: (in category
> 'initialize-release') -----
> > + ofBlock: aBlock select: aSelectBlock
> > + theBlock := aBlock.
> > + theSelectBlock := aSelectBlock!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitAssignmentNode: (in category
> 'visiting') -----
> > + visitAssignmentNode: anAssignmentNode
> > + (theSelectBlock isNil or: [theSelectBlock value: anAssignmentNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: anAssignmentNode.
> > + ^super visitAssignmentNode: anAssignmentNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitBlockNode: (in category
> 'visiting') -----
> > + visitBlockNode: aBlockNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aBlockNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aBlockNode.
> > + ^super visitBlockNode: aBlockNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitBraceNode: (in category
> 'visiting') -----
> > + visitBraceNode: aBraceNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aBraceNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aBraceNode.
> > + ^super visitBraceNode: aBraceNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitCascadeNode: (in category
> 'visiting') -----
> > + visitCascadeNode: aCascadeNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aCascadeNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aCascadeNode.
> > + ^super visitCascadeNode: aCascadeNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitCommentNode: (in category
> 'visiting') -----
> > + visitCommentNode: aCommentNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aCommentNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aCommentNode.
> > + ^super visitCommentNode: aCommentNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitFieldNode: (in category
> 'visiting') -----
> > + visitFieldNode: aFieldNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aFieldNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aFieldNode.
> > + ^super visitFieldNode: aFieldNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitFutureNode: (in category
> 'visiting') -----
> > + visitFutureNode: aFutureNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aFutureNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aFutureNode.
> > + ^super visitFutureNode: aFutureNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitInstanceVariableNode: (in
> category 'visiting') -----
> > + visitInstanceVariableNode: anInstanceVariableNode
> > + (theSelectBlock isNil or: [theSelectBlock value:
> anInstanceVariableNode]) ifFalse:
> > + [^nil].
> > + theBlock value: anInstanceVariableNode.
> > + ^super visitInstanceVariableNode: anInstanceVariableNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitLiteralNode: (in category
> 'visiting') -----
> > + visitLiteralNode: aLiteralNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aLiteralNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aLiteralNode.
> > + ^super visitLiteralNode: aLiteralNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitLiteralVariableNode: (in
> category 'visiting') -----
> > + visitLiteralVariableNode: aLiteralVariableNode
> > + (theSelectBlock isNil or: [theSelectBlock value:
> aLiteralVariableNode]) ifFalse:
> > + [^nil].
> > + theBlock value: aLiteralVariableNode.
> > + ^super visitLiteralVariableNode: aLiteralVariableNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitMessageNode: (in category
> 'visiting') -----
> > + visitMessageNode: aMessageNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aMessageNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aMessageNode.
> > + ^super visitMessageNode: aMessageNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitMessageNodeInCascade: (in
> category 'visiting') -----
> > + visitMessageNodeInCascade: aMessageNodeInCascade
> > + (theSelectBlock isNil or: [theSelectBlock value:
> aMessageNodeInCascade]) ifFalse:
> > + [^nil].
> > + theBlock value: aMessageNodeInCascade.
> > + ^super visitMessageNodeInCascade: aMessageNodeInCascade!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitMethodNode: (in category
> 'visiting') -----
> > + visitMethodNode: aMethodNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aMethodNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aMethodNode.
> > + ^super visitMethodNode: aMethodNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitNewArrayNode: (in category
> 'visiting') -----
> > + visitNewArrayNode: aNewArrayNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aNewArrayNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aNewArrayNode.
> > + ^super visitNewArrayNode: aNewArrayNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitRemoteTempVectorNode: (in
> category 'visiting') -----
> > + visitRemoteTempVectorNode: aRemoteTempVectorNode
> > + (theSelectBlock isNil or: [theSelectBlock value:
> aRemoteTempVectorNode]) ifFalse:
> > + [^nil].
> > + theBlock value: aRemoteTempVectorNode.
> > + ^super visitRemoteTempVectorNode: aRemoteTempVectorNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitReturnNode: (in category
> 'visiting') -----
> > + visitReturnNode: aReturnNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aReturnNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aReturnNode.
> > + ^super visitReturnNode: aReturnNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitSelectorNode: (in category
> 'visiting') -----
> > + visitSelectorNode: aSelectorNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aSelectorNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aSelectorNode.
> > + ^super visitSelectorNode: aSelectorNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitTempVariableNode: (in category
> 'visiting') -----
> > + visitTempVariableNode: aTempVariableNode
> > + (theSelectBlock isNil or: [theSelectBlock value:
> aTempVariableNode]) ifFalse:
> > + [^nil].
> > + theBlock value: aTempVariableNode.
> > + ^super visitTempVariableNode: aTempVariableNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeEnumerator>>visitVariableNode: (in category
> 'visiting') -----
> > + visitVariableNode: aVariableNode
> > + (theSelectBlock isNil or: [theSelectBlock value: aVariableNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aVariableNode.
> > + ^super visitVariableNode: aVariableNode!
> >
> > Item was added:
> > + Object subclass: #ParseNodeVisitor
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> > +
> > + !ParseNodeVisitor commentStamp: '<historical>' prior: 0!
> > + I am an abstract superclass for ParseNode visitors that functions as a
> null visitor. Here's the code that defines my interface:
> > +
> > + (SystemNavigation default allImplementorsOf: #accept: localTo:
> ParseNode) do:
> > + [:methodReference|
> > + methodReference compiledMethod messages do:
> > + [:sel|
> > + ((sel beginsWith: 'visit')
> > + and: [sel numArgs = 1]) ifTrue:
> > + [ParseNodeVisitor
> > + compile: (String streamContents:
> > + [:str|
> > + str nextPutAll: sel;
> > + space;
> > + nextPut: $a.
> > + methodReference classSymbol first isVowel
> ifTrue:
> > + [str nextPut: $n].
> > + str nextPutAll: methodReference
> classSymbol])
> > + classified: 'visiting']]]!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitAssignmentNode: (in category
> 'visiting') -----
> > + visitAssignmentNode: anAssignmentNode
> > + "N.B. since assigment happens after the value is evaluated the
> value is visited first."
> > + anAssignmentNode value accept: self.
> > + anAssignmentNode variable accept: self!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitBlockNode: (in category
> 'visiting') -----
> > + visitBlockNode: aBlockNode
> > + aBlockNode statements do:
> > + [:statement| statement accept: self]!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitBraceNode: (in category
> 'visiting') -----
> > + visitBraceNode: aBraceNode
> > + aBraceNode elements do:
> > + [:element| element accept: self]!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitCascadeNode: (in category
> 'visiting') -----
> > + visitCascadeNode: aCascadeNode
> > + aCascadeNode receiver accept: self.
> > + aCascadeNode messages do:
> > + [:message| self visitMessageNodeInCascade: message]!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitCommentNode: (in category
> 'visiting') -----
> > + visitCommentNode: aCommentNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitFieldNode: (in category
> 'visiting') -----
> > + visitFieldNode: aFieldNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitFutureNode: (in category
> 'visiting') -----
> > + visitFutureNode: aFutureNode
> > + aFutureNode receiver accept: self.
> > + (aFutureNode originalSelector isKindOf: SelectorNode) ifTrue:
> > + [aFutureNode originalSelector accept: self]!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitInstanceVariableNode: (in
> category 'visiting') -----
> > + visitInstanceVariableNode: anInstanceVariableNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitLiteralNode: (in category
> 'visiting') -----
> > + visitLiteralNode: aLiteralNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitLiteralVariableNode: (in category
> 'visiting') -----
> > + visitLiteralVariableNode: aLiteralVariableNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitMessageNode: (in category
> 'visiting') -----
> > + visitMessageNode: aMessageNode
> > + aMessageNode receiver accept: self.
> > + "receiver notNil ifTrue: ''receiver is nil for cascades''
> > + [receiver accept: self]."
> > + aMessageNode selector accept: self.
> > + aMessageNode argumentsInEvaluationOrder do:
> > + [:argument| argument accept: self]!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitMessageNodeInCascade: (in
> category 'visiting') -----
> > + visitMessageNodeInCascade: aMessageNode
> > + "receiver is nil for cascades"
> > + aMessageNode selector accept: self.
> > + aMessageNode argumentsInEvaluationOrder do:
> > + [:argument| argument accept: self]!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitMethodNode: (in category
> 'visiting') -----
> > + visitMethodNode: aMethodNode
> > + aMethodNode block accept: self!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitNewArrayNode: (in category
> 'visiting') -----
> > + visitNewArrayNode: aNewArrayNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitRemoteTempVectorNode: (in
> category 'visiting') -----
> > + visitRemoteTempVectorNode: aRemoteTempVectorNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitReturnNode: (in category
> 'visiting') -----
> > + visitReturnNode: aReturnNode
> > + aReturnNode expr accept: self!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitSelectorNode: (in category
> 'visiting') -----
> > + visitSelectorNode: aSelectorNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitTempVariableNode: (in category
> 'visiting') -----
> > + visitTempVariableNode: aTempVariableNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitUndeclaredVariableNode: (in
> category 'visiting') -----
> > + visitUndeclaredVariableNode: aVariableNode!
> >
> > Item was added:
> > + ----- Method: ParseNodeVisitor>>visitVariableNode: (in category
> 'visiting') -----
> > + visitVariableNode: aVariableNode!
> >
> > Item was added:
> > + ParseNodeEnumerator subclass:
> #ParseNodeWithPrecedingStatementEnumerator
> > + instanceVariableNames: 'precedingStatement'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> > +
> > + !ParseNodeWithPrecedingStatementEnumerator commentStamp: 'eem
> 3/19/2019 11:55' prior: 0!
> > + A ParseNodeWithPrecedingStatementEnumerator is a ParseNodeEnumerator
> that accepts a binary block in ofBlock:, and hence enumerates statement
> nodes with their preceding statement, or nil if they are the first.
> > +
> > + Instance Variables
> > + precedingStatement: <ParseNode | nil>
> > +
> > + precedingStatement
> > + - the preceding statement node, if any
> > + !
> >
> > Item was added:
> > + ----- Method: ParseNodeWithPrecedingStatementEnumerator>>ofBlock: (in
> category 'initialize-release') -----
> > + ofBlock: aBlock
> > + "N.B. This enumerator visits a node before any of the node's
> children.
> > + Hence, when enumerating statements in a block, we can ensure that
> > + the second argument to the block, the preceding statement, is
> non-nil
> > + only for top-level statements in the block by nilling out
> precedingStatement
> > + once the block is evaluated. Perhaps stronger would be to capture
> its value
> > + in a temporary and nil it before evaluating, but this is good
> enough."
> > + theBlock := [:node|
> > + aBlock value: node value: precedingStatement.
> > + precedingStatement := nil]!
> >
> > Item was added:
> > + ----- Method:
> ParseNodeWithPrecedingStatementEnumerator>>ofBlock:select: (in category
> 'initialize-release') -----
> > + ofBlock: aBlock select: aSelectBlock
> > + self ofBlock: aBlock.
> > + theSelectBlock := aSelectBlock!
> >
> > Item was added:
> > + ----- Method:
> ParseNodeWithPrecedingStatementEnumerator>>visitBlockNode: (in category
> 'visiting') -----
> > + visitBlockNode: aBlockNode
> > + | savedPrecedingStatement |
> > + (theSelectBlock isNil or: [theSelectBlock value: aBlockNode])
> ifFalse:
> > + [^nil].
> > + theBlock value: aBlockNode.
> > + savedPrecedingStatement := precedingStatement.
> > + precedingStatement := nil.
> > + [aBlockNode statements do:
> > + [:statement|
> > + statement accept: self.
> > + precedingStatement := statement]] ensure:
> > + [precedingStatement := savedPrecedingStatement]!
> >
> > Item was added:
> > + Object subclass: #ParseStack
> > + instanceVariableNames: 'position length'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> > +
> > + !ParseStack commentStamp: '<historical>' prior: 0!
> > + I keep track of the current and high position of the stack that will
> be needed by code being compiled.!
> >
> > Item was added:
> > + ----- Method: ParseStack>>init (in category 'initialize-release') -----
> > + init
> > +
> > + length := position := 0!
> >
> > Item was added:
> > + ----- Method: ParseStack>>pop: (in category 'accessing') -----
> > + pop: n
> > +
> > + (position := position - n) < 0
> > + ifTrue: [self error: 'Parse stack underflow']!
> >
> > Item was added:
> > + ----- Method: ParseStack>>position (in category 'results') -----
> > + position
> > +
> > + ^position!
> >
> > Item was added:
> > + ----- Method: ParseStack>>position: (in category 'accessing') -----
> > + position: n
> > + (position := n) > length
> > + ifTrue: [length := position]!
> >
> > Item was added:
> > + ----- Method: ParseStack>>printOn: (in category 'printing') -----
> > + printOn: aStream
> > +
> > + super printOn: aStream.
> > + aStream nextPutAll: ' at '; print: position; nextPutAll: ' of ';
> print: length!
> >
> > Item was added:
> > + ----- Method: ParseStack>>push: (in category 'accessing') -----
> > + push: n
> > +
> > + (position := position + n) > length
> > + ifTrue: [length := position]!
> >
> > Item was added:
> > + ----- Method: ParseStack>>size (in category 'accessing') -----
> > + size
> > +
> > + ^length!
> >
> > Item was added:
> > + Scanner subclass: #Parser
> > + instanceVariableNames: 'here hereType hereMark hereEnd prevMark
> prevEnd encoder parseNode failBlock requestorOffset tempsMark doitFlag
> properties queriedUnusedTemporaries cue'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> > +
> > + !Parser commentStamp: 'cwp 12/26/2012 23:34' prior: 0!
> > + I parse Smalltalk syntax and create a MethodNode that is the root of
> the parse tree. I look one token ahead.!
> >
> > Item was added:
> > + ----- Method: Parser class>>primitivePragmaSelectors (in category
> 'accessing') -----
> > + primitivePragmaSelectors
> > + "Answer the selectors of pragmas that specify VM primitives.
> > + Needed for compile and decomple."
> > + ^#(primitive:
> > + primitive:error:
> > + primitive:error:module:
> > + primitive:module:
> > + primitive:module:error:)!
> >
> > Item was added:
> > + ----- Method: Parser>>addComment (in category 'private') -----
> > + addComment
> > +
> > + parseNode ~~ nil
> > + ifTrue:
> > + [parseNode comment: currentComment.
> > + currentComment := nil]!
> >
> > Item was added:
> > + ----- Method: Parser>>addPragma: (in category 'pragmas') -----
> > + addPragma: aPragma
> > + properties := self properties copyWith: aPragma!
> >
> > Item was added:
> > + ----- Method: Parser>>addWarning: (in category 'error handling') -----
> > + addWarning: aString
> > + "ignored by the default compiler."!
> >
> > Item was added:
> > + ----- Method: Parser>>advance (in category 'scanning') -----
> > + advance
> > + | this |
> > + prevMark := hereMark.
> > + prevEnd := hereEnd.
> > + this := here.
> > + here := token.
> > + hereType := tokenType.
> > + hereMark := mark.
> > + hereEnd := source position - (aheadChar == DoItCharacter
> > + ifTrue: [hereChar == DoItCharacter
> > + ifTrue: [0]
> > + ifFalse: [1]]
> > + ifFalse: [2]).
> > + self scanToken.
> > + "Transcript show: 'here: ', here printString, ' mark: ', hereMark
> printString, ' end: ', hereEnd printString; cr."
> > + ^this!
> >
> > Item was added:
> > + ----- Method: Parser>>allocateLiteral: (in category 'primitives') -----
> > + allocateLiteral: lit
> > + encoder litIndex: lit!
> >
> > Item was added:
> > + ----- Method: Parser>>allowUnderscoreAssignments (in category
> 'private') -----
> > + allowUnderscoreAssignments
> > + "Query class + preference"
> > + ^ (encoder ifNotNil: [:e |
> > + e == self
> > + ifTrue: [nil]
> > + ifFalse: [e classEncoding allowUnderscoreAssignments]])
> > + ifNil: [super allowUnderscoreAssignments]!
> >
> > Item was added:
> > + ----- Method: Parser>>ambiguousSelector:inRange: (in category 'error
> correction') -----
> > + ambiguousSelector: aString inRange: anInterval
> > + | correctedSelector intervalWithOffset |
> > +
> > + self interactive ifFalse: [
> > + "In non interactive mode, compile with backward comapatibility:
> $- is part of literal argument"
> > + Transcript cr; store: encoder classEncoding;
> nextPutAll:#'>>';store: encoder selector; show: ' would send ' , token ,
> '-'.
> > + ^super ambiguousSelector: aString inRange: anInterval].
> > +
> > + "handle the text selection"
> > + intervalWithOffset := anInterval first + requestorOffset to:
> anInterval last + requestorOffset.
> > + self selectFrom: intervalWithOffset first to: intervalWithOffset
> last
> > + during:
> > + ["Build the menu with alternatives"
> > + correctedSelector := AmbiguousSelector
> > + signalName: aString
> > + inRange: intervalWithOffset.
> > + correctedSelector ifNil: [^self fail]].
> > +
> > + "Execute the selected action"
> > + self substituteWord: correctedSelector wordInterval:
> intervalWithOffset offset: 0.
> > + token := (correctedSelector readStream upTo: Character space)
> asSymbol!
> >
> > Item was added:
> > + ----- Method: Parser>>argumentName (in category 'expression types')
> -----
> > + argumentName
> > +
> > + hereType == #word
> > + ifFalse: [^self expected: 'Argument name'].
> > + ^self advance!
> >
> > Item was added:
> > + ----- Method: Parser>>assignment: (in category 'expression types')
> -----
> > + assignment: varNode
> > + " var ':=' expression => AssignmentNode."
> > + | loc start |
> > + (loc := varNode assignmentCheck: encoder at: prevMark +
> requestorOffset) >= 0
> > + ifTrue: [^self notify: 'Cannot store into' at: loc].
> > + start := self startOfNextToken.
> > + self advance.
> > + self expression ifFalse: [^self expected: 'Expression'].
> > + parseNode := AssignmentNode new
> > + variable: varNode
> > + value: parseNode
> > + from: encoder
> > + sourceRange: (start to: self endOfLastToken).
> > + varNode nowHasDef.
> > + ^true!
> >
> > Item was added:
> > + ----- Method: Parser>>bindArg: (in category 'temps') -----
> > + bindArg: name
> > +
> > + ^ self bindTemp: name!
> >
> > Item was added:
> > + ----- Method: Parser>>bindTemp: (in category 'temps') -----
> > + bindTemp: name
> > +
> > + ^name!
> >
> > Item was added:
> > + ----- Method: Parser>>bindTemp:in: (in category 'temps') -----
> > + bindTemp: name in: methodSelector
> > +
> > + ^name!
> >
> > Item was added:
> > + ----- Method: Parser>>blockExpression (in category 'expression types')
> -----
> > + blockExpression
> > + "[ ({:var} |) (| {temps} |) (statements) ] => BlockNode."
> > +
> > + | blockNode variableNodes temporaryBlockVariables start |
> > + blockNode := BlockNode new.
> > + variableNodes := OrderedCollection new.
> > + start := prevMark + requestorOffset.
> > + "Gather parameters."
> > + [self match: #colon] whileTrue:
> > + [variableNodes addLast: (encoder bindBlockArg: self
> argumentName within: blockNode)].
> > + (variableNodes size > 0 & (hereType ~~ #rightBracket) and: [(self
> match: #verticalBar) not]) ifTrue:
> > + [^self expected: 'Vertical bar'].
> > +
> > + temporaryBlockVariables := self temporaryBlockVariablesFor:
> blockNode.
> > + self statements: variableNodes innerBlock: true blockNode:
> blockNode.
> > + blockNode temporaries: temporaryBlockVariables.
> > +
> > + (self match: #rightBracket) ifFalse: [^self expected: 'Period or
> right bracket'].
> > +
> > + blockNode noteSourceRangeStart: start end: self endOfLastToken
> encoder: encoder.
> > +
> > + "The scope of the parameters and temporary block variables is no
> longer active."
> > + temporaryBlockVariables do: [:variable | variable scope: -1].
> > + variableNodes do: [:variable | variable scope: -1]!
> >
> > Item was added:
> > + ----- Method: Parser>>braceExpression (in category 'expression types')
> -----
> > + braceExpression
> > + " { elements } => BraceNode."
> > +
> > + | elements locations loc more |
> > + elements := OrderedCollection new.
> > + locations := OrderedCollection new.
> > + self advance.
> > + more := hereType ~~ #rightBrace.
> > + [more]
> > + whileTrue:
> > + [loc := hereMark + requestorOffset.
> > + self expression
> > + ifTrue:
> > + [elements addLast: parseNode.
> > + locations addLast: loc]
> > + ifFalse:
> > + [^self expected: 'Variable or expression or right
> brace'].
> > + (self match: #period)
> > + ifTrue: [more := hereType ~~ #rightBrace]
> > + ifFalse: [more := false]].
> > + parseNode := BraceNode new elements: elements sourceLocations:
> locations.
> > + (self match: #rightBrace)
> > + ifFalse: [^self expected: 'Period or right brace'].
> > + ^true!
> >
> > Item was added:
> > + ----- Method: Parser>>canDeclareClassVariable (in category 'error
> correction') -----
> > + canDeclareClassVariable
> > + ^encoder classEncoding ~~ UndefinedObject!
> >
> > Item was added:
> > + ----- Method: Parser>>canDeclareInstanceVariable (in category 'error
> correction') -----
> > + canDeclareInstanceVariable
> > + ^encoder classEncoding ~~ UndefinedObject!
> >
> > Item was added:
> > + ----- Method: Parser>>cascade (in category 'expression types') -----
> > + cascade
> > + " {; message} => CascadeNode."
> > +
> > + | rcvr msgs |
> > + parseNode canCascade ifFalse:
> > + [^self expected: 'Cascading not'].
> > + parseNode ensureCanCascade: encoder.
> > + rcvr := parseNode cascadeReceiver.
> > + msgs := OrderedCollection with: parseNode.
> > + [self match: #semicolon]
> > + whileTrue:
> > + [parseNode := rcvr.
> > + (self messagePart: 3 repeat: false)
> > + ifFalse: [^self expected: 'Cascade'].
> > + parseNode canCascade ifFalse:
> > + [^self expected: '<- No special messages'].
> > + parseNode ensureCanCascade: encoder.
> > + parseNode cascadeReceiver.
> > + msgs addLast: parseNode].
> > + parseNode := CascadeNode new receiver: rcvr messages: msgs!
> >
> > Item was added:
> > + ----- Method: Parser>>collectTemporaryDeclarationsFrom: (in category
> 'error correction') -----
> > + collectTemporaryDeclarationsFrom: methodNode
> > + | tempsMarks str |
> > + tempsMarks := OrderedCollection new.
> > + str := cue requestor text asString.
> > + methodNode accept: (ParseNodeEnumerator
> > + ofBlock: [ :aNode |
> > + | mark |
> > + (aNode class canUnderstand: #tempsMark)
> > + ifTrue:
> > + [mark := aNode tempsMark.
> > + (mark notNil and: [ mark between: 1 and: str size ]
> and: [ (str at: mark) = $| ])
> > + ifTrue: [ tempsMarks addLast: aNode ]]]).
> > + (tempsMark notNil and: [ tempsMark between: 1 and: str size ] and:
> [ (str at: tempsMark) = $| ])
> > + ifTrue: [ tempsMarks addLast: self ].
> > + ^ tempsMarks sorted: [ :a :b | a tempsMark > b tempsMark ]!
> >
> > Item was added:
> > + ----- Method:
> Parser>>correctSelector:wordIntervals:exprInterval:ifAbort: (in category
> 'error correction') -----
> > + correctSelector: proposedKeyword wordIntervals: spots exprInterval:
> expInt ifAbort: abortAction
> > + "Correct the proposedKeyword to some selector symbol, correcting
> the original text if such action is indicated. abortAction is invoked if
> the proposedKeyword couldn't be converted into a valid selector. Spots is
> an ordered collection of intervals within the test stream of the for each
> of the keyword parts."
> > +
> > + | correctSelector |
> > + "If we can't ask the user, assume that the keyword will be defined
> later"
> > + self interactive ifFalse: [^ proposedKeyword asSymbol].
> > +
> > + self selectFrom: spots first first to: spots last last during: [
> > + correctSelector := UnknownSelector name: proposedKeyword.
> > + correctSelector ifNil: [^ abortAction value]].
> > +
> > + self substituteSelector: correctSelector keywords wordIntervals:
> spots.
> > + ^ (proposedKeyword last ~~ $:
> > + and: [correctSelector last == $:])
> > + ifTrue: [abortAction value]
> > + ifFalse: [correctSelector]!
> >
> > Item was added:
> > + ----- Method: Parser>>correctVariable:interval: (in category 'error
> correction') -----
> > + correctVariable: proposedVariable interval: spot
> > + "Correct the proposedVariable to a known variable, or declare it as
> a new
> > + variable if such action is requested. We support declaring
> lowercase
> > + variables as temps or inst-vars, and uppercase variables as Globals
> or
> > + ClassVars, depending on whether the context is nil
> (class=UndefinedObject).
> > + Spot is the interval within the test stream of the variable."
> > +
> > + | binding action |
> > + "Check if this is an i-var, that has been corrected already (ugly)"
> > + (encoder classEncoding instVarNames includes: proposedVariable)
> ifTrue:
> > + [^InstanceVariableNode new
> > + name: proposedVariable
> > + index: (encoder classEncoding allInstVarNames indexOf:
> proposedVariable)].
> > +
> > + "First check to see if the requestor knows anything about the
> variable"
> > + (binding := cue requestor ifNotNil: [:object | object bindingOf:
> proposedVariable])
> > + ifNotNil: [^encoder global: binding name: proposedVariable].
> > +
> > + "If we can't ask the user for correction, make it undeclared"
> > + self interactive ifFalse: [^encoder undeclared: proposedVariable].
> > +
> > + self selectFrom: spot first to: spot last
> > + during:
> > + ["Build the menu with alternatives"
> > + action := UndeclaredVariable
> > + signalFor: self
> > + name: proposedVariable
> > + inRange: spot.
> > + action ifNil: [^self fail]].
> > +
> > + "Execute the selected action"
> > + ^action value!
> >
> > Item was added:
> > + ----- Method: Parser>>declareClassVar: (in category 'error
> correction') -----
> > + declareClassVar: name
> > + | sym class |
> > + sym := name asSymbol.
> > + class := encoder classEncoding.
> > + class := class theNonMetaClass. "not the metaclass"
> > + class addClassVarName: name.
> > + Smalltalk logChange: class definition.
> > + ^ encoder global: (class classPool associationAt: sym)
> > + name: sym!
> >
> > Item was added:
> > + ----- Method: Parser>>declareGlobal: (in category 'error correction')
> -----
> > + declareGlobal: name
> > + | sym |
> > + sym := name asSymbol.
> > + ^encoder
> > + global: (encoder environment
> > + at: sym put: nil;
> > + associationAt: sym)
> > + name: sym!
> >
> > Item was added:
> > + ----- Method: Parser>>declareInstVar: (in category 'error correction')
> -----
> > + declareInstVar: name
> > + "Declare an instance variable. Since the variable will get added
> after any existing
> > + inst vars its index is the instSize."
> > + encoder classEncoding addInstVarName: name.
> > + Smalltalk logChange: encoder classEncoding definition.
> > + ^InstanceVariableNode new name: name index: encoder classEncoding
> instSize
> > + !
> >
> > Item was added:
> > + ----- Method: Parser>>declareTemp:at: (in category 'error correction')
> -----
> > + declareTemp: name at: levelTag
> > + "Defer declaring the temp until the parse has completed. This
> allows
> > + the parser to declare the temp in the minimum enclosing block
> instead
> > + of always at method level. See Parser>>declareUndeclaredTemps:"
> > + ^(encoder bindUndeclaredTemp: name)
> > + tag: levelTag;
> > + yourself!
> >
> > Item was added:
> > + ----- Method: Parser>>declareTempAndPaste: (in category 'error
> correction') -----
> > + declareTempAndPaste: name
> > + "Defer declaring the temp until the parse has completed. This
> allows
> > + the parser to declare the temp in the minimum enclosing block
> instead
> > + of always at method level. See Parser>>declareUndeclaredTemps:"
> > + ^encoder bindUndeclaredTemp: name!
> >
> > Item was added:
> > + ----- Method: Parser>>declareUndeclaredTemps: (in category 'error
> correction') -----
> > + declareUndeclaredTemps: methodNode
> > + "Declare any undeclared temps, declaring them at the smallest
> enclosing scope."
> > +
> > + | undeclared blocksToVars |
> > + (undeclared := encoder undeclaredTemps) isEmpty ifTrue:
> > + [^self].
> > + blocksToVars := IdentityDictionary new.
> > + undeclared do:
> > + [:var|
> > + (blocksToVars
> > + at: (var tag == #method
> > + ifTrue: [methodNode block]
> > + ifFalse: [methodNode accept: (VariableScopeFinder
> new ofVariable: var)])
> > + ifAbsentPut: [SortedCollection new]) add: var name].
> > + (blocksToVars removeKey: methodNode block ifAbsent: []) ifNotNil:
> > + [:rootVars|
> > + rootVars do: [:varName| self pasteTempAtMethodLevel: varName]].
> > + (blocksToVars keys sorted: [:a :b| a tempsMark < b tempsMark]) do:
> > + [:block| | decl |
> > + decl := (blocksToVars at: block) reduce: [:a :b| a, ' ', b].
> > + block temporaries isEmpty
> > + ifTrue:
> > + [self substituteWord: ' | ', decl, ' |'
> > + wordInterval: (block tempsMark + 1 to: block
> tempsMark)
> > + offset: requestorOffset]
> > + ifFalse:
> > + [self substituteWord: decl, ' '
> > + wordInterval: (block tempsMark to: block tempsMark
> - 1)
> > + offset: requestorOffset]].
> > + ReparseAfterSourceEditing signal!
> >
> > Item was added:
> > + ----- Method: Parser>>defineClass: (in category 'error correction')
> -----
> > + defineClass: className
> > + "prompts the user to define a new class,
> > + asks for it's category, and lets the users edit further
> > + the definition"
> > + | sym cat def d2 |
> > + sym := className asSymbol.
> > + cat := Project uiManager request: 'Enter class category : '
> initialAnswer: self encoder classEncoding theNonMetaClass category.
> > + cat
> > + ifEmpty: [cat := 'Unknown'].
> > + def := 'Object subclass: #' , sym , '
> > + instanceVariableNames: ''''
> > + classVariableNames: ''''
> > + poolDictionaries: ''''
> > + category: ''' , cat , ''''.
> > + d2 := Project uiManager request: 'Edit class definition : '
> initialAnswer: def.
> > + d2
> > + ifEmpty: [d2 := def].
> > + Compiler evaluate: d2.
> > + ^ encoder
> > + global: (cue environment bindingOf: sym)
> > + name: sym!
> >
> > Item was added:
> > + ----- Method: Parser>>encoder (in category 'private') -----
> > + encoder
> > + ^encoder ifNil:
> > + [encoder := CompiledMethod preferredBytecodeSetEncoderClass
> new]!
> >
> > Item was added:
> > + ----- Method: Parser>>encoderClass: (in category 'public access') -----
> > + encoderClass: anEncoderClass
> > + encoder ifNotNil: [
> > + self error: 'encoder already set'].
> > + encoder := anEncoderClass new!
> >
> > Item was added:
> > + ----- Method: Parser>>encoderFromCue: (in category 'private') -----
> > + encoderFromCue: aCompilationCue
> > + ^encoder ifNil:
> > + [encoder := (aCompilationCue encoderClass ifNil:
> [CompiledMethod preferredBytecodeSetEncoderClass]) new]!
> >
> > Item was added:
> > + ----- Method: Parser>>endOfLastToken (in category 'scanning') -----
> > + endOfLastToken
> > +
> > + ^ prevEnd ifNil: [mark]!
> >
> > Item was added:
> > + ----- Method: Parser>>expected: (in category 'error handling') -----
> > + expected: aString
> > + "Notify a problem at token 'here'."
> > +
> > + ^ self notify: aString , ' expected' at: hereMark + requestorOffset!
> >
> > Item was added:
> > + ----- Method: Parser>>expression (in category 'expression types') -----
> > + expression
> > + (hereType == #word
> > + and: [tokenType == #leftArrow]) ifTrue:
> > + [^self assignment: self variable].
> > + self primaryExpression ifFalse:
> > + [^false].
> > + ((self messagePart: 3 repeat: true)
> > + and: [hereType == #semicolon]) ifTrue:
> > + [self cascade].
> > + ^true!
> >
> > Item was added:
> > + ----- Method: Parser>>fail (in category 'error handling') -----
> > + fail
> > +
> > + | exitBlock |
> > + (encoder == nil or: [encoder == self])
> > + ifFalse: [encoder release. encoder := nil]. "break cycle"
> > + exitBlock := failBlock.
> > + failBlock := nil.
> > + ^exitBlock value!
> >
> > Item was added:
> > + ----- Method: Parser>>init:cue:failBlock: (in category 'private') -----
> > + init: sourceStream cue: aCue failBlock: aBlock
> > +
> > + self setCue: aCue.
> > + failBlock := aBlock.
> > + requestorOffset := 0.
> > + super scan: sourceStream.
> > + prevMark := hereMark := mark.
> > + self advance
> > + !
> >
> > Item was added:
> > + ----- Method: Parser>>initPattern:return: (in category 'private') -----
> > + initPattern: aString return: aBlock
> > +
> > + | result |
> > + self
> > + init: (ReadStream on: aString asString)
> > + cue: (CompilationCue source: aString)
> > + failBlock: [^nil].
> > + encoder := self.
> > + result := aBlock value: (self pattern: false inContext: nil).
> > + encoder := failBlock := nil. "break cycles"
> > + ^result!
> >
> > Item was added:
> > + ----- Method: Parser>>interactive (in category 'error handling') -----
> > + interactive
> > + "The compilation is interactive if there is a requestor and that
> requestor does either not care or explicitly allow interactive error
> correction."
> > +
> > + ^ cue requestor notNil
> > + and: [(cue requestor respondsTo:
> #wantsInteractiveErrorCorrection) not
> > + or: [cue requestor perform:
> #wantsInteractiveErrorCorrection]]!
> >
> > Item was added:
> > + ----- Method: Parser>>match: (in category 'scanning') -----
> > + match: type
> > + "Answer with true if next tokens type matches."
> > +
> > + hereType == type
> > + ifTrue:
> > + [self advance.
> > + ^true].
> > + ^false!
> >
> > Item was added:
> > + ----- Method: Parser>>matchReturn (in category 'scanning') -----
> > + matchReturn
> > +
> > + ^ self match: #upArrow!
> >
> > Item was added:
> > + ----- Method: Parser>>matchToken: (in category 'scanning') -----
> > + matchToken: thing
> > + "Matches the token, not its type."
> > +
> > + here = thing ifTrue: [self advance. ^true].
> > + ^false!
> >
> > Item was added:
> > + ----- Method: Parser>>messagePart:repeat: (in category 'expression
> types') -----
> > + messagePart: level repeat: repeat
> > +
> > + | start receiver selector args precedence words keywordStart |
> > + [receiver := parseNode.
> > + (hereType == #keyword and: [level >= 3])
> > + ifTrue:
> > + [start := self startOfNextToken.
> > + selector := WriteStream on: (String new: 32).
> > + args := OrderedCollection new.
> > + words := OrderedCollection new.
> > + [hereType == #keyword]
> > + whileTrue:
> > + [keywordStart := self startOfNextToken +
> requestorOffset.
> > + selector nextPutAll: self advance.
> > + words addLast: (keywordStart to: self
> endOfLastToken + requestorOffset).
> > + self primaryExpression ifFalse: [^self expected:
> 'Argument'].
> > + self messagePart: 2 repeat: true.
> > + args addLast: parseNode].
> > + selector := (Symbol lookup: selector contents)
> > + ifNil: [ self correctSelector: selector contents
> > + wordIntervals: words
> > + exprInterval: (start to: self
> endOfLastToken)
> > + ifAbort: [ ^ self fail ] ].
> > + precedence := 3]
> > + ifFalse: [
> > + (level >= 2 and: [hereType == #verticalBar]) ifTrue: [self
> transformAVerticalBarIntoABinarySelector].
> > + (hereType == #binary and: [level >= 2])
> > + ifTrue:
> > + [start := self startOfNextToken.
> > + selector := self advance asOctetString asSymbol.
> > + self primaryExpression ifFalse: [^self expected:
> 'Argument'].
> > + self messagePart: 1 repeat: true.
> > + args := Array with: parseNode.
> > + precedence := 2]
> > + ifFalse: [hereType == #word
> > + ifTrue:
> > + [start := self startOfNextToken.
> > + selector := self advance.
> > + args := #().
> > + words := OrderedCollection with: (start +
> requestorOffset to: self endOfLastToken + requestorOffset).
> > + selector := (Symbol lookup: selector)
> > + ifNil: [ self correctSelector: selector
> > + wordIntervals: words
> > + exprInterval: (start to:
> self endOfLastToken)
> > + ifAbort: [ ^ self fail ] ].
> > + precedence := 1]
> > + ifFalse: [^args notNil]]].
> > + parseNode := MessageNode new
> > + receiver: receiver
> > + selector: selector
> > + arguments: args
> > + precedence: precedence
> > + from: encoder
> > + sourceRange: (start to: self endOfLastToken).
> > + repeat]
> > + whileTrue: [].
> > + ^true!
> >
> > Item was added:
> > + ----- Method: Parser>>method:context: (in category 'expression types')
> -----
> > + method: doit context: ctxt
> > + " pattern [ | temporaries ] block => MethodNode."
> > +
> > + | sap blk prim temps messageComment methodNode |
> > + sap := self pattern: doit inContext: ctxt.
> > + "sap={selector, arguments, precedence}"
> > + self properties selector: (sap at: 1).
> > + encoder selector: (sap at: 1).
> > + (sap at: 2) do: [:argNode | argNode beMethodArg].
> > + doit ifFalse: [self pragmaSequence].
> > + temps := self temporaries.
> > + messageComment := currentComment.
> > + currentComment := nil.
> > + doit ifFalse: [self pragmaSequence].
> > + prim := self pragmaPrimitives.
> > + self statements: #() innerBlock: false blockNode: BlockNode new.
> > + blk := parseNode.
> > + doit ifTrue: [blk returnLast]
> > + ifFalse: [blk returnSelfIfNoOther: encoder].
> > + hereType == #doIt ifFalse: [^self expected: 'Nothing more'].
> > + methodNode := self newMethodNode comment: messageComment.
> > + methodNode
> > + selector: (sap at: 1)
> > + arguments: (sap at: 2)
> > + precedence: (sap at: 3)
> > + temporaries: temps
> > + block: blk
> > + encoder: encoder
> > + primitive: prim
> > + properties: properties.
> > + self interactive ifTrue:
> > + [self declareUndeclaredTemps: methodNode.
> > + self removeUnusedTemps: methodNode].
> > + ^methodNode!
> >
> > Item was added:
> > + ----- Method: Parser>>newMethodNode (in category 'expression types')
> -----
> > + newMethodNode
> > + ^self encoder methodNodeClass new!
> >
> > Item was added:
> > + ----- Method: Parser>>notify: (in category 'error handling') -----
> > + notify: aString
> > + "Notify problem at token before 'here'."
> > +
> > + ^self notify: aString at: prevMark + requestorOffset!
> >
> > Item was added:
> > + ----- Method: Parser>>notify:at: (in category 'error handling') -----
> > + notify: string at: location
> > + | messageText |
> > + messageText := '"' , string , ' ->"'.
> > + cue requestor isNil
> > + ifTrue: [
> > + | notification |
> > + (encoder == self or: [encoder isNil])
> > + ifTrue: [^ self fail "failure setting up syntax error"].
> > + (notification := SyntaxErrorNotification
> > + cue: (cue copy
> > + source: (source contents asText
> > + copyReplaceFrom: location
> > + to: location - 1
> > + with: messageText);
> > + yourself)
> > + doitFlag: doitFlag
> > + errorMessage: string
> > + location: location) signal.
> > + notification tryNewSourceIfAvailable]
> > + ifFalse: [cue requestor
> > + notify: messageText
> > + at: location
> > + in: source].
> > + ^ self fail!
> >
> > Item was added:
> > + ----- Method: Parser>>offEnd: (in category 'error handling') -----
> > + offEnd: aString
> > + "Notify a problem beyond 'here' (in lookAhead token). Don't be
> offEnded!!"
> > +
> > + requestorOffset == nil
> > + ifTrue: [^ self notify: aString at: mark]
> > + ifFalse: [^ self notify: aString at: mark + requestorOffset]
> > + !
> >
> > Item was added:
> > + ----- Method: Parser>>parse:class: (in category 'public access') -----
> > + parse: sourceStreamOrString class: behavior
> > +
> > + ^ self parse: sourceStreamOrString readStream class: behavior
> > + noPattern: false notifying: nil ifFail: [^nil]!
> >
> > Item was added:
> > + ----- Method: Parser>>parse:class:noPattern:notifying:ifFail: (in
> category 'public access') -----
> > + parse: sourceStream class: class noPattern: noPattern notifying: req
> ifFail: aBlock
> > + | c |
> > + c := CompilationCue
> > + source: sourceStream
> > + class: class
> > + requestor: req.
> > + ^ self
> > + parseCue: c
> > + noPattern: noPattern
> > + ifFail: aBlock!
> >
> > Item was added:
> > + ----- Method: Parser>>parseArgsAndTemps: (in category 'public access')
> -----
> > + parseArgsAndTemps: aString
> > + "Parse the argument, aString, answer nil if an error occurs.
> Otherwise,
> > + answer an Array of strings (the argument names and temporary
> variable names)."
> > +
> > + aString == nil ifTrue: [^#()].
> > + doitFlag := false. "Don't really know if a doit
> or not!!"
> > + ^self initPattern: aString
> > + return: [:pattern | (pattern at: 2) , (self
> temporariesIn: (pattern at: 1))]!
> >
> > Item was added:
> > + ----- Method: Parser>>parseCue:noPattern:ifFail: (in category 'public
> access') -----
> > + parseCue: aCue noPattern: noPattern ifFail: aBlock
> > + "Answer a MethodNode for the argument, sourceStream, that is the
> root
> > + of a parse tree. Parsing is done with respect to the
> CompilationCue to
> > + resolve variables, etc. Errors in parsing are reported to the
> cue's requestor;
> > + otherwise aBlock is evaluated. The argument noPattern is a Boolean
> that is
> > + true if the the sourceStream does not contain a method header
> (i.e., for DoIts)."
> > +
> > + | methNode repeatNeeded myStream s p subSelection |
> > + myStream := aCue sourceStream.
> > + [repeatNeeded := false.
> > + p := myStream position.
> > + s := myStream upToEnd.
> > + myStream position: p.
> > +
> > + doitFlag := noPattern.
> > + [(self encoderFromCue: aCue) init: aCue notifying: self.
> > + self init: myStream cue: aCue failBlock: [^aBlock value].
> > +
> > + subSelection := self interactive and: [cue requestor
> selectionInterval = (p + 1 to: p + s size)].
> > +
> > + failBlock:= aBlock.
> > + methNode := self method: noPattern context: cue context]
> > + on: ReparseAfterSourceEditing
> > + do: [ :ex |
> > + repeatNeeded := true.
> > + properties := nil. "Avoid accumulating pragmas and
> primitives Number"
> > + myStream := ex newSource
> > + ifNil: [subSelection
> > + ifTrue:
> > + [ReadStream
> > + on: cue requestor text string
> > + from: cue requestor
> selectionInterval first
> > + to: cue requestor selectionInterval
> last]
> > + ifFalse:
> > + [ReadStream on: cue requestor text
> string]]
> > + ifNotNil: [:src | myStream := src readStream]].
> > + repeatNeeded] whileTrue:
> > + [encoder := self encoder class new].
> > + methNode sourceText: s.
> > + ^methNode!
> >
> > Item was added:
> > + ----- Method: Parser>>parseMethodComment:setPattern: (in category
> 'public access') -----
> > + parseMethodComment: aString setPattern: aBlock
> > + "Answer the method comment for the argument, aString. Evaluate
> aBlock
> > + with the message pattern in the form #(selector, arguments,
> precedence)."
> > +
> > + self
> > + initPattern: aString
> > + return: aBlock.
> > + currentComment==nil
> > + ifTrue: [^OrderedCollection new]
> > + ifFalse: [^currentComment]!
> >
> > Item was added:
> > + ----- Method: Parser>>parseParameterNames: (in category 'public
> access') -----
> > + parseParameterNames: aString
> > + "Answer the parameter names for the argument, aString, which should
> > + parse successfully up to the temporary declaration or the end of
> the
> > + method header."
> > +
> > + self initScannerForTokenization.
> > + ^self
> > + initPattern: aString
> > + return: [:pattern | pattern at: 2]!
> >
> > Item was added:
> > + ----- Method: Parser>>parseSelector: (in category 'public access')
> -----
> > + parseSelector: aString
> > + "Answer the message selector for the argument, aString, which
> should
> > + parse successfully up to the temporary declaration or the end of
> the
> > + method header."
> > +
> > + self allowUnderscoreSelectors ifFalse: [self
> initScannerForTokenization].
> > + ^self
> > + initPattern: aString
> > + return: [:pattern | pattern at: 1]!
> >
> > Item was added:
> > + ----- Method: Parser>>pasteTempAtMethodLevel: (in category 'error
> correction') -----
> > + pasteTempAtMethodLevel: name
> > + | insertion delta theTextString characterBeforeMark |
> > +
> > + theTextString := cue requestor text string.
> > + characterBeforeMark := theTextString at: tempsMark-1 ifAbsent: [$ ].
> > + (theTextString at: tempsMark) = $| ifTrue: [
> > + "Paste it before the second vertical bar"
> > + insertion := name, ' '.
> > + characterBeforeMark isSeparator ifFalse: [ insertion := ' ',
> insertion].
> > + delta := 0.
> > + ] ifFalse: [
> > + "No bars - insert some with CR, tab"
> > + insertion := '| ' , name , ' |',String cr.
> > + delta := 2. "the bar and CR"
> > + characterBeforeMark = Character tab ifTrue: [
> > + insertion := insertion , String tab.
> > + delta := delta + 1. "the tab"
> > + ].
> > + ].
> > + tempsMark := tempsMark +
> > + (self substituteWord: insertion
> > + wordInterval: (tempsMark to: tempsMark-1)
> > + offset: 0) - delta!
> >
> > Item was added:
> > + ----- Method: Parser>>pattern:inContext: (in category 'expression
> types') -----
> > + pattern: fromDoit inContext: ctxt
> > + " unarySelector | binarySelector arg | keyword arg {keyword arg} =>
> > + {selector, arguments, precedence}."
> > + | args selector |
> > + doitFlag := fromDoit.
> > + fromDoit ifTrue:
> > + [^ctxt == nil
> > + ifTrue: [{#DoIt. {}. 1}]
> > + ifFalse: [{#DoItIn:. {encoder encodeVariable: encoder
> doItInContextName}. 3}]].
> > +
> > + hereType == #word ifTrue: [^ {self advance asSymbol. {}. 1}].
> > +
> > + (hereType == #binary or: [hereType == #verticalBar]) ifTrue:
> > + [selector := self advance asSymbol.
> > + args := Array with: (encoder bindArg: self argumentName).
> > + ^ {selector. args. 2}].
> > +
> > + hereType == #keyword ifTrue:
> > + [selector := WriteStream on: (String new: 32).
> > + args := OrderedCollection new.
> > + [hereType == #keyword] whileTrue:[
> > + selector nextPutAll: self advance.
> > + args addLast: (encoder bindArg: self argumentName).
> > + ].
> > + ^ {selector contents asSymbol. args. 3}].
> > + ^self expected: 'Message pattern'!
> >
> > Item was added:
> > + ----- Method: Parser>>possibleVariablesFor: (in category 'error
> correction') -----
> > + possibleVariablesFor: proposedVariable
> > + ^encoder possibleVariablesFor: proposedVariable!
> >
> > Item was added:
> > + ----- Method: Parser>>pragmaLiteral: (in category 'pragmas') -----
> > + pragmaLiteral: selectorSoFar
> > + "Read a pragma literal. As a nicety we allow a variable name
> (rather
> > + than a literal string) as the second argument to primitive:error:"
> > +
> > + (hereType == #string or: [ hereType == #literal or: [ hereType ==
> #number or: [ hereType == #character ] ] ])
> > + ifTrue: [ ^ self advance ].
> > + (here == $# and: [ tokenType == #word ])
> > + ifTrue: [ ^ self advance ].
> > + (here == #- and: [ tokenType == #number ])
> > + ifTrue: [ ^ (self advance; advance) negated ].
> > + (here = 'true' or: [ here = 'false' or: [ here = 'nil' ] ])
> > + ifTrue: [ ^ (Scanner new scanTokens: self advance) first ].
> > + "This nicety allows one to supply a primitive error
> > + temp as a variable name, rather than a string."
> > + ((selectorSoFar beginsWith: 'primitive:')
> > + and: [(selectorSoFar endsWith: 'error:')
> > + and: [hereType == #word]]) ifTrue:
> > + [^self advance].
> > + ^self expected: 'Literal constant'!
> >
> > Item was added:
> > + ----- Method: Parser>>pragmaPrimitives (in category 'pragmas') -----
> > + pragmaPrimitives
> > + | primitives |
> > + self properties isEmpty ifTrue:
> > + [^0].
> > + primitives := properties pragmas select:
> > + [:pragma|
> > + self class primitivePragmaSelectors includes:
> pragma keyword].
> > + primitives isEmpty ifTrue:
> > + [^0].
> > + primitives size > 1 ifTrue:
> > + [^self notify: 'Ambigous primitives'].
> > + ^self perform: primitives first keyword withArguments: primitives
> first arguments!
> >
> > Item was added:
> > + ----- Method: Parser>>pragmaSequence (in category 'pragmas') -----
> > + pragmaSequence
> > + "Parse a sequence of method pragmas."
> > +
> > + [ (hereType == #binary and: [self matchToken: #<])
> > + ifFalse: [ ^ self ].
> > + self pragmaStatement.
> > + (hereType == #binary and: [self matchToken: #>])
> > + ifFalse: [ ^ self expected: '>' ] ] repeat!
> >
> > Item was added:
> > + ----- Method: Parser>>pragmaStatement (in category 'pragmas') -----
> > + pragmaStatement
> > + "Parse a pragma statement. The leading '<' has already been
> consumed. The 'here' token is the first one in the pragma. Use that token
> to dispatch to a custom pragma-parsing method if one can be found with a
> selector that matches it.
> > +
> > + Note that custom pragma parsers need to fulfill two requirements:
> > + - method selector must match the current token as simple getter,
> > + e.g., <apicall: ...> matches #apicall or <primitive:
> ...> matches #primitive
> > + - method must have pragma <pragmaParser> to be called."
> > +
> > + "0) Early exit"
> > + (hereType = #keyword or: [ hereType = #word or: [ hereType =
> #binary ] ])
> > + ifFalse: [ ^ self expected: 'pragma declaration' ].
> > +
> > + "1) Do not consider one-word pragmas such as <primitive> and
> <foobar>. Only keyword pragmas."
> > + here last == $: ifTrue: [
> > + "2) Avoid interning new symbols for made-up pragmas such as #my
> for <my: 1 pragma: 2>."
> > + (Symbol lookup: here allButLast) ifNotNil: [:parserSelector |
> > + Parser methodDict at: parserSelector ifPresent:
> [:parserMethod |
> > + "3) Only call methods that claim to be a custom pragma
> parser via <pragmaParser>."
> > + (parserMethod hasPragma: #pragmaParser)
> > + ifTrue: [^ self executeMethod: parserMethod]]]].
> > +
> > + "X) No custom pragma parser found. Use the default one."
> > + ^ self pragmaStatementKeywords!
> >
> > Item was added:
> > + ----- Method: Parser>>pragmaStatementKeywords (in category 'pragmas')
> -----
> > + pragmaStatementKeywords
> > + "Read a single pragma statement. Parse all generic pragmas in the
> form of: <key1: val1 key2: val2 ...> and remember them, including
> primitives."
> > +
> > + | selector arguments words index keyword |
> > + selector := String new.
> > + arguments := OrderedCollection new.
> > + words := OrderedCollection new.
> > + [ hereType = #keyword or: [ (hereType = #word or: [ hereType =
> #binary ]) and: [ selector isEmpty ] ] ] whileTrue: [
> > + index := self startOfNextToken + requestorOffset.
> > + selector := selector , self advance.
> > + words add: (index to: self endOfLastToken + requestorOffset).
> > + (selector last = $: or: [ selector first isLetter not ])
> > + ifTrue: [ arguments add: (self pragmaLiteral: selector) ] ].
> > + selector numArgs ~= arguments size
> > + ifTrue: [ ^ self expected: 'pragma argument' ].
> > + keyword := (Symbol lookup: selector)
> > + ifNil: [ self
> > + correctSelector: selector wordIntervals: words
> > + exprInterval: (words first first to: words last last)
> > + ifAbort: [ ^ self fail ] ].
> > + self addPragma: (Pragma keyword: keyword arguments: arguments
> asArray).
> > + ^ true!
> >
> > Item was added:
> > + ----- Method: Parser>>primaryExpression (in category 'expression
> types') -----
> > + primaryExpression
> > + hereType == #word
> > + ifTrue:
> > + [parseNode := self variable.
> > + (parseNode isUndefTemp and: [self interactive])
> > + ifTrue: [self queryUndefined].
> > + parseNode nowHasRef.
> > + ^ true].
> > + hereType == #leftBracket
> > + ifTrue:
> > + [self advance.
> > + self blockExpression.
> > + ^true].
> > + hereType == #leftBrace
> > + ifTrue:
> > + [self braceExpression.
> > + ^true].
> > + hereType == #leftParenthesis
> > + ifTrue:
> > + [self advance.
> > + self expression ifFalse: [^self expected: 'expression'].
> > + (self match: #rightParenthesis)
> > + ifFalse: [^self expected: 'right parenthesis'].
> > + ^true].
> > + (hereType == #string or: [hereType == #number or: [hereType ==
> #literal or: [hereType == #character]]])
> > + ifTrue:
> > + [parseNode := encoder encodeLiteral: self advance.
> > + ^true].
> > + (here == #- and: [tokenType == #number and: [1 + hereEnd = mark]])
> > + ifTrue:
> > + [self advance.
> > + parseNode := encoder encodeLiteral: self advance negated.
> > + ^true].
> > + ^false!
> >
> > Item was added:
> > + ----- Method: Parser>>primitive (in category 'primitives') -----
> > + primitive
> > + "Pragmas that encode primitive calls are parsed as normal keyword
> pragmas. This hook exists so that packages do not break primitive-pragma
> parsing by accident. Instead, this method needs to be replaced
> intentionally.
> > +
> > + Note that primitive pragmas are special because they will be called
> back from the parser into the parser. See #pragmaPrimitives.
> > +
> > + Examples:
> > + <primitive: 42>
> > + <primitive: 'primitiveDirectoryCreate' module: 'FilePlugin'>
> > + <primitive: 'primitiveRegisterExternalFill' module: 'B2DPlugin'
> error: errorCode>"
> > +
> > + <pragmaParser>
> > + ^ self pragmaStatementKeywords!
> >
> > Item was added:
> > + ----- Method: Parser>>primitive: (in category 'primitives') -----
> > + primitive: anIntegerOrString
> > + "Create indexed primitive."
> > +
> > + ^self primitive: anIntegerOrString error: nil!
> >
> > Item was added:
> > + ----- Method: Parser>>primitive:error: (in category 'primitives') -----
> > + primitive: anIntegerOrString error: errorCodeVariableOrNil
> > + "Create indexed primitive with optional error code."
> > +
> > + ^anIntegerOrString isInteger
> > + ifTrue:
> > + [errorCodeVariableOrNil ifNotNil:
> > + [encoder floatTemp: (encoder bindTemp:
> errorCodeVariableOrNil) nowHasDef].
> > + anIntegerOrString]
> > + ifFalse:
> > + [anIntegerOrString isString
> > + ifTrue: [self primitive: anIntegerOrString module: nil
> error: errorCodeVariableOrNil]
> > + ifFalse: [self expected: 'Indexed primitive']]!
> >
> > Item was added:
> > + ----- Method: Parser>>primitive:error:module: (in category
> 'primitives') -----
> > + primitive: aNameString error: errorCodeVariableOrNil module:
> aModuleStringOrNil
> > + "Create named primitive with optional error code."
> > +
> > + ^self primitive: aNameString module: aModuleStringOrNil error:
> errorCodeVariableOrNil!
> >
> > Item was added:
> > + ----- Method: Parser>>primitive:module: (in category 'primitives')
> -----
> > + primitive: aNameString module: aModuleStringOrNil
> > + "Create named primitive."
> > +
> > + ^self primitive: aNameString module: aModuleStringOrNil error: nil!
> >
> > Item was added:
> > + ----- Method: Parser>>primitive:module:error: (in category
> 'primitives') -----
> > + primitive: aNameString module: aModuleStringOrNil error:
> errorCodeVariableOrNil
> > + "Create named primitive with optional error code."
> > + | firstLiteral |
> > + (aNameString isString and: [ aModuleStringOrNil isNil or: [
> aModuleStringOrNil isString ] ])
> > + ifFalse: [ ^ self expected: 'Named primitive' ].
> > + firstLiteral := { aModuleStringOrNil ifNotNil:
> [aModuleStringOrNil asSymbol].
> > + aNameString asSymbol.
> > + 0.
> > + 0 }.
> > + (encoder litIndex: firstLiteral) ~= 0 ifTrue:
> > + [self error: 'parser failed to allocate [primitive binding
> array as first literal'].
> > + firstLiteral beWritableObject. "Undo the read-only setting in
> litIndex:"
> > + errorCodeVariableOrNil ifNotNil:
> > + [encoder floatTemp: (encoder bindTemp: errorCodeVariableOrNil)
> nowHasDef].
> > + ^117!
> >
> > Item was added:
> > + ----- Method: Parser>>properties (in category 'pragmas') -----
> > + properties
> > + ^ properties ifNil: [ properties := AdditionalMethodState new ]!
> >
> > Item was added:
> > + ----- Method: Parser>>queriedUnusedTemporaries (in category
> 'accessing') -----
> > + queriedUnusedTemporaries
> > +
> > + queriedUnusedTemporaries ifNil:
> > + [queriedUnusedTemporaries := Dictionary new].
> > + ^queriedUnusedTemporaries!
> >
> > Item was added:
> > + ----- Method: Parser>>queryUndefined (in category 'error correction')
> -----
> > + queryUndefined
> > + | varStart varName |
> > + varName := parseNode key.
> > + varStart := self endOfLastToken + requestorOffset - varName size +
> 1.
> > + self selectFrom: varStart to: varStart + varName size - 1 during: [
> > + (UndefinedVariable name: varName) ifFalse: [^ self fail]].!
> >
> > Item was added:
> > + ----- Method: Parser>>removeEmptyTempDeclarationsFrom: (in category
> 'error correction') -----
> > + removeEmptyTempDeclarationsFrom: methodNode
> > +
> > + | sourceCode madeChanges tempsMarkHolder |
> > + sourceCode := cue requestor text asString.
> > + tempsMarkHolder := self collectTemporaryDeclarationsFrom:
> methodNode.
> > + madeChanges := false.
> > + tempsMarkHolder do: [ :currentBlock | | tempsMarkChar0
> tempsMarkChar1 tempsMarkChar2 end start |
> > + tempsMarkChar0 := (sourceCode at: currentBlock tempsMark).
> > + tempsMarkChar1 := (sourceCode at: currentBlock tempsMark - 1).
> > + tempsMarkChar2 := (sourceCode at: currentBlock tempsMark - 2
> ifAbsent: []).
> > + (tempsMarkChar0 == $| and: [ tempsMarkChar1 == $| ])
> > + ifTrue:
> > + [ end := currentBlock tempsMark.
> > + start := end - 1].
> > + (tempsMarkChar0 == $| and: [ tempsMarkChar1 == $ and: [
> tempsMarkChar2 == $| ] ])
> > + ifTrue:
> > + [ end := currentBlock tempsMark.
> > + start := end - 2].
> > +
> > + (start notNil and: [ end notNil ]) ifTrue: [
> > + | lineStart lineEnd |
> > + lineStart := 1 + (sourceCode
> > + lastIndexOf: Character cr
> > + startingAt: start - 1).
> > + lineEnd := sourceCode
> > + indexOf: Character cr
> > + startingAt: end + 1
> > + ifAbsent: [ sourceCode size ].
> > + ((sourceCode indexOfAnyOf: CharacterSet nonSeparators
> startingAt: lineStart) >= start
> > + and: [ (sourceCode indexOfAnyOf: CharacterSet
> nonSeparators startingAt: end + 1) > lineEnd ]) ifTrue: [
> > + start := lineStart.
> > + end := lineEnd ].
> > + cue requestor correctFrom: start to: end with: ''.
> > + madeChanges := true.
> > + currentBlock tempsMark: nil ] ].
> > + madeChanges ifTrue: [ReparseAfterSourceEditing signal]!
> >
> > Item was added:
> > + ----- Method:
> Parser>>removeUnusedTemporaryNamed:from:lookingAt:movingTempMarksOf: (in
> category 'error correction') -----
> > + removeUnusedTemporaryNamed: temp from: str lookingAt: currentBlock
> movingTempMarksOf: someBlocks
> > +
> > + | start end |
> > + end := currentBlock tempsMark - 1.
> > + ["Beginning at right temp marker..."
> > + start := end - temp size + 1.
> > + end < temp size or: [ (str at: start) = $| ]
> > + or: [ temp = (str copyFrom: start to: end)
> > + and: [ ((str at: start - 1) = $| | (str at: start - 1)
> isSeparator)
> > + & ((str at: end + 1) = $| | (str at: end + 1)
> isSeparator) ] ]]
> > + whileFalse: [
> > + "Search left for the unused temp"
> > + end := cue requestor nextTokenFrom: end direction: -1 ].
> > + (end < temp size or: [ (str at: start) = $| ])
> > + ifFalse:
> > + [(str at: start - 1) = $
> > + ifTrue: [ start := start - 1 ].
> > + cue requestor correctFrom: start to: end with: ''.
> > + someBlocks do: [ :aBlock | aBlock tempsMark: aBlock
> tempsMark - (end - start + 1)].
> > + ^true ].
> > + ^false!
> >
> > Item was added:
> > + ----- Method: Parser>>removeUnusedTemps: (in category 'error
> correction') -----
> > + removeUnusedTemps: methodNode
> > + "Scan for unused temp names, and prompt the user about the prospect
> of removing each one found"
> > +
> > + | madeChanges tempsMarkHolder unusedTempNames
> tempMarkHoldersToChange |
> > + madeChanges := false.
> > + tempMarkHoldersToChange := OrderedCollection new.
> > + tempsMarkHolder := self collectTemporaryDeclarationsFrom:
> methodNode.
> > + unusedTempNames := encoder unusedTempNames select:
> > + [ :temp | (encoder lookupVariable: temp ifAbsent: [ ])
> isUndefTemp
> > + and: [ self queriedUnusedTemporaries at: temp ifAbsentPut: [
> > + (UnusedVariable name: temp) ifNil: [ ^ self fail ]] ]].
> > + tempsMarkHolder do: [ :currentBlock |
> > + tempMarkHoldersToChange add: currentBlock.
> > + unusedTempNames do:
> > + [ :temp |
> > + (self
> > + removeUnusedTemporaryNamed: temp
> > + from: cue requestor text asString
> > + lookingAt: currentBlock
> > + movingTempMarksOf: tempMarkHoldersToChange) ifTrue: [
> madeChanges := true ]]].
> > + madeChanges
> > + ifTrue: [ self removeEmptyTempDeclarationsFrom: methodNode.
> > + ReparseAfterSourceEditing signal ]!
> >
> > Item was added:
> > + ----- Method: Parser>>selectFrom:to:during: (in category 'error
> correction') -----
> > + selectFrom: start to: stop during: aBlock
> > + "Temporarily focus user attention on a zone of error thru text
> section.
> > + Then restore original user selection.
> > + Note: the original selection is restored invisibly (not displayed).
> > + This will avoid flickering when chaining multiple corrections."
> > +
> > + | userSelection |
> > + userSelection := cue requestor selectionInterval.
> > + cue requestor selectFrom: start to: stop.
> > + aBlock value.
> > + cue requestor selectIntervalInvisibly: userSelection!
> >
> > Item was added:
> > + ----- Method: Parser>>setCue: (in category 'private') -----
> > + setCue: aCue
> > + cue := aCue!
> >
> > Item was added:
> > + ----- Method: Parser>>startOfNextToken (in category 'scanning') -----
> > + startOfNextToken
> > + "Return starting position in source of next token."
> > +
> > + hereType == #doIt ifTrue: [^source position + 1].
> > + ^hereMark!
> >
> > Item was added:
> > + ----- Method: Parser>>statements:innerBlock: (in category 'expression
> types') -----
> > + statements: argNodes innerBlock: inner
> > +
> > + ^self statements: argNodes innerBlock: inner blockNode: BlockNode
> new!
> >
> > Item was added:
> > + ----- Method: Parser>>statements:innerBlock:blockNode: (in category
> 'expression types') -----
> > + statements: argNodes innerBlock: inner blockNode: theBlockNode
> > +
> > + | stmts returns start |
> > + "give initial comment to block, since others trail statements"
> > + theBlockNode comment: currentComment.
> > + currentComment := nil.
> > + stmts := OrderedCollection new.
> > + returns := false.
> > + hereType ~~ #rightBracket ifTrue:
> > + [[theBlockNode startOfLastStatement: (start := self
> startOfNextToken).
> > + (returns := self matchReturn)
> > + ifTrue:
> > + [self expression ifFalse:
> > + [^self expected: 'Expression to return'].
> > + self addComment.
> > + stmts addLast: (parseNode isReturningIf
> > + ifTrue: [parseNode]
> > + ifFalse: [ReturnNode new
> > + expr: parseNode
> > + encoder: encoder
> > + sourceRange: (start to:
> self endOfLastToken)])]
> > + ifFalse:
> > + [self expression
> > + ifTrue:
> > + [self addComment.
> > + "if both branches return, following code is
> unreachable, let's avoid this.
> > + But only if interactive, we don't want to
> prevent loading of legacy code"
> > + self interactive ifTrue: [returns := parseNode
> isReturningIf].
> > + stmts addLast: parseNode]
> > + ifFalse:
> > + [self addComment.
> > + stmts size = 0 ifTrue:
> > + [stmts addLast:
> > + (encoder encodeVariable:
> > + (inner ifTrue: ['nil'] ifFalse:
> ['self']))]]].
> > + returns ifTrue:
> > + [self match: #period.
> > + (hereType == #rightBracket or: [hereType == #doIt])
> ifFalse:
> > + [^self expected: 'End of block']].
> > + returns not and: [self match: #period]] whileTrue].
> > + theBlockNode
> > + arguments: argNodes
> > + statements: stmts
> > + returns: returns
> > + from: encoder.
> > + parseNode := theBlockNode.
> > + ^true!
> >
> > Item was added:
> > + ----- Method: Parser>>substituteSelector:wordIntervals: (in category
> 'error correction') -----
> > + substituteSelector: selectorParts wordIntervals: spots
> > + "Substitute the correctSelector into the (presumed interactive)
> receiver."
> > + | offset |
> > + offset := 0.
> > + selectorParts with: spots do:
> > + [ :word :interval |
> > + offset := self substituteWord: word wordInterval: interval
> offset: offset ]
> > + !
> >
> > Item was added:
> > + ----- Method: Parser>>substituteVariable:atInterval: (in category
> 'error correction') -----
> > + substituteVariable: each atInterval: anInterval
> > + self
> > + substituteWord: each
> > + wordInterval: anInterval
> > + offset: 0.
> > + ^encoder encodeVariable: each!
> >
> > Item was added:
> > + ----- Method: Parser>>substituteWord:wordInterval:offset: (in category
> 'error correction') -----
> > + substituteWord: correctWord wordInterval: spot offset: o
> > + "Substitute the correctSelector into the (presumed interactive)
> receiver.
> > + Update requestorOffset based on the delta size and answer the
> updated offset."
> > +
> > + cue requestor correctFrom: spot first + o to: spot last + o with:
> correctWord.
> > + requestorOffset := requestorOffset + correctWord size - spot size.
> > + ^o + correctWord size - spot size!
> >
> > Item was added:
> > + ----- Method: Parser>>temporaries (in category 'expression types')
> -----
> > + temporaries
> > + " [ '|' (variable)* '|' ]"
> > + | vars theActualText |
> > + (self match: #verticalBar) ifFalse:
> > + ["no temps"
> > + doitFlag ifTrue:
> > + [tempsMark := self interactive
> > + ifTrue: [cue requestor
> selectionInterval first]
> > + ifFalse: [1].
> > + ^ #()].
> > + tempsMark := hereMark "formerly --> prevMark + prevToken".
> > + tempsMark > 0 ifTrue:
> > + [theActualText := source contents.
> > + [tempsMark < theActualText size and: [(theActualText at:
> tempsMark) isSeparator]]
> > + whileTrue: [tempsMark := tempsMark + 1]].
> > + ^ #()].
> > + vars := OrderedCollection new.
> > + [hereType == #word]
> > + whileTrue: [vars addLast: (encoder bindTemp: self advance)].
> > + (self match: #verticalBar) ifTrue:
> > + [tempsMark := prevMark.
> > + ^ vars].
> > + ^ self expected: 'Vertical bar'
> > + !
> >
> > Item was added:
> > + ----- Method: Parser>>temporariesIn: (in category 'expression types')
> -----
> > + temporariesIn: methodSelector
> > + " [ '|' (variable)* '|' ]"
> > + | vars theActualText |
> > + (self match: #verticalBar) ifFalse:
> > + ["no temps"
> > + doitFlag ifTrue:
> > + [tempsMark := self interactive
> > + ifTrue: [cue requestor
> selectionInterval first]
> > + ifFalse: [1].
> > + ^ #()].
> > + tempsMark := hereMark "formerly --> prevMark + prevToken".
> > + tempsMark > 0 ifTrue:
> > + [theActualText := source contents.
> > + [tempsMark < theActualText size and: [(theActualText at:
> tempsMark) isSeparator]]
> > + whileTrue: [tempsMark := tempsMark + 1]].
> > + ^ #()].
> > + vars := OrderedCollection new.
> > + [hereType == #word]
> > + whileTrue: [vars addLast: (encoder bindTemp: self advance in:
> methodSelector)].
> > + (self match: #verticalBar) ifTrue:
> > + [tempsMark := prevMark.
> > + ^ vars].
> > + ^ self expected: 'Vertical bar'!
> >
> > Item was added:
> > + ----- Method: Parser>>temporaryBlockVariablesFor: (in category
> 'expression types') -----
> > + temporaryBlockVariablesFor: aBlockNode
> > + "Scan and answer temporary block variables."
> > +
> > + | variables |
> > + (self match: #verticalBar) ifFalse:
> > + "There are't any temporary variables."
> > + [aBlockNode tempsMark: prevMark + requestorOffset.
> > + ^#()].
> > +
> > + variables := OrderedCollection new.
> > + [hereType == #word] whileTrue:
> > + [variables addLast: (encoder bindBlockTemp: self advance
> within: aBlockNode)].
> > + (self match: #verticalBar) ifFalse:
> > + [^self expected: 'Vertical bar'].
> > + aBlockNode tempsMark: prevMark + requestorOffset.
> > + ^variables!
> >
> > Item was added:
> > + ----- Method: Parser>>tempsMark (in category 'accessing') -----
> > + tempsMark
> > + ^ tempsMark!
> >
> > Item was added:
> > + ----- Method: Parser>>tempsMark: (in category 'accessing') -----
> > + tempsMark: aNumber
> > + tempsMark := aNumber!
> >
> > Item was added:
> > + ----- Method: Parser>>transformAVerticalBarIntoABinarySelector (in
> category 'scanning') -----
> > + transformAVerticalBarIntoABinarySelector
> > + "Transform a vertical bar into a binary selector.
> > + Eventually aggregate a serie of immediately following vertical bars
> and a binary selector.
> > + Note that this aggregation cannot occur at scan time, because a
> pair of vertical bars can be encountered in two valid constructs:
> > + - either as an empty temporaries specification,
> > + - or as a local temporaries specification in a block of arity > 0"
> > + here := '|'.
> > + hereType := #binary.
> > + [tokenType == #verticalBar and: [hereMark + here size = mark]]
> > + whileTrue: [
> > + here := here , '|'.
> > + hereEnd := hereEnd + 1.
> > + self scanToken].
> > + (tokenType == #binary and: [hereMark + here size = mark])
> > + ifTrue: [
> > + here := here asString , token.
> > + hereType := #binary.
> > + hereEnd := hereEnd + token size.
> > + self scanToken].!
> >
> > Item was added:
> > + ----- Method: Parser>>variable (in category 'expression types') -----
> > + variable
> > +
> > + | varName varStart varEnd |
> > + varStart := self startOfNextToken + requestorOffset.
> > + varName := self advance.
> > + varEnd := self endOfLastToken + requestorOffset.
> > + ^ encoder encodeVariable: varName
> > + sourceRange: (varStart to: varEnd)
> > + ifUnknown: [self correctVariable: varName interval: (varStart
> to: varEnd)]!
> >
> > Item was added:
> > + Notification subclass: #ParserNotification
> > + instanceVariableNames: 'name'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Exceptions'!
> >
> > Item was added:
> > + ----- Method: ParserNotification class>>name: (in category 'instance
> creation') -----
> > + name: aString
> > + ^ (self new setName: aString) signal!
> >
> > Item was added:
> > + ----- Method: ParserNotification>>openMenuIn: (in category 'handling')
> -----
> > + openMenuIn: aBlock
> > + self subclassResponsibility!
> >
> > Item was added:
> > + ----- Method: ParserNotification>>setName: (in category
> 'initialization') -----
> > + setName: aString
> > + name := aString!
> >
> > Item was added:
> > + TempVariableNode subclass: #RemoteTempVectorNode
> > + instanceVariableNames: 'remoteTemps readNode writeNode'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !RemoteTempVectorNode commentStamp: '<historical>' prior: 0!
> > + I am a node for a vector of remote temps, created to share temps
> between closures when those temps are written to in closures other than
> their defining ones.!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>accept: (in category 'visiting')
> -----
> > + accept: aVisitor
> > + ^aVisitor visitRemoteTempVectorNode: self!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>addRemoteTemp:encoder: (in
> category 'closure analysis') -----
> > + addRemoteTemp: aTempVariableNode encoder: encoder
> > + remoteTemps ifNil:
> > + [remoteTemps := OrderedCollection new].
> > + remoteTemps addLast: aTempVariableNode.
> > + aTempVariableNode referenceScopesAndIndicesDo:
> > + [:scopeBlock "<BlockNode>" :location "<Integer>"|
> > + self addReadWithin: scopeBlock at: location]!
> >
> > Item was added:
> > + ----- Method:
> RemoteTempVectorNode>>emitCodeForStoreInto:stack:encoder: (in category
> 'code generation') -----
> > + emitCodeForStoreInto: aTempVariableNode stack: stack encoder: encoder
> > + encoder
> > + genStoreRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
> > + inVectorAt: index!
> >
> > Item was added:
> > + ----- Method:
> RemoteTempVectorNode>>emitCodeForStorePopInto:stack:encoder: (in category
> 'code generation') -----
> > + emitCodeForStorePopInto: aTempVariableNode stack: stack encoder:
> encoder
> > + encoder
> > + genStorePopRemoteTemp: (remoteTemps indexOf: aTempVariableNode)
> - 1
> > + inVectorAt: index.
> > + stack pop: 1!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>emitCodeForValueOf:stack:encoder:
> (in category 'code generation') -----
> > + emitCodeForValueOf: aTempVariableNode stack: stack encoder: encoder
> > + encoder
> > + genPushRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
> > + inVectorAt: index.
> > + stack push: 1!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>isIndirectTempVector (in category
> 'closure analysis') -----
> > + isIndirectTempVector
> > + ^true!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>nodeToInitialize: (in category
> 'code generation') -----
> > + nodeToInitialize: encoder
> > + ^AssignmentNode new
> > + variable: self
> > + value: (NewArrayNode new numElements: remoteTemps size)!
> >
> > Item was added:
> > + ----- Method:
> RemoteTempVectorNode>>printDefinitionForClosureAnalysisOn: (in category
> 'printing') -----
> > + printDefinitionForClosureAnalysisOn: aStream
> > + | refs |
> > + aStream
> > + nextPut: ${;
> > + nextPutAll: key.
> > + definingScope ifNotNil: [definingScope blockExtent ifNotNil: [:be|
> aStream nextPutAll: ' d@'; print: be first]].
> > + readingScopes ifNotNil: [
> > + refs := Set new.
> > + readingScopes do: [:elems| refs addAll: elems].
> > + refs sorted do: [:read| aStream nextPutAll: ' r@'; print:
> read]].
> > + remoteTemps
> > + do: [:rt| rt printDefinitionForClosureAnalysisOn: aStream]
> > + separatedBy: [aStream nextPut: $,; space].
> > + aStream nextPut: $}!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>referenceScopesAndIndicesDo: (in
> category 'closure analysis') -----
> > + referenceScopesAndIndicesDo: aBinaryBlock
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>remoteTemps (in category
> 'accessing') -----
> > + remoteTemps
> > + ^remoteTemps!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>remoteTemps: (in category
> 'decompiler') -----
> > + remoteTemps: anArray
> > + remoteTemps := anArray.
> > + anArray do: [:tempNode| tempNode remoteNode: self]!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>scope (in category 'code
> generation') -----
> > + scope
> > + "Answer scope of temporary variables.
> > + Currently only the following distinctions are made:
> > + 0 outer level: args and user-declared temps
> > + 1 block args and doLimiT temps
> > + -1 a block temp that is no longer active
> > + -2 a block temp that held limit of to:do:
> > + -3 an indirect temp vector"
> > + ^-3!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>sizeCodeForStoreInto:encoder: (in
> category 'code generation') -----
> > + sizeCodeForStoreInto: aTempVariableNode encoder: encoder
> > + ^encoder
> > + sizeStoreRemoteTemp: (remoteTemps indexOf: aTempVariableNode) -
> 1
> > + inVectorAt: index!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>sizeCodeForStorePopInto:encoder:
> (in category 'code generation') -----
> > + sizeCodeForStorePopInto: aTempVariableNode encoder: encoder
> > + ^encoder
> > + sizeStorePopRemoteTemp: (remoteTemps indexOf:
> aTempVariableNode) - 1
> > + inVectorAt: index!
> >
> > Item was added:
> > + ----- Method: RemoteTempVectorNode>>sizeCodeForValueOf:encoder: (in
> category 'code generation') -----
> > + sizeCodeForValueOf: aTempVariableNode encoder: encoder
> > + ^encoder
> > + sizePushRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
> > + inVectorAt: index!
> >
> > Item was added:
> > + Notification subclass: #ReparseAfterSourceEditing
> > + instanceVariableNames: 'newSource'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> > +
> > + !ReparseAfterSourceEditing commentStamp: 'nice 9/18/2013 22:05' prior:
> 0!
> > + A ReparseAfterSourceEditing is a Notification used to restart the
> syntax parsing phase of a compilation after a source code edition.
> > +
> > + Instance Variables
> > + newSource: <UndefinedObject | String | Text | Stream>
> > +
> > + newSource
> > + - this is the new source code to be used for restarting compilation
> if non interactive
> > +
> > + In case of interactive compilation, newSource variable is nil because
> source code edition is performed directly in the source code editor, and
> the new source code will be picked directly there by the compiler.
> > +
> > + In case of non interactive compilation, source code edition typically
> occurs in a SyntaxError window popping up. But the compiler has no direct
> access to this object, so newSource has to be passed by our intermediate.
> > + !
> >
> > Item was added:
> > + ----- Method: ReparseAfterSourceEditing class>>withNewSource: (in
> category 'instance creation') -----
> > + withNewSource: aStringOrStream
> > + ^(self new withNewSource: aStringOrStream) signal!
> >
> > Item was added:
> > + ----- Method: ReparseAfterSourceEditing>>newSource (in category
> 'accessing') -----
> > + newSource
> > + ^newSource!
> >
> > Item was added:
> > + ----- Method: ReparseAfterSourceEditing>>withNewSource: (in category
> 'initialize-release') -----
> > + withNewSource: aStringOrStream
> > + newSource := aStringOrStream!
> >
> > Item was added:
> > + ParseNode subclass: #ReturnNode
> > + instanceVariableNames: 'expr'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !ReturnNode commentStamp: '<historical>' prior: 0!
> > + I represent an expression of the form ^expr.!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitReturnNode: self!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>analyseTempsWithin:rootNode:assignmentPools:
> (in category 'closure analysis') -----
> > + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode
> "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + "Note we could do this:
> > + scopeBlock ~~ rootNode block ifTrue:
> > + [scopeBlock noteNonLocalReturn].
> > + and pass up the flag in <BlockNode>>>analyseTempsWithin:rootNode:
> > + which may be fast but will also give less information the debugger.
> > + For now we consider clean blocks a premature optimization."
> > + self flag: 'consider clean blocks'.
> > + expr analyseTempsWithin: scopeBlock rootNode: rootNode
> assignmentPools: assignmentPools!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>asReturnNode (in category 'converting') -----
> > + asReturnNode!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>code (in category 'code generation') -----
> > + code
> > +
> > + ^expr code!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>emitCodeForReturn:encoder: (in category
> 'code generation') -----
> > + emitCodeForReturn: stack encoder: encoder
> > +
> > + expr emitCodeForReturn: stack encoder: encoder.
> > + pc := encoder pc!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>emitCodeForValue:encoder: (in category 'code
> generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > +
> > + expr emitCodeForReturn: stack encoder: encoder.
> > + pc := encoder pc!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>expr (in category 'printing') -----
> > + expr
> > +
> > + ^ expr.
> > + !
> >
> > Item was added:
> > + ----- Method: ReturnNode>>expr: (in category 'initialize-release')
> -----
> > + expr: e
> > +
> > + expr := e!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>expr:encoder:sourceRange: (in category
> 'initialize-release') -----
> > + expr: e encoder: encoder sourceRange: range
> > +
> > + expr := e.
> > + encoder noteSourceRange: range forNode: self!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>isReturnSelf (in category 'testing') -----
> > + isReturnSelf
> > +
> > + ^expr == NodeSelf!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>isSpecialConstant (in category 'testing')
> -----
> > + isSpecialConstant
> > +
> > + ^expr isSpecialConstant!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>isVariableReference (in category 'testing')
> -----
> > + isVariableReference
> > +
> > + ^expr isVariableReference!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>printOn:indent: (in category 'printing')
> -----
> > + printOn: aStream indent: level
> > +
> > + aStream nextPutAll: '^ '. "make this a preference??"
> > + expr printOn: aStream indent: level.
> > + expr printCommentOn: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level
> > +
> > + aStream nextPutAll: '^ '. "make this a preference??"
> > + expr printWithClosureAnalysisOn: aStream indent: level.
> > + expr printCommentOn: aStream indent: level!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>sizeCodeForReturn: (in category 'code
> generation') -----
> > + sizeCodeForReturn: encoder
> > +
> > + ^expr sizeCodeForReturn: encoder!
> >
> > Item was added:
> > + ----- Method: ReturnNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > +
> > + ^expr sizeCodeForReturn: encoder!
> >
> > Item was added:
> > + Object subclass: #Scanner
> > + instanceVariableNames: 'source mark hereChar aheadChar token
> tokenType currentComment buffer typeTable'
> > + classVariableNames: 'AllowBlockArgumentAssignment
> AllowUnderscoreAssignments AllowUnderscoreSelectors AllowUnicharSymbol
> DoItCharacter TypeTable'
> > + poolDictionaries: ''
> > + category: 'Compiler-Kernel'!
> > +
> > + !Scanner commentStamp: 'ul 4/3/2011 02:04' prior: 0!
> > + I scan a string or text, picking out Smalltalk syntactic tokens. I
> look one character ahead. I put each token found into the instance
> variable, token, and its type (a Symbol) into the variable, tokenType. At
> the end of the input stream, I pretend to see an endless sequence of
> special characters called doIts.
> > +
> > + Instance Variables
> > + aheadChar: <Character>
> > + buffer: <WriteStream>
> > + currentComment: <OrderedCollection>
> > + hereChar: <Character>
> > + mark: <Integer>
> > + source: <ReadStream>
> > + token: <Symbol|String|NumberCharacter|Boolean|nil>
> > + tokenType: <Symbol>
> > + typeTable: <Array>
> > +
> > + aheadChar
> > + - the next character in the input stream
> > +
> > + buffer
> > + - a reusable WriteStream on a String which is used for building
> strings. Shouldn't be used from multiple methods without resetting.
> > +
> > + currentComment
> > + - an OrderedCollection of strings which contain all comments
> between the current token and the previous token or the beginning of the
> source.
> > +
> > + hereChar
> > + - the current character
> > +
> > + mark
> > + - the position of the current token in the source stream
> > +
> > + source
> > + - the input stream of characters
> > +
> > + token
> > + - the current token
> > +
> > + tokenType
> > + - the type of the current token. The possible token types are:
> #binary, #character, #colon, #doIt, #keyword, #leftArrow, #leftBrace,
> #leftBracket, #leftParenthesis, #literal, #period, #rightBrace,
> #rightBracket, #rightParenthesis, #semicolon, #string, #upArrow,
> #verticalBar, #word, #xBinary, #xColon, #xDelimiter, #xDigit, #xDollar,
> #xDoubleQuote, #xLetter, #xLitQuote, #xSingleQuote, #xUnderscore
> > +
> > + typeTable
> > + - an array that maps each an evaluable tokenType to each character
> with asciiValue between 0 and 255!
> >
> > Item was added:
> > + ----- Method: Scanner class>>allowBlockArgumentAssignment (in category
> 'preferences') -----
> > + allowBlockArgumentAssignment
> > + "Accessor for the system-wide preference"
> > +
> > + <preference: 'Allow block argument assignment.'
> > + category: 'Compiler'
> > + description: 'If enabled, the compiler will allow assignment
> into block arguments.
> > + This provides backward compatibility with the pre-closure compiler.'
> > + type: #Boolean>
> > + ^AllowBlockArgumentAssignment ifNil: [ false ]!
> >
> > Item was added:
> > + ----- Method: Scanner class>>allowBlockArgumentAssignment: (in
> category 'preferences') -----
> > + allowBlockArgumentAssignment: aBoolean
> > + "Accessor for the system-wide preference"
> > +
> > + AllowBlockArgumentAssignment := aBoolean!
> >
> > Item was added:
> > + ----- Method: Scanner class>>allowUnderscoreAsAssignment (in category
> 'preferences') -----
> > + allowUnderscoreAsAssignment
> > + "Accessor for the system-wide preference"
> > + <preference: 'Allow underscore assignments'
> > + category: 'Compiler'
> > + description: 'When true, underscore can be used as assignment
> operator'
> > + type: #Boolean>
> > + ^AllowUnderscoreAssignments ifNil:[true]!
> >
> > Item was added:
> > + ----- Method: Scanner class>>allowUnderscoreAsAssignment: (in category
> 'preferences') -----
> > + allowUnderscoreAsAssignment: aBool
> > + "Accessor for the system-wide preference"
> > + AllowUnderscoreAssignments := aBool!
> >
> > Item was added:
> > + ----- Method: Scanner class>>initialize (in category 'initialization')
> -----
> > + initialize
> > +
> > + self initializeTypeTable.
> > + "The unicode ending with FFFE or FFFF are non characters and can be
> used by applications if they wish.
> > + We use last legal unicode 16r10FFFF to encode the end of source
> stream"
> > + DoItCharacter := Character value: 16r10FFFF!
> >
> > Item was added:
> > + ----- Method: Scanner class>>initializeTypeTable (in category
> 'initialization') -----
> > + initializeTypeTable
> > + "self initializeTypeTable"
> > +
> > + | newTable |
> > + newTable := Array new: 256 withAll: #xBinary. "default"
> > + newTable atAll: #(9 10 12 13 32 16ra0) put: #xDelimiter. "tab lf ff
> cr space nbsp"
> > + newTable atAll: ($0 asciiValue to: $9 asciiValue) put: #xDigit.
> > +
> > + 1 to: 255
> > + do: [:index |
> > + (Character value: index) isLetter
> > + ifTrue: [newTable at: index put: #xLetter]].
> > +
> > + newTable at: $" asciiValue put: #xDoubleQuote.
> > + newTable at: $# asciiValue put: #xLitQuote.
> > + newTable at: $$ asciiValue put: #xDollar.
> > + newTable at: $' asciiValue put: #xSingleQuote.
> > + newTable at: $: asciiValue put: #xColon.
> > + newTable at: $( asciiValue put: #leftParenthesis.
> > + newTable at: $) asciiValue put: #rightParenthesis.
> > + newTable at: $. asciiValue put: #period.
> > + newTable at: $; asciiValue put: #semicolon.
> > + newTable at: $[ asciiValue put: #leftBracket.
> > + newTable at: $] asciiValue put: #rightBracket.
> > + newTable at: ${ asciiValue put: #leftBrace.
> > + newTable at: $} asciiValue put: #rightBrace.
> > + newTable at: $^ asciiValue put: #upArrow.
> > + newTable at: $_ asciiValue put: #xUnderscore.
> > + newTable at: $| asciiValue put: #verticalBar.
> > + TypeTable := newTable "bon voyage!!"!
> >
> > Item was added:
> > + ----- Method: Scanner class>>inviolateInstanceVariableNames (in
> category 'testing') -----
> > + inviolateInstanceVariableNames
> > + "Answer a list of instance variable names not to be used. (Place
> holder for real list)"
> > + ^ #('thisContext' 'self')!
> >
> > Item was added:
> > + ----- Method: Scanner class>>isLegalInstVarName: (in category
> 'testing') -----
> > + isLegalInstVarName: aString
> > + "Answer whether aString is a legal instance variable name."
> > +
> > + ^ ((self isLiteralSymbol: aString) and: [(aString includes: $:)
> not]) and:
> > + [(self inviolateInstanceVariableNames includes: aString) not]!
> >
> > Item was added:
> > + ----- Method: Scanner class>>isLiteralSymbol: (in category 'testing')
> -----
> > + isLiteralSymbol: aSymbol
> > + "Test whether a symbol can be stored as # followed by its
> characters.
> > + Symbols created internally with asSymbol may not have this
> property,
> > + e.g. '3' asSymbol."
> > +
> > + | i ascii type next last |
> > + i := aSymbol size.
> > + i = 0 ifTrue: [^ false].
> > +
> > + "TypeTable should have been origined at 0 rather than 1 ..."
> > + ascii := (aSymbol at: 1) asciiValue.
> > + type := TypeTable at: ascii ifAbsent: [^false].
> > + type == #xLetter ifTrue: [
> > + next := last := nil.
> > + [i > 1]
> > + whileTrue:
> > + [ascii := (aSymbol at: i) asciiValue.
> > + type := TypeTable at: ascii ifAbsent: [^false].
> > + (type == #xLetter or: [type == #xDigit or: [type ==
> #xColon
> > + and: [
> > + next == nil
> > + ifTrue: [last := #xColon. true]
> > + ifFalse: [last == #xColon and:
> [next ~~ #xDigit and: [next ~~ #xColon]]]]]])
> > + ifFalse: [^ false].
> > + next := type.
> > + i := i - 1].
> > + ^ true].
> > + type == #xBinary ifTrue:
> > + [^(2 to: i) allSatisfy: [:j |
> > + ascii := (aSymbol at: j) asciiValue.
> > + (TypeTable at: ascii ifAbsent: []) == #xBinary]].
> > + type == #verticalBar ifTrue: [^i = 1].
> > + ^false!
> >
> > Item was added:
> > + ----- Method: Scanner class>>isMessageSelector: (in category
> 'testing') -----
> > + isMessageSelector: aSymbol
> > + "Answer if the argument is a valid message selector.
> > + This is optimized for fast filtering."
> > + | first last sz type |
> > + (sz := aSymbol size) = 0 ifTrue: [^false].
> > + first := aSymbol at: 1.
> > + last := aSymbol at: sz.
> > + type := TypeTable at: first asciiValue.
> > +
> > + type == #xLetter ifTrue:
> > + ["Alas some people (myself included) do create selectors with
> an initial capital.
> > + But this is unusual, and it is even rarer for these to be
> unary selectors, so I think
> > + it is better to exclude class names than include the few
> exceptions."
> > + (first isUppercase and: [last ~~ $:]) ifTrue:
> > + [^false].
> > + "Could be unary or keyword, may include underscores if
> AllowUnderscoreSelectors.
> > + It is possible to be more agressive here, filtering out two
> successive colons, but I'm lazy"
> > + ^aSymbol allSatisfy: (AllowUnderscoreSelectors
> > + ifTrue:
> > + [last == $:
> > + ifTrue: [[:c| c == $: or: [c ==
> $_ or: [c isAlphaNumeric]]]]
> > + ifFalse: [[:c| c ~~ $: and: [c
> == $_ or: [c isAlphaNumeric]]]]]
> > + ifFalse:
> > + [last == $:
> > + ifTrue: [[:c| c == $: or: [c
> isAlphaNumeric]]]
> > + ifFalse: [[:c| c ~~ $: and: [c
> isAlphaNumeric]]]])].
> > +
> > + type == #xBinary ifTrue:
> > + [^aSymbol allSatisfy: [:c| c == $| or: [(TypeTable at: c
> asciiValue) == #xBinary]]].
> > +
> > + ^type == #xUnderscore
> > + and: [AllowUnderscoreSelectors
> > + and: [self isMessageSelector: aSymbol allButFirst]]
> > +
> > + "| implemented |
> > + implemented := Set new.
> > + self systemNavigation allSelect: [:m| implemented add: m selector.
> false].
> > + ^Symbol allSubInstances select: [:s| (implemented includes: s) not
> and: [self isMessageSelector: s]]"
> > +
> > + "| implemented |
> > + implemented := Set new.
> > + self systemNavigation allSelect: [:m| implemented add: m selector.
> false].
> > + ^implemented reject: [:s| self isMessageSelector: s]"!
> >
> > Item was added:
> > + ----- Method: Scanner class>>prefAllowUnderscoreAssignments (in
> category 'preferences') -----
> > + prefAllowUnderscoreAssignments
> > + "Accessor for the system-wide preference"
> > +
> > + self deprecated: 'Use #allowUnderscoreAsAssignment'.
> > + ^self allowUnderscoreAsAssignment!
> >
> > Item was added:
> > + ----- Method: Scanner class>>prefAllowUnderscoreAssignments: (in
> category 'preferences') -----
> > + prefAllowUnderscoreAssignments: aBool
> > + "Accessor for the system-wide preference"
> > +
> > + self deprecated: 'Use #allowUnderscoreAsAssignment:'.
> > + self allowUnderscoreAsAssignment: aBool!
> >
> > Item was added:
> > + ----- Method: Scanner class>>prefAllowUnderscoreSelectors (in category
> 'preferences') -----
> > + prefAllowUnderscoreSelectors
> > + "Accessor for the system-wide preference"
> > + <preference: 'Allow underscore selectors'
> > + category: 'Compiler'
> > + description: 'When true, underscore can be used in selectors
> and varibable names'
> > + type: #Boolean>
> > + ^AllowUnderscoreSelectors ifNil:[false]!
> >
> > Item was added:
> > + ----- Method: Scanner class>>prefAllowUnderscoreSelectors: (in
> category 'preferences') -----
> > + prefAllowUnderscoreSelectors: aBool
> > + "Accessor for the system-wide preference"
> > + AllowUnderscoreSelectors := aBool.
> > +
> > + "Reinitialize String's tokenish character map"
> > + String initialize!
> >
> > Item was added:
> > + ----- Method: Scanner class>>prefAllowUnicharSymbol (in category
> 'preferences') -----
> > + prefAllowUnicharSymbol
> > + "Accessor for the system-wide preference"
> > + <preference: 'Allow symbols with unique character like #.'
> > + category: 'Compiler'
> > + description: 'When true, the historical syntax #., #,, or # is
> allowed.'
> > + type: #Boolean>
> > + ^AllowUnicharSymbol ifNil: [false]!
> >
> > Item was added:
> > + ----- Method: Scanner class>>prefAllowUnicharSymbol: (in category
> 'preferences') -----
> > + prefAllowUnicharSymbol: aBoolean
> > + "Accessor for the system-wide preference"
> > + AllowUnicharSymbol := aBoolean!
> >
> > Item was added:
> > + ----- Method: Scanner class>>wellFormedInstanceVariableNameFrom: (in
> category 'testing') -----
> > + wellFormedInstanceVariableNameFrom: aString
> > + "Answer a legal instance variable name, derived from aString"
> > +
> > + | cleansedString |
> > + cleansedString := aString select: [:ch | ch isDigit or: [ch
> isLetter]].
> > + (cleansedString isEmpty or: [cleansedString first isDigit])
> > + ifTrue: [cleansedString := 'a', cleansedString]
> > + ifFalse: [cleansedString := cleansedString
> withFirstCharacterDownshifted].
> > +
> > + [self isLegalInstVarName: cleansedString] whileFalse:
> > + [cleansedString := cleansedString, 'x'].
> > + ^ cleansedString
> > +
> > + "Scanner wellFormedInstanceVariableNameFrom: '234 xx\ Uml
> /ler42342380-4'"!
> >
> > Item was added:
> > + ----- Method: Scanner>>advance (in category 'expression types') -----
> > + advance
> > +
> > + | prevToken |
> > + prevToken := token.
> > + self scanToken.
> > + ^prevToken!
> >
> > Item was added:
> > + ----- Method: Scanner>>allowUnderscoreAssignments (in category
> 'private') -----
> > + allowUnderscoreAssignments
> > + "Query preference"
> > + ^self class allowUnderscoreAsAssignment!
> >
> > Item was added:
> > + ----- Method: Scanner>>allowUnderscoreSelectors (in category
> 'private') -----
> > + allowUnderscoreSelectors
> > + "Query preference"
> > + ^self class prefAllowUnderscoreSelectors!
> >
> > Item was added:
> > + ----- Method: Scanner>>ambiguousSelector:inRange: (in category 'error
> handling') -----
> > + ambiguousSelector: aString inRange: anInterval
> > + "Compile with backward compatibility: $- is part of literal
> argument.."
> > +
> > + token := token asSymbol.
> > + ^self!
> >
> > Item was added:
> > + ----- Method: Scanner>>initScannerForTokenization (in category
> 'initialize-release') -----
> > + initScannerForTokenization
> > + "Use a version of typeTable that doesn't raise xIllegal when
> enocuntering an _"
> > + | underscoreIndex |
> > + underscoreIndex := typeTable identityIndexOf: #xUnderscore
> ifAbsent: [^self].
> > + typeTable := typeTable copy.
> > + typeTable at: underscoreIndex put: #xUnderscoreForTokenization.
> > + typeTable at: (typeTable identityIndexOf: #xLitQuote) put:
> #xLitQuoteForTokenization!
> >
> > Item was added:
> > + ----- Method: Scanner>>initialize (in category 'initialize-release')
> -----
> > + initialize
> > +
> > + super initialize.
> > + buffer := WriteStream on: (String new: 40).
> > + typeTable := TypeTable!
> >
> > Item was added:
> > + ----- Method: Scanner>>notify: (in category 'error handling') -----
> > + notify: string
> > + "Refer to the comment in Object|notify:."
> > + self error: string!
> >
> > Item was added:
> > + ----- Method: Scanner>>notify:at: (in category 'error handling') -----
> > + notify: string at: posiiton
> > + "Parser compatible message"
> > +
> > + ^self notify: string !
> >
> > Item was added:
> > + ----- Method: Scanner>>offEnd: (in category 'error handling') -----
> > + offEnd: aString
> > + "Parser overrides this"
> > +
> > + ^self notify: aString!
> >
> > Item was added:
> > + ----- Method: Scanner>>scan: (in category 'initialize-release') -----
> > + scan: inputStream
> > + "Bind the input stream, fill the character buffers and first token
> buffer."
> > +
> > + source := inputStream.
> > + self step.
> > + self step.
> > + self scanToken!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanAllTokenPositionsInto: (in category
> 'expression types') -----
> > + scanAllTokenPositionsInto: aBlock
> > + "Evaluate aBlock with the start and end positions of all separate
> non-white-space tokens, including comments."
> > +
> > + | lastMark |
> > + lastMark := 1.
> > + [currentComment ifNotNil:
> > + [currentComment do:
> > + [:cmnt| | idx |
> > + idx := source originalContents findLastOccurrenceOfString:
> cmnt startingAt: lastMark.
> > + (idx > 0 and: [idx < mark]) ifTrue:
> > + [aBlock value: idx - 1 value: (lastMark := idx + cmnt
> size)]].
> > + currentComment := nil].
> > + mark ifNotNil:
> > + [(token == #-
> > + and: [(self typeTableAt: hereChar) == #xDigit]) ifTrue:
> > + [| savedMark |
> > + savedMark := mark.
> > + self scanToken.
> > + token := token negated.
> > + mark := savedMark].
> > + "Compensate for the fact that the parser uses two character
> lookahead. Normally we must
> > + remove the extra two characters. But this mustn't happen for
> the last token at the end of stream."
> > + aBlock
> > + value: mark
> > + value: source position - (aheadChar == DoItCharacter
> > + ifTrue: [hereChar == DoItCharacter
> > + ifTrue: [0]
> > + ifFalse: [1]]
> > + ifFalse: [2])].
> > + (tokenType == #rightParenthesis
> > + or: [tokenType == #doIt]) ifTrue:
> > + [^self].
> > + tokenType == #leftParenthesis
> > + ifTrue:
> > + [self scanToken; scanAllTokenPositionsInto: aBlock]
> > + ifFalse:
> > + [(tokenType == #word or: [tokenType == #keyword or:
> [tokenType == #colon]])
> > + ifTrue:
> > + [self scanLitWord.
> > + token == #true ifTrue: [token := true].
> > + token == #false ifTrue: [token := false].
> > + token == #nil ifTrue: [token := nil]]
> > + ifFalse:
> > + [(token == #-
> > + and: [(self typeTableAt: hereChar) == #xDigit])
> > + ifTrue:
> > + [self scanToken.
> > + token := token negated]]].
> > + self scanToken ] repeat!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanFieldNames: (in category 'public access')
> -----
> > + scanFieldNames: stringOrArray
> > + "Answer an Array of Strings that are the identifiers in the input
> string,
> > + stringOrArray. If passed an Array, just answer with that Array,
> i.e.,
> > + assume it has already been scanned."
> > +
> > + | strm |
> > + (stringOrArray isMemberOf: Array)
> > + ifTrue: [^stringOrArray].
> > + self scan: (ReadStream on: stringOrArray asString).
> > + strm := WriteStream on: (Array new: 10).
> > + [tokenType == #doIt]
> > + whileFalse:
> > + [tokenType == #word ifTrue: [strm nextPut: token].
> > + self scanToken].
> > + ^strm contents
> > +
> > + "Scanner new scanFieldNames: 'abc def ghi' ('abc' 'def' 'ghi' )"!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanLitByteVec (in category 'expression types')
> -----
> > + scanLitByteVec
> > + | stream |
> > + stream := (ByteArray new: 16) writeStream.
> > + [ tokenType == #rightBracket or: [ tokenType == #doIt ] ]
> whileFalse: [
> > + tokenType == #word
> > + ifTrue: [ self scanLitWord ].
> > + (token isInteger and: [ token between: 0 and: 255 ])
> > + ifFalse: [ ^ self offEnd: '8-bit integer or right bracket
> expected' ].
> > + stream nextPut: token.
> > + self scanToken ].
> > + token := stream contents!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanLitVec (in category 'expression types')
> -----
> > + scanLitVec
> > + | s |
> > + s := WriteStream on: (Array new: 16).
> > + [tokenType == #rightParenthesis or: [tokenType == #doIt]]
> whileFalse:
> > + [tokenType == #leftParenthesis
> > + ifTrue:
> > + [self scanToken; scanLitVec]
> > + ifFalse:
> > + [(tokenType == #word or: [tokenType == #keyword or:
> [tokenType == #colon]])
> > + ifTrue:
> > + [self scanLitWord.
> > + token == #true ifTrue: [token := true].
> > + token == #false ifTrue: [token := false].
> > + token == #nil ifTrue: [token := nil]]
> > + ifFalse:
> > + [(token isCharacter and: [tokenType ~~
> #character])
> > + ifTrue: [token := token asSymbol]
> > + ifFalse: [(token == #-
> > + and: [(self typeTableAt: hereChar) ==
> #xDigit]) ifTrue:
> > + [self scanToken.
> > + token := token negated]]]].
> > + s nextPut: token.
> > + self scanToken].
> > + token := s contents!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanLitWord (in category 'expression types')
> -----
> > + scanLitWord
> > + "Accumulate keywords and asSymbol the result."
> > +
> > + token := (String streamContents: [ :stream |
> > + stream nextPutAll: token.
> > + [ (self typeTableAt: hereChar) == #xLetter ] whileTrue: [
> > + self xLetter.
> > + stream nextPutAll: token ] ]) asSymbol!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanMessageParts: (in category 'public access')
> -----
> > + scanMessageParts: sourceString
> > + "Return an array of the form (comment keyword comment arg comment
> keyword comment arg comment) for the message pattern of this method.
> Courtesy of Ted Kaehler, June 1999"
> > +
> > + | coll nonKeywords |
> > + coll := OrderedCollection new.
> > + self scan: (ReadStream on: sourceString asString).
> > + nonKeywords := 0.
> > + [tokenType == #doIt] whileFalse:
> > + [(currentComment == nil or: [currentComment isEmpty])
> > + ifTrue: [coll addLast: nil]
> > + ifFalse: [coll addLast: currentComment removeFirst.
> > + [currentComment isEmpty] whileFalse:
> > + [coll at: coll size put: (coll last, ' ',
> currentComment removeFirst)]].
> > + (token numArgs < 1 or: [token = #| and: [ coll size > 1 ] ])
> > + ifTrue: [(nonKeywords := nonKeywords + 1) > 1 ifTrue: [^
> coll]]
> > + "done with header"
> > + ifFalse: [nonKeywords := 0].
> > + coll addLast: token.
> > + self scanToken].
> > + (currentComment == nil or: [currentComment isEmpty])
> > + ifTrue: [coll addLast: nil]
> > + ifFalse: [coll addLast: currentComment removeFirst.
> > + [currentComment isEmpty] whileFalse: [
> > + coll at: coll size put: (coll last, ' ', currentComment
> removeFirst)]].
> > + ^ coll!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanStringStruct (in category 'expression
> types') -----
> > + scanStringStruct
> > +
> > + | s |
> > + s := WriteStream on: (Array new: 16).
> > + [tokenType == #rightParenthesis or: [tokenType == #doIt]]
> > + whileFalse:
> > + [tokenType == #leftParenthesis
> > + ifTrue:
> > + [self scanToken; scanStringStruct]
> > + ifFalse:
> > + [tokenType == #word ifFalse:
> > + [^self error: 'only words and parens allowed']].
> > + s nextPut: token.
> > + self scanToken].
> > + token := s contents!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanStringStruct: (in category 'public access')
> -----
> > + scanStringStruct: textOrString
> > + "The input is a string whose elements are identifiers and
> parenthesized
> > + groups of identifiers. Answer an array reflecting that structure,
> representing
> > + each identifier by an uninterned string."
> > +
> > + self scan: (ReadStream on: textOrString asString).
> > + self scanStringStruct.
> > + ^token
> > +
> > + "Scanner new scanStringStruct: 'a b (c d) (e f g)'"!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanToken (in category 'expression types') -----
> > + scanToken
> > +
> > + [(tokenType := self typeTableAt: hereChar) == #xDelimiter]
> > + whileTrue: [self step]. "Skip delimiters fast, there almost
> always is one."
> > + mark := aheadChar == DoItCharacter
> > + ifTrue: [hereChar == DoItCharacter
> > + ifTrue: [source position + 1]
> > + ifFalse: [source position]]
> > + ifFalse: [source position - 1].
> > + (tokenType at: 1) == $x "x as first letter"
> > + ifTrue: [self perform: tokenType "means perform to compute
> token & type"]
> > + ifFalse: [token := self step "else just unique the first char"].
> > + ^token!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanTokenPositionsIn:into: (in category 'public
> access') -----
> > + scanTokenPositionsIn: textOrString into: aBlock
> > + "Evaluate aBlock with the start and end positions of all separate
> non-white-space tokens, including comments, in textOrString."
> > +
> > + self initScannerForTokenization.
> > + source := (ReadStream on: textOrString asString).
> > + self step.
> > + self step.
> > + self scanAllTokenPositionsInto: aBlock
> > +
> > + "| code |
> > + code := ' #( 1 2 #( 3 4 )) 16r123 123 123.0 ', (Scanner
> sourceCodeAt: #scanTokenPositionsIn:into:).
> > + Scanner new scanTokenPositionsIn: code into: [:start :end|
> Transcript cr; nextPut: $_; nextPutAll: (code copyFrom: start to: end);
> nextPut: $_; endEntry]"
> > +
> > + "CodeDiffBuilder buildDisplayPatchFrom: (Scanner sourceCodeAt:
> #scanTokenPositionsIn:into:) to: ((Scanner sourceCodeAt:
> #scanTokenPositionsIn:into:) copyReplaceAll: (String with: Character cr)
> with: '')"
> > +
> > + "CodeDiffBuilder buildDisplayPatchFrom: 'colorTable ^colorTable
> ifNil: [colorTable _ ST80ColorTable]' to:'colorTable ^colorTable ifNil:
> [colorTable _ ST80ColorTable]'"!
> >
> > Item was added:
> > + ----- Method: Scanner>>scanTokens: (in category 'public access') -----
> > + scanTokens: textOrString
> > + "Answer an Array that has been tokenized as though the input text,
> > + textOrString, had appeared between the array delimitors #( and ) in
> a
> > + Smalltalk literal expression."
> > +
> > + self scan: (ReadStream on: textOrString asString).
> > + self scanLitVec.
> > + ^token
> > +
> > + "Scanner new scanTokens: 'identifier keyword: 8r31 ''string'' .'"!
> >
> > Item was added:
> > + ----- Method: Scanner>>step (in category 'expression types') -----
> > + step
> > +
> > + | c |
> > + c := hereChar.
> > + hereChar := aheadChar.
> > + source atEnd
> > + ifTrue: [aheadChar := DoItCharacter]
> > + ifFalse: [aheadChar := source next].
> > + ^c!
> >
> > Item was added:
> > + ----- Method: Scanner>>typeTableAt: (in category 'multi-character
> scans') -----
> > + typeTableAt: aCharacter
> > + ^typeTable
> > + at: aCharacter charCode
> > + ifAbsent:
> > + [aCharacter == DoItCharacter
> > + ifTrue: [#doIt]
> > + ifFalse: [#xLetter]]!
> >
> > Item was added:
> > + ----- Method: Scanner>>typedScan:do: (in category 'public access')
> -----
> > + typedScan: textOrString do: aBinaryBlock
> > + "Evaluate aBinaryBlock with the token and its type for the first
> token in input,
> > + mapping literals to type #literal and anything else to type #word."
> > + | theTokensType atNumber theToken |
> > + self initScannerForTokenization.
> > + self scan: (ReadStream on: textOrString asString).
> > + atNumber := hereChar notNil and: [hereChar isDigit].
> > + theTokensType := tokenType.
> > + theToken := self advance.
> > + (theToken == #- and: [atNumber and: [token isNumber]]) ifTrue:
> > + [theToken := self advance negated].
> > + theToken isNumber ifTrue: [theTokensType := #number].
> > + ^aBinaryBlock
> > + value: theToken
> > + value: ((#(number string literal character) includes:
> theTokensType)
> > + ifTrue: [#literal]
> > + ifFalse: [#word])!
> >
> > Item was added:
> > + ----- Method: Scanner>>typedScanTokens: (in category 'public access')
> -----
> > + typedScanTokens: textOrString
> > + "Answer an Array that has been tokenized with literals mapped to
> literals,
> > + special characters mapped to symbols and variable names and
> keywords
> > + to strings. This methiod accepts _ (underscore) as an assignment
> token
> > + irrespective of whether the system prefers := as the assignment
> token."
> > + | s |
> > + self initScannerForTokenization.
> > + self scan: (ReadStream on: textOrString asString).
> > + s := WriteStream on: (Array new: 16).
> > + [tokenType == #doIt] whileFalse:
> > + [(token == #-
> > + and: [(self typeTableAt: hereChar) == #xDigit]) ifTrue:
> > + [self scanToken.
> > + token := token negated].
> > + s nextPut: token.
> > + self scanToken].
> > + ^s contents
> > +
> > + "Scanner new typedScanTokens: (Scanner sourceCodeAt:
> #typedScanTokens:)"!
> >
> > Item was added:
> > + ----- Method: Scanner>>xBinary (in category 'multi-character scans')
> -----
> > + xBinary
> > +
> > + | startOfToken |
> > + tokenType := #binary.
> > + startOfToken := mark.
> > + token := String with: self step.
> > + [(self typeTableAt: hereChar) == #xBinary or: [(self typeTableAt:
> hereChar) == #verticalBar]] whileTrue:
> > + [(hereChar == $- and: [(self typeTableAt: aheadChar) ==
> #xDigit])
> > + ifTrue: [^self ambiguousSelector: (token , '-')
> > + inRange: (startOfToken to: source position - 1).].
> > + token := token, (String with: self step)].
> > + token := token asSymbol!
> >
> > Item was added:
> > + ----- Method: Scanner>>xColon (in category 'multi-character scans')
> -----
> > + xColon
> > + "Allow := for assignment"
> > +
> > + aheadChar == $= ifTrue:
> > + [self step.
> > + tokenType := #leftArrow.
> > + self step.
> > + ^ token := #':='].
> > + "Otherwise, just do what normal scan of colon would do"
> > + tokenType := #colon.
> > + ^ token := self step asSymbol!
> >
> > Item was added:
> > + ----- Method: Scanner>>xDelimiter (in category 'multi-character
> scans') -----
> > + xDelimiter
> > + "Ignore blanks, etc."
> > +
> > + self scanToken!
> >
> > Item was added:
> > + ----- Method: Scanner>>xDigit (in category 'multi-character scans')
> -----
> > + xDigit
> > + "Form a number."
> > +
> > + tokenType := #number.
> > + aheadChar == DoItCharacter
> > + ifTrue: [source skip: -1 "Read off the end last time"]
> > + ifFalse: [source skip: -2].
> > + token := (SqNumberParser on: source)
> > + failBlock: [:errorString :position | self notify: errorString
> at:position];
> > + nextNumber.
> > + self step; step!
> >
> > Item was added:
> > + ----- Method: Scanner>>xDollar (in category 'multi-character scans')
> -----
> > + xDollar
> > + "Form a Character literal."
> > +
> > + aheadChar == DoItCharacter
> > + ifTrue:
> > + [mark := mark + 1. "Let the notification lie behind the
> dollar"
> > + ^self offEnd: 'A Character was expected'].
> > + self step. "pass over $"
> > + token := self step.
> > + tokenType := #character!
> >
> > Item was added:
> > + ----- Method: Scanner>>xDoubleQuote (in category 'multi-character
> scans') -----
> > + xDoubleQuote
> > + "Collect a comment."
> > +
> > + buffer reset.
> > + self step.
> > + [ hereChar == $" ] whileFalse: [
> > + hereChar == DoItCharacter ifTrue: [
> > + ^self offEnd: 'Unmatched comment quote' ].
> > + buffer nextPut: self step ].
> > + self step.
> > + (currentComment ifNil: [
> > + currentComment := OrderedCollection new ])
> > + add: buffer contents.
> > + self scanToken!
> >
> > Item was added:
> > + ----- Method: Scanner>>xIllegal (in category 'multi-character scans')
> -----
> > + xIllegal
> > + "An illegal character was encountered"
> > + self notify: 'Illegal character (char code ' , hereChar charCode ,
> ' ' , hereChar charCode storeStringHex , ')' at: mark!
> >
> > Item was added:
> > + ----- Method: Scanner>>xLetter (in category 'multi-character scans')
> -----
> > + xLetter
> > + "Form a word or keyword."
> > +
> > + | type |
> > + buffer reset.
> > + [(type := self typeTableAt: hereChar) == #xLetter
> > + or: [type == #xDigit
> > + or: [type == #xUnderscore and:[self
> allowUnderscoreSelectors]]]] whileTrue:
> > + [buffer nextPut: self step].
> > + tokenType := (type == #xColon and: [aheadChar ~~ $=])
> > + ifTrue:
> > + [buffer nextPut: self step.
> > + "Allow any number of embedded colons in literal
> symbols"
> > + [(self typeTableAt: hereChar) == #xColon]
> whileTrue:
> > + [buffer nextPut: self step].
> > + #keyword]
> > + ifFalse:
> > + [#word].
> > + token := buffer contents!
> >
> > Item was added:
> > + ----- Method: Scanner>>xLitQuote (in category 'multi-character scans')
> -----
> > + xLitQuote
> > + "Symbols and vectors: #(1 (4 5) 2 3) #ifTrue:ifFalse: #'abc'."
> > + | start |
> > + start := mark.
> > + self step. "litQuote"
> > + self scanToken.
> > + tokenType == #leftParenthesis
> > + ifTrue: [self scanToken; scanLitVec.
> > + mark := start + 1.
> > + tokenType == #doIt
> > + ifTrue: [self offEnd: 'Unmatched parenthesis']]
> > + ifFalse: [tokenType == #leftBracket
> > + ifTrue: [self scanToken; scanLitByteVec.
> > + mark := start + 1.
> > + tokenType == #doIt
> > + ifTrue: [self offEnd: 'Unmatched bracket']]
> > + ifFalse: [(tokenType == #word or: [tokenType ==
> #keyword or: [tokenType == #colon]])
> > + ifTrue: [self scanLitWord]
> > + ifFalse: [(tokenType == #string or: [ tokenType
> == #verticalBar ])
> > + ifTrue: [token := token asSymbol]
> > + ifFalse: [tokenType == #binary
> > + ifFalse: [(token isCharacter and:
> [tokenType ~~ #character and: [self class prefAllowUnicharSymbol]])
> > + ifTrue: [token := token asSymbol]
> > + ifFalse: [self notify: 'Invalid
> literal character' at: start + 1]]]]]].
> > + mark := start.
> > + tokenType := #literal
> > +
> > + "#(Pen)
> > + #Pen
> > + #'Pen'
> > + "!
> >
> > Item was added:
> > + ----- Method: Scanner>>xLitQuoteForTokenization (in category
> 'multi-character scans') -----
> > + xLitQuoteForTokenization
> > + "Parse underscores as per the regular parser when following a #
> symbol, so that e.g. #_WIN32 is correctly tokenized."
> > + | index |
> > + index := typeTable identityIndexOf: #xUnderscoreForTokenization
> ifAbsent: [^self xLitQuote].
> > + typeTable at: index put: #xUnderscore.
> > + [self xLitQuote] ensure:
> > + [typeTable at: index put: #xUnderscoreForTokenization]!
> >
> > Item was added:
> > + ----- Method: Scanner>>xSingleQuote (in category 'multi-character
> scans') -----
> > + xSingleQuote
> > + "String."
> > +
> > + self step.
> > + buffer reset.
> > + [hereChar == $'
> > + and: [aheadChar == $'
> > + ifTrue: [self step. false]
> > + ifFalse: [true]]]
> > + whileFalse:
> > + [hereChar == DoItCharacter
> > + ifTrue: [^self offEnd: 'Unmatched string quote'].
> > + buffer nextPut: self step].
> > + self step.
> > + token := buffer contents.
> > + tokenType := #string!
> >
> > Item was added:
> > + ----- Method: Scanner>>xUnderscore (in category 'multi-character
> scans') -----
> > + xUnderscore
> > + self allowUnderscoreAssignments ifTrue:
> > + "Figure out if x _foo (no space between _ and foo) should be a
> selector or assignment."
> > + [(self allowUnderscoreSelectors
> > + and: [#(xLetter xDigit xUnderscore xColon) includes: (self
> typeTableAt: aheadChar)])
> > + ifFalse:
> > + [self step.
> > + tokenType := #leftArrow.
> > + ^token := #'_']].
> > + self allowUnderscoreSelectors ifTrue:
> > + [^self xLetter].
> > + ^self xIllegal!
> >
> > Item was added:
> > + ----- Method: Scanner>>xUnderscoreForTokenization (in category
> 'multi-character scans') -----
> > + xUnderscoreForTokenization
> > + "Parse underscores as assignments so as to be able to correctly
> tokenize ancient source code."
> > + self step.
> > + tokenType := #leftArrow.
> > + ^token := #'_'!
> >
> > Item was added:
> > + LeafNode subclass: #SelectorNode
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !SelectorNode commentStamp: '<historical>' prior: 0!
> > + I am a parse tree leaf representing a selector.!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitSelectorNode: self!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>emitCode:args:encoder: (in category 'code
> generation') -----
> > + emitCode: stack args: nArgs encoder: encoder
> > +
> > + self emitCode: stack
> > + args: nArgs
> > + encoder: encoder
> > + super: false!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>emitCode:args:encoder:super: (in category
> 'code generation') -----
> > + emitCode: stack args: nArgs encoder: encoder super: supered
> > + code < Send ifTrue:
> > + [self internalEncodingError].
> > + stack pop: nArgs.
> > + supered
> > + ifTrue:
> > + [(encoder supportsFullBlocks
> > + and: [encoder generatingFullBlock])
> > + ifTrue:
> > + [encoder genPushLiteral: (encoder sharableLitIndex:
> encoder classEncoding).
> > + encoder genSendDirectedSuper: index numArgs: nArgs]
> > + ifFalse: [encoder genSendSuper: index numArgs: nArgs]]
> > + ifFalse:
> > + [encoder genSend: index numArgs: nArgs]!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>emitCodeForEffect:encoder: (in category
> 'code generation') -----
> > + emitCodeForEffect: stack encoder: encoder
> > +
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>emitCodeForValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > +
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>emitForEffect:on: (in category
> 'inappropriate') -----
> > + emitForEffect: stack on: strm
> > +
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>emitForValue:on: (in category
> 'inappropriate') -----
> > + emitForValue: stack on: strm
> > +
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>forSuperSend (in category 'code
> generation') -----
> > + forSuperSend
> > + "Answer the receiver or a derivative, suitable for use in a super
> send.
> > + This is overridden by SpecialSelectorNode to return a SelectorNode
> clone."
> > + ^self!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>internalEncodingError (in category
> 'private') -----
> > + internalEncodingError
> > + self error: 'with the split between SelectorNode and
> SpecialSelectorNode code should never be < Send for normal sends.'!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>isForFFICall (in category 'testing') -----
> > + isForFFICall
> > + ^key asString includesSubstring: '()/'!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>isPvtSelector (in category 'testing') -----
> > + isPvtSelector
> > + "Answer if this selector node is a private message selector."
> > +
> > + ^key isPvtSelector!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>key: (in category 'printing') -----
> > + key: aSelector
> > + "This is for printing of FFI selectors."
> > + key := aSelector!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>key:code:index: (in category
> 'initialize-release') -----
> > + key: object code: byte index: idx
> > +
> > + key := object.
> > + code := byte.
> > + index := idx!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>name:key:index:type: (in category
> 'initialize-release') -----
> > + name: literal key: object index: i type: type
> > + "For compatibility with Encoder>>name:key:class:type:set:"
> > + ^self key: object index: i type: type!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>printAsFFICallWithArguments:on:indent: (in
> category 'printing') -----
> > + printAsFFICallWithArguments: aSequence on: aStream indent: level
> > + aStream nextPutAll: (key copyUpTo: $)).
> > + aSequence
> > + do: [:arg| arg printOn: aStream indent: level]
> > + separatedBy: [aStream nextPutAll: ', '].
> > + aStream nextPut: $)!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>printOn:indent: (in category 'printing')
> -----
> > + printOn: aStream indent: level
> > + aStream nextPutAll: (key == nil
> > + ifTrue: ['<key==nil>']
> > + ifFalse: [key])!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level
> > + aStream nextPutAll: (key == nil
> > + ifTrue: ['<key==nil>']
> > + ifFalse: [key])!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>reserve: (in category 'code generation')
> -----
> > + reserve: encoder
> > + "If this is a yet unused literal of type -code, reserve it."
> > +
> > + index ifNil:
> > + [index := encoder sharableLitIndex: key.
> > + code := Send]!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>resetForBlockGeneration (in category 'code
> generation') -----
> > + resetForBlockGeneration
> > + "Reset the receiver to an unassigned state such that its index
> > + in the encoder's literalStream is as yet to be determined."
> > + code := SendType negated.
> > + index := nil!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>sizeCode:args:super: (in category 'code
> generation') -----
> > + sizeCode: encoder args: nArgs super: supered
> > + self reserve: encoder.
> > + code < Send ifTrue:
> > + [self internalEncodingError].
> > + supered ifFalse:
> > + [^encoder sizeSend: index numArgs: nArgs].
> > + (encoder supportsFullBlocks
> > + and: [encoder generatingFullBlock]) ifTrue:
> > + [^(encoder sizePushLiteral: (encoder sharableLitIndex: encoder
> classEncoding))
> > + + (encoder sizeSendDirectedSuper: index numArgs: nArgs)].
> > + ^encoder sizeSendSuper: index numArgs: nArgs!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>sizeCodeForEffect: (in category 'code
> generation') -----
> > + sizeCodeForEffect: encoder
> > +
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: SelectorNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > +
> > + self shouldNotImplement!
> >
> > Item was added:
> > + Notification subclass: #ShadowedVariableNotification
> > + instanceVariableNames: 'name selector class'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> > +
> > + !ShadowedVariableNotification commentStamp: 'ct 2/7/2022 22:18' prior:
> 0!
> > + I tell interested exception handlers or the Transcript about an
> attempt to compile a method with a shadowed variable, i.e., a temporary
> variable that has the same name as an existing instance variable in the
> subject class. The use and usage of shadowed variables are generally
> disputed: They can lead to confusion when a temporary variable declaration
> is missed, but they can also be utilized to make an instance variable
> unaccessible in a local scope.!
> >
> > Item was added:
> > + ----- Method: ShadowedVariableNotification>>defaultAction (in category
> 'handling') -----
> > + defaultAction
> > +
> > + Transcript showln: ('{1} ({2} is shadowed)' translated format:
> > + {self methodClass name , '>>' , self selector.
> > + self variableName}).!
> >
> > Item was added:
> > + ----- Method: ShadowedVariableNotification>>methodClass (in category
> 'accessing') -----
> > + methodClass
> > +
> > + ^ class!
> >
> > Item was added:
> > + ----- Method: ShadowedVariableNotification>>name:selector:class: (in
> category 'initialize-release') -----
> > + name: aString selector: aSymbolOrNil class: aBehavior
> > +
> > + name := aString.
> > + selector := aSymbolOrNil.
> > + class := aBehavior.!
> >
> > Item was added:
> > + ----- Method: ShadowedVariableNotification>>selector (in category
> 'accessing') -----
> > + selector
> > +
> > + ^ selector!
> >
> > Item was added:
> > + ----- Method: ShadowedVariableNotification>>variableName (in category
> 'accessing') -----
> > + variableName
> > +
> > + ^ name!
> >
> > Item was added:
> > + LiteralNode subclass: #SpecialLiteralNode
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> >
> > Item was added:
> > + ----- Method: SpecialLiteralNode>>emitCodeForValue:encoder: (in
> category 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + stack push: 1.
> > + encoder genPushSpecialLiteral: key!
> >
> > Item was added:
> > + ----- Method: SpecialLiteralNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + ^encoder sizePushSpecialLiteral: key!
> >
> > Item was added:
> > + SelectorNode subclass: #SpecialSelectorNode
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !SpecialSelectorNode commentStamp: 'eem 8/5/2014 20:18' prior: 0!
> > + A SpecialSelectorNode is a subclass of SelectorNode that handles the
> special selectors, a high static and/or dynamic frequency set of selectors
> that are assigned their own bytecodes. Special selectors both save space
> in the literal frame and allow an interpreter to implement these sends
> directly for certain classes of receiver and argument, for example the
> SmallIntegers, a technique known as static receiver prediction.!
> >
> > Item was added:
> > + ----- Method: SpecialSelectorNode>>emitCode:args:encoder:super: (in
> category 'code generation') -----
> > + emitCode: stack args: nArgs encoder: encoder super: supered
> > + "Generate a special selector send.
> > + A super send of a special selector must be handled like a normal
> send.
> > + This is handled in MessageNode>>sizeCodeForValue: by mapping any
> > + SpecialSelectorNodes used in super sends into normal
> SelectorNodes."
> > + supered ifTrue: [self invalidSuperSendError].
> > + stack pop: nArgs.
> > + encoder genSendSpecial: code numArgs: nArgs!
> >
> > Item was added:
> > + ----- Method: SpecialSelectorNode>>forSuperSend (in category 'code
> generation') -----
> > + forSuperSend
> > + "Answer the receiver or a derivative, suitable for use in a super
> send."
> > +
> > + "Excuse the code negation nonsense. It is a vestige of a very
> concise but now
> > + obsolete back-end bytecode encoding scheme. We're working on
> removing it."
> > + ^SelectorNode new
> > + key: key
> > + code: SendType negated
> > + index: index!
> >
> > Item was added:
> > + ----- Method: SpecialSelectorNode>>invalidSuperSendError (in category
> 'private') -----
> > + invalidSuperSendError
> > + self error: 'special selectors can only be used for ordinary sends'!
> >
> > Item was added:
> > + ----- Method: SpecialSelectorNode>>resetForBlockGeneration (in
> category 'code generation') -----
> > + resetForBlockGeneration
> > + "Reset the receiver to an unassigned state such that its index
> > + in the encoder's literalStream is as yet to be determined."
> > + index := nil!
> >
> > Item was added:
> > + ----- Method: SpecialSelectorNode>>sizeCode:args:super: (in category
> 'code generation') -----
> > + sizeCode: encoder args: nArgs super: supered
> > + "Size a special selector send.
> > + A super send of a special selector must be handled like a normal
> send.
> > + This is handled in MessageNode>>sizeCodeForValue: by mapping any
> > + SpecialSelectorNodes used in super sends into normal
> SelectorNodes."
> > + supered ifTrue: [self invalidSuperSendError].
> > + ^encoder sizeSendSpecial: code numArgs: nArgs!
> >
> > Item was added:
> > + Error subclass: #SyntaxErrorNotification
> > + instanceVariableNames: 'cue doitFlag errorMessage location
> newSource'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Exceptions'!
> > +
> > + !SyntaxErrorNotification commentStamp: 'ct 10/24/2020 00:01' prior: 0!
> > + A SyntaxErrorNotification is an Exception occuring when compiling a
> Smalltalk source code with incorrect syntax.
> > + Note that in interactive mode, this exception is not raised because
> the Compiler will interact directly with source code editor.
> > + The defaultAction is to raise a SyntaxError pop up window so as to
> enable interactive handling even in non interactive mode.
> > +
> > + Instance Variables
> > + cue: <CompilationCue>
> > + doitFlag: <Boolean>
> > + errorMessage: <String>
> > + location: <Integer>
> > + newSource: <String | Text | Stream | nil>
> > +
> > + cue
> > + - the cue for compilation, including receiver class, optional
> context, and original source code
> > +
> > + doitFlag
> > + - true if this is a doIt (code to evaluate), false if this is a
> method (code of a method to be compiled)
> > +
> > + errorMessage
> > + - contains information about the syntax error
> > +
> > + location
> > + - position in the source code where the syntax error occured
> > +
> > + newSource
> > + - eventually hold a source code replacement typically passed by the
> SyntaxError window!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification
> class>>cue:doitFlag:errorMessage:location: (in category 'instance
> creation') -----
> > + cue: aCue doitFlag: doitFlag errorMessage: errorString location:
> location
> > +
> > + ^ self new
> > + setCue: aCue
> > + doitFlag: doitFlag
> > + errorMessage: errorString
> > + location: location!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification
> class>>inClass:withCode:doitFlag:errorMessage:location: (in category
> 'instance creation') -----
> > + inClass: aClass withCode: codeString doitFlag: doitFlag errorMessage:
> errorString location: location
> > +
> > + self deprecated: 'ct: Use #cue:doitFlag:errorMessage:location:'.
> > + ^ self
> > + cue: (CompilationCue source: codeString class: aClass
> requestor: nil)
> > + doitFlag: doitFlag
> > + errorMessage: errorString
> > + location: location!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>context (in category
> 'accessing') -----
> > + context
> > +
> > + ^ cue context!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>doitFlag (in category
> 'accessing') -----
> > + doitFlag
> > + ^doitFlag!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>environment (in category
> 'accessing') -----
> > + environment
> > +
> > + ^ cue environment!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>errorClass (in category
> 'accessing') -----
> > + errorClass
> > +
> > + ^ cue getClass!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>errorCode (in category
> 'accessing') -----
> > + errorCode
> > +
> > + ^ cue source!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>errorMessage (in category
> 'accessing') -----
> > + errorMessage
> > + ^errorMessage!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>isResumable (in category
> 'accessing') -----
> > + isResumable
> > +
> > + ^ true!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>location (in category
> 'accessing') -----
> > + location
> > + ^location!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>messageText (in category
> 'accessing') -----
> > + messageText
> > + ^ super messageText
> > + ifEmpty: [messageText := self errorCode]!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>newSource (in category
> 'accessing') -----
> > + newSource
> > + ^newSource!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>reparse:notifying:ifFail: (in
> category 'accessing') -----
> > + reparse: aString notifying: aController ifFail: failBlock
> > + "Try to parse if aString has correct syntax, but do not
> evaluate/install any code.
> > + In case of incorrect syntax, execute failBlock and let a Compiler
> interact with the requestor.
> > + In case of correct syntax, set newSource."
> > +
> > + (doitFlag ifTrue: [nil class] ifFalse: [self errorClass])
> newCompiler
> > + compileCue: (cue copy
> > + source: aString;
> > + requestor: aController;
> > + yourself)
> > + noPattern: doitFlag
> > + ifFail: failBlock.
> > + newSource := aString.!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>retryWithNewSource: (in
> category 'handling') -----
> > + retryWithNewSource: source
> > + "Retry the compilation with new source code.
> > + Assume
> > + - that the signallerContext will tryNewSourceIfAvailable
> > + - the presence of a handler of ReparseAfterSourceEditing on the
> sender stack"
> > +
> > + newSource := source.
> > + ^ self resume!
> >
> > Item was added:
> > + ----- Method:
> SyntaxErrorNotification>>setCue:doitFlag:errorMessage:location: (in
> category 'initialize-release') -----
> > + setCue: aCue doitFlag: aBoolean errorMessage: errorString location:
> anInteger
> > +
> > + cue := aCue.
> > + doitFlag := aBoolean.
> > + errorMessage := errorString.
> > + location := anInteger!
> >
> > Item was added:
> > + ----- Method: SyntaxErrorNotification>>tryNewSourceIfAvailable (in
> category 'accessing') -----
> > + tryNewSourceIfAvailable
> > + newSource ifNotNil: [ReparseAfterSourceEditing withNewSource:
> newSource]!
> >
> > Item was added:
> > + VariableNode subclass: #TempVariableNode
> > + instanceVariableNames: 'argType hasRefs hasDefs scope definingScope
> readingScopes writingScopes remoteNode'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !TempVariableNode commentStamp: '<historical>' prior: 0!
> > + I am a parse tree leaf representing a temporary variable!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>absorbHoistedTemp: (in category
> 'closure analysis') -----
> > + absorbHoistedTemp: aTempVar
> > + "Collapse aTempVar into the receiver, being sure to update any
> closure analysis."
> > + aTempVar copyScopeAccessTo: self.
> > + aTempVar becomeForward: self!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitTempVariableNode: self!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>addReadWithin:at: (in category
> 'closure analysis') -----
> > + addReadWithin: scopeBlock "<BlockNode>" at: location "<Integer>"
> > + readingScopes ifNil: [readingScopes := Dictionary new].
> > + (readingScopes at: scopeBlock ifAbsentPut: [Set new]) add: location.
> > + remoteNode ifNotNil:
> > + [remoteNode addReadWithin: scopeBlock at: location]!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>addWriteWithin:at: (in category
> 'closure analysis') -----
> > + addWriteWithin: scopeBlock "<BlockNode>" at: location "<Integer>"
> > + writingScopes ifNil: [writingScopes := Dictionary new].
> > + (writingScopes at: scopeBlock ifAbsentPut: [Set new]) add: location.
> > + remoteNode ifNotNil:
> > + [remoteNode addReadWithin: scopeBlock at: location]!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>analyseClosure: (in category 'closure
> analysis') -----
> > + analyseClosure: rootNode "<MethodNode>"
> > + "Analyse whether the temporary needs to be made remote
> > + or not, and answer whether it was made remote.
> > + A temp cannot be local if it is written to remotely,
> > + or if it is written to after it is closed-over. An exception
> > + is an inlined block argument that appears to be written
> > + remotely but is actually local to a block."
> > + | latestWrite |
> > + self isBlockArg ifTrue: [^false].
> > + remoteNode ifNotNil: [^false]. "If already remote, don't remote a
> second time"
> > + latestWrite := 0.
> > + ((writingScopes notNil
> > + and: [writingScopes associations anySatisfy: [:assoc|
> > + [:blockScope :refs|
> > + refs do: [:write| latestWrite := write max: latestWrite].
> > + "A temp cannot be local if it is written to remotely."
> > + blockScope actualScope ~~ definingScope actualScope]
> > + value: assoc key value: assoc value]])
> > + or: [readingScopes notNil
> > + and: [readingScopes associations anySatisfy: [:assoc|
> > + [:blockScope :refs|
> > + "A temp cannot be local if it is written to after it
> is closed-over."
> > + blockScope actualScope ~~ definingScope actualScope
> > + and: [refs anySatisfy: [:read| read < latestWrite]]]
> > + value: assoc key value: assoc value]]]) ifTrue:
> > + [remoteNode := definingScope addRemoteTemp: self rootNode:
> rootNode.
> > + ^true].
> > + ^false!
> >
> > Item was added:
> > + ----- Method:
> TempVariableNode>>analyseTempsWithin:rootNode:assignmentPools: (in category
> 'closure analysis') -----
> > + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode
> "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + self addReadWithin: scopeBlock at: rootNode locationCounter!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>assignmentCheck:at: (in category
> 'testing') -----
> > + assignmentCheck: encoder at: location
> > + ^((self isBlockArg and: [Scanner allowBlockArgumentAssignment not])
> > + or: [self isMethodArg])
> > + ifTrue: [location]
> > + ifFalse: [-1]!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>beBlockArg (in category 'testing')
> -----
> > + beBlockArg
> > + argType := #block!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>beMethodArg (in category 'testing')
> -----
> > + beMethodArg
> > + argType := #method!
> >
> > Item was added:
> > + ----- Method:
> TempVariableNode>>beingAssignedToAnalyseTempsWithin:rootNode:assignmentPools:
> (in category 'closure analysis') -----
> > + beingAssignedToAnalyseTempsWithin: scopeBlock "<BlockNode>" rootNode:
> rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + self addWriteWithin: scopeBlock at: rootNode locationCounter.
> > + "For analysis of optimized blocks also record the set of
> temporaries written to
> > + within optimized blocks so that additional writes can be added at
> locations that
> > + represent subsequent iterations of the loop. e.g.
> testInlineBlockCollectionSD1"
> > + assignmentPools keysAndValuesDo:
> > + [:outerScopeBlock :set|
> > + "definingScope can be nil in expr in expr ifNil: [:arg|...]
> expressions because
> > + arg gets its definingScope set when [:arg|...] is analysed."
> > + outerScopeBlock actualScope
> > + = (definingScope
> > + ifNil: [scopeBlock]
> > + ifNotNil: [definingScope actualScope]) ifTrue:
> > + [set add: self]]!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>copyScopeAccessTo: (in category
> 'closure analysis') -----
> > + copyScopeAccessTo: aTempVar
> > + "For absorbHoistedTemp:, copy the receiver's reads and writes into
> the record in aTempVar."
> > + readingScopes ifNotNil:
> > + [readingScopes keysAndValuesDo:
> > + [:scopeBlock :reads|
> > + reads do:
> > + [:location|
> > + aTempVar addReadWithin: scopeBlock "<BlockNode>" at:
> location]]].
> > + writingScopes ifNotNil:
> > + [writingScopes keysAndValuesDo:
> > + [:scopeBlock :writes|
> > + writes do:
> > + [:location|
> > + aTempVar addWriteWithin: scopeBlock "<BlockNode>" at:
> location]]]!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>definingScope (in category 'closure
> analysis') -----
> > + definingScope
> > + ^definingScope!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>definingScope: (in category 'closure
> analysis') -----
> > + definingScope: scopeBlock "<BlockNode>"
> > + definingScope = scopeBlock ifTrue: [^ self]. "No need to bail"
> > + definingScope ifNotNil:
> > + [self error: 'temp has more than one defining scope. This is
> probably a parser error'].
> > + definingScope := scopeBlock!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>emitCodeForStore:encoder: (in category
> 'code generation') -----
> > + emitCodeForStore: stack encoder: encoder
> > + remoteNode ~~ nil ifTrue:
> > + [^remoteNode emitCodeForStoreInto: self stack: stack encoder:
> encoder].
> > + encoder genStoreTemp: index!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>emitCodeForStorePop:encoder: (in
> category 'code generation') -----
> > + emitCodeForStorePop: stack encoder: encoder
> > + remoteNode ~~ nil ifTrue:
> > + [^remoteNode emitCodeForStorePopInto: self stack: stack
> encoder: encoder].
> > + encoder genStorePopTemp: index.
> > + stack pop: 1!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>emitCodeForValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + remoteNode ~~ nil ifTrue:
> > + [^remoteNode emitCodeForValueOf: self stack: stack encoder:
> encoder].
> > + encoder genPushTemp: index.
> > + stack push: 1!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>index: (in category 'closure
> analysis') -----
> > + index: anInteger
> > + "For renumbering temps in the closure compiler."
> > + index := anInteger.
> > + code := self code: index type: LdTempType!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isArg (in category 'testing') -----
> > + isArg
> > + ^argType notNil!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isBlockArg (in category 'testing')
> -----
> > + isBlockArg
> > + ^#block == argType!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isDeclaredAtMethodLevel (in category
> 'testing') -----
> > + isDeclaredAtMethodLevel
> > + "For the explainer."
> > + ^scope = 0!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isDefinedWithinBlockExtent: (in
> category 'closure analysis') -----
> > + isDefinedWithinBlockExtent: anInterval
> > + ^anInterval rangeIncludes: definingScope actualScope blockExtent
> first!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isIndirectTempVector (in category
> 'closure analysis') -----
> > + isIndirectTempVector
> > + ^false!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isMethodArg (in category 'testing')
> -----
> > + isMethodArg
> > + ^#method == argType!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isReferencedWithinBlockExtent: (in
> category 'closure analysis') -----
> > + isReferencedWithinBlockExtent: anInterval
> > + readingScopes ~~ nil ifTrue:
> > + [readingScopes do:
> > + [:set "<Set of <Integer>>"|
> > + set do:
> > + [:location|
> > + (anInterval rangeIncludes: location) ifTrue:
> > + [^true]]]].
> > + writingScopes ~~ nil ifTrue:
> > + [writingScopes do:
> > + [:set "<Set of <Integer>>"|
> > + set do:
> > + [:location|
> > + (anInterval rangeIncludes: location) ifTrue:
> > + [^true]]]].
> > + ^false!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isRemote (in category 'testing') -----
> > + isRemote
> > + ^remoteNode notNil!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isTemp (in category 'testing') -----
> > + isTemp
> > + ^ true!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isUndefTemp (in category 'testing')
> -----
> > + isUndefTemp
> > + ^ hasDefs not!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>isUnusedTemp (in category 'testing')
> -----
> > + isUnusedTemp
> > + ^ hasRefs not!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>name:index:type:scope: (in category
> 'initialize-release') -----
> > + name: varName index: i type: type scope: level
> > + "Only used for initting temporary variables"
> > + hasDefs := hasRefs := false.
> > + scope := level.
> > + ^super name: varName key: varName index: i type: type!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>nowHasDef (in category
> 'initialize-release') -----
> > + nowHasDef
> > + hasDefs := true!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>nowHasRef (in category
> 'initialize-release') -----
> > + nowHasRef
> > + hasRefs := true!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>printDefinitionForClosureAnalysisOn:
> (in category 'printing') -----
> > + printDefinitionForClosureAnalysisOn: aStream
> > + | refs |
> > + aStream
> > + nextPut: ${;
> > + nextPutAll: key.
> > + definingScope ifNotNil: [definingScope blockExtent ifNotNil: [:be|
> aStream nextPutAll: ' d@'; print: be first]].
> > + readingScopes notNil ifTrue:
> > + [refs := Set new.
> > + readingScopes do: [:elems| refs addAll: elems].
> > + refs sorted do: [:read| aStream nextPutAll: ' r@'; print:
> read]].
> > + writingScopes notNil ifTrue:
> > + [refs := Set new.
> > + writingScopes do: [:elems| refs addAll: elems].
> > + refs sorted do: [:write| aStream nextPutAll: ' w@'; print:
> write]].
> > + aStream nextPut: $}!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>printOn:indent: (in category
> 'printing') -----
> > + printOn: aStream indent: level
> > +
> > + aStream nextPutAll: name!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level
> > +
> > + aStream nextPutAll: name.
> > + readingScopes notNil ifTrue:
> > + [(readingScopes inject: Set new into: [:them :reads| them
> addAll: reads. them]) sorted do:
> > + [:location|
> > + aStream space; nextPut: $r; nextPut: $@; print: location]].
> > + writingScopes notNil ifTrue:
> > + [(writingScopes inject: Set new into: [:them :writes| them
> addAll: writes. them]) sorted do:
> > + [:location|
> > + aStream space; nextPut: $w; nextPut: $@; print: location]]!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>referenceScopesAndIndicesDo: (in
> category 'closure analysis') -----
> > + referenceScopesAndIndicesDo: aBinaryBlock
> > + "Evaluate aBinaryBlock with all read or write scopes and locations.
> > + This is used to copy the reference information into
> RemoteTempVectorNodes"
> > + readingScopes ~~ nil ifTrue:
> > + [readingScopes keysAndValuesDo:
> > + [:scopeBlock "<BlockNode>" :set "<Set of <Integer>>"|
> > + set do: [:location| aBinaryBlock value: scopeBlock value:
> location]]].
> > + writingScopes ~~ nil ifTrue:
> > + [writingScopes keysAndValuesDo:
> > + [:scopeBlock "<BlockNode>" :set "<Set of <Integer>>"|
> > + set do: [:location| aBinaryBlock value: scopeBlock value:
> location]]]!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>remoteNode (in category 'testing')
> -----
> > + remoteNode
> > + ^remoteNode!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>remoteNode: (in category 'decompiler')
> -----
> > + remoteNode: aRemoteTempVectorNode
> > + remoteNode := aRemoteTempVectorNode!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>resetFromCopy: (in category 'code
> generation') -----
> > + resetFromCopy: aFieldNode
> > + "Reset the state of the recever to match that of the argument.
> > + This is used to reset nodes that may have been repurposed
> > + while generatig the compiled method for a full block.
> > + Temps are managed via the reindexingLocalsDo:encoder: route,
> > + not via reindexingLiteralsDo:."
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>scope (in category 'testing') -----
> > + scope
> > + "Answer scope of temporary variables.
> > + Currently only the following distinctions are made:
> > + 0 outer level: args and user-declared temps
> > + 1 block args and doLimiT temps
> > + -1 a block temp that is no longer active
> > + -2 a block temp that held limit of to:do:"
> > + ^scope!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>scope: (in category
> 'initialize-release') -----
> > + scope: level
> > + "Note scope of temporary variables.
> > + Currently only the following distinctions are made:
> > + 0 outer level: args and user-declared temps
> > + 1 block args and doLimiT temps
> > + -1 a block temp that is no longer active
> > + -2 a block temp that held limit of to:do:"
> > + scope := level!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>sizeCodeForStore: (in category 'code
> generation') -----
> > + sizeCodeForStore: encoder
> > + remoteNode ~~ nil ifTrue:
> > + [^remoteNode sizeCodeForStoreInto: self encoder: encoder].
> > + self reserve: encoder.
> > + ^encoder sizeStoreTemp: index!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>sizeCodeForStorePop: (in category
> 'code generation') -----
> > + sizeCodeForStorePop: encoder
> > + remoteNode ~~ nil ifTrue:
> > + [^remoteNode sizeCodeForStorePopInto: self encoder: encoder].
> > + self reserve: encoder.
> > + ^encoder sizeStorePopTemp: index!
> >
> > Item was added:
> > + ----- Method: TempVariableNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + remoteNode ~~ nil ifTrue:
> > + [^remoteNode sizeCodeForValueOf: self encoder: encoder].
> > + self reserve: encoder.
> > + ^encoder sizePushTemp: index!
> >
> > Item was added:
> > + ParserNotification subclass: #UndeclaredVariable
> > + instanceVariableNames: 'parser interval'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Exceptions'!
> >
> > Item was added:
> > + ----- Method: UndeclaredVariable class>>signalFor:name:inRange: (in
> category 'instance creation') -----
> > + signalFor: aParser name: aString inRange: anInterval
> > + ^ (self new setParser: aParser name: aString range: anInterval)
> signal!
> >
> > Item was added:
> > + ----- Method: UndeclaredVariable>>openMenuIn: (in category 'handling')
> -----
> > + openMenuIn: aBlock
> > + | alternatives labels actions lines caption choice |
> > + alternatives := parser possibleVariablesFor: name.
> > + labels := OrderedCollection new.
> > + actions := OrderedCollection new.
> > + lines := OrderedCollection new.
> > + name first isLowercase
> > + ifTrue:
> > + [labels add: 'declare method temp' translated.
> > + actions add: [parser declareTemp: name at: #method].
> > + labels add: 'declare block-local temp' translated.
> > + actions add: [parser declareTemp: name at: #block].
> > + parser canDeclareInstanceVariable
> > + ifTrue:
> > + [labels add: 'declare instance' translated.
> > + actions add: [parser declareInstVar: name]]]
> > + ifFalse:
> > + [labels add: 'define new class' translated.
> > + actions add: [parser defineClass: name].
> > + labels add: 'declare global' translated.
> > + actions add: [parser declareGlobal: name].
> > + parser canDeclareClassVariable
> > + ifTrue:
> > + [labels add: 'declare class variable' translated.
> > + actions add: [parser declareClassVar: name]]].
> > + lines add: labels size.
> > + alternatives do:
> > + [:each |
> > + labels add: each.
> > + actions add: [parser substituteVariable: each atInterval:
> interval]].
> > + lines add: labels size.
> > + labels add: 'cancel' translated.
> > + caption := 'Unknown variable: {1}!! please correct, or cancel:'
> translated format: {name}.
> > + choice := aBlock value: labels value: lines value: caption.
> > + self resume: (actions at: choice ifAbsent: [nil])!
> >
> > Item was added:
> > + ----- Method: UndeclaredVariable>>setParser:name:range: (in category
> 'initialize-release') -----
> > + setParser: aParser name: aString range: anInterval
> > + parser := aParser.
> > + name := aString.
> > + interval := anInterval!
> >
> > Item was added:
> > + VariableNode subclass: #UndeclaredVariableNode
> > + instanceVariableNames: 'tag'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> >
> > Item was added:
> > + ----- Method: UndeclaredVariableNode>>accept: (in category 'visiting')
> -----
> > + accept: aVisitor
> > + ^aVisitor visitUndeclaredVariableNode: self!
> >
> > Item was added:
> > + ----- Method: UndeclaredVariableNode>>isUndeclared (in category
> 'testing') -----
> > + isUndeclared
> > + ^true!
> >
> > Item was added:
> > + ----- Method: UndeclaredVariableNode>>tag (in category 'accessing')
> -----
> > + tag
> > + "Tag can be whatever one wants it to be; used by Parser to tag
> > + undeclared temps with the user's desired declaration level."
> > +
> > + ^tag!
> >
> > Item was added:
> > + ----- Method: UndeclaredVariableNode>>tag: (in category 'accessing')
> -----
> > + tag: anObject
> > + "Tag can be whatever one wants it to be; used by Parser to tag
> > + undeclared temps with the user's desired declaration level."
> > +
> > + tag := anObject!
> >
> > Item was added:
> > + Notification subclass: #UndeclaredVariableNotification
> > + instanceVariableNames: 'name selector class'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> >
> > Item was added:
> > + ----- Method: UndeclaredVariableNotification>>defaultAction (in
> category 'exceptionDescription') -----
> > + defaultAction
> > + "The user should be notified of the occurrence of an exceptional
> occurrence and
> > + given an option of continuing or aborting the computation. The
> description of the
> > + occurrence should include any text specified as the argument of
> the #signal: message."
> > +
> > + selector ifNotNil: [Transcript cr; nextPutAll: class name, '>>',
> selector, ' ']
> > + ifNil: [Transcript cr ].
> > + Transcript show: '(' , name , ' is Undeclared) '.
> > + ^true!
> >
> > Item was added:
> > + ----- Method: UndeclaredVariableNotification>>defaultResumeValue (in
> category 'initialize-release') -----
> > + defaultResumeValue
> > + "Answer the value that by default should be returned if the
> exception is resumed"
> > + ^true!
> >
> > Item was added:
> > + ----- Method: UndeclaredVariableNotification>>name:selector:class: (in
> category 'initialize-release') -----
> > + name: aString selector: aSymbolOrNil class: aBehavior
> > + name := aString.
> > + selector := aSymbolOrNil.
> > + class := aBehavior!
> >
> > Item was added:
> > + ParserNotification subclass: #UndefinedVariable
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Exceptions'!
> >
> > Item was added:
> > + ----- Method: UndefinedVariable>>openMenuIn: (in category 'handling')
> -----
> > + openMenuIn: aBlock
> > +
> > + self resume: (Project uiManager
> > + confirm: ('{1} appears to be undefined at this point.\Proceed
> anyway?' translated withCRs asText
> > + format: {name asText allBold})
> > + orCancel: [false]
> > + title: 'Undefined Variable' translated).!
> >
> > Item was added:
> > + ParserNotification subclass: #UnknownSelector
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Exceptions'!
> >
> > Item was added:
> > + ----- Method: UnknownSelector>>openMenuIn: (in category 'handling')
> -----
> > + openMenuIn: aBlock
> > + | alternatives labels lines caption choice |
> > + alternatives := Symbol possibleSelectorsFor: name.
> > + labels := Array streamContents:
> > + [:s | s nextPut: name; nextPutAll: alternatives].
> > + lines := {1. alternatives size + 1}.
> > + caption := 'Unknown selector, please\confirm, correct, or cancel'
> translated withCRs.
> > +
> > + choice := aBlock value: labels value: lines value: caption.
> > +
> > + choice = 0 ifTrue: [^ self resume: nil].
> > + choice = 1 ifTrue: [^ self resume: name asSymbol].
> > + self resume: (alternatives at: choice - 1)!
> >
> > Item was added:
> > + ParserNotification subclass: #UnusedVariable
> > + instanceVariableNames: ''
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Exceptions'!
> >
> > Item was added:
> > + ----- Method: UnusedVariable>>openMenuIn: (in category 'handling')
> -----
> > + openMenuIn: aBlock
> > +
> > + self resume: (Project uiManager
> > + confirm: ('{1} appears to be unused in this method.\Remove it
> from the code?' translated withCRs asText
> > + format: {name asText allBold})
> > + orCancel: [nil]
> > + title: 'Unused Variable' translated).!
> >
> > Item was added:
> > + LeafNode subclass: #VariableNode
> > + instanceVariableNames: 'name'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-ParseNodes'!
> > +
> > + !VariableNode commentStamp: '<historical>' prior: 0!
> > + I am a parse tree leaf representing a variable. Note that my name and
> key are different for pool variables: the key is the Object Reference.!
> >
> > Item was added:
> > + ----- Method: VariableNode class>>initialize (in category 'class
> initialization') -----
> > + initialize "VariableNode initialize"
> > + | encoder |
> > + encoder := Encoder new.
> > + StdVariables := Dictionary new: 16.
> > + encoder
> > + fillDict: StdVariables
> > + with: VariableNode
> > + mapping: #('self' 'thisContext' 'super' 'nil' 'false' 'true' )
> > + to: (Array with: LdSelf with: LdThisContext with: LdSuper)
> > + , (Array with: LdNil with: LdFalse with: LdTrue).
> > + StdSelectors := Dictionary new: 64.
> > + encoder
> > + fillDict: StdSelectors
> > + with: SpecialSelectorNode
> > + mapping: ((1 to: Smalltalk specialSelectorSize) collect:
> > + [:i | Smalltalk specialSelectorAt: i])
> > + to: (1 to: Smalltalk specialSelectorSize) asArray.
> > + StdLiterals := PluggableDictionary new equalBlock: #literalEqual:.
> "This is at least as fast as a block and eliminates a recompileAll
> dependency. eem 10/8/2019"
> > + encoder
> > + fillDict: StdLiterals
> > + with: LiteralNode
> > + mapping: #(-1 0 1 2 )
> > + to: (LdMinus1 to: LdMinus1 + 3).
> > + encoder initScopeAndLiteralTables.
> > +
> > + NodeNil := encoder encodeVariable: 'nil'.
> > + NodeTrue := encoder encodeVariable: 'true'.
> > + NodeFalse := encoder encodeVariable: 'false'.
> > + NodeSelf := encoder encodeVariable: 'self'.
> > + NodeThisContext := encoder encodeVariable: 'thisContext'.
> > + NodeSuper := encoder encodeVariable: 'super'!
> >
> > Item was added:
> > + ----- Method: VariableNode>>accept: (in category 'visiting') -----
> > + accept: aVisitor
> > + ^aVisitor visitVariableNode: self!
> >
> > Item was added:
> > + ----- Method: VariableNode>>asStorableNode: (in category
> 'initialize-release') -----
> > + asStorableNode: encoder
> > + ^ self!
> >
> > Item was added:
> > + ----- Method: VariableNode>>assignmentCheck:at: (in category
> 'testing') -----
> > + assignmentCheck: encoder at: location
> > + ^(encoder cantStoreInto: name) ifTrue: [location] ifFalse: [-1]!
> >
> > Item was added:
> > + ----- Method:
> VariableNode>>beingAssignedToAnalyseTempsWithin:rootNode:assignmentPools:
> (in category 'closure analysis') -----
> > + beingAssignedToAnalyseTempsWithin: scopeBlock "<BlockNode>" rootNode:
> rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> > + "No-op overridden by TempVariableNode"!
> >
> > Item was added:
> > + ----- Method: VariableNode>>emitCodeForReturn:encoder: (in category
> 'code generation') -----
> > + emitCodeForReturn: stack encoder: encoder
> > + encoder
> > + if: code
> > + isSpecialLiteralForReturn:
> > + [:specialLiteral|
> > + "short returns"
> > + encoder genReturnSpecialLiteral: specialLiteral.
> > + stack push: 1 "doesnt seem right".
> > + ^self].
> > + (self code = LdSelf or: [self code = LdSuper]) ifTrue:
> > + ["short returns"
> > + encoder genReturnReceiver.
> > + stack push: 1 "doesnt seem right".
> > + ^self].
> > + super emitCodeForReturn: stack encoder: encoder!
> >
> > Item was added:
> > + ----- Method: VariableNode>>emitCodeForStore:encoder: (in category
> 'code generation') -----
> > + emitCodeForStore: stack encoder: encoder
> > +
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: VariableNode>>emitCodeForStorePop:encoder: (in category
> 'code generation') -----
> > + emitCodeForStorePop: stack encoder: encoder
> > + self type ~= 1 ifTrue:
> > + [self halt].
> > + encoder genStorePopInstVar: index.
> > + stack pop: 1!
> >
> > Item was added:
> > + ----- Method: VariableNode>>emitCodeForValue:encoder: (in category
> 'code generation') -----
> > + emitCodeForValue: stack encoder: encoder
> > + stack push: 1.
> > + encoder
> > + if: code
> > + isSpecialLiteralForPush:
> > + [:specialLiteral|
> > + ^encoder genPushSpecialLiteral: specialLiteral].
> > + (code = LdSelf or: [code = LdSuper]) ifTrue:
> > + [^encoder genPushReceiver].
> > + code = LdThisContext ifTrue:
> > + [^encoder genPushThisContext].
> > + self error: 'internal compiler error; should not happen'!
> >
> > Item was added:
> > + ----- Method: VariableNode>>fieldOffset (in category 'code
> generation') -----
> > + fieldOffset
> > + "Return temp or instVar offset for this variable"
> > + ^index ifNil: [code < 256
> > + ifTrue: [code \\ 16]
> > + ifFalse: [code \\ 256]]!
> >
> > Item was added:
> > + ----- Method: VariableNode>>index (in category 'testing') -----
> > + index
> > + "If index is nil, this code attempts to reconstruct the index from
> its encoding in code."
> > + index ifNotNil:
> > + [^index].
> > + code < 0 ifTrue:[^nil].
> > + code > 256 ifTrue:
> > + [self assert: index = (code \\ 256).
> > + ^code \\ 256].
> > + code >= (CodeBases at: self type) ifTrue:
> > + [self assert: index = (code - (CodeBases at: self type)).
> > + ^code - (CodeBases at: self type)].
> > + self assert: index = (code - self type).
> > + ^code - self type!
> >
> > Item was added:
> > + ----- Method: VariableNode>>isSelfPseudoVariable (in category
> 'testing') -----
> > + isSelfPseudoVariable
> > + "Answer if this ParseNode represents the 'self' pseudo-variable."
> > +
> > + ^ key = 'self' or: [name = '{{self}}']!
> >
> > Item was added:
> > + ----- Method: VariableNode>>isUndeclared (in category 'testing') -----
> > + isUndeclared
> > + ^false!
> >
> > Item was added:
> > + ----- Method: VariableNode>>isVariableNode (in category 'testing')
> -----
> > + isVariableNode
> > + ^true!
> >
> > Item was added:
> > + ----- Method: VariableNode>>isVariableReference (in category
> 'testing') -----
> > + isVariableReference
> > +
> > + ^true!
> >
> > Item was added:
> > + ----- Method: VariableNode>>name (in category 'accessing') -----
> > + name
> > + ^ name!
> >
> > Item was added:
> > + ----- Method: VariableNode>>name: (in category 'initialize-release')
> -----
> > + name: string
> > + "Change name"
> > +
> > + name := string!
> >
> > Item was added:
> > + ----- Method: VariableNode>>name:index:type: (in category
> 'initialize-release') -----
> > + name: varName index: i type: type
> > + "Only used for initting instVar refs"
> > + ^self name: varName key: varName index: i type: type!
> >
> > Item was added:
> > + ----- Method: VariableNode>>name:key:code: (in category
> 'initialize-release') -----
> > + name: string key: object code: byte
> > + "Only used for initting std variables, nil, true, false, self, etc."
> > + name := string.
> > + key := object.
> > + code := byte!
> >
> > Item was added:
> > + ----- Method: VariableNode>>name:key:index:type: (in category
> 'initialize-release') -----
> > + name: varName key: objRef index: i type: type
> > + "Only used for initting global (litInd) variables"
> > + ^self name: varName key: objRef code: (self code: (index := i)
> type: type)!
> >
> > Item was added:
> > + ----- Method: VariableNode>>printOn:indent: (in category 'printing')
> -----
> > + printOn: aStream indent: level
> > +
> > + aStream nextPutAll: name!
> >
> > Item was added:
> > + ----- Method: VariableNode>>printWithClosureAnalysisOn:indent: (in
> category 'printing') -----
> > + printWithClosureAnalysisOn: aStream indent: level
> > +
> > + aStream nextPutAll: name!
> >
> > Item was added:
> > + ----- Method: VariableNode>>resetFromCopy: (in category 'code
> generation') -----
> > + resetFromCopy: aVariableNode
> > + "Reset the state of the recever to match that of the argument.
> > + This is used to reset nodes that may have been repurposed
> > + while generatig the compiled method for a full block."
> > +
> > + self assert: name == aVariableNode name.
> > + super resetFromCopy: aVariableNode!
> >
> > Item was added:
> > + ----- Method: VariableNode>>sizeCodeForReturn: (in category 'code
> generation') -----
> > + sizeCodeForReturn: encoder
> > + encoder
> > + if: code
> > + isSpecialLiteralForReturn:
> > + [:specialLiteral|
> > + ^encoder sizeReturnSpecialLiteral: specialLiteral].
> > + (self code = LdSelf or: [self code = LdSuper]) ifTrue:
> > + [^encoder sizeReturnReceiver].
> > + ^super sizeCodeForReturn: encoder!
> >
> > Item was added:
> > + ----- Method: VariableNode>>sizeCodeForStore: (in category 'code
> generation') -----
> > + sizeCodeForStore: encoder
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: VariableNode>>sizeCodeForStorePop: (in category 'code
> generation') -----
> > + sizeCodeForStorePop: encoder
> > + self shouldNotImplement!
> >
> > Item was added:
> > + ----- Method: VariableNode>>sizeCodeForValue: (in category 'code
> generation') -----
> > + sizeCodeForValue: encoder
> > + self reserve: encoder.
> > + encoder
> > + if: code
> > + isSpecialLiteralForPush:
> > + [:specialLiteral| "i.e. the pseudo-variables nil true &
> false"
> > + ^encoder sizePushSpecialLiteral: specialLiteral].
> > + (code = LdSelf or: [code = LdSuper]) ifTrue:
> > + [^encoder sizePushReceiver].
> > + code = LdThisContext ifTrue:
> > + [^encoder sizePushThisContext].
> > + self error: 'internal compiler error; should not happen'!
> >
> > Item was added:
> > + ----- Method: VariableNode>>type (in category 'testing') -----
> > + type
> > + "This code attempts to reconstruct the type from its encoding in
> code.
> > + This allows one to test, for instance, (aNode type =
> LdInstType)."
> > + | type |
> > + code < 0 ifTrue: [^code negated].
> > + code >= 256 ifTrue: [^code // 256].
> > + type := CodeBases findFirst: [:one | code < one].
> > + ^type = 0 ifTrue: [5] ifFalse: [type - 1]!
> >
> > Item was added:
> > + ParseNodeVisitor subclass: #VariableScopeFinder
> > + instanceVariableNames: 'theVariable'
> > + classVariableNames: ''
> > + poolDictionaries: ''
> > + category: 'Compiler-Support'!
> > +
> > + !VariableScopeFinder commentStamp: 'eem 8/14/2010 19:45' prior: 0!
> > + A VariableScopeFinder is used to find the minimum enclosing scope of a
> variable in a method. This is used when auto-declaring temporaries to find
> the smallest enclosing block in which to declare the temp.
> > +
> > + Instance Variables
> > + theVariable: <VariableNode>
> > +
> > + theVariable
> > + - the varable whose scope is to be determined
> > + !
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>enclosingNodeFor:of: (in category
> 'private') -----
> > + enclosingNodeFor: enumerator of: rootNode
> > + "Answer the minimum enclosing root node for aVariabe or nil if none.
> > + If the variable is accessed in more than one subnode then the
> rootNode is the
> > + enclosing node, otherwise it is which ever single subnode node
> that includes it, if any.
> > + enumerator applies its argument to all relevant subnodes of
> rootNode."
> > + | enclosingNodeOrNil |
> > + enclosingNodeOrNil := nil.
> > + enumerator value:
> > + [:subnode|
> > + (subnode accept: self) ifNotNil:
> > + [:enclosingNode|
> > + enclosingNodeOrNil := enclosingNodeOrNil
> > + ifNil: [enclosingNode]
> > + ifNotNil: [rootNode]]].
> > + ^enclosingNodeOrNil!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>ofVariable: (in category
> 'initialize-release') -----
> > + ofVariable: aVariableNode
> > + theVariable := aVariableNode!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitAssignmentNode: (in category
> 'visiting') -----
> > + visitAssignmentNode: anAssignmentNode
> > + "Answer the minimum enclosing node for aVariabe or nil if none.
> > + If the variable is accessed in more than one subexpression then
> anAssignmentNode
> > + is the enclosing node, otherwise it is which ever single node that
> includes it, if any."
> > + ^self
> > + enclosingNodeFor: [:aBlock|
> > + aBlock
> > + value: anAssignmentNode value;
> > + value: anAssignmentNode variable]
> > + of: anAssignmentNode!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitBlockNode: (in category
> 'visiting') -----
> > + visitBlockNode: aBlockNode
> > + "Answer the minimum enclosing node for aVariabe or nil if none.
> > + If the variable is accessed in more than one statement then
> aBlockNode is the
> > + enclosing node, otherwise it is which ever single block node that
> includes it, if any."
> > + ^(self enclosingNodeFor: [:aBlock| aBlockNode statements do:
> aBlock] of: aBlockNode) ifNotNil:
> > + [:aNode|
> > + aNode isBlockNode ifTrue: [aNode] ifFalse: [aBlockNode]]!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitBraceNode: (in category
> 'visiting') -----
> > + visitBraceNode: aBraceNode
> > + "Answer the minimum enclosing node for aVariabe or nil if none.
> > + If the variable is accessed in more than one subexpression then
> aBraceNode
> > + is the enclosing node, otherwise it is which ever single node that
> includes it, if any."
> > + ^self
> > + enclosingNodeFor: [:aBlock| aBraceNode elements do: aBlock]
> > + of: aBraceNode!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitCascadeNode: (in category
> 'visiting') -----
> > + visitCascadeNode: aCascadeNode
> > + "Answer the minimum enclosing node for aVariabe or nil if none.
> > + If the variable is accessed in more than one subexpression then
> aMessageNode is the
> > + enclosing node, otherwise it is which ever single node that
> includes it, if any."
> > + ^self
> > + enclosingNodeFor: [:aBlock|
> > + aBlock value: aCascadeNode receiver.
> > + aCascadeNode messages do:
> > + [:msg| msg argumentsInEvaluationOrder
> do: aBlock]]
> > + of: aCascadeNode!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitCommentNode: (in category
> 'visiting') -----
> > + visitCommentNode: aNode
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitFieldNode: (in category
> 'visiting') -----
> > + visitFieldNode: aNode
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitFutureNode: (in category
> 'visiting') -----
> > + visitFutureNode: aFutureNode
> > + ^aFutureNode receiver accept: self!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitInstanceVariableNode: (in
> category 'visiting') -----
> > + visitInstanceVariableNode: aNode
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitLiteralNode: (in category
> 'visiting') -----
> > + visitLiteralNode: aNode
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitLiteralVariableNode: (in
> category 'visiting') -----
> > + visitLiteralVariableNode: aNode
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitMessageNode: (in category
> 'visiting') -----
> > + visitMessageNode: aMessageNode
> > + "Answer the minimum enclosing node for aVariabe or nil if none.
> > + If the variable is accessed in more than one subexpression then
> aMessageNode is the
> > + enclosing node, otherwise it is which ever single node that
> includes it, if any."
> > + ^self
> > + enclosingNodeFor: [:aBlock|
> > + aBlock value: aMessageNode receiver.
> > + aMessageNode argumentsInEvaluationOrder do:
> aBlock]
> > + of: aMessageNode!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitMethodNode: (in category
> 'visiting') -----
> > + visitMethodNode: aMethodNode
> > + ^aMethodNode block accept: self!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitNewArrayNode: (in category
> 'visiting') -----
> > + visitNewArrayNode: aNode
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitRemoteTempVectorNode: (in
> category 'visiting') -----
> > + visitRemoteTempVectorNode: aNode
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitReturnNode: (in category
> 'visiting') -----
> > + visitReturnNode: aReturnNode
> > + ^aReturnNode expr accept: self!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitSelectorNode: (in category
> 'visiting') -----
> > + visitSelectorNode: aNode
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitTempVariableNode: (in category
> 'visiting') -----
> > + visitTempVariableNode: aNode
> > + ^nil!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitUndeclaredVariableNode: (in
> category 'visiting') -----
> > + visitUndeclaredVariableNode: aVariableNode
> > + ^theVariable name = aVariableNode name ifTrue: [theVariable]!
> >
> > Item was added:
> > + ----- Method: VariableScopeFinder>>visitVariableNode: (in category
> 'visiting') -----
> > + visitVariableNode: aVariableNode
> > + ^nil!
> >
> > Item was added:
> > + (PackageInfo named: 'Compiler') postscript: '"below, add code to be
> run after the loading of this package"
> > +
> > + "Recompile senders of caseOf:"
> > + self systemNavigation allSelectorsAndMethodsDo: [ :behavior :selector
> :method |
> > + (method hasLiteral: #caseOf:)
> > + ifTrue: [behavior recompile: selector]].
> > +
> > + "Treat non-breaking space (16ra0) as delimiter in parser/scanner
> (Compiler-ct.473)."
> > + Scanner initialize.'!
> >
> >
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20220913/b243f9d0/attachment-0001.html>
More information about the Squeak-dev
mailing list
|