[squeak-dev] The Trunk: Morphic-mt.1521.mcz

commits at source.squeak.org commits at source.squeak.org
Tue Sep 17 10:11:58 UTC 2019


Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1521.mcz

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

Name: Morphic-mt.1521
Author: mt
Time: 17 September 2019, 12:11:44.272406 pm
UUID: 8f7a9d88-4010-8947-a9a1-7a6174c8e3c9
Ancestors: Morphic-mt.1520

Refactoring of process debugging. Complements System-mt.1093

=============== Diff against Morphic-mt.1520 ===============

Item was removed:
- ----- Method: Debugger class>>morphicOpenOn:context:label:contents:fullView: (in category '*Morphic-opening') -----
- morphicOpenOn: process context: context label: title contents: contentsStringOrNil fullView: full 
- 	"Open a notifier in response to an error, halt, or notify. A notifier view just shows a short view of the sender stack and provides a menu that lets the user open a full debugger."
- 	
- 	ErrorRecursionGuard critical: [
- 		
- 		| errorWasInUIProcess debugger |
- 		ErrorRecursion ifTrue: [
- 			"self assert: process == Project current uiProcess -- DOCUMENTATION ONLY"
- 			self clearErrorRecursion.
- 			^ Project current handleFatalDrawingError: title].
- 		
- 		[ErrorRecursion not & Preferences logDebuggerStackToFile
- 			ifTrue: [Smalltalk logSqueakError: title inContext: context]]
- 				on: Error
- 				do: [:ex | ex return: nil].
- 		
- 		errorWasInUIProcess := Project current spawnNewProcessIfThisIsUI: process.
- 		
- 		"Schedule debugging in deferred UI message because
- 			1) If process is the current UI process, it is already broken.
- 			2) If process is some other process, it must not execute UI code"
- 		Project current addDeferredUIMessage: [
- 			self setErrorRecursion.
- 			
- 			debugger := self new process: process controller: nil context: context.
- 			full
- 				ifTrue: [debugger openFullNoSuspendLabel: title]
- 				ifFalse: [debugger openNotifierContents: contentsStringOrNil label: title].
- 			debugger errorWasInUIProcess: errorWasInUIProcess.
- 		
- 			"Try drawing the debugger tool at least once to avoid freeze."
- 			Project current world displayWorldSafely.
- 			
- 			self clearErrorRecursion]].
- 	
- 	process suspend.!

Item was removed:
- ----- Method: Debugger class>>openContext:label:contents: (in category '*Morphic-opening') -----
- openContext: aContext label: aString contents: contentsStringOrNil 
- 	"Open a notifier in response to an error, halt, or notify. A notifier view just shows a short view of the sender stack and provides a menu that lets the user open a full debugger."
- 	"Simulation guard"
- 	<primitive: 19>
- 	ErrorRecursionGuard critical:
- 		[ ErrorRecursion not & Preferences logDebuggerStackToFile ifTrue:
- 			[ Smalltalk
- 				logSqueakError: aString
- 				inContext: aContext ].
- 		ErrorRecursion ifTrue:
- 			[ ErrorRecursion := false.
- 			self primitiveError: aString ].
- 		ErrorRecursion := true.
- 		self
- 			informExistingDebugger: aContext
- 			label: aString.
- 		(Debugger context: aContext)
- 			openNotifierContents: contentsStringOrNil
- 			label: aString.
- 		ErrorRecursion := false].
- 	Processor activeProcess suspend !

Item was removed:
- ----- Method: Debugger class>>openInterrupt:onProcess: (in category '*Morphic-opening') -----
- openInterrupt: aString onProcess: interruptedProcess
- 	"Open a notifier in response to an interrupt. An interrupt occurs when the user types the interrupt key (cmd-. on Macs, ctrl-c or alt-. on other systems) or when the low-space watcher detects that memory is low."
- 	| debugger |
- 	<primitive: 19> "Simulation guard"
- 	debugger := self new.
- 	debugger
- 		process: interruptedProcess
- 		controller: (ScheduledControllers
- 				ifNotNil: [:sc | 
- 					"this means we are in an MVC project"
- 					sc inActiveControllerProcess == interruptedProcess
- 						ifTrue: [ScheduledControllers activeController]])
- 		context: interruptedProcess suspendedContext.
- 	debugger externalInterrupt: true.
- 
- 	Preferences logDebuggerStackToFile ifTrue:
- 		[(aString includesSubstring: 'Space') & (aString includesSubstring: 'low')
- 			ifTrue: [Smalltalk logError: aString inContext: debugger interruptedContext to: 'LowSpaceDebug.log']
- 			"logging disabled for 4.3 release, see
- 				http://lists.squeak.org/pipermail/squeak-dev/2011-December/162503.html"
- 			"ifFalse: [Smalltalk logSqueakError: aString inContext: debugger interruptedContext]"].
- 
- 	Preferences eToyFriendly ifTrue: [Project current world stopRunningAll].
- 	^debugger
- 		openNotifierContents: nil label: aString;
- 		yourself
- !

