224 |
226 |
225 |oldMethod newMethod compiler class selector| |
227 |oldMethod newMethod compiler class selector| |
226 |
228 |
227 oldMethod := codeView methodHolder value. |
229 oldMethod := codeView methodHolder value. |
228 (oldMethod notNil and:[oldMethod hasPrimitiveCode not]) ifTrue:[ |
230 (oldMethod notNil and:[oldMethod hasPrimitiveCode not]) ifTrue:[ |
229 "/ be careful: if the text has been edited/modified, do not compile |
231 "/ be careful: if the text has been edited/modified, do not compile |
230 textView modified ifTrue:[ |
232 textView modified ifTrue:[ |
231 self breakPoint: #cg. |
233 self breakPoint: #cg. |
232 self breakPoint: #jv. |
234 self breakPoint: #jv. |
233 ^self. |
235 ^self. |
234 ] ifFalse:[ |
236 ] ifFalse:[ |
235 "/ prepare to get reachable bpts |
237 "/ prepare to get reachable bpts |
236 breakpoints do:[:bp | bp isReached:false]. |
238 breakpoints do:[:bp | bp isReached:false]. |
237 |
239 |
238 class := oldMethod mclass. |
240 class := oldMethod mclass. |
239 class isNil ifTrue:[ |
241 class isNil ifTrue:[ |
240 class := codeView classHolder value. |
242 class := codeView classHolder value. |
241 class isNil ifTrue:[ |
243 class isNil ifTrue:[ |
242 self breakPoint:#jv. |
244 self breakPoint:#jv. |
243 Dialog warn:'oops - lost the methods''s class'. |
245 Dialog warn:'oops - lost the methods''s class'. |
244 ^ self. |
246 ^ self. |
245 ] |
247 ] |
246 ]. |
248 ]. |
247 selector := oldMethod selector. |
249 selector := oldMethod selector. |
248 |
250 |
249 Class withoutUpdatingChangesDo:[ |
251 Class withoutUpdatingChangesDo:[ |
250 compiler := ByteCodeCompilerWithBreakpointSupport new. |
252 compiler := ByteCodeCompilerWithBreakpointSupport new. |
251 compiler breakpoints:breakpoints. |
253 compiler breakpoints:breakpoints. |
252 compiler methodClass:MethodWithBreakpoints. |
254 compiler methodClass:MethodWithBreakpoints. |
253 newMethod := compiler |
255 newMethod := compiler |
254 compile:oldMethod source |
256 compile:oldMethod source |
255 forClass:class |
257 forClass:class |
256 inCategory:oldMethod category |
258 inCategory:oldMethod category |
257 notifying:nil |
259 notifying:nil |
258 install:false |
260 install:false |
259 skipIfSame:false |
261 skipIfSame:false |
260 silent:true |
262 silent:true |
261 foldConstants:true |
263 foldConstants:true |
262 ifFail:[ Transcript showCR:'BreakpointService: failed to recompile for breakpoint' ]. |
264 ifFail:[ Transcript showCR:'BreakpointService: failed to recompile for breakpoint' ]. |
263 |
265 |
264 selector isNil ifTrue:[ |
266 selector isNil ifTrue:[ |
265 "/ May happen as the selector is not stored in the method but |
267 "/ May happen as the selector is not stored in the method but |
266 "/ searches through method's mclass methodDictionary. |
268 "/ searches through method's mclass methodDictionary. |
267 "/ Following should be save as breakpoint is not installed when |
269 "/ Following should be save as breakpoint is not installed when |
268 "/ the code is modified... |
270 "/ the code is modified... |
269 selector := compiler selector. |
271 selector := compiler selector. |
270 ]. |
272 ]. |
271 |
273 |
272 oldMethod isWrapped ifTrue:[ |
274 oldMethod isWrapped ifTrue:[ |
273 "/ update the wrapped method - do not install |
275 "/ update the wrapped method - do not install |
274 newMethod originalMethod: oldMethod originalMethod. |
276 newMethod originalMethod: oldMethod originalMethod. |
275 oldMethod replaceOriginalMethodWith:newMethod. |
277 oldMethod replaceOriginalMethodWith:newMethod. |
276 ] ifFalse:[ |
278 ] ifFalse:[ |
277 "/ install |
279 "/ install |
278 newMethod originalMethod: oldMethod. |
280 newMethod originalMethod: oldMethod. |
279 (class primAddSelector: selector withMethod:newMethod) ifFalse:[ |
281 (class primAddSelector: selector withMethod:newMethod) ifFalse:[ |
280 oldMethod mclass:class. |
282 oldMethod mclass:class. |
281 self breakPoint: #cg. |
283 self breakPoint: #cg. |
282 self breakPoint: #jv. |
284 self breakPoint: #jv. |
283 ^ self |
285 ^ self |
284 ]. |
286 ]. |
285 ]. |
287 ]. |
286 "/ must come indirectly!! |
288 |
287 codeView methodHolder value:newMethod. |
289 breakpoints := breakpoints |
288 oldMethod mclass isNil ifTrue:[ |
290 select:[:bp | |
289 "/ although this is not strictly true, not doing this |
291 "/ bp isReached ifFalse:[ |
290 "/ would confuse a lot of other tools (such as the browser) |
292 "/ "/ Transcript show:'remove unreached:'; showCR:bp |
291 oldMethod mclass:class. |
293 "/ ]. |
292 ]. |
294 bp isReached |
293 class changed:#methodTrap with:selector. "/ tell browsers |
295 ]. |
294 Smalltalk changed:#methodTrap with:(MethodTrapChangeNotificationParameter changeClass:class changeSelector:selector). |
296 |
295 ]. |
297 "/ must update breakpoints BEFORE the following, because it leads to a change |
296 |
298 "/ notification, which may clear the breakpoints collection!! |
297 breakpoints := breakpoints |
299 codeView methodHolder value:newMethod. |
298 select:[:bp | |
300 oldMethod mclass isNil ifTrue:[ |
299 "/ bp isReached ifFalse:[ |
301 "/ although this is not strictly true, not doing this |
300 "/ "/ Transcript show:'remove unreached:'; showCR:bp |
302 "/ would confuse a lot of other tools (such as the browser) |
301 "/ ]. |
303 oldMethod mclass:class. |
302 bp isReached |
304 ]. |
303 ] |
305 class changed:#methodTrap with:selector. "/ tell browsers |
304 ] |
306 Smalltalk changed:#methodTrap with:(MethodTrapChangeNotificationParameter changeClass:class changeSelector:selector). |
|
307 ]. |
|
308 ] |
305 ] |
309 ] |
306 |
310 |
307 "Created: / 05-07-2011 / 21:33:13 / cg" |
311 "Created: / 05-07-2011 / 21:33:13 / cg" |
308 "Modified: / 18-07-2012 / 10:53:22 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
312 "Modified: / 18-07-2012 / 10:53:22 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
309 "Modified: / 02-08-2012 / 09:35:41 / cg" |
313 "Modified: / 02-08-2012 / 09:35:41 / cg" |
336 "/ We accept the additional overhead, as we are in debug mode anyway. |
340 "/ We accept the additional overhead, as we are in debug mode anyway. |
337 "/ prepareFullBreakSupport := false. |
341 "/ prepareFullBreakSupport := false. |
338 prepareFullBreakSupport := true. |
342 prepareFullBreakSupport := true. |
339 |
343 |
340 textView reallyModified ifTrue:[ |
344 textView reallyModified ifTrue:[ |
341 "/ leads to ugly behavior (method no longer found), if we allow |
345 "/ leads to ugly behavior (method no longer found), if we allow |
342 "/ this... |
346 "/ this... |
343 Dialog warn:'Please accept first (cannot set breakpoint while text is modified)'. |
347 Dialog warn:'Please accept first (cannot set breakpoint while text is modified)'. |
344 ^ self |
348 ^ self |
345 ]. |
349 ]. |
346 |
350 |
347 pos := textView characterPositionOfLine:line col:1. |
351 pos := textView characterPositionOfLine:line col:1. |
348 bpnt := self breakpointAtLine:line. |
352 bpnt := self breakpointAtLine:line. |
349 bpnt isNil ifTrue:[ |
353 bpnt isNil ifTrue:[ |
350 "/ no breakpoint there - add as required |
354 "/ no breakpoint there - add as required |
351 (self canCreateOrToggleBreakpointAtLine:line) ifTrue:[ |
355 (self canCreateOrToggleBreakpointAtLine:line) ifTrue:[ |
352 prepareFullBreakSupport ifTrue:[ |
356 prepareFullBreakSupport ifTrue:[ |
353 "/ add a (disabled) breakpoint for every source line. This |
357 "/ add a (disabled) breakpoint for every source line. This |
354 "/ allows for breakpoints to be enabled/disabled in the debugger... |
358 "/ allows for breakpoints to be enabled/disabled in the debugger... |
355 1 to:textView numberOfLines do:[:eachLine | |
359 1 to:textView numberOfLines do:[:eachLine | |
356 |oldBPnt eachPos otherBpnt| |
360 |oldBPnt eachPos otherBpnt| |
357 |
361 |
358 oldBPnt := self breakpointAtLine:eachLine. |
362 oldBPnt := self breakpointAtLine:eachLine. |
359 oldBPnt isNil ifTrue:[ |
363 oldBPnt isNil ifTrue:[ |
360 eachPos := textView characterPositionOfLine:eachLine col:1. |
364 eachPos := textView characterPositionOfLine:eachLine col:1. |
361 breakpoints isNil ifTrue:[ breakpoints := OrderedCollection new]. |
365 breakpoints isNil ifTrue:[ breakpoints := OrderedCollection new]. |
362 breakpoints add:((otherBpnt := Breakpoint new) position:eachPos line:eachLine). |
366 breakpoints add:((otherBpnt := Breakpoint new) position:eachPos line:eachLine). |
363 eachLine == line ifTrue:[ |
367 eachLine == line ifTrue:[ |
364 bpnt := otherBpnt. |
368 bpnt := otherBpnt. |
365 ] ifFalse:[ |
369 ] ifFalse:[ |
366 otherBpnt beInvisible. |
370 otherBpnt beInvisible. |
367 ] |
371 ] |
368 ]. |
372 ]. |
369 ]. |
373 ]. |
370 ] ifFalse:[ |
374 ] ifFalse:[ |
371 breakpoints add:((bpnt := Breakpoint new) position:pos line:line). |
375 breakpoints add:((bpnt := Breakpoint new) position:pos line:line). |
372 ]. |
376 ]. |
373 Display shiftDown ifTrue:[ |
377 Display shiftDown ifTrue:[ |
374 "/ trace |
378 "/ trace |
375 bpnt beTracepoint |
379 bpnt beTracepoint |
376 ]. |
380 ]. |
377 self recompile. |
381 self assert: breakpoints notEmptyOrNil. |
378 ] ifFalse:[ |
382 self recompile. |
379 codeView topView class == DebugView ifTrue:[ |
383 ] ifFalse:[ |
380 Dialog warn:'Sorry, can only add a new breakpoint in an already breakpointed method.'. |
384 codeView topView class == DebugView ifTrue:[ |
381 "/ Dialog warn:'Sorry, can only add a new breakpoint in a wrapped method which has not yet started.'. |
385 Dialog warn:'Sorry, in an active method, I can only add new breakpoints in an already breakpointed method. |
382 ] ifFalse:[ |
386 (i.e. a method stopped at a method breakpoint or one which already has statement breakpoints) |
383 Dialog warn:'Sorry, cannot add a new breakpoint here.'. |
387 The reason is that the method needs to be recompiled for the breakpoint, which would not affect the currently executed method.'. |
384 ]. |
388 "/ Dialog warn:'Sorry, can only add a new breakpoint in a wrapped method which has not yet started.'. |
385 ] |
389 ] ifFalse:[ |
|
390 Dialog warn:'Sorry, cannot add a new breakpoint here.'. |
|
391 ]. |
|
392 ] |
386 ] ifFalse:[ |
393 ] ifFalse:[ |
387 "/ breakpoint already there - just enable/disable |
394 "/ breakpoint already there - just enable/disable |
388 Display shiftDown ifTrue:[ |
395 Display shiftDown ifTrue:[ |
389 bpnt toggleTracing |
396 bpnt toggleTracing |
390 ] ifFalse:[ |
397 ] ifFalse:[ |
391 bpnt toggle. |
398 bpnt toggle. |
392 ]. |
399 ]. |
393 currentMethod mclass isNil ifTrue:[ |
400 currentMethod mclass isNil ifTrue:[ |
394 "/ hack: ouch - was wrapped in the meantime; |
401 "/ hack: ouch - was wrapped in the meantime; |
395 "/ hurry up and update. Should be done elsewhere (in codeView) |
402 "/ hurry up and update. Should be done elsewhere (in codeView) |
396 self updateCurrentMethod. |
403 self updateCurrentMethod. |
397 ]. |
404 ]. |
398 Smalltalk changed:#methodTrap with:(MethodTrapChangeNotificationParameter changeClass:currentMethod mclass changeSelector:currentMethod selector). |
405 Smalltalk changed:#methodTrap with:(MethodTrapChangeNotificationParameter changeClass:currentMethod mclass changeSelector:currentMethod selector). |
399 ]. |
406 ]. |
400 |
407 |
401 gutterView redrawLine:line. |
408 gutterView redrawLine:line. |
402 |
409 |
403 "Created: / 17-06-2011 / 13:45:22 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
410 "Created: / 17-06-2011 / 13:45:22 / Jan Vrany <jan.vrany@fit.cvut.cz>" |