The Trunk: Compiler-eem.361.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

The Trunk: Compiler-eem.361.mcz

commits-2
Eliot Miranda uploaded a new version of Compiler to project The Trunk:
http://source.squeak.org/trunk/Compiler-eem.361.mcz

==================== Summary ====================

Name: Compiler-eem.361
Author: eem
Time: 2 January 2018, 5:47:32.911397 pm
UUID: 5fe8c44c-f098-43cc-b689-1bf367f5ed8e
Ancestors: Compiler-eem.360

First cut of FullBlockClosure support in the compiler.  If the encoder answers true to supportsFullBlocks then non-optimized blocks are compiled to their own CompiledBlock instance.

Reduce the use of code in a few ParseNode subclasses.  Use the more generic isSpecialLiteralForPush:  [todo: use SistaV1's BlockReturn nil].

[And for the curious here's a way to exercise the compiler
(self systemNavigation allMethodsSelect: [:m| m scanFor: 143]) do:
        [:mr|
        (Parser new
        encoderClass: EncoderForSistaV1;
                parse: mr sourceString
                class: mr actualClass) generate]

=============== Diff against Compiler-eem.360 ===============

Item was changed:
  ----- Method: BlockNode>>constructClosureCreationNode: (in category 'code generation') -----
  constructClosureCreationNode: encoder
  copiedValues := self computeCopiedValues: encoder rootNode.
+ ^self ensureClosureCreationNode: encoder!
- ^self ensureClosureCreationNode!

Item was added:
+ ----- Method: BlockNode>>createBlockLiteral: (in category 'code generation (closures)') -----
+ createBlockLiteral: encoder
+ ^self
+ reindexingLocalsDo:
+ [encoder reindexingLiteralsDo:
+ [encoder copyWithNewLiterals
+ generateBlockMethodOfClass: CompiledBlock
+ trailer: CompiledMethodTrailer empty
+ from: self]]
+ encoder: encoder!

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 emitCodeForBlockValue: stack encoder: encoder.
+ self returns ifFalse:
+ [encoder genReturnTopToCaller.
+ pc := encoder methodStreamPosition].
+ self assert: stack position - 1 = position!

Item was added:
+ ----- Method: BlockNode>>emitCodeForFullBlockValue:encoder: (in category 'code generation (closures)') -----
+ emitCodeForFullBlockValue: stack encoder: encoder
+ copiedValues do:
+ [:copiedValue| copiedValue emitCodeForValue: stack encoder: encoder].
+ encoder
+ genPushFullClosure: closureCreationNode index
+ numCopied: copiedValues size.
+ stack
+ pop: copiedValues size;
+ push: 1!

Item was changed:
  ----- 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 methodStreamPosition + 1.
  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 removed:
- ----- Method: BlockNode>>ensureClosureCreationNode (in category 'accessing') -----
- ensureClosureCreationNode
- closureCreationNode ifNil:
- [closureCreationNode := LeafNode new
- key: #closureCreationNode
- code: nil].
- ^closureCreationNode!

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>>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 changed:
  ----- 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).
- forNode: self ensureClosureCreationNode.
  startOfLastStatement
  ifNil:
  [encoder
  noteSourceRange: (start to: end)
  forNode: self]
  ifNotNil:
  [encoder
  noteSourceRange: (startOfLastStatement to: end - 1)
  forNode: self]!

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."
+ ^(self sizeCodeForEvaluatedValue: encoder)
+ + (self returns ifTrue: [0] ifFalse: [encoder sizeReturnTopToCaller])!

Item was changed:
  ----- 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)].
- self ensureClosureCreationNode.
  "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: BytecodeEncoder>>copyWithNewLiterals (in category 'full blocks') -----
+ copyWithNewLiterals
+ ^self shallowCopy resetLiteralStreamForFullBlock!

Item was added:
+ ----- Method: BytecodeEncoder>>generateBlockMethodOfClass:trailer:from: (in category 'method encoding') -----
+ 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 allLiterals) 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.
+ [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'].
+ self methodStreamPosition ~= (method size - trailer size) ifTrue:
+ [^self error: 'Compiler code size discrepancy'].
+ method needsFrameSize: stack size - method numTemps.
+ ^method!

Item was changed:
  ----- Method: BytecodeEncoder>>generateMethodOfClass:trailer:from: (in category 'method encoding') -----
  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]].