Item was removed:
- ----- Method: Debugger>>morphicResumeProcess: (in category '*Morphic-opening') -----
- morphicResumeProcess: aTopView 
- 
- 	| processToResume |
- 	processToResume := interruptedProcess.
- 	interruptedProcess := nil. "Before delete, so release doesn't terminate it"
- 	aTopView delete.
- 	Project current world displayWorld. "We have to redraw *before* resuming the old process."
- 	Smalltalk installLowSpaceWatcher. "restart low space handler"
- 
- 	savedCursor
- 		ifNotNil: [Cursor currentCursor: savedCursor].
- 	processToResume isTerminated ifFalse: [
- 		errorWasInUIProcess
- 					ifTrue: [Project resumeProcess: processToResume]
- 					ifFalse: [processToResume resume]].
- 	"if old process was terminated, just terminate current one"
- 	errorWasInUIProcess == false
- 		ifFalse: [Processor terminateActive]!

Item was added:
+ Debugger subclass: #MorphicDebugger
+ 	instanceVariableNames: 'errorWasInUIProcess'
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Morphic-Support'!

Item was added:
+ ----- Method: MorphicDebugger class>>openDrawingErrors: (in category 'opening') -----
+ openDrawingErrors: errors
+ 	"Open debuggers for all different errors found."
+ 	
+ 	self setErrorRecursion.
+ 	errors do: [:processToLabel |
+ 			(MorphicDebugger new process: processToLabel key context: processToLabel key suspendedContext)
+ 				errorWasInUIProcess: Processor activeProcess = Project current uiProcess;
+ 				openNotifierContents: nil label: processToLabel value].
+ 
+ 	"Try to draw the debuggers or else there will be no chance to escape from this catch-drawing-error loop."
+ 	Project current world displayWorld.
+ 	self clearErrorRecursion.!

Item was added:
+ ----- Method: MorphicDebugger class>>openInterrupt:onProcess: (in category 'opening') -----
+ openInterrupt: aString onProcess: interruptedProcess
+ 	"Open a notifier in response to an interrupt. An interrupt occurs when the user types the interrupt key (cmd-. on Macs, ctrl-c or alt-. on other systems) or when the low-space watcher detects that memory is low."
+ 
+ 	| errorWasInUIProcess debugger |
+ 	<primitive: 19> "Simulation guard"
+ 	
+ 	errorWasInUIProcess := Project current spawnNewProcessIfThisIsUI: interruptedProcess.
+ 	debugger := self new.
+ 	debugger
+ 		process: interruptedProcess
+ 		context: interruptedProcess suspendedContext.
+ 	debugger
+ 		externalInterrupt: true;
+ 		errorWasInUIProcess: errorWasInUIProcess.
+ 
+ 	Preferences logDebuggerStackToFile ifTrue:
+ 		[(aString includesSubstring: 'Space') & (aString includesSubstring: 'low')
+ 			ifTrue: [Smalltalk logError: aString inContext: debugger interruptedContext to: 'LowSpaceDebug.log']
+ 			"logging disabled for 4.3 release, see
+ 				http://lists.squeak.org/pipermail/squeak-dev/2011-December/162503.html"
+ 			"ifFalse: [Smalltalk logSqueakError: aString inContext: debugger interruptedContext]"].
+ 
+ 	Preferences eToyFriendly ifTrue: [Project current world stopRunningAll].
+ 	^debugger
+ 		openNotifierContents: nil label: aString;
+ 		yourself
+ !

