The Trunk: Morphic-mt.1521.mcz

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

The Trunk: Morphic-mt.1521.mcz

commits-2
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@0 corner: 1@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@0.15 corner: 1@1).
-
- ^ window openInWorldExtent: 380@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].!