- 1 to: nLits do: [:lit | method literalAt: lit put: (literals at: lit)].
  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)
- do: [:ex|  "to grow, and the grow attempt will fail in CompiledMethod class>>#new:"
- ex signalerContext sender method = (CompiledMethod class>>#new:)
  ifTrue: [^self error: 'Compiler code size discrepancy']
  ifFalse: [ex pass]].
  stack position ~= (method numTemps + 1) ifTrue:
  [^self error: 'Compiler stack discrepancy'].
  self methodStreamPosition ~= (method size - trailer size) ifTrue:
  [^self error: 'Compiler code size discrepancy'].
  method needsFrameSize: stack size - method numTemps.
  ^method!

Item was changed:
  ----- 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
- 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)
+    and: [aBlock value: (#(true false nil) at: code - LdSelf).
- ^(code between: LdTrue and: LdNil + 4)
-    and: [aBlock value: (#(true false nil -1 0 1 2) at: code - LdSelf).
  true]!

Item was added:
+ ----- Method: BytecodeEncoder>>reindexingLiteralsDo: (in category 'code generation') -----
+ reindexingLiteralsDo: aBlock
+ | savedLiterals |
+ savedLiterals := PluggableDictionary new equalBlock: litSet equalBlock.
+ litSet associationsDo:
+ [:assoc|
+ savedLiterals at: assoc key put: assoc value shallowCopy].
+ litIndSet associationsDo:
+ [:assoc|
+ savedLiterals at: assoc key put: assoc value shallowCopy].
+ ^[aBlock value]
+ ensure:
+ [litSet associationsDo:
+ [:assoc|
+ assoc value resetFromCopy: (savedLiterals at: assoc key)].
+ litIndSet associationsDo:
+ [:assoc|
+ assoc value resetFromCopy: (savedLiterals at: assoc key)]]!

Item was added:
+ ----- Method: BytecodeEncoder>>resetLiteralStreamForFullBlock (in category 'code generation') -----
+ resetLiteralStreamForFullBlock
+ literalStream := WriteStream on: (Array new: 32).
+ addedSelectorAndMethodClassLiterals := false.
+ optimizedSelectors := Set new!

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: Decompiler>>doClosureCopy:copiedValues: (in category 'control') -----
+ doClosureCopy: aCompiledBlock copiedValues: blockCopiedValues
+ | savedTemps savedTempVarCount savedNumLocalTemps savedMethod savedPC
+  blockArgs blockTemps blockTempsOffset block |
+ savedTemps := tempVars.
+ savedTempVarCount := tempVarCount.
+ savedNumLocalTemps := numLocalTemps.
+ numLocalTemps := aCompiledBlock numTemps - aCompiledBlock numArgs - blockCopiedValues size.
+ blockTempsOffset := aCompiledBlock 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: 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.
+ savedMethod := self method. savedPC := pc.
+ super method: aCompiledBlock pc: aCompiledBlock initialPC.
+ block := [self blockTo: aCompiledBlock endPC]
+ ensure: [super method: savedMethod pc: savedPC].
+ stack addLast: ((constructor
+ codeArguments: (tempVars copyFrom: 1 to: aCompiledBlock numArgs)
+ temps: (tempVars copyFrom: blockTempsOffset + 1 to: blockTempsOffset + numLocalTemps)
+ block: block)
+ pc: pc;
+ yourself).
+ tempVars := savedTemps.
+ tempVarCount := savedTempVarCount.
+ numLocalTemps := savedNumLocalTemps!

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.
+ self doClosureCopy: aCompiledBlock copiedValues: copiedValues!

Item was removed:
- ----- Method: Encoder>>bindAndJuggle: (in category 'temps') -----
- bindAndJuggle: name
-
- | node nodes first thisCode |
- node := self reallyBind: name.
-
- "Declared temps must precede block temps for decompiler and debugger to work right"
- nodes := self tempNodes.
- (first := nodes findFirst: [:n | n scope > 0]) > 0 ifTrue:
- [node == nodes last ifFalse: [self error: 'logic error'].
- thisCode := (nodes at: first) code.
- first to: nodes size - 1 do:
- [:i | (nodes at: i) key: (nodes at: i) key
- code: (nodes at: i+1) code].
- nodes last key: nodes last key code: thisCode].
-
- ^ node!

Item was changed:
  ----- Method: Encoder>>fixTemp: (in category 'temps') -----
  fixTemp: name
  | node |
  node := scopeTable at: name ifAbsent: [].
+ (node isTemp and: [node isIndirectTempVector not]) ifFalse:
- node class ~~ TempVariableNode ifTrue:
  [self error: 'can only fix a floating temp var'].
  node index: nTemps.
  nTemps := nTemps + 1.
  ^node!

Item was changed:
  ----- Method: Encoder>>floatTemp: (in category 'temps') -----
  floatTemp: node
+ (node == (scopeTable at: node name ifAbsent: [])
+ and: [node isTemp
+ and: [node index = (nTemps - 1)]]) ifFalse:
- (node ~~ (scopeTable at: node name ifAbsent: [])
- or: [node class ~~ TempVariableNode
- or: [node code ~= (node code: nTemps - 1 type: LdTempType)]]) ifTrue:
  [self error: 'can only float the last allocated temp var'].
  nTemps := nTemps - 1!

Item was changed:
  ----- 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]!
- ^tempNodes sort: [:n1 :n2 | n1 code <= n2 code]!

Item was changed:
  ----- 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)"
- 232 11101000 iiiiiiii Push Integer #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)"
  | 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 changed:
  ----- 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:
+ [literal asInteger between: 0 and: 65535]]
+ ifTrue:
+ [literal between: -32768 and: 32767]!
- ^literal == false
-  or: [literal == true
-  or: [literal == nil
-  or: [(literal isInteger and: [literal between: -32768 and: 32767])
-  or: [(literal isCharacter and: [literal asInteger between: 0 and: 65535])]]]]!

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: 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: 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: 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>>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 changed:
  ----- 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]!
