[squeak-dev] The Trunk: Kernel-eem.1092.mcz

commits at source.squeak.org commits at source.squeak.org
Mon Apr 10 18:53:15 UTC 2017


Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1092.mcz

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

Name: Kernel-eem.1092
Author: eem
Time: 10 April 2017, 11:52:56.611122 am
UUID: 49255d6b-cd3d-4604-b9ba-6ac025d951b3
Ancestors: Kernel-eem.1091

Add FullBlockClosure (blocks with independent bytecode methods; needed for Scorch/Sista).  Give BlockClosure an informative comment.

=============== Diff against Kernel-eem.1091 ===============

Item was changed:
  Object variableSubclass: #BlockClosure
  	instanceVariableNames: 'outerContext startpc numArgs'
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'Kernel-Methods'!
  
+ !BlockClosure commentStamp: 'eem 4/10/2017 11:17' prior: 0!
+ Instances of BlockClosure represent blocks, a sequence of statements inside square brackets that can be evaluated at any time via one of the value messages (value, value:, value:value:, ... valueWithArguments:), which answer their last statement.  Blocks therefore allow deferred evaluation and so are used to buikld control structures where a sequence of statements are evaluated or not depending on other values in the program.
+ 
+ Blocks can close over variables in their enclosing method or block.  The method in which a block is nested is called its home method.  Blocks can return from their home method via an up-arrow return, and returns to the sender of the message that created the home method, just like a return from the method itself.  BlockClosures are fully first-class objects; they can outlive their enclosing method activation and be answered as results and/or assigned to variables.
+ 
+ BlockClosures are central to the implementation of control structures in Smalltalk.  The arguments to the conditional message ifTrue:ifFalse: are zero-argument blocks, which the receiver is a boolean which responds by evaluating ether the first argument or the second.  The bytecode compiler inlines blocks for certain selectors, compiling to conditional branch and branch bytecodes.  This is done for efficiency.  The full list of inlined messages can be found in MessageNode's MacroSelectors class variable (at time of writing ther=se are 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: and repeat.
+ 
+ Examples (more can be found in BlockClosureTest's class comment):
+ 	[1 at 2] value
+ 
+ 	| counter |
+ 	counter := 0.
+ 	{ counter. (1 to: 10) collect: [:n| counter := counter + 1. n + counter]. counter }
+ 
+ 	| fibonacciBlock |
+ 	fibonacciBlock := [:n|
+ 					n > 1 ifTrue: [(fibonacciBlock value: n - 1) + (fibonacciBlock value: n - 2)] ifFalse: [1]].
+ 	(1 to: 10) collect: fibonacciBlock
+ 
+ 	| randomNumbers |
+ 	randomNumbers := Random new next: 20.
+ 	{ randomNumbers. randomNumbers sorted: [:a :b| a > b] }
+ 
+ Implementation:
+ BlockClosure implements blocks that are nested within an enclosing method or block context.  Further, the bytecodes for the block are embedded within the home method.  BlockClosure's subclass FullBlockClosure has an independent CompiledBlock as its method, and may or may not have an outerContext.
+ 
+ Instance Variables
+ 	numArgs:		<Integer>
+ 	outerContext:	<Context>
+ 	startpc:			<Integer>
+ 
+ numArgs
+ 	- the number of arguments the block expects
+ 
+ outerContext
+ 	- the Context of the method or block activation in which the receiver is created
+ 
+ startpc
+ 	- the startpc of the block's bytecodes within the home method.!
- !BlockClosure commentStamp: '<historical>' prior: 0!
- I am a block closure for Eliot's closure implementation.  Not to be confused with the old BlockClosure.!

Item was added:
+ BlockClosure variableSubclass: #FullBlockClosure
+ 	instanceVariableNames: 'receiver'
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Kernel-Methods'!
+ 
+ !FullBlockClosure commentStamp: 'eem 4/10/2017 11:18' prior: 0!
+ Instances of FullBlockClosure represent blocks, a sequence of statements inside square brackets that can be evaluated at any time via one of the value messages (value, value:, value:value:, ... valueWithArguments:), which answer their last statement.  Blocks therefore allow deferred evaluation and so are used to buikld control structures where a sequence of statements are evaluated or not depending on other values in the program.
+ 
+ FullBlockClosure is a refinement of BlockClosure that allows the block to use its own method to hold its code instead of embedding that code within its home method.
+ 
+ Implementation:
+ 
+ A FullBlockClosure is a closure that can be independent of any outerContext if desired.  It has its own method (currently reusing the startpc inst var) and its own receiver.  outerContext can be either a Context or nil.
+ 
+ This closure design, implemented by Eliot Miranda and Clement Bera along with the sista work aims to simplify the block closure model while enhacing its capabilities. It allows lazy decompilation of closures and fast machine code dispatch in Cog's JIT, while allowing inlining of methods and blocks to be independent from their enclosing blocks.
+ 
+ At closure creation time, the bytecode specifies:
+ - the compiledBlock to execute when executing this block's code (in the literal frame)
+ - if the receiver is the current receiver or a receiver passed on stack before the copied values.
+ - if the closure needs an outerContext. outerContexts are used for non local returns and debugging. Blocks with non local returns have to set their outerContext. For other blocks (97% of blocks), it's a trade-off between performance and debuggability.
+ 
+ Instance Variables (inherited)
+ 	numArgs				<SmallInteger> 
+ 	outerContext:			<Context|nil> 
+ 	compiledBlock(startpc) <CompiledBlock>
+ 
+ Instance Variables
+ 	receiver:				<Object>
+ 
+ numArgs
+ 	- the number of arguments the block expects. This is superfluous; the number of arguments can be obtained from the receiver's compiledBlock.
+ 
+ outerContext
+ 	- the Context of the method or block activation in which the receiver is created.
+ 
+ compiledBlock(startpc)
+ 	- reused to refer to the CompiledBlock that implements the receiver's code.
+ 
+ receiver
+ 	- the receiver of the message that created the block's home method activation.!

Item was added:
+ ----- Method: FullBlockClosure>>abstractBytecodeMessagesDo: (in category 'scanning') -----
+ abstractBytecodeMessagesDo: aBlock
+ 	^ self compiledBlock abstractBytecodeMessagesDo: aBlock!

Item was added:
+ ----- Method: FullBlockClosure>>asContextWithSender: (in category 'private') -----
+ asContextWithSender: aContext
+ 	"Inner private support method for evaluation.  Do not use unless you know what you're doing."
+ 
+ 	^(Context newForMethod: self compiledBlock)
+ 		setSender: aContext
+ 		receiver: self receiver
+ 		method: self compiledBlock
+ 		closure: self
+ 		startpc: self startpc;
+ 		privRefresh!

Item was added:
+ ----- Method: FullBlockClosure>>compiledBlock (in category 'accessing') -----
+ compiledBlock
+ 	"To be able to inherit from BlockClosure"
+ 	^ startpc!

Item was added:
+ ----- Method: FullBlockClosure>>compiledBlock: (in category 'accessing') -----
+ compiledBlock: aCompiledMethod
+ 	"To be able to inherit from BlockClosure"
+ 	startpc := aCompiledMethod!

Item was added:
+ ----- Method: FullBlockClosure>>endPC (in category 'accessing') -----
+ endPC
+ 	^ self compiledBlock endPC!

Item was added:
+ ----- Method: FullBlockClosure>>hasMethodReturn (in category 'scanning') -----
+ hasMethodReturn
+ 	"Answer whether the receiver has a method-return ('^') in its code."
+ 	^ self compiledBlock hasMethodReturn!

Item was added:
+ ----- Method: FullBlockClosure>>home (in category 'accessing') -----
+ home
+ 	^ outerContext ifNotNil: [ outerContext home ]!

Item was added:
+ ----- Method: FullBlockClosure>>method (in category 'accessing') -----
+ method
+ 	^ self compiledBlock!

Item was added:
+ ----- Method: FullBlockClosure>>numArgs: (in category 'accessing') -----
+ numArgs: n
+ 	numArgs := n!

Item was added:
+ ----- Method: FullBlockClosure>>numTemps (in category 'accessing') -----
+ numTemps
+ 	^ self compiledBlock numTemps!

Item was added:
+ ----- Method: FullBlockClosure>>outerContext: (in category 'accessing') -----
+ outerContext: ctxt
+ 	outerContext := ctxt!

Item was added:
+ ----- Method: FullBlockClosure>>printOn: (in category 'private') -----
+ printOn: s
+ 	[ super printOn: s ] on: Error do: [ :ex | s << '!![' << ex messageText << ']!!' ]!

Item was added:
+ ----- Method: FullBlockClosure>>receiver (in category 'accessing') -----
+ receiver
+ 	^ receiver!

Item was added:
+ ----- Method: FullBlockClosure>>receiver: (in category 'accessing') -----
+ receiver: anObject
+ 	receiver := anObject!

Item was added:
+ ----- Method: FullBlockClosure>>simulateValueWithArguments:caller: (in category 'simulation') -----
+ simulateValueWithArguments: anArray caller: aContext
+ 	"Simulate the valueWithArguments: primitive. Fail if anArray is not an array of the right arity."
+ 	| newContext |
+ 	newContext := (Context newForMethod: self compiledBlock)
+ 						setSender: aContext
+ 						receiver: receiver
+ 						method: self compiledBlock
+ 						closure: self
+ 						startpc: self compiledBlock initialPC.
+ 	((newContext objectClass: anArray) ~~ Array
+ 	 or: [numArgs ~= anArray size]) ifTrue:
+ 		[^Context primitiveFailTokenFor: nil].
+ 	newContext stackp: self compiledBlock numTemps.
+ 	1 to: numArgs do:
+ 		[:i| newContext at: i put: (anArray at: i)].
+ 	1 to: self basicSize do:
+ 		[:i| newContext at: i + numArgs put: (self at: i)].
+ 	^newContext!

Item was added:
+ ----- Method: FullBlockClosure>>startpc (in category 'accessing') -----
+ startpc
+ 	^ self compiledBlock initialPC!

Item was added:
+ ----- Method: FullBlockClosure>>value (in category 'evaluating') -----
+ value
+ 	"Activate the receiver, creating a closure activation (MethodContext)
+ 	 whose closure is the receiver and whose caller is the sender of this
+ 	 message. Supply the copied values to the activation as its copied
+ 	 temps. Primitive. Essential."
+ 	<primitive: 207>
+ 	| newContext |
+ 	numArgs ~= 0 ifTrue:
+ 		[self numArgsError: 0].
+ 	false
+ 		ifTrue: "Old code to simulate the closure value primitive on VMs that lack it."
+ 			[newContext := self asContextWithSender: thisContext sender.
+ 			thisContext privSender: newContext]
+ 		ifFalse: [self primitiveFailed]!

Item was added:
+ ----- Method: FullBlockClosure>>value: (in category 'evaluating') -----
+ value: firstArg
+ 	"Activate the receiver, creating a closure activation (MethodContext)
+ 	 whose closure is the receiver and whose caller is the sender of this
+ 	 message. Supply the argument and copied values to the activation
+ 	 as its argument and copied temps. Primitive. Essential."
+ 	<primitive: 207>
+ 	| newContext |
+ 	numArgs ~= 1 ifTrue:
+ 		[self numArgsError: 1].
+ 	false
+ 		ifTrue: "Old code to simulate the closure value primitive on VMs that lack it."
+ 			[newContext := self asContextWithSender: thisContext sender.
+ 			newContext at: 1 put: firstArg.
+ 			thisContext privSender: newContext]
+ 		ifFalse: [self primitiveFailed]!

Item was added:
+ ----- Method: FullBlockClosure>>value:value: (in category 'evaluating') -----
+ value: firstArg value: secondArg
+ 	"Activate the receiver, creating a closure activation (MethodContext)
+ 	 whose closure is the receiver and whose caller is the sender of this
+ 	 message. Supply the arguments and copied values to the activation
+ 	 as its arguments and copied temps. Primitive. Essential."
+ 	<primitive: 207>
+ 	| newContext |
+ 	numArgs ~= 2 ifTrue:
+ 		[self numArgsError: 2].
+ 	false
+ 		ifTrue: "Old code to simulate the closure value primitive on VMs that lack it."
+ 			[newContext := self asContextWithSender: thisContext sender.
+ 			newContext at: 1 put: firstArg.
+ 			newContext at: 2 put: secondArg.
+ 			thisContext privSender: newContext]
+ 		ifFalse: [self primitiveFailed]!

Item was added:
+ ----- Method: FullBlockClosure>>value:value:value: (in category 'evaluating') -----
+ value: firstArg value: secondArg value: thirdArg
+ 	"Activate the receiver, creating a closure activation (MethodContext)
+ 	 whose closure is the receiver and whose caller is the sender of this
+ 	 message. Supply the arguments and copied values to the activation
+ 	 as its arguments and copied temps. Primitive. Essential."
+ 	<primitive: 207>
+ 	| newContext |
+ 	numArgs ~= 3 ifTrue:
+ 		[self numArgsError: 3].
+ 	false
+ 		ifTrue: "Old code to simulate the closure value primitive on VMs that lack it."
+ 			[newContext := self asContextWithSender: thisContext sender.
+ 			newContext at: 1 put: firstArg.
+ 			newContext at: 2 put: secondArg.
+ 			newContext at: 3 put: thirdArg.
+ 			thisContext privSender: newContext]
+ 		ifFalse: [self primitiveFailed]!

Item was added:
+ ----- Method: FullBlockClosure>>value:value:value:value: (in category 'evaluating') -----
+ value: firstArg value: secondArg value: thirdArg value: fourthArg
+ 	"Activate the receiver, creating a closure activation (MethodContext)
+ 	 whose closure is the receiver and whose caller is the sender of this
+ 	 message. Supply the arguments and copied values to the activation
+ 	 as its arguments and copied temps. Primitive. Essential."
+ 	<primitive: 207>
+ 	| newContext |
+ 	numArgs ~= 4 ifTrue:
+ 		[self numArgsError: 4].
+ 	false
+ 		ifTrue: "Old code to simulate the closure value primitive on VMs that lack it."
+ 			[newContext := self asContextWithSender: thisContext sender.
+ 			newContext at: 1 put: firstArg.
+ 			newContext at: 2 put: secondArg.
+ 			newContext at: 3 put: thirdArg.
+ 			newContext at: 4 put: fourthArg.
+ 			thisContext privSender: newContext]
+ 		ifFalse: [self primitiveFailed]!

Item was added:
+ ----- Method: FullBlockClosure>>valueNoContextSwitch (in category 'evaluating') -----
+ valueNoContextSwitch
+ 	"An exact copy of BlockClosure>>value except that this version will not preempt
+ 	 the current process on block activation if a higher-priority process is runnable.
+ 	 Primitive. Essential."
+ 	<primitive: 209>
+ 	numArgs ~= 0 ifTrue:
+ 		[self numArgsError: 0].
+ 	self primitiveFailed!

Item was added:
+ ----- Method: FullBlockClosure>>valueNoContextSwitch: (in category 'evaluating') -----
+ valueNoContextSwitch: anArg
+ 	"An exact copy of BlockClosure>>value: except that this version will not preempt
+ 	 the current process on block activation if a higher-priority process is runnable.
+ 	 Primitive. Essential."
+ 	<primitive: 209>
+ 	numArgs ~= 1 ifTrue:
+ 		[self numArgsError: 1].
+ 	self primitiveFailed!

Item was added:
+ ----- Method: FullBlockClosure>>valueWithArguments: (in category 'evaluating') -----
+ valueWithArguments: anArray
+ 	"Activate the receiver, creating a closure activation (MethodContext)
+ 	 whose closure is the receiver and whose caller is the sender of this
+ 	 message. Supply the arguments in an anArray and copied values to
+ 	 the activation as its arguments and copied temps. Primitive. Essential."
+ 	<primitive: 208>
+ 	| newContext |
+ 	numArgs ~= anArray size ifTrue:
+ 		[self numArgsError: anArray size].
+ 	false
+ 		ifTrue: "Old code to simulate the closure value primitive on VMs that lack it."
+ 			[newContext := self asContextWithSender: thisContext sender.
+ 			1 to: numArgs do:
+ 				[:i| newContext at: i put: (anArray at: i)].
+ 			thisContext privSender: newContext]
+ 		ifFalse: [self primitiveFailed]!



More information about the Squeak-dev mailing list