Metaclass.st
changeset 159 514c749165c3
parent 93 e31220cb391f
child 175 82ba8d2e3569
equal deleted inserted replaced
158:be947d4e7fb2 159:514c749165c3
     1 "
     1 "
     2  COPYRIGHT (c) 1988 by Claus Gittinger
     2  COPYRIGHT (c) 1988 by Claus Gittinger
     3               All Rights Reserved
     3 	      All Rights Reserved
     4 
     4 
     5  This software is furnished under a license and may be used
     5  This software is furnished under a license and may be used
     6  only in accordance with the terms of that license and with the
     6  only in accordance with the terms of that license and with the
     7  inclusion of the above copyright notice.   This software may not
     7  inclusion of the above copyright notice.   This software may not
     8  be provided or otherwise made available to, or used by, any
     8  be provided or otherwise made available to, or used by, any
    17        category:'Kernel-Classes'
    17        category:'Kernel-Classes'
    18 !
    18 !
    19 
    19 
    20 Metaclass comment:'
    20 Metaclass comment:'
    21 COPYRIGHT (c) 1988 by Claus Gittinger
    21 COPYRIGHT (c) 1988 by Claus Gittinger
    22               All Rights Reserved
    22 	      All Rights Reserved
    23 
    23 
    24 $Header: /cvs/stx/stx/libbasic/Metaclass.st,v 1.14 1994-08-05 00:58:57 claus Exp $
    24 $Header: /cvs/stx/stx/libbasic/Metaclass.st,v 1.15 1994-10-10 00:26:39 claus Exp $
    25 '!
    25 '!
    26 
    26 
    27 !Metaclass class methodsFor:'documentation'!
    27 !Metaclass class methodsFor:'documentation'!
    28 
    28 
    29 copyright
    29 copyright
    30 "
    30 "
    31  COPYRIGHT (c) 1988 by Claus Gittinger
    31  COPYRIGHT (c) 1988 by Claus Gittinger
    32               All Rights Reserved
    32 	      All Rights Reserved
    33 
    33 
    34  This software is furnished under a license and may be used
    34  This software is furnished under a license and may be used
    35  only in accordance with the terms of that license and with the
    35  only in accordance with the terms of that license and with the
    36  inclusion of the above copyright notice.   This software may not
    36  inclusion of the above copyright notice.   This software may not
    37  be provided or otherwise made available to, or used by, any
    37  be provided or otherwise made available to, or used by, any
    40 "
    40 "
    41 !
    41 !
    42 
    42 
    43 version
    43 version
    44 "
    44 "
    45 $Header: /cvs/stx/stx/libbasic/Metaclass.st,v 1.14 1994-08-05 00:58:57 claus Exp $
    45 $Header: /cvs/stx/stx/libbasic/Metaclass.st,v 1.15 1994-10-10 00:26:39 claus Exp $
    46 "
    46 "
    47 !
    47 !
    48 
    48 
    49 documentation
    49 documentation
    50 "
    50 "
    55 ! !
    55 ! !
    56 
    56 
    57 !Metaclass methodsFor:'creating classes'!
    57 !Metaclass methodsFor:'creating classes'!
    58 
    58 
    59 name:newName inEnvironment:aSystemDictionary
    59 name:newName inEnvironment:aSystemDictionary
    60              subclassOf:aClass
    60 	     subclassOf:aClass
    61              instanceVariableNames:stringOfInstVarNames
    61 	     instanceVariableNames:stringOfInstVarNames
    62              variable:variableBoolean
    62 	     variable:variableBoolean
    63              words:wordsBoolean
    63 	     words:wordsBoolean
    64              pointers:pointersBoolean
    64 	     pointers:pointersBoolean
    65              classVariableNames:stringOfClassVarNames
    65 	     classVariableNames:stringOfClassVarNames
    66              poolDictionaries:stringOfPoolNames
    66 	     poolDictionaries:stringOfPoolNames
    67              category:categoryString
    67 	     category:categoryString
    68              comment:commentString
    68 	     comment:commentString
    69              changed:changed
    69 	     changed:changed
    70 
    70 
    71     "this is the main workhorse for installing new classes - special care
    71     "this is the main workhorse for installing new classes - special care
    72      has to be taken, when changing an existing classes definition. In this
    72      has to be taken, when changing an existing classes definition. In this
    73      case, some or all of the methods and subclasses methods have to be
    73      case, some or all of the methods and subclasses methods have to be
    74      recompiled.
    74      recompiled.
    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 ?
   695      this forces recompilation (recursively) if needed
   699      this forces recompilation (recursively) if needed
   696      (dont update change file for the subclass changes)
   700      (dont update change file for the subclass changes)
   697     "
   701     "
   698     upd := Class updateChanges:false.
   702     upd := Class updateChanges:false.
   699     [
   703     [
   700         oldClass subclassesDo:[:aClass |
   704 	oldClass subclassesDo:[:aClass |
   701 " "
   705 " "
   702             Transcript showCr:'changing superclass of:' , aClass name.
   706 	    Transcript showCr:'changing superclass of:' , aClass name.
   703             Transcript endEntry.
   707 	    Transcript endEntry.
   704 " "
   708 " "
   705             aClass superclass:newClass
   709 	    aClass superclass:newClass
   706         ]
   710 	]
   707     ] valueNowOrOnUnwindDo:[
   711     ] valueNowOrOnUnwindDo:[
   708         Class updateChanges:upd.
   712 	Class updateChanges:upd.
   709     ].
   713     ].
   710 
   714 
   711     "
   715     "
   712      change category in oldClass - so we see immediately what it is ...
   716      change category in oldClass - so we see immediately what it is ...
   713     "
   717     "
   718      and make the new class globally known
   722      and make the new class globally known
   719     "
   723     "
   720     aSystemDictionary at:classSymbol put:newClass.
   724     aSystemDictionary at:classSymbol put:newClass.
   721 
   725 
   722     oldClass category ~= categoryString ifTrue:[
   726     oldClass category ~= categoryString ifTrue:[
   723         "notify change of organization"
   727 	"notify change of organization"
   724         aSystemDictionary changed
   728 	aSystemDictionary changed
   725     ].
   729     ].
   726 
   730 
   727     "
   731     "
   728      Not becoming the old class creates some update problems;
   732      Not becoming the old class creates some update problems;
   729      the browsers must check carefully - a simple identity compare is
   733      the browsers must check carefully - a simple identity compare is
   730      not enought ...
   734      not enough ...
   731      QUESTION: is this a good idea ?
   735      QUESTION: is this a good idea ?
   732     "
   736     "
   733 
   737 
   734     newClass dependents:(oldClass dependents).
   738     newClass dependents:(oldClass dependents).
   735     newClass changed.
   739     newClass changed.
   736 
   740 
   737     "just to make certain ... - telle dependents of oldClass, that something changed
   741     "just to make certain ... - tell dependents of oldClass, that something changed
   738      (systemBrowsers will react on this, and update their views)"
   742      (systemBrowsers will react on this, and update their views)"
   739     oldClass changed:newClass.
   743     oldClass changed:#definition with:newClass.
   740 
   744 
   741     ObjectMemory flushCaches.
   745     ObjectMemory flushCaches.
   742 
   746 
   743     ^ newClass
   747     ^ newClass
   744 !
   748 !
   748 
   752 
   749     |newClass|
   753     |newClass|
   750 
   754 
   751     newClass := self basicNew.
   755     newClass := self basicNew.
   752     newClass setSuperclass:(Object class)
   756     newClass setSuperclass:(Object class)
   753                  selectors:(Array new:0)
   757 		 selectors:(Array new:0)
   754                    methods:(Array new:0)
   758 		   methods:(Array new:0)
   755                   instSize:0
   759 		  instSize:0
   756                      flags:(Behavior flagNotIndexed).
   760 		     flags:(Behavior flagNotIndexed).
   757     newClass setComment:(self comment) category:(self category).
   761     newClass setComment:(self comment) category:(self category).
   758     ^ newClass
   762     ^ newClass
   759 ! !
   763 ! !
   760 
   764 
   761 !Metaclass methodsFor:'class instance variables'!
   765 !Metaclass methodsFor:'class instance variables'!
   776     "
   780     "
   777 
   781 
   778     oldVars := self instanceVariableString.
   782     oldVars := self instanceVariableString.
   779     aString = oldVars ifTrue:[
   783     aString = oldVars ifTrue:[
   780 "
   784 "
   781         Transcript showCr:'no change (', oldVars , ') -> (', aString , ')'.
   785 	Transcript showCr:'no change (', oldVars , ') -> (', aString , ')'.
   782 "
   786 "
   783         ^ self
   787 	^ self
   784     ].
   788     ].
   785 
   789 
   786     oldNames := oldVars asCollectionOfWords.
   790     oldNames := oldVars asCollectionOfWords.
   787     newNames := aString asCollectionOfWords.
   791     newNames := aString asCollectionOfWords.
   788 
   792 
   789     oldNames = newNames ifTrue:[
   793     oldNames = newNames ifTrue:[
   790 "
   794 "
   791         Transcript showCr:'no real change'.
   795 	Transcript showCr:'no real change'.
   792 "
   796 "
   793         "no real change (just formatting)"
   797 	"no real change (just formatting)"
   794         self instanceVariableString:aString.
   798 	self instanceVariableString:aString.
   795         ^ self
   799 	^ self
   796     ]. 
   800     ]. 
   797 
   801 
   798     "
   802     "
   799      let user confirm, if any name is no good (and was good before)
   803      let user confirm, if any name is no good (and was good before)
   800     "
   804     "
   801     (oldNames inject:true
   805     (oldNames inject:true
   802                 into:[:okSoFar :word |
   806 		into:[:okSoFar :word |
   803                          okSoFar and:[word first isUppercase]
   807 			 okSoFar and:[word first isUppercase]
   804                      ])
   808 		     ])
   805     ifTrue:[
   809     ifTrue:[
   806         "was ok before"
   810 	"was ok before"
   807         (newNames inject:true
   811 	(newNames inject:true
   808                     into:[:okSoFar :word |
   812 		    into:[:okSoFar :word |
   809                              okSoFar and:[word first isUppercase]
   813 			     okSoFar and:[word first isUppercase]
   810                          ])
   814 			 ])
   811         ifFalse:[
   815 	ifFalse:[
   812             (self confirm:'class instance variable names should start with an uppercase letter
   816 	    (self confirm:'class instance variable names should start with an uppercase letter
   813 (by convention only)
   817 (by convention only)
   814 
   818 
   815 install anyway ?' withCRs)
   819 install anyway ?' withCRs)
   816             ifFalse:[
   820 	    ifFalse:[
   817                 ^ nil
   821 		^ nil
   818             ]
   822 	    ]
   819         ]
   823 	]
   820     ].
   824     ].
   821 
   825 
   822     nClassInstVars := newNames size.
   826     nClassInstVars := newNames size.
   823 
   827 
   824 "
   828 "
   828     "create the new metaclass"
   832     "create the new metaclass"
   829     newMetaclass := Metaclass new.
   833     newMetaclass := Metaclass new.
   830     newMetaclass setSuperclass:superclass.
   834     newMetaclass setSuperclass:superclass.
   831     newMetaclass instSize:(superclass instSize + nClassInstVars).
   835     newMetaclass instSize:(superclass instSize + nClassInstVars).
   832     (nClassInstVars ~~ 0) ifTrue:[
   836     (nClassInstVars ~~ 0) ifTrue:[
   833         newMetaclass instanceVariableString:aString
   837 	newMetaclass instanceVariableString:aString
   834     ].
   838     ].
   835     newMetaclass flags:(Behavior flagNotIndexed).
   839     newMetaclass flags:(Behavior flagNotIndexed).
   836     newMetaclass setName:name.
   840     newMetaclass setName:name.
   837     newMetaclass classVariableString:classvars.
   841     newMetaclass classVariableString:classvars.
   838     newMetaclass category:category.
   842     newMetaclass category:category.
   840 
   844 
   841     "find the class which is my sole instance"
   845     "find the class which is my sole instance"
   842 
   846 
   843     t := Smalltalk allClasses select:[:element | element class == self].
   847     t := Smalltalk allClasses select:[:element | element class == self].
   844     (t size ~~ 1) ifTrue:[
   848     (t size ~~ 1) ifTrue:[
   845         self error:'oops - I should have exactly one instance'.
   849 	self error:'oops - I should have exactly one instance'.
   846         ^ nil
   850 	^ nil
   847     ].
   851     ].
   848     oldClass := t anElement.
   852     oldClass := t anElement.
   849 
   853 
   850     "create a new class"
   854     "create a new class"
   851     newClass := newMetaclass new.
   855     newClass := newMetaclass new.
   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"
  1109     trap := Metaclass compiledMethodAt:#invalidMethod.
  1134     trap := Metaclass compiledMethodAt:#invalidMethod.
  1110     trapCode := trap code.
  1135     trapCode := trap code.
  1111     trapByteCode := trap byteCode.
  1136     trapByteCode := trap byteCode.
  1112 
  1137 
  1113     aClass methodArray do:[:aMethod |
  1138     aClass methodArray do:[:aMethod |
  1114         trapCode notNil ifTrue:[
  1139 	trapCode notNil ifTrue:[
  1115             (aMethod code == trapCode) ifTrue:[^ true]
  1140 	    (aMethod code == trapCode) ifTrue:[^ true]
  1116         ].
  1141 	].
  1117         trapByteCode notNil ifTrue:[
  1142 	trapByteCode notNil ifTrue:[
  1118             (aMethod byteCode == trapByteCode) ifTrue:[^ true]
  1143 	    (aMethod byteCode == trapByteCode) ifTrue:[^ true]
  1119         ]
  1144 	]
  1120     ].
  1145     ].
  1121     ^ false
  1146     ^ false
  1122 ! !
  1147 ! !