Item was added:
+ ----- Method: MorphicDebugger class>>openOn:context:label:contents:fullView: (in category 'opening') -----
+ openOn: process context: context label: title contents: contentsStringOrNil fullView: full 
+ 	"Open a notifier in response to an error, halt, or notify. A notifier view just shows a short view of the sender stack and provides a menu that lets the user open a full debugger."
+ 	
+ 	ErrorRecursionGuard critical: [
+ 		
+ 		| errorWasInUIProcess debugger |
+ 		ErrorRecursion ifTrue: [
+ 			"self assert: process == Project current uiProcess -- DOCUMENTATION ONLY"
+ 			self clearErrorRecursion.
+ 			^ Project current handleFatalDrawingError: title].
+ 		
+ 		[ErrorRecursion not & Preferences logDebuggerStackToFile
+ 			ifTrue: [Smalltalk logSqueakError: title inContext: context]]
+ 				on: Error
+ 				do: [:ex | ex return: nil].
+ 		
+ 		errorWasInUIProcess := Project current spawnNewProcessIfThisIsUI: process.
+ 		
+ 		"Schedule debugging in deferred UI message because
+ 			1) If process is the current UI process, it is already broken.
+ 			2) If process is some other process, it must not execute UI code"
+ 		Project current addDeferredUIMessage: [
+ 			self setErrorRecursion.
+ 			
+ 			self informExistingDebugger: context label: title.
+ 			
+ 			debugger := self new process: process context: context.
+ 			full
+ 				ifTrue: [debugger openFullNoSuspendLabel: title]
+ 				ifFalse: [debugger openNotifierContents: contentsStringOrNil label: title].
+ 			debugger errorWasInUIProcess: errorWasInUIProcess.
+ 		
+ 			"Try drawing the debugger tool at least once to avoid freeze."
+ 			Project current world displayWorldSafely.
+ 			
+ 			self clearErrorRecursion]].
+ 	
+ 	process suspend.!

