82 changeSet1 changeSet2 offset oldOffsets newOffsets addedNames |
82 changeSet1 changeSet2 offset oldOffsets newOffsets addedNames |
83 anyChange oldInstVars newInstVars oldClassVars newClassVars upd superFlags newFlags| |
83 anyChange oldInstVars newInstVars oldClassVars newClassVars upd superFlags newFlags| |
84 |
84 |
85 "NOTICE: |
85 "NOTICE: |
86 this method is too complex and should be splitted into managable pieces ... |
86 this method is too complex and should be splitted into managable pieces ... |
87 I dont like it anymore :-) |
87 I dont like it anymore :-) |
|
88 (However, its a good test for the compilers ability to handle big, complex methods ;-) |
88 " |
89 " |
89 |
90 |
90 newName = aClass name ifTrue:[ |
91 newName = aClass name ifTrue:[ |
91 self error:'trying to create circular class definition'. |
92 self error:'trying to create circular class definition'. |
92 ^ nil |
93 ^ nil |
93 ]. |
94 ]. |
94 |
95 |
95 "check for invalid subclassing of UndefinedObject and SmallInteger" |
96 "check for invalid subclassing of UndefinedObject and SmallInteger" |
96 aClass canBeSubclassed ifFalse:[ |
97 aClass canBeSubclassed ifFalse:[ |
97 self error:('it is not possible to subclass ' , aClass name). |
98 self error:('it is not possible to subclass ' , aClass name). |
98 ^ oldClass |
99 ^ oldClass |
99 ]. |
100 ]. |
100 |
101 |
101 nInstVars := stringOfInstVarNames countWords. |
102 nInstVars := stringOfInstVarNames countWords. |
102 nameString := newName asString. |
103 nameString := newName asString. |
103 classSymbol := newName asSymbol. |
104 classSymbol := newName asSymbol. |
104 newComment := commentString. |
105 newComment := commentString. |
105 |
106 |
106 "look, if it already exists as a class" |
107 "look, if it already exists as a class" |
107 oldClass := aSystemDictionary at:classSymbol ifAbsent:[nil]. |
108 oldClass := aSystemDictionary at:classSymbol ifAbsent:[nil]. |
108 oldClass isBehavior ifFalse:[ |
109 oldClass isBehavior ifFalse:[ |
109 oldClass := nil. |
110 oldClass := nil. |
110 ] ifTrue:[ |
111 ] ifTrue:[ |
111 oldClass superclass notNil ifTrue:[ |
112 oldClass superclass notNil ifTrue:[ |
112 oldClass allSuperclasses do:[:cls | |
113 oldClass allSuperclasses do:[:cls | |
113 cls name = nameString ifTrue:[ |
114 cls name = nameString ifTrue:[ |
114 self error:'trying to create circular class definition'. |
115 self error:'trying to create circular class definition'. |
115 ^ nil |
116 ^ nil |
116 ] |
117 ] |
117 ] |
118 ] |
118 ]. |
119 ]. |
119 |
120 |
120 aClass superclass notNil ifTrue:[ |
121 aClass superclass notNil ifTrue:[ |
121 aClass allSuperclasses do:[:cls | |
122 aClass allSuperclasses do:[:cls | |
122 cls name = nameString ifTrue:[ |
123 cls name = nameString ifTrue:[ |
123 self error:'trying to create circular class definition'. |
124 self error:'trying to create circular class definition'. |
124 ^ nil |
125 ^ nil |
125 ] |
126 ] |
126 ]. |
127 ]. |
127 ]. |
128 ]. |
128 |
129 |
129 newComment isNil ifTrue:[ |
130 newComment isNil ifTrue:[ |
130 newComment := oldClass comment |
131 newComment := oldClass comment |
131 ]. |
132 ]. |
132 |
133 |
133 " |
134 " |
134 warn, if it exists with different category and different instvars, |
135 warn, if it exists with different category and different instvars, |
135 and the existing is not an autoload class. |
136 and the existing is not an autoload class. |
136 Usually, this indicates that someone wants to create a new class with |
137 Usually, this indicates that someone wants to create a new class with |
137 a name, which already exists (it happened a few times to myself, while |
138 a name, which already exists (it happened a few times to myself, while |
138 I wanted to create a new class called ReturnNode ...). |
139 I wanted to create a new class called ReturnNode ...). |
139 This will be much less of a problem, once multiple name spaces are |
140 This will be much less of a problem, once multiple name spaces are |
140 implemented and classes can be put into separate packages. |
141 implemented and classes can be put into separate packages. |
141 " |
142 " |
142 oldClass isLoaded ifTrue:[ |
143 oldClass isLoaded ifTrue:[ |
143 oldClass category ~= categoryString ifTrue:[ |
144 oldClass category ~= categoryString ifTrue:[ |
144 oldClass instanceVariableString asCollectionOfWords |
145 oldClass instanceVariableString asCollectionOfWords |
145 ~= stringOfInstVarNames asCollectionOfWords ifTrue:[ |
146 ~= stringOfInstVarNames asCollectionOfWords ifTrue:[ |
146 (self confirm:'a class named ' , oldClass name , ' already exists - |
147 (self confirm:'a class named ' , oldClass name , ' already exists - |
147 |
148 |
148 create (i.e. change) anyway ?' withCRs) |
149 create (i.e. change) anyway ?' withCRs) |
149 ifFalse:[ |
150 ifFalse:[ |
150 ^ nil |
151 ^ nil |
151 ] |
152 ] |
152 ] |
153 ] |
153 ] |
154 ] |
154 ] |
155 ] |
155 ]. |
156 ]. |
156 |
157 |
157 " |
158 " |
158 Check for some 'considered bad-style' things, like lower case names. |
159 Check for some 'considered bad-style' things, like lower case names. |
159 But only do these checks for new classes - |
160 But only do these checks for new classes - |
164 the outer codeview a chance to highlight the error. |
165 the outer codeview a chance to highlight the error. |
165 (but thats how its defined in the book - maybe I will change anyway). |
166 (but thats how its defined in the book - maybe I will change anyway). |
166 " |
167 " |
167 |
168 |
168 oldClass isNil ifTrue:[ |
169 oldClass isNil ifTrue:[ |
169 "let user confirm, if the classname is no good" |
170 "let user confirm, if the classname is no good" |
170 newName first isUppercase ifFalse:[ |
171 newName first isUppercase ifFalse:[ |
171 (self confirm:'classenames should start with an uppercase letter |
172 (self confirm:'classenames should start with an uppercase letter |
172 (by convention only) |
173 (by convention only) |
173 |
174 |
174 install anyway ?' withCRs) |
175 install anyway ?' withCRs) |
175 ifFalse:[ |
176 ifFalse:[ |
176 ^ nil |
177 ^ nil |
177 ] |
178 ] |
178 ]. |
179 ]. |
179 |
180 |
180 "let user confirm, if any instvarname is no good" |
181 "let user confirm, if any instvarname is no good" |
181 (stringOfInstVarNames asCollectionOfWords |
182 (stringOfInstVarNames asCollectionOfWords |
182 inject:true |
183 inject:true |
183 into:[:okSoFar :word | |
184 into:[:okSoFar :word | |
184 okSoFar and:[word first isLowercase] |
185 okSoFar and:[word first isLowercase] |
185 ] |
186 ] |
186 |
187 |
187 ) ifFalse:[ |
188 ) ifFalse:[ |
188 (self confirm:'instance variable names should start with a lowercase letter |
189 (self confirm:'instance variable names should start with a lowercase letter |
189 (by convention only) |
190 (by convention only) |
190 |
191 |
191 install anyway ?' withCRs) |
192 install anyway ?' withCRs) |
192 ifFalse:[ |
193 ifFalse:[ |
193 ^ nil |
194 ^ nil |
194 ] |
195 ] |
195 ]. |
196 ]. |
196 |
197 |
197 "let user confirm, if any classvarname is no good" |
198 "let user confirm, if any classvarname is no good" |
198 (stringOfClassVarNames asCollectionOfWords |
199 (stringOfClassVarNames asCollectionOfWords |
199 inject:true |
200 inject:true |
200 into:[:okSoFar :word | |
201 into:[:okSoFar :word | |
201 okSoFar and:[word first isUppercase] |
202 okSoFar and:[word first isUppercase] |
202 ] |
203 ] |
203 |
204 |
204 ) ifFalse:[ |
205 ) ifFalse:[ |
205 (self confirm:'class variable names should start with an uppercase letter |
206 (self confirm:'class variable names should start with an uppercase letter |
206 (by convention only) |
207 (by convention only) |
207 |
208 |
208 install anyway ?' withCRs) |
209 install anyway ?' withCRs) |
209 ifFalse:[ |
210 ifFalse:[ |
210 ^ nil |
211 ^ nil |
211 ] |
212 ] |
212 ] |
213 ] |
213 ]. |
214 ]. |
214 |
215 |
215 "create the metaclass first" |
216 "create the metaclass first" |
216 newMetaclass := Metaclass new. |
217 newMetaclass := Metaclass new. |
217 newMetaclass setSuperclass:(aClass class). |
218 newMetaclass setSuperclass:(aClass class). |
232 |
233 |
233 ST-80 code will pass true or false as variableBoolean, |
234 ST-80 code will pass true or false as variableBoolean, |
234 while ST/X also calls it with symbols such as #float, #double etc. |
235 while ST/X also calls it with symbols such as #float, #double etc. |
235 " |
236 " |
236 (variableBoolean == true) ifTrue:[ |
237 (variableBoolean == true) ifTrue:[ |
237 pointersBoolean ifTrue:[ |
238 pointersBoolean ifTrue:[ |
238 newFlags := Behavior flagPointers |
239 newFlags := Behavior flagPointers |
239 ] ifFalse:[ |
240 ] ifFalse:[ |
240 wordsBoolean ifTrue:[ |
241 wordsBoolean ifTrue:[ |
241 newFlags := Behavior flagWords |
242 newFlags := Behavior flagWords |
242 ] ifFalse:[ |
243 ] ifFalse:[ |
243 newFlags := Behavior flagBytes |
244 newFlags := Behavior flagBytes |
244 ] |
245 ] |
245 ] |
246 ] |
246 ] ifFalse:[ |
247 ] ifFalse:[ |
247 (variableBoolean == #float) ifTrue:[ |
248 (variableBoolean == #float) ifTrue:[ |
248 newFlags := Behavior flagFloats |
249 newFlags := Behavior flagFloats |
249 ] ifFalse:[ |
250 ] ifFalse:[ |
250 (variableBoolean == #double) ifTrue:[ |
251 (variableBoolean == #double) ifTrue:[ |
251 newFlags := Behavior flagDoubles |
252 newFlags := Behavior flagDoubles |
252 ] ifFalse:[ |
253 ] ifFalse:[ |
253 (variableBoolean == #long) ifTrue:[ |
254 (variableBoolean == #long) ifTrue:[ |
254 newFlags := Behavior flagLongs |
255 newFlags := Behavior flagLongs |
255 ] ifFalse:[ |
256 ] ifFalse:[ |
256 newFlags := Behavior flagNotIndexed |
257 newFlags := Behavior flagNotIndexed |
257 ] |
258 ] |
258 ] |
259 ] |
259 ]. |
260 ]. |
260 ]. |
261 ]. |
261 superFlags := aClass flags bitAnd:(Behavior maskIndexType bitInvert). "preserve other bits" |
262 superFlags := aClass flags bitAnd:(Behavior maskIndexType bitInvert). "preserve other bits" |
262 oldClass notNil ifTrue:[ |
263 oldClass notNil ifTrue:[ |
263 oldClass isBuiltInClass ifTrue:[ |
264 oldClass isBuiltInClass ifTrue:[ |
264 " |
265 " |
265 special care when redefining Method, Block and other built-in classes, |
266 special care when redefining Method, Block and other built-in classes, |
266 which might have other flag bits ... |
267 which might have other flag bits ... |
267 " |
268 " |
268 |
269 |
269 newFlags := newFlags bitOr:(oldClass flags bitAnd:(Behavior maskIndexType bitInvert)) |
270 newFlags := newFlags bitOr:(oldClass flags bitAnd:(Behavior maskIndexType bitInvert)) |
270 ] |
271 ] |
271 ]. |
272 ]. |
272 newClass flags:(newFlags bitOr:superFlags). "preserve inherited special bits" |
273 newClass flags:(newFlags bitOr:superFlags). "preserve inherited special bits" |
273 |
274 |
274 (nInstVars ~~ 0) ifTrue:[ |
275 (nInstVars ~~ 0) ifTrue:[ |
275 newClass instanceVariableString:stringOfInstVarNames |
276 newClass instanceVariableString:stringOfInstVarNames |
276 ]. |
277 ]. |
277 oldClass notNil ifTrue:[ |
278 oldClass notNil ifTrue:[ |
278 "setting first will make new class clear obsolete classvars" |
279 "setting first will make new class clear obsolete classvars" |
279 newClass setClassVariableString:(oldClass classVariableString) |
280 newClass setClassVariableString:(oldClass classVariableString) |
280 ]. |
281 ]. |
281 newClass classVariableString:stringOfClassVarNames. |
282 newClass classVariableString:stringOfClassVarNames. |
282 |
283 |
283 " |
284 " |
284 for new classes, we are almost done here |
285 for new classes, we are almost done here |
285 (also for autoloaded classes) |
286 (also for autoloaded classes) |
286 " |
287 " |
287 (oldClass isNil or:[oldClass isLoaded not]) ifTrue:[ |
288 (oldClass isNil or:[oldClass isLoaded not]) ifTrue:[ |
288 oldClass isNil ifTrue:[ |
289 oldClass isNil ifTrue:[ |
289 self addChangeRecordForClass:newClass. |
290 self addChangeRecordForClass:newClass. |
290 ]. |
291 ]. |
291 |
292 |
292 commentString notNil ifTrue:[ |
293 commentString notNil ifTrue:[ |
293 newClass comment:commentString |
294 newClass comment:commentString |
294 ]. |
295 ]. |
295 |
296 |
296 aSystemDictionary at:classSymbol put:newClass. |
297 aSystemDictionary at:classSymbol put:newClass. |
297 aSystemDictionary changed. |
298 aSystemDictionary changed:#newClass with:newClass. |
298 ^ newClass |
299 ^ newClass |
299 ]. |
300 ]. |
300 |
301 |
301 |
302 |
302 " |
303 " |
303 here comes the hard part - we are actually changing the |
304 here comes the hard part - we are actually changing the |
316 inheritance do not change. |
317 inheritance do not change. |
317 In this case, we can go ahead and patch the class object. |
318 In this case, we can go ahead and patch the class object. |
318 " |
319 " |
319 (oldClass superclass == newClass superclass) ifTrue:[ |
320 (oldClass superclass == newClass superclass) ifTrue:[ |
320 (oldClass instSize == newClass instSize) ifTrue:[ |
321 (oldClass instSize == newClass instSize) ifTrue:[ |
321 (oldClass flags == newClass flags) ifTrue:[ |
322 (oldClass flags == newClass flags) ifTrue:[ |
322 (oldClass name = newClass name) ifTrue:[ |
323 (oldClass name = newClass name) ifTrue:[ |
323 (oldInstVars = newInstVars) ifTrue:[ |
324 (oldInstVars = newInstVars) ifTrue:[ |
324 |
325 |
325 (newComment ~= oldClass comment) ifTrue:[ |
326 (newComment ~= oldClass comment) ifTrue:[ |
326 oldClass comment:newComment. "writes a change-chunk" |
327 oldClass setComment:newComment. "writes a change-chunk" |
327 ]. |
328 oldClass changed:#comment with:oldClass comment. |
328 |
329 self addChangeRecordForClassComment:oldClass. |
329 (oldClassVars = newClassVars) ifTrue:[ |
330 ]. |
330 " |
331 |
331 really no change (just comment and/or category) |
332 (oldClassVars = newClassVars) ifTrue:[ |
332 " |
333 " |
333 anyChange := false. |
334 really no change (just comment and/or category) |
334 |
335 " |
335 oldClass instanceVariableString:(newClass instanceVariableString). |
336 anyChange := false. |
336 oldClass setClassVariableString:(newClass classVariableString). |
337 |
337 |
338 oldClass instanceVariableString:(newClass instanceVariableString). |
338 oldClass category ~= categoryString ifTrue:[ |
339 oldClass setClassVariableString:(newClass classVariableString). |
339 "notify change of organization" |
340 |
340 |
341 oldClass category ~= categoryString ifTrue:[ |
341 oldClass category:categoryString. |
342 oldClass category:categoryString. |
342 self addChangeRecordForClass:newClass. |
343 self addChangeRecordForClass:newClass. |
343 aSystemDictionary changed |
344 "notify change of organization" |
344 ]. |
345 aSystemDictionary changed |
345 "notify change of class" |
346 ]. |
346 oldClass changed. |
347 "notify change of class" |
347 ^ oldClass |
348 "/ oldClass changed. |
348 ]. |
349 ^ oldClass |
349 |
350 ]. |
350 " |
351 |
351 when we arrive here, class variables have changed |
352 " |
352 " |
353 when we arrive here, class variables have changed |
353 oldClass category ~= categoryString ifTrue:[ |
354 " |
354 "notify change of organization" |
355 oldClass category ~= categoryString ifTrue:[ |
355 oldClass category:categoryString. |
356 "notify change of organization" |
356 aSystemDictionary changed |
357 oldClass category:categoryString. |
357 ]. |
358 "notify change of organization" |
358 |
359 aSystemDictionary changed |
359 " |
360 ]. |
360 set class variable string; |
361 |
361 this also updates the set of class variables |
362 " |
362 by creating new / deleting obsolete ones. |
363 set class variable string; |
363 " |
364 this also updates the set of class variables |
364 oldClass classVariableString:stringOfClassVarNames. |
365 by creating new / deleting obsolete ones. |
365 |
366 " |
366 " |
367 oldClass classVariableString:stringOfClassVarNames. |
367 get the set of changed class variables |
368 |
368 " |
369 " |
369 changeSet1 := Set new. |
370 get the set of changed class variables |
370 oldClassVars do:[:nm | |
371 " |
371 (newClassVars includes:nm) ifFalse:[ |
372 changeSet1 := Set new. |
372 changeSet1 add:nm |
373 oldClassVars do:[:nm | |
373 ] |
374 (newClassVars includes:nm) ifFalse:[ |
374 ]. |
375 changeSet1 add:nm |
375 newClassVars do:[:nm | |
376 ] |
376 (oldClassVars includes:nm) ifFalse:[ |
377 ]. |
377 changeSet1 add:nm |
378 newClassVars do:[:nm | |
378 ] |
379 (oldClassVars includes:nm) ifFalse:[ |
379 ]. |
380 changeSet1 add:nm |
380 |
381 ] |
381 " |
382 ]. |
382 recompile all methods accessing set of changed classvars |
383 |
383 here and also in all subclasses ... |
384 " |
384 " |
385 recompile all methods accessing set of changed classvars |
385 |
386 here and also in all subclasses ... |
386 " |
387 " |
387 dont update change file for the recompilation |
388 |
388 " |
389 " |
389 upd := Class updateChanges:false. |
390 dont update change file for the recompilation |
390 [ |
391 " |
391 " " |
392 upd := Class updateChanges:false. |
392 Transcript showCr:'recompiling class & inst methods accessing ' , changeSet1 printString. |
393 [ |
393 Transcript endEntry. |
394 " " |
394 " " |
395 Transcript showCr:'recompiling class & inst methods accessing ' , changeSet1 printString. |
395 oldClass withAllSubclasses do:[:aClass | |
396 Transcript endEntry. |
396 aClass class recompileMethodsAccessingAny:changeSet1. |
397 " " |
397 aClass recompileMethodsAccessingAny:changeSet1. |
398 oldClass withAllSubclasses do:[:aClass | |
398 ]. |
399 aClass class recompileMethodsAccessingAny:changeSet1. |
399 ] valueNowOrOnUnwindDo:[ |
400 aClass recompileMethodsAccessingAny:changeSet1. |
400 Class updateChanges:upd. |
401 ]. |
401 ]. |
402 ] valueNowOrOnUnwindDo:[ |
402 |
403 Class updateChanges:upd. |
403 "notify change of class" |
404 ]. |
404 self addChangeRecordForClass:oldClass. |
405 |
405 oldClass changed. |
406 "notify change of class" |
406 |
407 self addChangeRecordForClass:oldClass. |
407 ^ oldClass |
408 oldClass changed:#definition. |
408 ] |
409 |
409 ] |
410 ^ oldClass |
410 ] |
411 ] |
|
412 ] |
|
413 ] |
411 ] |
414 ] |
412 ]. |
415 ]. |
413 |
416 |
414 "tell dependents ..." |
|
415 "OLD: |
|
416 oldClass changed. |
|
417 " |
|
418 |
|
419 |
|
420 " |
417 " |
421 here we enter the darkness of mordor ... |
418 here we enter the darkness of mordor ... |
|
419 since instance variable layout and/or inheritance has changed. |
422 " |
420 " |
423 |
421 |
424 (newComment ~= oldClass comment) ifTrue:[ |
422 (newComment ~= oldClass comment) ifTrue:[ |
425 newClass comment:newComment |
423 newClass comment:newComment |
426 ]. |
424 ]. |
427 |
425 |
428 superClassChange := oldClass superclass ~~ newClass superclass. |
426 superClassChange := oldClass superclass ~~ newClass superclass. |
429 |
427 |
430 " |
428 " |
431 dont allow built-in classes to be modified this way |
429 dont allow built-in classes to be modified this way |
432 " |
430 " |
433 (oldClass notNil and:[oldClass isBuiltInClass and:[superClassChange]]) ifTrue:[ |
431 (oldClass notNil and:[oldClass isBuiltInClass and:[superClassChange]]) ifTrue:[ |
434 self error:'the inheritance of this class is fixed - you cannot change it'. |
432 self error:'the inheritance of this class is fixed - you cannot change it'. |
435 ^ oldClass |
433 ^ oldClass |
436 ]. |
434 ]. |
437 |
435 |
438 " |
436 " |
439 catch special case, where superclass changed its layout and thus |
437 catch special case, where superclass changed its layout and thus |
440 forced redefinition of this class; |
438 forced redefinition of this class; |
443 (superClassChange |
441 (superClassChange |
444 and:[(oldClass superclass isNil or:[oldClass superclass name = newClass superclass name]) |
442 and:[(oldClass superclass isNil or:[oldClass superclass name = newClass superclass name]) |
445 and:[(oldClassVars = newClassVars) |
443 and:[(oldClassVars = newClassVars) |
446 and:[(oldInstVars = newInstVars) |
444 and:[(oldInstVars = newInstVars) |
447 and:[newComment = oldClass comment]]]]) ifFalse:[ |
445 and:[newComment = oldClass comment]]]]) ifFalse:[ |
448 self addChangeRecordForClass:newClass. |
446 self addChangeRecordForClass:newClass. |
449 ]. |
447 ]. |
450 |
448 |
451 " |
449 " |
452 care for class methods ... |
450 care for class methods ... |
453 " |
451 " |
454 changeSet1 := Set new. |
452 changeSet1 := Set new. |
455 |
453 |
456 classVarChange := false. |
454 classVarChange := false. |
457 |
455 |
458 superClassChange ifTrue:[ |
456 superClassChange ifTrue:[ |
459 " |
457 " |
460 superclass changed: |
458 superclass changed: |
461 must recompile all class methods accessing ANY classvar |
459 must recompile all class methods accessing ANY classvar |
462 ( |
460 ( |
463 actually, we could be less strict and handle the case where |
461 actually, we could be less strict and handle the case where |
464 both the old and the new superclass have a common ancestor, |
462 both the old and the new superclass have a common ancestor, |
465 and both have no new classvariables in between. |
463 and both have no new classvariables in between. |
466 This would speedup the case when a class is inserted into |
464 This would speedup the case when a class is inserted into |
467 the inheritance chain. |
465 the inheritance chain. |
468 ) |
466 ) |
469 " |
467 " |
470 |
468 |
471 oldClass allClassVarNames do:[:nm | changeSet1 add:nm]. |
469 oldClass allClassVarNames do:[:nm | changeSet1 add:nm]. |
472 newClass allClassVarNames do:[:nm | changeSet1 add:nm]. |
470 newClass allClassVarNames do:[:nm | changeSet1 add:nm]. |
473 |
471 |
474 " " |
472 " " |
475 Transcript showCr:'recompiling class methods accessing any classvar'. |
473 Transcript showCr:'recompiling class methods accessing any classvar'. |
476 Transcript endEntry. |
474 Transcript endEntry. |
477 " " |
475 " " |
478 self copyInvalidatedMethodsFrom:(oldClass class) for:newMetaclass accessingAny:changeSet1. |
476 self copyInvalidatedMethodsFrom:(oldClass class) |
479 newMetaclass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
477 for:newMetaclass |
|
478 accessingAny:changeSet1 |
|
479 orSuper:true. |
|
480 newMetaclass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
480 ] ifFalse:[ |
481 ] ifFalse:[ |
481 " |
482 " |
482 same superclass, find out which classvars have changed |
483 same superclass, find out which classvars have changed |
483 " |
484 " |
484 classVarChange := oldClassVars ~= newClassVars. |
485 classVarChange := oldClassVars ~= newClassVars. |
485 classVarChange ifTrue:[ |
486 classVarChange ifTrue:[ |
486 oldClassVars do:[:nm | |
487 oldClassVars do:[:nm | |
487 (newClassVars includes:nm) ifFalse:[ |
488 (newClassVars includes:nm) ifFalse:[ |
488 changeSet1 add:nm |
489 changeSet1 add:nm |
489 ] |
490 ] |
490 ]. |
491 ]. |
491 newClassVars do:[:nm | |
492 newClassVars do:[:nm | |
492 (oldClassVars includes:nm) ifFalse:[ |
493 (oldClassVars includes:nm) ifFalse:[ |
493 changeSet1 add:nm |
494 changeSet1 add:nm |
494 ] |
495 ] |
495 ]. |
496 ]. |
496 ]. |
497 ]. |
497 |
498 |
498 classVarChange ifTrue:[ |
499 classVarChange ifTrue:[ |
499 " |
500 " |
500 must recompile some class-methods |
501 must recompile some class-methods |
501 " |
502 " |
502 " " |
503 " " |
503 Transcript showCr:'recompiling class methods accessing ' , changeSet1 printString. |
504 Transcript showCr:'recompiling class methods accessing ' , changeSet1 printString. |
504 Transcript endEntry. |
505 Transcript endEntry. |
505 " " |
506 " " |
506 self copyInvalidatedMethodsFrom:(oldClass class) for:newMetaclass accessingAny:changeSet1. |
507 self copyInvalidatedMethodsFrom:(oldClass class) for:newMetaclass accessingAny:changeSet1. |
507 newMetaclass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
508 newMetaclass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
508 ] ifFalse:[ |
509 ] ifFalse:[ |
509 " |
510 " |
510 class methods still work |
511 class methods still work |
511 " |
512 " |
512 self copyMethodsFrom:(oldClass class) for:newMetaclass |
513 self copyMethodsFrom:(oldClass class) for:newMetaclass |
513 ]. |
514 ]. |
514 ]. |
515 ]. |
515 |
516 |
516 " |
517 " |
517 care for instance methods ... |
518 care for instance methods ... |
518 " |
519 " |
519 changeSet2 := Set new. |
520 changeSet2 := Set new. |
520 |
521 |
521 superClassChange ifTrue:[ |
522 superClassChange ifTrue:[ |
522 "superclass changed, |
523 "superclass changed, |
523 must recompile all methods accessing any class or instvar. |
524 must recompile all methods accessing any class or instvar. |
524 If number of instvars (i.e. the instances instSize) is the same, |
525 If number of instvars (i.e. the instances instSize) is the same, |
525 we can limit the set of recompiled instance methods to those methods, |
526 we can limit the set of recompiled instance methods to those methods, |
526 which refer to an instvar with a different inst-index |
527 which refer to an instvar with a different inst-index |
527 " |
528 " |
528 |
529 |
529 " |
530 " |
530 collect the instvar-indices in the old and new class |
531 collect the instvar-indices in the old and new class |
531 " |
532 " |
532 offset := 0. oldOffsets := Dictionary new. |
533 offset := 0. oldOffsets := Dictionary new. |
533 oldClass allInstVarNames do:[:nm | offset := offset + 1. oldOffsets at:nm put:offset]. |
534 oldClass allInstVarNames do:[:nm | offset := offset + 1. oldOffsets at:nm put:offset]. |
534 offset := 0. newOffsets := Dictionary new. |
535 offset := 0. newOffsets := Dictionary new. |
535 newClass allInstVarNames do:[:nm | offset := offset + 1. newOffsets at:nm put:offset]. |
536 newClass allInstVarNames do:[:nm | offset := offset + 1. newOffsets at:nm put:offset]. |
536 |
537 |
537 " |
538 " |
538 the changeset consists of instance variables, |
539 the changeset consists of instance variables, |
539 whith a different position |
540 whith a different position |
540 " |
541 " |
541 oldOffsets associationsDo:[:a | |
542 oldOffsets associationsDo:[:a | |
542 |k| |
543 |k| |
543 |
544 |
544 k := a key. |
545 k := a key. |
545 (newOffsets includesKey:k) ifFalse:[ |
546 (newOffsets includesKey:k) ifFalse:[ |
546 changeSet2 add:k |
547 changeSet2 add:k |
547 ] ifTrue:[ |
548 ] ifTrue:[ |
548 (a value ~~ (newOffsets at:k)) ifTrue:[ |
549 (a value ~~ (newOffsets at:k)) ifTrue:[ |
549 changeSet2 add:k |
550 changeSet2 add:k |
550 ] |
551 ] |
551 ] |
552 ] |
552 ]. |
553 ]. |
553 newOffsets associationsDo:[:a | |
554 newOffsets associationsDo:[:a | |
554 |k| |
555 |k| |
555 |
556 |
556 k := a key. |
557 k := a key. |
557 (oldOffsets includesKey:k) ifFalse:[ |
558 (oldOffsets includesKey:k) ifFalse:[ |
558 changeSet2 add:k |
559 changeSet2 add:k |
559 ] ifTrue:[ |
560 ] ifTrue:[ |
560 (a value ~~ (oldOffsets at:k)) ifTrue:[ |
561 (a value ~~ (oldOffsets at:k)) ifTrue:[ |
561 changeSet2 add:k |
562 changeSet2 add:k |
562 ] |
563 ] |
563 ] |
564 ] |
564 ]. |
565 ]. |
565 |
566 |
566 " |
567 " |
567 merge in the changed class variables |
568 merge in the changed class variables |
568 " |
569 " |
569 changeSet1 do:[:nm | changeSet2 add:nm]. |
570 changeSet1 do:[:nm | changeSet2 add:nm]. |
570 |
571 |
571 " " |
572 " " |
572 Transcript showCr:'recompiling instance methods accessing ' , changeSet2 printString , ' ...'. |
573 Transcript showCr:'recompiling instance methods accessing ' , changeSet2 printString , ' ...'. |
573 Transcript endEntry. |
574 Transcript endEntry. |
574 " " |
575 " " |
575 self copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:changeSet2. |
576 self copyInvalidatedMethodsFrom:oldClass |
576 newClass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
577 for:newClass |
|
578 accessingAny:changeSet2 |
|
579 orSuper:true. |
|
580 newClass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
577 |
581 |
578 ] ifFalse:[ |
582 ] ifFalse:[ |
579 " |
583 " |
580 same inheritance ... |
584 same inheritance ... |
581 " |
585 " |
582 instVarChange := oldInstVars ~= newInstVars. |
586 instVarChange := oldInstVars ~= newInstVars. |
583 instVarChange ifFalse:[ |
587 instVarChange ifFalse:[ |
584 " |
588 " |
585 same instance variables ... |
589 same instance variables ... |
586 " |
590 " |
587 classVarChange ifTrue:[ |
591 classVarChange ifTrue:[ |
588 "recompile all inst methods accessing changed classvars" |
592 "recompile all inst methods accessing changed classvars" |
589 |
593 |
590 " " |
594 " " |
591 Transcript showCr:'recompiling instance methods accessing ' , changeSet1 printString , ' ...'. |
595 Transcript showCr:'recompiling instance methods accessing ' , changeSet1 printString , ' ...'. |
592 Transcript endEntry. |
596 Transcript endEntry. |
593 " " |
597 " " |
594 self copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:changeSet1. |
598 self copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:changeSet1. |
595 newClass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
599 newClass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
596 ] |
600 ] |
597 ] ifTrue:[ |
601 ] ifTrue:[ |
598 " |
602 " |
599 dont allow built-in classes to be modified |
603 dont allow built-in classes to be modified |
600 " |
604 " |
601 (oldClass notNil and:[oldClass isBuiltInClass and:[instVarChange]]) ifTrue:[ |
605 (oldClass notNil and:[oldClass isBuiltInClass and:[instVarChange]]) ifTrue:[ |
602 self error:'the layout of this class is fixed - you cannot change it'. |
606 self error:'the layout of this class is fixed - you cannot change it'. |
603 ^ oldClass |
607 ^ oldClass |
604 ]. |
608 ]. |
605 |
609 |
606 ((oldInstVars size == 0) |
610 ((oldInstVars size == 0) |
607 or:[newInstVars startsWith:oldInstVars]) ifTrue:[ |
611 or:[newInstVars startsWith:oldInstVars]) ifTrue:[ |
608 " |
612 " |
609 only new inst variable(s) has/have been added - |
613 only new inst variable(s) has/have been added - |
610 old methods still work (the existing inst-indices are still valid) |
614 old methods still work (the existing inst-indices are still valid) |
611 " |
615 " |
612 " " |
616 " " |
613 Transcript showCr:'copying methods ...'. |
617 Transcript showCr:'copying methods ...'. |
614 Transcript endEntry. |
618 Transcript endEntry. |
615 " " |
619 " " |
616 self copyMethodsFrom:oldClass for:newClass. |
620 self copyMethodsFrom:oldClass for:newClass. |
617 |
621 |
618 " |
622 " |
619 but: we have to recompile all methods accessing new instars |
623 but: we have to recompile all methods accessing new instars |
620 (it might have been a classVar/global before ...) |
624 (it might have been a classVar/global before ...) |
621 " |
625 " |
622 addedNames := newInstVars select:[:nm | (oldInstVars includes:nm) not]. |
626 addedNames := newInstVars select:[:nm | (oldInstVars includes:nm) not]. |
623 "merge in class variables" |
627 "merge in class variables" |
624 changeSet1 do:[:nm | addedNames add:nm]. |
628 changeSet1 do:[:nm | addedNames add:nm]. |
625 |
629 |
626 " " |
630 " " |
627 Transcript showCr:'recompiling instance methods accessing ' , addedNames printString , '...'. |
631 Transcript showCr:'recompiling instance methods accessing ' , addedNames printString , '...'. |
628 Transcript endEntry. |
632 Transcript endEntry. |
629 " " |
633 " " |
630 newClass recompileMethodsAccessingAny:addedNames. |
634 newClass recompileMethodsAccessingAny:addedNames. |
631 ] ifFalse:[ |
635 ] ifFalse:[ |
632 " |
636 " |
633 collect the instvar-indices in the old and new class |
637 collect the instvar-indices in the old and new class |
634 " |
638 " |
635 offset := 0. oldOffsets := Dictionary new. |
639 offset := 0. oldOffsets := Dictionary new. |
636 oldInstVars do:[:nm | offset := offset + 1. oldOffsets at:nm put:offset]. |
640 oldInstVars do:[:nm | offset := offset + 1. oldOffsets at:nm put:offset]. |
637 offset := 0. newOffsets := Dictionary new. |
641 offset := 0. newOffsets := Dictionary new. |
638 newInstVars do:[:nm | offset := offset + 1. newOffsets at:nm put:offset]. |
642 newInstVars do:[:nm | offset := offset + 1. newOffsets at:nm put:offset]. |
639 |
643 |
640 " |
644 " |
641 the changeset consists of instance variables, |
645 the changeset consists of instance variables, |
642 whith a different position |
646 whith a different position |
643 " |
647 " |
644 oldOffsets associationsDo:[:a | |
648 oldOffsets associationsDo:[:a | |
645 |k| |
649 |k| |
646 |
650 |
647 k := a key. |
651 k := a key. |
648 (newOffsets includesKey:k) ifFalse:[ |
652 (newOffsets includesKey:k) ifFalse:[ |
649 changeSet2 add:k |
653 changeSet2 add:k |
650 ] ifTrue:[ |
654 ] ifTrue:[ |
651 (a value ~~ (newOffsets at:k)) ifTrue:[ |
655 (a value ~~ (newOffsets at:k)) ifTrue:[ |
652 changeSet2 add:k |
656 changeSet2 add:k |
653 ] |
657 ] |
654 ] |
658 ] |
655 ]. |
659 ]. |
656 newOffsets associationsDo:[:a | |
660 newOffsets associationsDo:[:a | |
657 |k| |
661 |k| |
658 |
662 |
659 k := a key. |
663 k := a key. |
660 (oldOffsets includesKey:k) ifFalse:[ |
664 (oldOffsets includesKey:k) ifFalse:[ |
661 changeSet2 add:k |
665 changeSet2 add:k |
662 ] ifTrue:[ |
666 ] ifTrue:[ |
663 (a value ~~ (oldOffsets at:k)) ifTrue:[ |
667 (a value ~~ (oldOffsets at:k)) ifTrue:[ |
664 changeSet2 add:k |
668 changeSet2 add:k |
665 ] |
669 ] |
666 ] |
670 ] |
667 ]. |
671 ]. |
668 "merge in class variables" |
672 "merge in class variables" |
669 changeSet1 do:[:nm | changeSet2 add:nm]. |
673 changeSet1 do:[:nm | changeSet2 add:nm]. |
670 " " |
674 " " |
671 Transcript showCr:'recompiling instance methods accessing ' , changeSet2 printString , ' ...'. |
675 Transcript showCr:'recompiling instance methods accessing ' , changeSet2 printString , ' ...'. |
672 Transcript endEntry. |
676 Transcript endEntry. |
673 " " |
677 " " |
674 self copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:changeSet2. |
678 self copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:changeSet2. |
675 newClass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
679 newClass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
676 ]. |
680 ]. |
677 ]. |
681 ]. |
678 ]. |
682 ]. |
679 |
683 |
680 " |
684 " |
681 WOW, everything done for this class |
685 WOW, everything done for this class |
682 what about subclasses ? |
686 what about subclasses ? |
863 offset := 0. newOffsets := Dictionary new. |
867 offset := 0. newOffsets := Dictionary new. |
864 newNames do:[:nm | offset := offset + 1. newOffsets at:nm put:offset]. |
868 newNames do:[:nm | offset := offset + 1. newOffsets at:nm put:offset]. |
865 changeSet := Set new. |
869 changeSet := Set new. |
866 |
870 |
867 oldOffsets associationsDo:[:a | |
871 oldOffsets associationsDo:[:a | |
868 |k| |
872 |k| |
869 |
873 |
870 k := a key. |
874 k := a key. |
871 (newOffsets includesKey:k) ifFalse:[ |
875 (newOffsets includesKey:k) ifFalse:[ |
872 changeSet add:k |
876 changeSet add:k |
873 ] ifTrue:[ |
877 ] ifTrue:[ |
874 (a value ~~ (newOffsets at:k)) ifTrue:[ |
878 (a value ~~ (newOffsets at:k)) ifTrue:[ |
875 changeSet add:k |
879 changeSet add:k |
876 ] |
880 ] |
877 ] |
881 ] |
878 ]. |
882 ]. |
879 newOffsets associationsDo:[:a | |
883 newOffsets associationsDo:[:a | |
880 |k| |
884 |k| |
881 |
885 |
882 k := a key. |
886 k := a key. |
883 (oldOffsets includesKey:k) ifFalse:[ |
887 (oldOffsets includesKey:k) ifFalse:[ |
884 changeSet add:k |
888 changeSet add:k |
885 ] ifTrue:[ |
889 ] ifTrue:[ |
886 (a value ~~ (oldOffsets at:k)) ifTrue:[ |
890 (a value ~~ (oldOffsets at:k)) ifTrue:[ |
887 changeSet add:k |
891 changeSet add:k |
888 ] |
892 ] |
889 ] |
893 ] |
890 ]. |
894 ]. |
891 |
895 |
892 ((oldNames size == 0) |
896 ((oldNames size == 0) |
893 or:[newNames startsWith:oldNames]) ifTrue:[ |
897 or:[newNames startsWith:oldNames]) ifTrue:[ |
894 "new variable(s) has/have been added - old methods still work" |
898 "new variable(s) has/have been added - old methods still work" |
895 |
899 |
896 " " |
900 " " |
897 Transcript showCr:'copying methods ...'. |
901 Transcript showCr:'copying methods ...'. |
898 Transcript endEntry. |
902 Transcript endEntry. |
899 " " |
903 " " |
900 self copyMethodsFrom:self for:newMetaclass. |
904 self copyMethodsFrom:self for:newMetaclass. |
901 self copyMethodsFrom:oldClass for:newClass. |
905 self copyMethodsFrom:oldClass for:newClass. |
902 |
906 |
903 "but have to recompile methods accessing stuff now defined |
907 "but have to recompile methods accessing stuff now defined |
904 (it might have been a global before ...)" |
908 (it might have been a global before ...)" |
905 |
909 |
906 addedNames := newNames select:[:nm | (oldNames includes:nm) not]. |
910 addedNames := newNames select:[:nm | (oldNames includes:nm) not]. |
907 " |
911 " |
908 Transcript showCr:'recompiling methods accessing ' , addedNames printString , '...'. |
912 Transcript showCr:'recompiling methods accessing ' , addedNames printString , '...'. |
909 Transcript endEntry. |
913 Transcript endEntry. |
910 " |
914 " |
911 "recompile class-methods" |
915 "recompile class-methods" |
912 newMetaclass recompileMethodsAccessingAny:addedNames. |
916 newMetaclass recompileMethodsAccessingAny:addedNames. |
913 ] ifFalse:[ |
917 ] ifFalse:[ |
914 " |
918 " |
915 Transcript showCr:'recompiling methods accessing ' , changeSet printString , ' ...'. |
919 Transcript showCr:'recompiling methods accessing ' , changeSet printString , ' ...'. |
916 Transcript endEntry. |
920 Transcript endEntry. |
917 " |
921 " |
918 "recompile class-methods" |
922 "recompile class-methods" |
919 self copyInvalidatedMethodsFrom:self for:newMetaclass accessingAny:changeSet. |
923 self copyInvalidatedMethodsFrom:self for:newMetaclass accessingAny:changeSet. |
920 newMetaclass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
924 newMetaclass recompileInvalidatedMethods:(Metaclass compiledMethodAt:#invalidMethod). |
921 |
925 |
922 self copyMethodsFrom:oldClass for:newClass. |
926 self copyMethodsFrom:oldClass for:newClass. |
923 ]. |
927 ]. |
924 |
928 |
925 delta := newNames size - oldNames size. |
929 delta := newNames size - oldNames size. |
926 |
930 |
927 " |
931 " |
928 get list of all subclasses - do before superclass is changed |
932 get list of all subclasses - do before superclass is changed |
929 " |
933 " |
930 allSubclasses := oldClass allSubclasses. |
934 allSubclasses := oldClass allSubclasses. |
931 allSubclasses := allSubclasses asSortedCollection:[:a :b | |
935 allSubclasses := allSubclasses asSortedCollection:[:a :b | |
932 b isSubclassOf:a |
936 b isSubclassOf:a |
933 ]. |
937 ]. |
934 |
938 |
935 oldToNew := IdentityDictionary new. |
939 oldToNew := IdentityDictionary new. |
936 |
940 |
937 "create a new class tree, based on new version" |
941 "create a new class tree, based on new version" |
938 |
942 |
939 allSubclasses do:[:aSubclass | |
943 allSubclasses do:[:aSubclass | |
940 oldSuper := aSubclass superclass. |
944 oldSuper := aSubclass superclass. |
941 oldSubMeta := aSubclass class. |
945 oldSubMeta := aSubclass class. |
942 |
946 |
943 newSubMeta := Metaclass new. |
947 newSubMeta := Metaclass new. |
944 oldSuper == oldClass ifTrue:[ |
948 oldSuper == oldClass ifTrue:[ |
945 newSubMeta setSuperclass:newMetaclass. |
949 newSubMeta setSuperclass:newMetaclass. |
946 ] ifFalse:[ |
950 ] ifFalse:[ |
947 newSubMeta setSuperclass:(oldToNew at:oldSuper) class. |
951 newSubMeta setSuperclass:(oldToNew at:oldSuper) class. |
948 ]. |
952 ]. |
949 newSubMeta instSize:(oldSubMeta instSize + delta). |
953 newSubMeta instSize:(oldSubMeta instSize + delta). |
950 newSubMeta flags:(oldSubMeta flags). |
954 newSubMeta flags:(oldSubMeta flags). |
951 newSubMeta setName:(oldSubMeta name). |
955 newSubMeta setName:(oldSubMeta name). |
952 newSubMeta classVariableString:(oldSubMeta classVariableString). |
956 newSubMeta classVariableString:(oldSubMeta classVariableString). |
953 newSubMeta setComment:(oldSubMeta comment). |
957 newSubMeta setComment:(oldSubMeta comment). |
954 newSubMeta category:(oldSubMeta category). |
958 newSubMeta category:(oldSubMeta category). |
955 |
959 |
956 newSub := newSubMeta new. |
960 newSub := newSubMeta new. |
957 oldSuper == oldClass ifTrue:[ |
961 oldSuper == oldClass ifTrue:[ |
958 newSub setSuperclass:newClass. |
962 newSub setSuperclass:newClass. |
959 ] ifFalse:[ |
963 ] ifFalse:[ |
960 newSub setSuperclass:(oldToNew at:oldSuper). |
964 newSub setSuperclass:(oldToNew at:oldSuper). |
961 ]. |
965 ]. |
962 newSub setSelectorArray:(aSubclass selectorArray). |
966 newSub setSelectorArray:(aSubclass selectorArray). |
963 newSub setMethodArray:(aSubclass methodArray). |
967 newSub setMethodArray:(aSubclass methodArray). |
964 newSub setName:(aSubclass name). |
968 newSub setName:(aSubclass name). |
965 newSub classVariableString:(aSubclass classVariableString). |
969 newSub classVariableString:(aSubclass classVariableString). |
966 newSub setComment:(aSubclass comment). |
970 newSub setComment:(aSubclass comment). |
967 newSub category:(aSubclass category). |
971 newSub category:(aSubclass category). |
968 |
972 |
969 oldToNew at:aSubclass put:newSub. |
973 oldToNew at:aSubclass put:newSub. |
970 |
974 |
971 " |
975 " |
972 aSubclass setName:(aSubclass name , '-old'). |
976 aSubclass setName:(aSubclass name , '-old'). |
973 aSubclass category:'obsolete classes' |
977 aSubclass category:'obsolete classes' |
974 " |
978 " |
975 aSubclass category:'obsolete'. |
979 aSubclass category:'obsolete'. |
976 aSubclass class category:'obsolete'. |
980 aSubclass class category:'obsolete'. |
977 ]. |
981 ]. |
978 |
982 |
979 "recompile what needs to be" |
983 "recompile what needs to be" |
980 |
984 |
981 delta == 0 ifTrue:[ |
985 delta == 0 ifTrue:[ |
982 "only have to recompile class methods accessing |
986 "only have to recompile class methods accessing |
983 class instvars from changeset |
987 class instvars from changeset |
984 " |
988 " |
985 |
989 |
986 allSubclasses do:[:aClass | |
990 allSubclasses do:[:aClass | |
987 aClass class recompileMethodsAccessingAny:changeSet. |
991 aClass class recompileMethodsAccessingAny:changeSet. |
988 ] |
992 ] |
989 ] ifFalse:[ |
993 ] ifFalse:[ |
990 " |
994 " |
991 have to recompile all class methods accessing class instvars |
995 have to recompile all class methods accessing class instvars |
992 " |
996 " |
993 |
997 |
994 allSubclasses do:[:aClass | |
998 allSubclasses do:[:aClass | |
995 |classInstVars| |
999 |classInstVars| |
996 |
1000 |
997 classInstVars := aClass class allInstVarNames. |
1001 classInstVars := aClass class allInstVarNames. |
998 aClass class recompileMethodsAccessingAny:classInstVars. |
1002 aClass class recompileMethodsAccessingAny:classInstVars. |
999 ] |
1003 ] |
1000 ]. |
1004 ]. |
1001 |
1005 |
1002 self addChangeRecordForClassInstvars:newClass. |
1006 self addChangeRecordForClassInstvars:newClass. |
1003 |
1007 |
1004 "install all new classes" |
1008 "install all new classes" |
1005 |
1009 |
1006 Smalltalk at:(oldClass name asSymbol) put:newClass. |
1010 Smalltalk at:(oldClass name asSymbol) put:newClass. |
1007 ObjectMemory flushCachesFor:oldClass. |
1011 ObjectMemory flushCachesFor:oldClass. |
1008 allSubclasses do:[:aClass | |
1012 allSubclasses do:[:aClass | |
1009 Smalltalk at:(oldToNew at:aClass) name asSymbol put:(oldToNew at:aClass). |
1013 Smalltalk at:(oldToNew at:aClass) name asSymbol put:(oldToNew at:aClass). |
1010 ObjectMemory flushCachesFor:aClass. |
1014 ObjectMemory flushCachesFor:aClass. |
1011 ]. |
1015 ]. |
1012 |
1016 |
1013 "tell dependents ..." |
1017 "tell dependents ..." |
1014 |
1018 |
1015 oldClass changed. |
1019 oldClass changed. |
1037 |
1041 |
1038 self error:'invalid method - this method failed to compile when the class was changed' |
1042 self error:'invalid method - this method failed to compile when the class was changed' |
1039 ! |
1043 ! |
1040 |
1044 |
1041 copyMethodsFrom:oldClass for:newClass |
1045 copyMethodsFrom:oldClass for:newClass |
1042 "when a class has changed, but metaclass is unaffected (i.e. classVars |
1046 "copy all methods from oldClass to newClass. |
1043 have not changed) there is no need to recompile them" |
1047 This is used for class-methods when a class has changed, but metaclass is |
|
1048 unaffected (i.e. classVars/inheritance have not changed) so there is no need |
|
1049 to recompile the class methods." |
1044 |
1050 |
1045 newClass selectors:(oldClass selectorArray copy) |
1051 newClass selectors:(oldClass selectorArray copy) |
1046 methods:(oldClass methodArray copy) |
1052 methods:(oldClass methodArray copy) |
1047 ! |
1053 ! |
1048 |
1054 |
1049 copyInvalidatedMethodsFrom:oldClass for:newClass |
1055 copyInvalidatedMethodsFrom:oldClass for:newClass |
1050 "when a class has been changed, copy all old methods into the new class |
1056 "copy all methods from oldClass to newClass and change their code |
1051 - changing code to a trap method giving an error message; |
1057 to a trap method reporting an error. |
1052 this allows us to keep the source while trapping uncompilable (due to |
1058 This is used when a class has been changed its layout or inheritance, |
1053 now undefined instvars) methods" |
1059 for all methods; before recompilation is attempted. |
|
1060 This allows us to keep the source while trapping uncompilable (due to |
|
1061 now undefined instvars) methods. Compilation of these methods will show |
|
1062 an error on the transcript and lead to the debugger once called." |
1054 |
1063 |
1055 |trap trapCode trapByteCode newMethod oldMethodArray newMethodArray| |
1064 |trap trapCode trapByteCode newMethod oldMethodArray newMethodArray| |
1056 |
1065 |
1057 trap := Metaclass compiledMethodAt:#invalidMethod. |
1066 trap := Metaclass compiledMethodAt:#invalidMethod. |
1058 trapCode := trap code. |
1067 trapCode := trap code. |
1059 trapByteCode := trap byteCode. |
1068 trapByteCode := trap byteCode. |
1060 |
1069 |
1061 oldMethodArray := oldClass methodArray. |
1070 oldMethodArray := oldClass methodArray. |
1062 newMethodArray := Array new:(oldMethodArray size). |
1071 newMethodArray := Array new:(oldMethodArray size). |
1063 newClass selectors:(oldClass selectorArray copy) |
1072 newClass selectors:(oldClass selectorArray copy) |
1064 methods:newMethodArray. |
1073 methods:newMethodArray. |
1065 1 to:oldMethodArray size do:[:i | |
1074 1 to:oldMethodArray size do:[:i | |
1066 newMethod := (oldMethodArray at:i) copy. |
1075 newMethod := (oldMethodArray at:i) copy. |
1067 newMethod code:trapCode. |
1076 newMethod code:trapCode. |
1068 newMethod literals:nil. |
1077 newMethod literals:nil. |
1069 newMethod byteCode:trapByteCode. |
1078 newMethod byteCode:trapByteCode. |
1070 newMethodArray at:i put:newMethod |
1079 newMethodArray at:i put:newMethod |
1071 ] |
1080 ] |
1072 ! |
1081 ! |
1073 |
1082 |
1074 copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:setOfNames |
1083 copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:setOfNames |
1075 "copy all methods from oldClass to newClass. Those methods accessing |
1084 "copy all methods from oldClass to newClass. Those methods accessing |
1076 a variable in setOfNames will be copied as invalid method, leading to |
1085 a variable in setOfNames will be copied as invalid method, leading to |
1077 a trap when its executed." |
1086 a trap when its executed. This is used when a class has changed its |
|
1087 layout for all methods which are affected by the change." |
|
1088 |
|
1089 self copyInvalidatedMethodsFrom:oldClass |
|
1090 for:newClass |
|
1091 accessingAny:setOfNames |
|
1092 orSuper:false |
|
1093 ! |
|
1094 |
|
1095 copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:setOfNames orSuper:superBoolean |
|
1096 "copy all methods from oldClass to newClass. |
|
1097 Those methods accessing a variable in setOfNames will be copied as invalid method, |
|
1098 leading to a trap when its executed. If superBoolean is true, this is also done |
|
1099 for methods accessing super. This is used when a class has changed its |
|
1100 layout for all methods which are affected by the change." |
1078 |
1101 |
1079 |trap trapCode trapByteCode p oldMethod newMethod oldMethodArray newMethodArray| |
1102 |trap trapCode trapByteCode p oldMethod newMethod oldMethodArray newMethodArray| |
1080 |
1103 |
1081 trap := Metaclass compiledMethodAt:#invalidMethod. |
1104 trap := Metaclass compiledMethodAt:#invalidMethod. |
1082 trapCode := trap code. |
1105 trapCode := trap code. |
1083 trapByteCode := trap byteCode. |
1106 trapByteCode := trap byteCode. |
1084 |
1107 |
1085 oldMethodArray := oldClass methodArray. |
1108 oldMethodArray := oldClass methodArray. |
1086 newMethodArray := Array new:(oldMethodArray size). |
1109 newMethodArray := Array new:(oldMethodArray size). |
1087 newClass selectors:(oldClass selectorArray copy) |
1110 newClass selectors:(oldClass selectorArray copy) |
1088 methods:newMethodArray. |
1111 methods:newMethodArray. |
1089 1 to:oldMethodArray size do:[:i | |
1112 1 to:oldMethodArray size do:[:i | |
1090 oldMethod := oldMethodArray at:i. |
1113 oldMethod := oldMethodArray at:i. |
1091 p := Parser parseMethod:(oldMethod source) in:newClass. |
1114 p := Parser parseMethod:(oldMethod source) in:newClass. |
1092 (p isNil or:[p usedVars notNil and:[p usedVars includesAny:setOfNames]]) ifTrue:[ |
1115 (p isNil |
1093 newMethod := oldMethod copy. |
1116 or:[(p usedVars notNil and:[p usedVars includesAny:setOfNames]) |
1094 newMethod code:trapCode. |
1117 or:[superBoolean and:[p usesSuper]]]) ifTrue:[ |
1095 newMethod literals:nil. |
1118 newMethod := oldMethod copy. |
1096 newMethod byteCode:trapByteCode |
1119 newMethod code:trapCode. |
1097 ] ifFalse:[ |
1120 newMethod literals:nil. |
1098 newMethod := oldMethod. |
1121 newMethod byteCode:trapByteCode |
1099 ]. |
1122 ] ifFalse:[ |
1100 newMethodArray at:i put:newMethod |
1123 newMethod := oldMethod. |
|
1124 ]. |
|
1125 newMethodArray at:i put:newMethod |
1101 ] |
1126 ] |
1102 ! |
1127 ! |
1103 |
1128 |
1104 anyInvalidatedMethodsIn:aClass |
1129 anyInvalidatedMethodsIn:aClass |
1105 "return true, if aClass has any invalidated methods in it" |
1130 "return true, if aClass has any invalidated methods in it" |