David T. Lewis uploaded a new version of Environments to project The Trunk:
http://source.squeak.org/trunk/Environments-jr.69.mcz
==================== Summary ====================
Name: Environments-jr.69
Author: jr
Time: 22 January 2017, 1:58:32.760832 am
UUID: bef4785f-f66c-1246-bae6-6a15be9aaf33
Ancestors: Environments-jr.68
prevent the removal of third-party imported bindings
Previously, when environment T imported from A and B, which both had a binding for #x, unbinding #x from either A or B would remove the binding from T.
Now if the binding of #x is removed from A it will only be removed from T if T actually uses the binding from A, but not if T uses the binding from B.
It also prevents an environment A from unbinding something in an imported environment B when A imports itself and A and B both have a declaration with the same key.
=============== Diff against Environments-jr.68 ===============
Item was changed:
----- Method: Environment>>hideBinding: (in category 'binding') -----
hideBinding: aBinding
+ (bindings bindingOf: aBinding key) == aBinding ifFalse: [^ self].
self undeclare: aBinding key from: bindings!
David T. Lewis uploaded a new version of Environments to project The Trunk:
http://source.squeak.org/trunk/Environments-jr.71.mcz
==================== Summary ====================
Name: Environments-jr.71
Author: jr
Time: 28 February 2017, 2:36:25.745081 am
UUID: a50d4dbb-f587-6d46-bd22-bfcba43c4187
Ancestors: Environments-jr.69
add a signal to ask for an environment
to be used by Monticello to choose an environment
=============== Diff against Environments-jr.69 ===============
Item was changed:
SystemOrganization addCategory: #'Environments-Core'!
SystemOrganization addCategory: #'Environments-Loading'!
SystemOrganization addCategory: #'Environments-Policies'!
SystemOrganization addCategory: #'Environments-Help'!
+ SystemOrganization addCategory: #'Environments-Notifications'!
Item was added:
+ Notification subclass: #EnvironmentRequest
+ instanceVariableNames: ''
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Environments-Notifications'!
+
+ !EnvironmentRequest commentStamp: 'jr 1/15/2017 00:34' prior: 0!
+ I represent a request for an Environment that is not necessarily the CurrentEnvironment, but any Environment available in the system.
+
+ Instance Variables
+ !
Item was added:
+ ----- Method: EnvironmentRequest>>defaultAction (in category 'exceptionDescription') -----
+ defaultAction
+ | all environment |
+ all := Environment allInstances.
+ environment := UIManager default chooseFrom: all values: all.
+ self resume: environment.!
David T. Lewis uploaded a new version of ToolsTests to project The Trunk:
http://source.squeak.org/trunk/ToolsTests-jr.79.mcz
==================== Summary ====================
Name: ToolsTests-jr.79
Author: jr
Time: 28 February 2017, 2:07:52.478388 pm
UUID: 633800f6-1e23-1744-8e1a-01ecd6e88cd2
Ancestors: ToolsTests-eem.78
change testSelectedEnvironment to fit with Tools-jr.745
=============== Diff against ToolsTests-eem.78 ===============
Item was changed:
----- Method: BrowserTest>>testSelectedEnvironment (in category 'as yet unclassified') -----
testSelectedEnvironment
browser selectSystemCategory: browser class category.
+ self assert: browser selectedEnvironment = Smalltalk globals.
- self assert: browser selectedEnvironment = Smalltalk.
+ "browser selectSystemCategory: nil.
+ self assert: browser selectedEnvironment isNil."
+ "selectedClass would not work in a hierarchy browser that has to display classes from different environments (because the correct categories might be missing)"!
- browser selectSystemCategory: nil.
- self assert: browser selectedEnvironment isNil.!
David T. Lewis uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-jr.745.mcz
==================== Summary ====================
Name: Tools-jr.745
Author: jr
Time: 28 February 2017, 2:20:44.822081 am
UUID: c3e3bfae-ac2c-0d4e-a606-c41b7d388d67
Ancestors: Tools-cmm.744
improve Tools support for environments
allows...
- navigating senders/implementors
- using the hierarchy browser
- defining new classes and traits
- enjoying a Workspace
...in other environments
Also ensure all objects understand #environment, so tools can send it without fear.
Depends on ToolBuilder-Kernel-jr.109 for choosing something in 'find class'.
=============== Diff against Tools-cmm.744 ===============
Item was changed:
----- Method: Browser>>copyClass (in category 'class functions') -----
copyClass
| originalClass originalName copysName |
self hasClassSelected ifFalse: [^ self].
self okToChange ifFalse: [^ self].
originalClass := self selectedClass.
originalName := originalClass name.
copysName := self request: 'Please type new class name' initialAnswer: originalName.
copysName = '' ifTrue: [^ self]. " Cancel returns '' "
copysName := copysName asSymbol.
copysName = originalName ifTrue: [^ self].
+ (self environment hasClassNamed: copysName)
- (Smalltalk hasClassNamed: copysName)
ifTrue: [^ self error: copysName , ' already exists'].
Cursor wait showWhile: [
| newDefinition newMetaDefinition newClass |
newDefinition := originalClass definition
copyReplaceAll: originalName printString
with: copysName printString.
+ newClass := Compiler evaluate: newDefinition environment: self environment
+ logged: true.
- newClass := Compiler evaluate: newDefinition logged: true.
newMetaDefinition := originalClass class definition
copyReplaceAll: originalClass class name
with: newClass class name.
+ Compiler evaluate: newMetaDefinition environment: self environment
+ logged: true.
- Compiler evaluate: newMetaDefinition logged: true.
newClass copyAllCategoriesFrom: originalClass.
newClass class copyAllCategoriesFrom: originalClass class.
originalClass hasComment ifTrue: [
newClass comment: originalClass comment ] ].
self classListIndex: 0.
self changed: #classList!
Item was changed:
----- Method: Browser>>defineClass:notifying: (in category 'class functions') -----
defineClass: defString notifying: aController
"The receiver's textual content is a request to define a new class. The
source code is defString. If any errors occur in compilation, notify
aController."
| oldClass class newClassName defTokens keywdIx envt |
oldClass := self selectedClassOrMetaClass.
defTokens := defString findTokens: Character separators.
((defTokens first = 'Trait' and: [defTokens second = 'named:'])
or: [defTokens second = 'classTrait'])
ifTrue: [^self defineTrait: defString notifying: aController].
keywdIx := defTokens findFirst: [:x | x beginsWith: 'category'].
+ envt := self selectedEnvironment.
- envt := Smalltalk.
keywdIx := defTokens findFirst: [:x | '*subclass*' match: x].
newClassName := (defTokens at: keywdIx+1) copyWithoutAll: '#()'.
((oldClass isNil or: [oldClass theNonMetaClass name asString ~= newClassName])
and: [envt includesKey: newClassName asSymbol]) ifTrue:
["Attempting to define new class over existing one when
not looking at the original one in this browser..."
(self confirm: ((newClassName , ' is an existing class in this system.
Redefining it might cause serious problems.
Is this really what you want to do?') asText makeBoldFrom: 1 to: newClassName size))
ifFalse: [^ false]].
"ar 8/29/1999: Use oldClass superclass for defining oldClass
since oldClass superclass knows the definerClass of oldClass."
oldClass ifNotNil:[oldClass := oldClass superclass].
+ class := envt beCurrentDuring:
+ [oldClass subclassDefinerClass
- class := oldClass subclassDefinerClass
evaluate: defString
+ in: envt
notifying: aController
+ logged: false].
- logged: false.
(class isKindOf: Behavior)
ifTrue: [self changed: #systemCategoryList.
self changed: #classList.
self clearUserEditFlag.
self setClass: class selector: nil.
"self clearUserEditFlag; editClass."
^ true]
ifFalse: [^ false]!
Item was changed:
----- Method: Browser>>defineTrait:notifying: (in category 'traits') -----
defineTrait: defString notifying: aController
| defTokens keywdIx envt oldTrait newTraitName trait |
oldTrait := self selectedClassOrMetaClass.
defTokens := defString findTokens: Character separators.
keywdIx := defTokens findFirst: [:x | x = 'category'].
envt := self selectedEnvironment.
keywdIx := defTokens findFirst: [:x | x = 'named:'].
newTraitName := (defTokens at: keywdIx+1) copyWithoutAll: '#()'.
((oldTrait isNil or: [oldTrait baseTrait name asString ~= newTraitName])
and: [envt includesKey: newTraitName asSymbol]) ifTrue:
["Attempting to define new class/trait over existing one when
not looking at the original one in this browser..."
(self confirm: ((newTraitName , ' is an existing class/trait in this system.
Redefining it might cause serious problems.
Is this really what you want to do?') asText makeBoldFrom: 1 to: newTraitName size))
ifFalse: [^ false]].
+ trait := envt beCurrentDuring:
+ [Compiler evaluate: defString in: envt notifying: aController logged: true].
- trait := Compiler evaluate: defString notifying: aController logged: true.
^(trait isTrait)
ifTrue: [
self changed: #classList.
self classListIndex: (self classListIndexOf: trait baseTrait name).
self clearUserEditFlag; editClass.
true]
ifFalse: [ false ]
!
Item was added:
+ ----- Method: Browser>>environment (in category 'accessing') -----
+ environment
+ ^ environment ifNil: [super environment]!
Item was changed:
----- Method: Browser>>findClass (in category 'system category functions') -----
findClass
"Search for a class by name."
| foundClass |
(self multiWindowState notNil
or: [self okToChange]) ifFalse:
[^self classNotFound].
+ foundClass := UIManager default chooseClassOrTraitFrom: self environment.
- foundClass := UIManager default chooseClassOrTrait.
foundClass ifNil: [^self classNotFound].
(self selectedClass notNil
and: [self multiWindowState notNil
"Can only support multi-window if original window has all the right panes."
and: [self multiWindowState prototype isHierarchy not]]) ifTrue:
[(self classList includes: foundClass name)
ifTrue: [self multiWindowState copyWindow]
ifFalse: [self multiWindowState addNewWindow]].
self selectCategoryForClass: foundClass.
self selectClass: foundClass!
Item was changed:
----- Method: Browser>>hierarchicalClassList (in category 'class list') -----
hierarchicalClassList
"classNames are an arbitrary collection of classNames of the system.
Reorder those class names so that they are sorted and indended by inheritance"
| classes |
"Creating the hierarchy is *really slow* for the full class list. Skip it for now."
self selectedSystemCategory = SystemOrganizer allCategory
ifTrue: [^ self defaultClassList].
+ classes := self defaultClassList collect: [:sym | self environment classNamed: sym].
- classes := self defaultClassList collect: [:sym | Smalltalk classNamed: sym].
^ self
flattenHierarchyTree: (self createHierarchyTreeOf: classes)
on: OrderedCollection new
indent: ''.!
Item was changed:
----- Method: Browser>>selectedClass (in category 'class list') -----
selectedClass
"Answer the class that is currently selected. Answer nil if no selection
exists."
| name envt |
(name := self selectedClassName) ifNil: [^ nil].
(envt := self selectedEnvironment) ifNil: [^ nil].
+ ^ envt at: name ifAbsent: [envt valueOf: name ifAbsent: [nil]]!
- ^ envt at: name ifAbsent: [nil]!
Item was changed:
----- Method: Browser>>selectedEnvironment (in category 'system category list') -----
selectedEnvironment
+ "Answer the browsed environment. If this returned a system category dependent
+ value and possibly nil (as it did in previous versions), selectedClass would not work in
+ a hierarchy browser that has to display classes from different environments
+ (because the correct categories might be missing in the browser)"
- "Answer the name of the selected system category or nil."
+ ^ environment ifNil: [Smalltalk globals]!
- self hasSystemCategorySelected ifFalse: [^nil].
- ^ environment ifNil: [Smalltalk]!
Item was changed:
----- Method: ChangeList>>diffedVersionContents (in category 'viewing access') -----
diffedVersionContents
"Answer diffed version contents, maybe pretty maybe not"
| change class earlier later |
(listIndex = 0
or: [changeList size < listIndex])
ifTrue: [^ ''].
change := changeList at: listIndex.
later := change text.
+ class := change methodClass: self environment.
- class := change methodClass.
(listIndex == changeList size or: [class == nil])
ifTrue: [^ (self showingPrettyDiffs and: [class notNil])
ifTrue: [class prettyPrinterClass format: later in: class notifying: nil]
ifFalse: [later]].
earlier := (changeList at: listIndex + 1) text.
^ TextDiffBuilder buildDisplayPatchFrom: earlier to: later inClass: class prettyDiffs: self showingPrettyDiffs!
Item was changed:
----- Method: ChangeList>>fileInSelections (in category 'menu actions') -----
fileInSelections
| any |
any := false.
+ self selectedClass environment beCurrentDuring: [
+ listSelections with: changeList do:
+ [:selected :item | selected ifTrue: [any := true. item fileIn]]].
- listSelections with: changeList do:
- [:selected :item | selected ifTrue: [any := true. item fileIn]].
any ifFalse:
[self inform: 'nothing selected, so nothing done']!
Item was changed:
----- Method: DependencyBrowser>>selectedEnvironment (in category 'accessing') -----
selectedEnvironment
"Answer the name of the selected package or nil."
self hasPackageSelected ifFalse: [^nil].
+ ^ Smalltalk globals!
- ^ Smalltalk!
Item was changed:
----- Method: HierarchyBrowser>>classList (in category 'class list') -----
classList
+ classDisplayList := classDisplayList select: [:each | (self environment valueOf: each withBlanksTrimmed asSymbol) notNil].
- classDisplayList := classDisplayList select: [:each | Smalltalk includesKey: each withBlanksTrimmed asSymbol].
^ classDisplayList!
Item was changed:
----- Method: HierarchyBrowser>>classListIndex: (in category 'initialization') -----
classListIndex: newIndex
"Cause system organization to reflect appropriate category"
| newClassName ind |
newIndex ~= 0 ifTrue:
[newClassName := (classDisplayList at: newIndex) copyWithout: $ .
selectedSystemCategory := (systemOrganizer categories at:
+ (systemOrganizer numberOfCategoryOfElement: newClassName)
+ ifAbsent: [nil])].
- (systemOrganizer numberOfCategoryOfElement: newClassName))].
ind := super classListIndex: newIndex.
"What I'd like to write:"
"self selectedClassName ifNotNil:
[ selectedSystemCategory := self selectedClass category ]."
self changed: #systemCategorySingleton.
^ ind!
Item was changed:
----- Method: HierarchyBrowser>>initHierarchyForClass: (in category 'initialization') -----
initHierarchyForClass: aClassOrMetaClass
| nonMetaClass superclasses |
centralClass := aClassOrMetaClass.
nonMetaClass := aClassOrMetaClass theNonMetaClass.
+ self selectEnvironment: aClassOrMetaClass environment.
- self systemOrganizer: SystemOrganization.
metaClassIndicated := aClassOrMetaClass isMeta.
classDisplayList := OrderedCollection new.
(superclasses := nonMetaClass allSuperclasses reversed) withIndexDo:
[ : each : indent | classDisplayList add:
(String streamContents:
[ : stream | indent - 1 timesRepeat: [ stream nextPutAll: ' ' ].
stream nextPutAll: each name ]) ].
nonMetaClass
allSubclassesWithLevelDo:
[ : eachClass : lvl | classDisplayList add:
(String streamContents:
[ : stream | lvl timesRepeat: [ stream nextPutAll: ' ' ].
stream nextPutAll: eachClass name ]) ]
startingLevel: superclasses size.
self changed: #classList.
self selectClass: nonMetaClass!
Item was changed:
----- Method: MessageSet class>>parse:toClassAndSelector: (in category 'utilities') -----
parse: methodRef toClassAndSelector: csBlock
"Decode strings of the form <className> [class] <selectorName>."
| tuple cl |
self flag: #mref. "compatibility with pre-MethodReference lists"
methodRef ifNil: [^ csBlock value: nil value: nil].
methodRef isString ifFalse:
[^methodRef setClassAndSelectorIn: csBlock].
methodRef isEmpty ifTrue:
[^csBlock value: nil value: nil].
tuple := (methodRef asString includesSubstring: '>>')
ifTrue: [(methodRef findTokens: '>>') fold: [:a :b| (a findTokens: ' '), {b first = $# ifTrue: [b allButFirst] ifFalse: [b]}]]
ifFalse: [methodRef asString findTokens: ' .'].
+ self flag: #environments. "missing information about the class environment"
cl := Smalltalk at: tuple first asSymbol ifAbsent: [^ csBlock value: nil value: nil].
^(tuple size = 2 or: [tuple size > 2 and: [(tuple at: 2) ~= 'class']])
ifTrue: [csBlock value: cl value: (tuple at: 2) asSymbol]
ifFalse: [csBlock value: cl class value: (tuple at: 3) asSymbol]!
Item was changed:
----- Method: MessageTrace>>filteredSelectorsNamed: (in category 'filtering') -----
filteredSelectorsNamed: selectorSymbol
+ ^(SystemNavigation for: self environment) allImplementorsOf: selectorSymbol
- ^SystemNavigation new allImplementorsOf: selectorSymbol
!
Item was added:
+ ----- Method: Model>>environment (in category '*Tools') -----
+ environment
+ ^ (self selectedClass ifNil: [self class]) environment!
Item was added:
+ ----- Method: Object>>environment (in category '*Tools') -----
+ environment
+ "This is a fallback for models that do not inherit from Model or something else that provides
+ a useful Environment answer. You should consider copying this method to (base) classes of
+ objects from which you expect exactly the behavior below.
+ Absolutely feel free to override this method for objects that have or operate on a dedicated
+ environment, such as references to classes, code loaders, or tools."
+ ^ self class environment!
Item was changed:
StringHolder subclass: #Workspace
+ instanceVariableNames: 'bindings acceptDroppedMorphs acceptAction mustDeclareVariables shouldStyle environment'
- instanceVariableNames: 'bindings acceptDroppedMorphs acceptAction mustDeclareVariables shouldStyle'
classVariableNames: 'LookupPools ShouldStyle'
poolDictionaries: ''
category: 'Tools-Base'!
!Workspace commentStamp: 'fbs 6/2/2012 20:46' prior: 0!
A Workspace is a text area plus a lot of support for executable code. It is a great place to execute top-level commands to compute something useful, and it is a great place to develop bits of a program before those bits get put into class methods.
To open a new workspace, execute:
Workspace open
A workspace can have its own variables, called "workspace variables", to hold intermediate results. For example, if you type into a workspace "x := 5" and do-it, then later you could type in "y := x * 2" and y would become 10.
Additionally, in Morphic, a workspace can gain access to morphs that are on the screen. If acceptDroppedMorphs is turned on, then whenever a morph is dropped on the workspace, a variable will be created which references that morph. This functionality is toggled with the window-wide menu of a workspace.
The instance variables of this class are:
bindings - holds the workspace variables for this workspace
acceptDroppedMorphs - whether dropped morphs should create new variables!
Item was added:
+ ----- Method: Workspace>>environment (in category 'accessing') -----
+ environment
+ ^ environment ifNil: [Smalltalk globals]!
Item was added:
+ ----- Method: Workspace>>environment: (in category 'accessing') -----
+ environment: anEnvironment
+
+ environment := anEnvironment.!
Item was changed:
----- Method: Workspace>>initialize (in category 'initialize-release') -----
initialize
super initialize.
self initializeBindings.
acceptDroppedMorphs := false.
+ mustDeclareVariables := false.
+ environment := Environment current.!
- mustDeclareVariables := false!
David T. Lewis uploaded a new version of ToolBuilder-Kernel to project The Trunk:
http://source.squeak.org/trunk/ToolBuilder-Kernel-jr.109.mcz
==================== Summary ====================
Name: ToolBuilder-Kernel-jr.109
Author: jr
Time: 28 February 2017, 1:37:47.610081 am
UUID: edda3c34-f8df-fc4f-b6a5-6404053750f1
Ancestors: ToolBuilder-Kernel-tfel.108
offer a class selection from another environment
=============== Diff against ToolBuilder-Kernel-tfel.108 ===============
Item was changed:
----- Method: UIManager>>chooseClassOrTrait (in category 'ui requests') -----
chooseClassOrTrait
"Let the user choose a Class or Trait"
+ ^self chooseClassOrTraitFrom: Smalltalk globals!
- ^self chooseClassOrTrait: 'Class name or fragment?'!
Item was added:
+ ----- Method: UIManager>>chooseClassOrTraitFrom: (in category 'ui requests') -----
+ chooseClassOrTraitFrom: anEnvironment
+ "Let the user choose a Class or Trait from the given environment"
+
+ ^self chooseClassOrTrait: 'Class name or fragment?' from: anEnvironment!
Item was changed:
----- Method: UIManager>>classFromPattern:withCaption: (in category 'system introspecting') -----
classFromPattern: pattern withCaption: aCaption
+ ^self classFromPattern: pattern withCaption: aCaption in: Smalltalk environment
- "If there is a class or trait whose name exactly given by pattern, return it.
- If there is only one class or trait in the system whose name matches pattern, return it.
- Otherwise, put up a menu offering the names of all classes that match pattern, and return the class chosen, else nil if nothing chosen.
- This method ignores separator characters in the pattern"
-
- ^self classOrTraitFrom: Smalltalk environment pattern: pattern label: aCaption
"
self classFromPattern: 'CharRecog' withCaption: ''
self classFromPattern: 'rRecog' withCaption: ''
self classFromPattern: 'znak' withCaption: ''
self classFromPattern: 'orph' withCaption: ''
self classFromPattern: 'TCompil' withCaption: ''
"
!
Item was added:
+ ----- Method: UIManager>>classFromPattern:withCaption:in: (in category 'system introspecting') -----
+ classFromPattern: pattern withCaption: aCaption in: anEnvironment
+ "If there is a class or trait whose name exactly given by pattern, return it.
+ If there is only one class or trait in the system whose name matches pattern, return it.
+ Otherwise, put up a menu offering the names of all classes that match pattern, and return the class chosen, else nil if nothing chosen.
+ This method ignores separator characters in the pattern"
+
+ ^self classOrTraitFrom: anEnvironment pattern: pattern label: aCaption
+ "
+ for examples, see #classFromPattern:withCaption:
+ "
+ !
David T. Lewis uploaded a new version of Compiler to project The Trunk:
http://source.squeak.org/trunk/Compiler-jr.329.mcz
==================== Summary ====================
Name: Compiler-jr.329
Author: jr
Time: 28 February 2017, 12:19:04.434081 am
UUID: 6053da84-5a5b-b043-8dcc-019bc75762df
Ancestors: Compiler-nice.328
add method variants with environment parameters
=============== Diff against Compiler-nice.328 ===============
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: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: 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>>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>>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>>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: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"
+ | theClass |
+ theClass := (aContext == nil ifTrue: [receiver class] ifFalse: [aContext methodClass]).
+ ^self
+ evaluateCue: (CompilationCue
+ source: textOrStream
+ context: aContext
+ receiver: receiver
+ class: theClass
+ environment: anEnvironment
+ requestor: aRequestor)
+ ifFail: failBlock
+ logged: logFlag!
Hi Clément,
On Fri, Mar 3, 2017 at 4:54 AM, Clément Bera <bera.clement(a)gmail.com> wrote:
>
>
> On Fri, Mar 3, 2017 at 12:12 PM, Cyril Ferlicot D. <
> cyril.ferlicot(a)gmail.com> wrote:
>
>> On 03/03/2017 11:56, Clément Bera wrote:
>> > Hello everyone,
>> >
>> > This morning I investigated with Vincent Blondeau a problem reported by
>> > the Moose community a while ago: loading Moose model is slower in Spur
>> > (Pharo 5+) than in pre-Spur (Pharo 4 and older). In general, this
>> > problem was present for anyone growing images to a significant size.
>> >
>> > To investigate the problem, we loaded a 200Mb[3] Moose model on a 250Mb
>> > image, growing the image to 450Mb. Loading such a model takes 2 minutes
>> > in Spur and 1m30s in pre-Spur VMs.
>> >
>> > Using the stable Pharo VM, the analysis results were the following:
>> > - total time spent to load the Model: 2 minutes
>> > - time spent in full GC: 1 minute (4 fullGCs)
>> > - time spent in scavenges[1]: 15 seconds
>> > On the 2 minutes spent, we have 50% of the time spent in full GCs, 12.5%
>> > in scavenges, 37.5% executing code.
>> >
>> > We then used the latest VM that features the new compactor (VM from
>> > beginning of March 2017 and over). The full GC execution time went down
>> > from 1 minute to 2 seconds.
>> >
>> > In addition, we increased the size of Eden[2] from 4Mb to 12Mb. Time
>> > spent in scavenges decreased from 15 seconds to 5 seconds.
>> >
>> > Overall, loading the model is now taking ~50 seconds instead of 2
>> minutes.
>> >
>> > To increase Eden size, one needs to run a script similar to:
>> >
>> > | currentEdenSize desiredEdenSize |
>> > currentEdenSize := Smalltalk vm parameterAt: 44.
>> > desiredEdenSize := currentEdenSize * 4.
>> > Smalltalk vm parameterAt: 45 put: desiredEdenSize.
>> >
>> > _*And then restart the image.*_
>> >
>> > I hope this report can be useful for some of you. I will try to make a
>> > blog post out of it, detailing other GC settings one can change from the
>> > image to improve performance.
>> > _*
>> > *_
>> > Best,
>> >
>> > Clement
>> >
>> > [1] A scavenge is basically the garbage collection of only young objects
>> > [2] Eden is basically the space where objects are initially allocated.
>> > [3] All numbers in the report are order of magnitudes and not precise
>> > numbers
>> >
>> >
>> >
>>
>> Hi,
>>
>> This is great! We will probably try it soon on our models.
>>
>> Guillaume had a question also, what is the counterparty if we let the
>> EdenSize at this size when we are not loading/exporting a MSE?
>>
>
> There are 2 main counterparts:
> - You waste a bit of memory. If you increase from 4Mb to 12Mb, you waste
> 8Mb.
> - The user-pauses for scavenges may be more significant.
>
> There are customers using 64Mb Eden in production. It improves their
> performance, they do not care about wasting 60Mb on machine with 16Gb RAM
> and their application does heavy computation and does not need to be that
> responsive.
>
It is important to realize that scavenge time depends on the amount of
objects that survive, not on the size of new space. So increasing the size
of new space will only cause longer pause times when an application is
growing the heap, which is the case when Moose reads models. But if an
application is following the standard pattern of creating many objects,
most of which are collected, then a large eden should not cause noticeably
longer pause times. This is because a scavenge copies the surviving
objects from eden and past space into future space, overflowing into old
space, tracing reachable objects only. So only if lots of objects survive
does scavenging touch lots of data. If only a few objects survive the
scavenger touches (copies) only those objects.
The VM collects times so you could do some experiments and measure the
average scavenge time for the Moose application during its growth phase and
then during its normal phase. I think you'll find that the large new space
is not an issue for normal usage.
There is another variable that can affect pause times and that is the
number of stack pages. The roots of a scavenging collection are the
remembered table and the stack zone. So the larger the stack zone, the
more time is spent scanning the stack looking for references to objects in
new space. This is a difficult trade off. If one has lots of Smalltalk
processes in one's application with lots of context switchers between them
(this is the threading benchmark) then one wants lots of stack pages,
because otherwise a process switch may involve evicting some contexts from
a stack page in order to make room for the top context of a newly runnable
process. But the more stack pages one uses the slower scavenging becomes.
Cog's default used to be very high (160 pages IIRC) which was determined at
Qwaq, whose Teatime application uses lots of futures. I've reduced the
default to 50 but it is an important variable to play with.
> However for UI applications (typically the IDE), the scavenge pauses may
> become significant enough to be noticed by the programmer. Maybe not at
> 12Mb, but certainly at 64Mb.
>
I doubt this very much (because of the argument above). Remember that the
scavenger is a garbage collector specifically designed to work well with
systems like Smalltalk where lots of intermediate objects are created when
computing results. Scavenging doesn't touch objects that are reclaimed,
only objects that survive. So this works well. I think you'll find that
GUI applications fit this pattern very much and so a large new sad should
not present a problem.
>
> For your case:
> - Do you care that your application use some more Mb of RAM ?
> - Do you care if your application takes a couple extra ms to answer a
> request ? (In any case, the full GC takes much more time and also delays
> the answer right now)
> If you don't care, you can use larger Eden. In any case, an Eden of 12 or
> 16 Mb should be safe.
>
> There are other settings that can be useful in your case. I will try to
> write a post about it.
>
>
>> Because in our case we deploy a server that might need to read some MSE.
>> We cannot restart it with our current solution. In that case it would be
>> good to have more info to select the best EdenSize for the server.
>>
>> Thank you!
>>
>> --
>> Cyril Ferlicot
>>
>> http://www.synectique.eu
>>
>> 2 rue Jacques Prévert 01,
>> 59650 Villeneuve d'ascq France
>>
>>
>
--
_,,,^..^,,,_
best, Eliot