Item was added:
+ ----- Method: MorphicDebugger class>>openOnMethod:forReceiver:inContext: (in category 'opening') -----
+ openOnMethod: aCompiledMethod forReceiver: anObject inContext: aContextOrNil
+ 
+ 	| guineaPig debugger debuggerWindow context |
+ 	guineaPig :=
+ 		[aCompiledMethod
+ 			valueWithReceiver: anObject
+ 			 arguments: (aContextOrNil ifNil: [ #() ] ifNotNil: [ { aContextOrNil } ]).
+ 		 guineaPig := nil "spot the return from aCompiledMethod"] newProcess.
+ 	context := guineaPig suspendedContext.
+ 	debugger := self new
+ 		process: guineaPig
+ 		context: context.
+ 	debuggerWindow := debugger openFullNoSuspendLabel: 'Debug it'.
+ 	"Now step into the expression.  But if it is quick (is implemented as a primtiive, e.g. `0')
+ 	 it will return immediately back to the block that is sent newProcess above.  Guard
+ 	 against that with the check for home being thisContext."
+ 	[debugger interruptedContext method == aCompiledMethod]
+ 		whileFalse:
+ 			[(guineaPig isNil
+ 			  and: [debugger interruptedContext home == thisContext]) ifTrue:
+ 				[debuggerWindow delete.
+ 				 UIManager default inform: 'Nothing to debug; expression is optimized'.
+ 				 ^self].
+ 			debugger send]!

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

Item was added:
+ ----- Method: MorphicDebugger>>errorWasInUIProcess: (in category 'accessing') -----
+ errorWasInUIProcess: boolean
+ 
+ 	errorWasInUIProcess := boolean!

Item was added:
+ ----- Method: MorphicDebugger>>initialize (in category 'initialize') -----
+ initialize
+ 
+ 	super initialize.
+ 	
+ 	errorWasInUIProcess := false.!

Item was added:
+ ----- Method: MorphicDebugger>>resumeProcess: (in category 'private') -----
+ resumeProcess: debuggerWindow 
+ 
+ 	| processToResume |
+ 	processToResume := interruptedProcess.
+ 	
+ 	interruptedProcess := nil. "Before delete, so release doesn't terminate it"
+ 	debuggerWindow delete.
+ 	
+ 	Project current world displayWorld. "We have to redraw *before* resuming the old process."
+ 	Smalltalk installLowSpaceWatcher. "restart low space handler"
+ 
+ 	savedCursor
+ 		ifNotNil: [Cursor currentCursor: savedCursor].
+ 	processToResume isTerminated ifFalse: [
+ 		errorWasInUIProcess
+ 					ifTrue: [Project resumeProcess: processToResume]
+ 					ifFalse: [processToResume resume]].
+ 	"if old process was terminated, just terminate current one"
+ 	errorWasInUIProcess == false
+ 		ifFalse: [Processor terminateActive]!

Item was added:
+ ----- Method: MorphicDebugger>>windowIsClosing (in category 'initialize') -----
+ windowIsClosing
+ 	"Keep track of last debugger extent."
+ 
+ 	interruptedProcess ifNil: [ ^ self ].
+ 
+ 	SavedExtent ifNotNil:
+ 		[ self dependents
+ 			detect:
+ 				[ : each | each isWindowForModel: self ]
+ 			ifFound:
+ 				[ : topWindow | | isDebuggerNotNotifier |
+ 				isDebuggerNotNotifier := self dependents anySatisfy:
+ 					[ : each | each isTextView ].
+ 				isDebuggerNotNotifier ifTrue: [
+ 					SavedExtent := (topWindow extent / RealEstateAgent scaleFactor) rounded ] ]
+ 			ifNone: [ "do nothing" ] ].
+ 
+ 	super windowIsClosing.!

Item was changed:
+ ----- Method: MorphicProject>>addDeferredUIMessage: (in category 'scheduling & debugging') -----
- ----- Method: MorphicProject>>addDeferredUIMessage: (in category 'scheduling') -----
  addDeferredUIMessage: valuableObject 
  	"Arrange for valuableObject to be evaluated at a time when the user interface
  	is in a coherent state."
  
+ 	self flag: #discuss. "mt: Why are deferred UI messages shared among all Morphic projects? That's not the case for MVC projects..."
  	WorldState addDeferredUIMessage: valuableObject!

Item was removed:
- ----- Method: MorphicProject>>debugMethod:forReceiver:inContext: (in category 'debugging') -----
- debugMethod: aCompiledMethod forReceiver: anObject inContext: aContextOrNil
- 
- 	| guineaPig debugger debuggerWindow context |
- 	guineaPig :=
- 		[aCompiledMethod
- 			valueWithReceiver: anObject
- 			 arguments: (aContextOrNil ifNil: [ #() ] ifNotNil: [ { aContextOrNil } ]).
- 		 guineaPig := nil "spot the return from aCompiledMethod"] newProcess.
- 	context := guineaPig suspendedContext.
- 	debugger := Debugger new
- 		process: guineaPig
- 		controller: nil
- 		context: context.
- 	debuggerWindow := debugger openFullNoSuspendLabel: 'Debug it'.
- 	"Now step into the expression.  But if it is quick (is implemented as a primtiive, e.g. `0')
- 	 it will return immediately back to the block that is sent newProcess above.  Guard
- 	 against that with the check for home being thisContext."
- 	[debugger interruptedContext method == aCompiledMethod]
- 		whileFalse:
- 			[(guineaPig isNil
- 			  and: [debugger interruptedContext home == thisContext]) ifTrue:
- 				[debuggerWindow delete.
- 				 UIManager default inform: 'Nothing to debug; expression is optimized'.
- 				 ^self].
- 			debugger send]!

Item was added:
+ ----- Method: MorphicProject>>debuggerClass (in category 'scheduling & debugging') -----
+ debuggerClass
+ 
+ 	^ Smalltalk classNamed: #MorphicDebugger!

Item was changed:
+ ----- Method: MorphicProject>>interruptName: (in category 'scheduling & debugging') -----
- ----- Method: MorphicProject>>interruptName: (in category 'scheduling') -----
  interruptName: labelString
  	"Create a Notifier on the active scheduling process with the given label."
  
  	^ self interruptName: labelString preemptedProcess: nil!

Item was changed:
+ ----- Method: MorphicProject>>interruptName:preemptedProcess: (in category 'scheduling & debugging') -----
- ----- Method: MorphicProject>>interruptName:preemptedProcess: (in category 'utilities') -----
  interruptName: labelString preemptedProcess: theInterruptedProcess
  	"Create a Notifier on the active scheduling process with the given label."
  
  	| preemptedProcess projectProcess |
  	ActiveHand ifNotNil:[ActiveHand interrupted].
  	ActiveWorld := world. "reinstall active globals"
  	ActiveHand := world primaryHand.
  	ActiveHand interrupted. "make sure this one's interrupted too"
  	ActiveEvent := nil.
  
  	projectProcess := self uiProcess.	"we still need the accessor for a while"
  	preemptedProcess := theInterruptedProcess ifNil: [Processor preemptedProcess].
  	"Only debug preempted process if its priority is >= projectProcess' priority"
  	preemptedProcess priority < projectProcess priority 
  		ifTrue:[preemptedProcess := projectProcess].
  	preemptedProcess suspend.
+ 	
+ 	ToolSet
+ 		debugInterruptedProcess: preemptedProcess
+ 		label: labelString.!
- 	ToolSet interrupt: preemptedProcess label: labelString.!

Item was added:
+ ----- Method: MorphicProject>>syntaxError: (in category 'scheduling & debugging') -----
+ syntaxError: aSyntaxErrorNotification
+ 
+ 	| compilerProcess errorWasInUIProcess debugger |
+ 	debugger := (super syntaxError: aSyntaxErrorNotification) model debugger.
+ 	
+ 	compilerProcess := Processor activeProcess.
+ 	errorWasInUIProcess := self spawnNewProcessIfThisIsUI: compilerProcess.
+ 	
+ 	debugger errorWasInUIProcess: errorWasInUIProcess.
+ 	compilerProcess suspend.!

Item was removed:
- ----- Method: SyntaxError class>>buildMorphicViewOn: (in category '*Morphic-Support') -----
- buildMorphicViewOn: aSyntaxError
- 	"Answer an Morphic view on the given SyntaxError."
- 	| window |
- 	window := (SystemWindow labelled: 'Syntax Error') model: aSyntaxError.
- 
- 	window addMorph: (PluggableListMorph on: aSyntaxError list: #list
- 			selected: #listIndex changeSelected: nil menu: #listMenu:)
- 		frame: (0 at 0 corner: 1 at 0.15).
- 
- 	window addMorph: ((PluggableTextMorphPlus on: aSyntaxError text: #contents
- 			accept: #contents:notifying: readSelection: #contentsSelection
- 			menu: #codePaneMenu:shifted:)
- 				useDefaultStyler; updateStyleNow;
- 				selectionInterval: aSyntaxError errorMessageInterval;
- 				yourself)
- 		frame: (0 at 0.15 corner: 1 at 1).
- 
- 	^ window openInWorldExtent: 380 at 220!

Item was removed:
- ----- Method: SyntaxError class>>morphicOpen: (in category '*Morphic-Support') -----
- morphicOpen: aSyntaxError
- 	"Answer a view whose model is an instance of me."
- 
- 	self buildMorphicViewOn: aSyntaxError.
- 	Project current spawnNewProcessIfThisIsUI: Processor activeProcess.
- 	^ Processor activeProcess suspend!

Item was changed:
  ----- Method: WorldState>>displayWorldSafely: (in category 'update cycle') -----
  displayWorldSafely: aWorld
  	"Update this world's display and keep track of errors during draw methods."
  
  	| finished errors previousClasses |
  	finished := false.
  	errors := nil.
  	
  	[finished] whileFalse: [
  		[aWorld displayWorld. finished := true] on: Error do: [:ex |
  			"Handle a drawing error"
  			| err rcvr errCtx errMorph |
  			err := ex description.
  			rcvr := ex receiver.
  
  			errCtx := thisContext.
  			[
  				errCtx := errCtx sender.
  				"Search the sender chain to find the morph causing the problem"
  				[errCtx notNil and:[(errCtx receiver isMorph) not]] 
  					whileTrue:[errCtx := errCtx sender].
  				"If we're at the root of the context chain then we have a fatal drawing problem"
  				errCtx ifNil:[^Project current handleFatalDrawingError: err].
  				errMorph := errCtx receiver.
  				"If the morph causing the problem has already the #drawError flag set,
  				then search for the next morph above in the caller chain."
  				errMorph hasProperty: #errorOnDraw
  			] whileTrue.
  			errMorph setProperty: #errorOnDraw toValue: true.
  
  			"Catch all errors, one for each receiver class."
  			errors ifNil: [errors := OrderedCollection new].
  			previousClasses ifNil: [previousClasses := IdentitySet new].
  			(previousClasses includes: rcvr class) ifFalse: [
  				previousClasses add: rcvr class.
  				errors add: (Process forContext: ex signalerContext copyStack priority: Processor activeProcess priority) -> err].
  			aWorld fullRepaintNeeded.
  		]].
  
+ 	errors ifNotNil: [MorphicDebugger openDrawingErrors: errors].!
- 	"Open debuggers for all different errors found."
- 	errors ifNotNil: [
- 		Debugger setErrorRecursion.
- 		errors do: [:ea |
- 			(Debugger new process: ea key controller: nil context: ea key suspendedContext)
- 				errorWasInUIProcess: Processor activeProcess = Project current uiProcess;
- 				openNotifierContents: nil label: ea value].
- 		"Try to draw the debuggers or else there will be no chance to escape from this catch-drawing-error loop."
- 		ActiveWorld displayWorld.
- 		Debugger clearErrorRecursion].!



More information about the Squeak-dev mailing list