- (encoder
- if: code
- isSpecialLiteralForPush:
- [:specialLiteral|
- encoder genPushSpecialLiteral: specialLiteral])
- ifFalse:
- [encoder genPushLiteral: index]!

Item was changed:
  ----- Method: LiteralNode>>sizeCodeForValue: (in category 'code generation') -----
  sizeCodeForValue: encoder
  self reserve: encoder.
+ ^(encoder isSpecialLiteralForPush: key)
+ ifTrue: [encoder sizePushSpecialLiteral: key]
+ ifFalse: [encoder sizePushLiteral: index]!
- (encoder
- if: code
- isSpecialLiteralForPush:
- [:specialLiteral|
- ^encoder sizePushSpecialLiteral: specialLiteral])
- ifFalse:
- [^encoder sizePushLiteral: index]!

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: 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 changed:
  ----- 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'!
- self flag: 'probably superfluous'.
- self halt.
- ^encoder genPushInstVar: index!

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 changed:
  ----- 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'!
- self flag: 'probably superfluous'.
- self halt.
- ^encoder sizePushInstVar: index!


Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: Compiler-eem.361.mcz

Stéphane Rollandin
> Eliot Miranda uploaded a new version of Compiler to project The Trunk:
>...
> First cut of FullBlockClosure support in the compiler.
What are full block closures?

Stef

Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: Compiler-eem.361.mcz

Eliot Miranda-2
Hi Stéphane,

On Wed, Jan 3, 2018 at 1:41 AM, Stéphane Rollandin <[hidden email]> wrote:
Eliot Miranda uploaded a new version of Compiler to project The Trunk:
...
First cut of FullBlockClosure support in the compiler.
What are full block closures?

FullBlockClosure has a separate compiled method from its home; when in use CompiledMethod is the default class for methods; CompiledBlock is the default class for blocks.  This gives faster block activation.  It also means better support for clean blocks (blocks with no home) in that no outer context is needed.  FullBlockClosure is important in Scorch, Clément's adaptive optimizer, in that deoptimization is much simplified.  The old embedded block scheme where the block byte codes are included in the home method, and literals are shared between the two, is compact, but very difficult to interact with when the adaptive optimizer has to (de)optimize a single block or method activation, since the embedding of block byte codes means that the one method is serving several different scopes.

This year we should install the SistaV1 bytecode set and FullBlockClosures as the default in the Squeak image, hopefully in time for the next full release.  In Pharo, Clément is already preparing to deploy the full Scorch/Sista optimizer.  Hopefully I'll be able to port Scorch to Squeak later this year.

_,,,^..^,,,_
best, Eliot