Metaclass.st
author claus
Mon, 20 Dec 1993 18:32:29 +0100
changeset 27 d98f9dd437f7
parent 13 62303f84ff5f
child 33 50cf0f6bc0ad
permissions -rw-r--r--
*** empty log message ***
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
     1
"
5
67342904af11 *** empty log message ***
claus
parents: 3
diff changeset
     2
 COPYRIGHT (c) 1988 by Claus Gittinger
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
     3
              All Rights Reserved
a27a279701f8 Initial revision
claus
parents:
diff changeset
     4
a27a279701f8 Initial revision
claus
parents:
diff changeset
     5
 This software is furnished under a license and may be used
a27a279701f8 Initial revision
claus
parents:
diff changeset
     6
 only in accordance with the terms of that license and with the
a27a279701f8 Initial revision
claus
parents:
diff changeset
     7
 inclusion of the above copyright notice.   This software may not
a27a279701f8 Initial revision
claus
parents:
diff changeset
     8
 be provided or otherwise made available to, or used by, any
a27a279701f8 Initial revision
claus
parents:
diff changeset
     9
 other person.  No title to or ownership of the software is
a27a279701f8 Initial revision
claus
parents:
diff changeset
    10
 hereby transferred.
a27a279701f8 Initial revision
claus
parents:
diff changeset
    11
"
a27a279701f8 Initial revision
claus
parents:
diff changeset
    12
a27a279701f8 Initial revision
claus
parents:
diff changeset
    13
Class subclass:#Metaclass
a27a279701f8 Initial revision
claus
parents:
diff changeset
    14
       instanceVariableNames:''
a27a279701f8 Initial revision
claus
parents:
diff changeset
    15
       classVariableNames:''
a27a279701f8 Initial revision
claus
parents:
diff changeset
    16
       poolDictionaries:''
a27a279701f8 Initial revision
claus
parents:
diff changeset
    17
       category:'Kernel-Classes'
a27a279701f8 Initial revision
claus
parents:
diff changeset
    18
!
a27a279701f8 Initial revision
claus
parents:
diff changeset
    19
a27a279701f8 Initial revision
claus
parents:
diff changeset
    20
Metaclass comment:'
a27a279701f8 Initial revision
claus
parents:
diff changeset
    21
5
67342904af11 *** empty log message ***
claus
parents: 3
diff changeset
    22
COPYRIGHT (c) 1988 by Claus Gittinger
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
    23
              All Rights Reserved
a27a279701f8 Initial revision
claus
parents:
diff changeset
    24
a27a279701f8 Initial revision
claus
parents:
diff changeset
    25
every class-class is a subclass of Metaclass
a27a279701f8 Initial revision
claus
parents:
diff changeset
    26
- this adds support for creating new subclasses or changing the definition
a27a279701f8 Initial revision
claus
parents:
diff changeset
    27
of an already existing class.
a27a279701f8 Initial revision
claus
parents:
diff changeset
    28
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    29
$Header: /cvs/stx/stx/libbasic/Metaclass.st,v 1.6 1993-12-11 00:50:35 claus Exp $
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
    30
'!
a27a279701f8 Initial revision
claus
parents:
diff changeset
    31
a27a279701f8 Initial revision
claus
parents:
diff changeset
    32
!Metaclass methodsFor:'creating classes'!
a27a279701f8 Initial revision
claus
parents:
diff changeset
    33
a27a279701f8 Initial revision
claus
parents:
diff changeset
    34
name:newName inEnvironment:aSystemDictionary
a27a279701f8 Initial revision
claus
parents:
diff changeset
    35
             subclassOf:aClass
a27a279701f8 Initial revision
claus
parents:
diff changeset
    36
             instanceVariableNames:stringOfInstVarNames
a27a279701f8 Initial revision
claus
parents:
diff changeset
    37
             variable:variableBoolean
a27a279701f8 Initial revision
claus
parents:
diff changeset
    38
             words:wordsBoolean
a27a279701f8 Initial revision
claus
parents:
diff changeset
    39
             pointers:pointersBoolean
a27a279701f8 Initial revision
claus
parents:
diff changeset
    40
             classVariableNames:stringOfClassVarNames
a27a279701f8 Initial revision
claus
parents:
diff changeset
    41
             poolDictionaries:stringOfPoolNames
a27a279701f8 Initial revision
claus
parents:
diff changeset
    42
             category:categoryString
a27a279701f8 Initial revision
claus
parents:
diff changeset
    43
             comment:commentString
a27a279701f8 Initial revision
claus
parents:
diff changeset
    44
             changed:changed
a27a279701f8 Initial revision
claus
parents:
diff changeset
    45
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    46
    "this is the main workhorse for installing new classes - special care
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    47
     has to be taken, when changing an existing classes definition. In this
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    48
     case, some or all of the methods and subclasses methods have to be
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    49
     recompiled.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    50
     Also, the old class(es) are still kept (but not accessable as a global),
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    51
     to allow existing instances some life. 
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    52
     This might change in the future.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    53
    "
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    54
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
    55
    |newClass newMetaclass nInstVars nameString classSymbol oldClass 
a27a279701f8 Initial revision
claus
parents:
diff changeset
    56
     allSubclasses classVarChange instVarChange superClassChange newComment
10
claus
parents: 5
diff changeset
    57
     changeSet1 changeSet2 offset oldOffsets newOffsets addedNames
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    58
     anyChange oldInstVars newInstVars oldClassVars newClassVars upd|
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    59
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    60
    "this method is too complex and should be splitted into managable pieces ..."
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    61
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    62
    newName = aClass name ifTrue:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    63
        self error:'trying to create circular class definition'.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    64
        ^ nil
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    65
    ].
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
    66
a27a279701f8 Initial revision
claus
parents:
diff changeset
    67
    nInstVars := stringOfInstVarNames countWords.
a27a279701f8 Initial revision
claus
parents:
diff changeset
    68
    nameString := newName asString.
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    69
    classSymbol := newName asSymbol.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
    70
    newComment := commentString.
a27a279701f8 Initial revision
claus
parents:
diff changeset
    71
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    72
    "look, if it already exists as a class"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
    73
    (aSystemDictionary includesKey:classSymbol) ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
    74
        oldClass := aSystemDictionary at:classSymbol.
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    75
        (oldClass isBehavior not or:[oldClass name ~= newName]) ifTrue:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    76
            oldClass := nil.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    77
        ] ifFalse:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    78
            oldClass allSuperclasses do:[:aClass |
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    79
                aClass name = newName ifTrue:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    80
                    self error:'trying to create circular class definition'.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    81
                    ^ nil
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    82
                ]
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    83
            ].
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    84
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    85
            newComment isNil ifTrue:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    86
                newComment := oldClass comment
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
    87
            ]
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
    88
        ]
a27a279701f8 Initial revision
claus
parents:
diff changeset
    89
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
    90
a27a279701f8 Initial revision
claus
parents:
diff changeset
    91
    "create the metaclass first"
a27a279701f8 Initial revision
claus
parents:
diff changeset
    92
    newMetaclass := Metaclass new.
a27a279701f8 Initial revision
claus
parents:
diff changeset
    93
    newMetaclass setSuperclass:(aClass class).
a27a279701f8 Initial revision
claus
parents:
diff changeset
    94
    newMetaclass instSize:(aClass class instSize).
a27a279701f8 Initial revision
claus
parents:
diff changeset
    95
    newMetaclass flags:0.            "not indexed"
a27a279701f8 Initial revision
claus
parents:
diff changeset
    96
    newMetaclass setName:(nameString , 'class').
a27a279701f8 Initial revision
claus
parents:
diff changeset
    97
    newMetaclass classVariableString:'' "stringOfClassVarNames".
a27a279701f8 Initial revision
claus
parents:
diff changeset
    98
    newMetaclass setComment:newComment category:categoryString.
a27a279701f8 Initial revision
claus
parents:
diff changeset
    99
a27a279701f8 Initial revision
claus
parents:
diff changeset
   100
    newClass := newMetaclass new.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   101
    newClass setSuperclass:aClass.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   102
    newClass instSize:(aClass instSize + nInstVars).
a27a279701f8 Initial revision
claus
parents:
diff changeset
   103
a27a279701f8 Initial revision
claus
parents:
diff changeset
   104
    (variableBoolean == true) ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   105
        pointersBoolean ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   106
            newClass flags:4         "pointerarray"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   107
        ] ifFalse:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   108
            wordsBoolean ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   109
                newClass flags:2     "wordarray"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   110
            ] ifFalse:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   111
                newClass flags:1     "bytearray"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   112
            ]
a27a279701f8 Initial revision
claus
parents:
diff changeset
   113
        ]
a27a279701f8 Initial revision
claus
parents:
diff changeset
   114
    ] ifFalse:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   115
        "this is a backward compatible hack"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   116
a27a279701f8 Initial revision
claus
parents:
diff changeset
   117
        (variableBoolean == #float) ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   118
            newClass flags:6         "float array"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   119
        ] ifFalse:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   120
            (variableBoolean == #double) ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   121
                newClass flags:7     "double array"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   122
            ] ifFalse:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   123
                (variableBoolean == #long) ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   124
                    newClass flags:3     "long array"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   125
                ] ifFalse:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   126
                    newClass flags:0   
a27a279701f8 Initial revision
claus
parents:
diff changeset
   127
                ]
a27a279701f8 Initial revision
claus
parents:
diff changeset
   128
            ]
a27a279701f8 Initial revision
claus
parents:
diff changeset
   129
        ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   130
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   131
a27a279701f8 Initial revision
claus
parents:
diff changeset
   132
    newClass setName:nameString.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   133
    (nInstVars ~~ 0) ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   134
        newClass instanceVariableString:stringOfInstVarNames
a27a279701f8 Initial revision
claus
parents:
diff changeset
   135
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   136
    oldClass notNil ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   137
        "setting first will make new class clear obsolete classvars"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   138
        newClass setClassVariableString:(oldClass classVariableString)
a27a279701f8 Initial revision
claus
parents:
diff changeset
   139
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   140
    newClass classVariableString:stringOfClassVarNames.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   141
2
claus
parents: 1
diff changeset
   142
    oldClass isNil ifTrue:[
claus
parents: 1
diff changeset
   143
        self addChangeRecordForClass:newClass.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   144
a27a279701f8 Initial revision
claus
parents:
diff changeset
   145
        commentString notNil ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   146
            newClass comment:commentString
2
claus
parents: 1
diff changeset
   147
        ].
claus
parents: 1
diff changeset
   148
        aSystemDictionary at:classSymbol put:newClass.
claus
parents: 1
diff changeset
   149
        Smalltalk changed.
claus
parents: 1
diff changeset
   150
        ^ newClass
claus
parents: 1
diff changeset
   151
    ].
claus
parents: 1
diff changeset
   152
10
claus
parents: 5
diff changeset
   153
claus
parents: 5
diff changeset
   154
    oldInstVars := oldClass instanceVariableString asCollectionOfWords.
claus
parents: 5
diff changeset
   155
    newInstVars := newClass instanceVariableString asCollectionOfWords.
claus
parents: 5
diff changeset
   156
    oldClassVars := oldClass classVariableString asCollectionOfWords.
claus
parents: 5
diff changeset
   157
    newClassVars := newClass classVariableString asCollectionOfWords.
claus
parents: 5
diff changeset
   158
2
claus
parents: 1
diff changeset
   159
    "if only category/comment has changed, do not recompile .."
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   160
2
claus
parents: 1
diff changeset
   161
    (oldClass superclass == newClass superclass) ifTrue:[
claus
parents: 1
diff changeset
   162
      (oldClass instSize == newClass instSize) ifTrue:[
claus
parents: 1
diff changeset
   163
        (oldClass flags == newClass flags) ifTrue:[
claus
parents: 1
diff changeset
   164
          (oldClass name = newClass name) ifTrue:[
10
claus
parents: 5
diff changeset
   165
            (oldInstVars = newInstVars) ifTrue:[
claus
parents: 5
diff changeset
   166
              (oldClassVars = newClassVars) ifTrue:[
claus
parents: 5
diff changeset
   167
                anyChange := false.
claus
parents: 5
diff changeset
   168
claus
parents: 5
diff changeset
   169
claus
parents: 5
diff changeset
   170
                oldClass instanceVariableString:(newClass instanceVariableString).
claus
parents: 5
diff changeset
   171
                oldClass setClassVariableString:(newClass classVariableString).
claus
parents: 5
diff changeset
   172
2
claus
parents: 1
diff changeset
   173
                (newComment ~= oldClass comment) ifTrue:[
10
claus
parents: 5
diff changeset
   174
                    oldClass comment:newComment.        "already writes change-chunk"
2
claus
parents: 1
diff changeset
   175
                ]. 
claus
parents: 1
diff changeset
   176
                oldClass category ~= categoryString ifTrue:[
claus
parents: 1
diff changeset
   177
                    "notify change of organization"
10
claus
parents: 5
diff changeset
   178
                    oldClass category:categoryString. 
claus
parents: 5
diff changeset
   179
                    self addChangeRecordForClass:newClass.
2
claus
parents: 1
diff changeset
   180
                    Smalltalk changed
claus
parents: 1
diff changeset
   181
                ].
claus
parents: 1
diff changeset
   182
                "notify change of class"
claus
parents: 1
diff changeset
   183
                oldClass changed.
claus
parents: 1
diff changeset
   184
                ^ oldClass
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   185
              ]
a27a279701f8 Initial revision
claus
parents:
diff changeset
   186
            ]
a27a279701f8 Initial revision
claus
parents:
diff changeset
   187
          ]
2
claus
parents: 1
diff changeset
   188
        ]
claus
parents: 1
diff changeset
   189
      ]
claus
parents: 1
diff changeset
   190
    ].
claus
parents: 1
diff changeset
   191
10
claus
parents: 5
diff changeset
   192
    "tell dependents of class ..."
claus
parents: 5
diff changeset
   193
    oldClass changed.
claus
parents: 5
diff changeset
   194
2
claus
parents: 1
diff changeset
   195
    "catch special case, where superclass changed its layout and thus
claus
parents: 1
diff changeset
   196
     forced redefinition of this class - this will not be logged here"
claus
parents: 1
diff changeset
   197
claus
parents: 1
diff changeset
   198
    (newComment ~= oldClass comment) ifTrue:[
claus
parents: 1
diff changeset
   199
        newClass comment:newComment
claus
parents: 1
diff changeset
   200
    ].
claus
parents: 1
diff changeset
   201
claus
parents: 1
diff changeset
   202
    superClassChange := oldClass superclass ~~ newClass superclass.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   203
3
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   204
    "dont allow built-in classes to be modified"
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   205
    (oldClass notNil and:[oldClass isBuiltInClass and:[superClassChange]]) ifTrue:[
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   206
        self error:'the inheritance of this class is fixed - you cannot change it'.
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   207
        ^ oldClass
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   208
    ].
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   209
2
claus
parents: 1
diff changeset
   210
    (superClassChange 
claus
parents: 1
diff changeset
   211
     and:[
claus
parents: 1
diff changeset
   212
        (oldClass superclass isNil or:[oldClass superclass name = newClass superclass name])
claus
parents: 1
diff changeset
   213
        and:[
10
claus
parents: 5
diff changeset
   214
            (oldClassVars = newClassVars) 
2
claus
parents: 1
diff changeset
   215
            and:[
10
claus
parents: 5
diff changeset
   216
                (oldInstVars = newInstVars)
2
claus
parents: 1
diff changeset
   217
                and:[newComment = oldClass comment]]]]) ifFalse:[
claus
parents: 1
diff changeset
   218
            self addChangeRecordForClass:newClass.
claus
parents: 1
diff changeset
   219
    ].
claus
parents: 1
diff changeset
   220
claus
parents: 1
diff changeset
   221
    changeSet1 := Set new.
claus
parents: 1
diff changeset
   222
    changeSet2 := Set new.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   223
2
claus
parents: 1
diff changeset
   224
    classVarChange := false.
claus
parents: 1
diff changeset
   225
claus
parents: 1
diff changeset
   226
    superClassChange ifTrue:[
claus
parents: 1
diff changeset
   227
        "superclass changed,
claus
parents: 1
diff changeset
   228
         must recompile all class methods accessing any classvar"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   229
2
claus
parents: 1
diff changeset
   230
        oldClass allClassVarNames do:[:nm | changeSet1 add:nm].
claus
parents: 1
diff changeset
   231
        newClass allClassVarNames do:[:nm | changeSet1 add:nm].
claus
parents: 1
diff changeset
   232
claus
parents: 1
diff changeset
   233
" "
claus
parents: 1
diff changeset
   234
        Transcript showCr:'recompiling class methods accessing any classvar'.
claus
parents: 1
diff changeset
   235
" "
claus
parents: 1
diff changeset
   236
        self copyInvalidatedMethodsFrom:(oldClass class) for:newMetaclass accessingAny:changeSet1.
claus
parents: 1
diff changeset
   237
        newMetaclass recompileInvalidatedMethods.
claus
parents: 1
diff changeset
   238
    ] ifFalse:[
claus
parents: 1
diff changeset
   239
        "same superclass, find out which classvars have changed"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   240
10
claus
parents: 5
diff changeset
   241
        classVarChange := oldClassVars ~= newClassVars.
2
claus
parents: 1
diff changeset
   242
        classVarChange ifTrue:[
10
claus
parents: 5
diff changeset
   243
            oldClassVars do:[:nm |
claus
parents: 5
diff changeset
   244
                (newClassVars includes:nm) ifFalse:[
claus
parents: 5
diff changeset
   245
                    changeSet1 add:nm
claus
parents: 5
diff changeset
   246
                ]
claus
parents: 5
diff changeset
   247
            ].
claus
parents: 5
diff changeset
   248
            newClassVars do:[:nm |
claus
parents: 5
diff changeset
   249
                (oldClassVars includes:nm) ifFalse:[
claus
parents: 5
diff changeset
   250
                    changeSet1 add:nm
claus
parents: 5
diff changeset
   251
                ]
2
claus
parents: 1
diff changeset
   252
            ].
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   253
        ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   254
2
claus
parents: 1
diff changeset
   255
" "
claus
parents: 1
diff changeset
   256
        Transcript showCr:'recompiling class methods accessing ' , changeSet1 printString.
claus
parents: 1
diff changeset
   257
" "
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   258
        classVarChange ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   259
            "must recompile class-methods"
2
claus
parents: 1
diff changeset
   260
            self copyInvalidatedMethodsFrom:(oldClass class) for:newMetaclass accessingAny:changeSet1.
claus
parents: 1
diff changeset
   261
            newMetaclass recompileInvalidatedMethods.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   262
        ] ifFalse:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   263
            "class methods still work"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   264
            self copyMethodsFrom:(oldClass class) for:newMetaclass
a27a279701f8 Initial revision
claus
parents:
diff changeset
   265
        ].
2
claus
parents: 1
diff changeset
   266
    ].
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   267
2
claus
parents: 1
diff changeset
   268
    superClassChange ifTrue:[
claus
parents: 1
diff changeset
   269
        "superclass changed,
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   270
         must recompile all class methods accessing any class or instvar"
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   271
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   272
	"no, if number of instvars is the same, only the changed ones ..."
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   273
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   274
        "find set of changed instvars"
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   275
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   276
        offset := 0. oldOffsets := Dictionary new.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   277
	oldClass allInstVarNames do:[:nm | offset := offset + 1. oldOffsets at:nm put:offset].
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   278
        offset := 0. newOffsets := Dictionary new.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   279
        newClass allInstVarNames do:[:nm | offset := offset + 1. newOffsets at:nm put:offset].
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   280
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   281
        oldOffsets associationsDo:[:a |
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   282
            |k|
2
claus
parents: 1
diff changeset
   283
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   284
            k := a key.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   285
            (newOffsets includesKey:k) ifFalse:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   286
                changeSet2 add:k
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   287
            ] ifTrue:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   288
                (a value ~~ (newOffsets at:k)) ifTrue:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   289
                    changeSet2 add:k
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   290
                ]
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   291
            ]
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   292
        ].
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   293
        newOffsets associationsDo:[:a |
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   294
            |k|
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   295
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   296
            k := a key.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   297
            (oldOffsets includesKey:k) ifFalse:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   298
                changeSet2 add:k
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   299
            ] ifTrue:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   300
                (a value ~~ (oldOffsets at:k)) ifTrue:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   301
                    changeSet2 add:k
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   302
                ]
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   303
            ]
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   304
        ].
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   305
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   306
        changeSet1 do:[:nm | changeSet2 add:nm].
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   307
" "
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   308
        Transcript showCr:'recompiling instance methods accessing ' , changeSet2 printString , '
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   309
 ...'.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   310
" "
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   311
        self copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:changeSet2.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   312
        newClass recompileInvalidatedMethods.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   313
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   314
false ifTrue:[
2
claus
parents: 1
diff changeset
   315
        oldClass allClassVarNames do:[:nm | changeSet1 add:nm].
claus
parents: 1
diff changeset
   316
        newClass allClassVarNames do:[:nm | changeSet1 add:nm].
claus
parents: 1
diff changeset
   317
        oldClass allInstVarNames do:[:nm | changeSet1 add:nm].
claus
parents: 1
diff changeset
   318
        newClass allInstVarNames do:[:nm | changeSet1 add:nm].
claus
parents: 1
diff changeset
   319
claus
parents: 1
diff changeset
   320
" "
claus
parents: 1
diff changeset
   321
        Transcript showCr:'recompiling instance methods accessing any class or instvar' .
claus
parents: 1
diff changeset
   322
" "
claus
parents: 1
diff changeset
   323
        self copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:changeSet1.
claus
parents: 1
diff changeset
   324
        newClass recompileInvalidatedMethods.
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   325
]
2
claus
parents: 1
diff changeset
   326
    ] ifFalse:[
10
claus
parents: 5
diff changeset
   327
        instVarChange := oldInstVars ~= newInstVars.
2
claus
parents: 1
diff changeset
   328
        instVarChange ifFalse:[
claus
parents: 1
diff changeset
   329
            classVarChange ifTrue:[
claus
parents: 1
diff changeset
   330
                "recompile all inst methods accessing classvars"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   331
2
claus
parents: 1
diff changeset
   332
" "
claus
parents: 1
diff changeset
   333
                Transcript showCr:'recompiling instance methods accessing ' , changeSet1 printString , ' ...'.
claus
parents: 1
diff changeset
   334
" "
claus
parents: 1
diff changeset
   335
                self copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:changeSet1.
claus
parents: 1
diff changeset
   336
                newClass recompileInvalidatedMethods.
claus
parents: 1
diff changeset
   337
            ]
claus
parents: 1
diff changeset
   338
        ] ifTrue:[
10
claus
parents: 5
diff changeset
   339
            instVarChange := (oldInstVars ~= newInstVars).
3
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   340
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   341
            "dont allow built-in classes to be modified"
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   342
            (oldClass notNil and:[oldClass isBuiltInClass and:[instVarChange]]) ifTrue:[
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   343
                self error:'the layout of this class is fixed - you cannot change it'.
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   344
                ^ oldClass
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   345
            ].
24d81bf47225 *** empty log message ***
claus
parents: 2
diff changeset
   346
2
claus
parents: 1
diff changeset
   347
            instVarChange ifTrue:[
claus
parents: 1
diff changeset
   348
10
claus
parents: 5
diff changeset
   349
                ((oldInstVars size == 0) 
claus
parents: 5
diff changeset
   350
                or:[newInstVars startsWith:oldInstVars]) ifTrue:[
2
claus
parents: 1
diff changeset
   351
                    "new variable(s) has/have been added - old methods still work"
claus
parents: 1
diff changeset
   352
claus
parents: 1
diff changeset
   353
                    Transcript showCr:'copying methods ...'.
claus
parents: 1
diff changeset
   354
                    self copyMethodsFrom:oldClass for:newClass.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   355
2
claus
parents: 1
diff changeset
   356
                    "but have to recompile methods accessing stuff now defined
claus
parents: 1
diff changeset
   357
                     (it might have been a global before ...)"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   358
10
claus
parents: 5
diff changeset
   359
                    addedNames := newInstVars select:[:nm | (oldInstVars includes:nm) not].
2
claus
parents: 1
diff changeset
   360
                    changeSet1 do:[:nm | addedNames add:nm].
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   361
2
claus
parents: 1
diff changeset
   362
" "
claus
parents: 1
diff changeset
   363
                    Transcript showCr:'recompiling instance methods accessing ' , addedNames printString ,  '...'.
claus
parents: 1
diff changeset
   364
" "
claus
parents: 1
diff changeset
   365
                    newClass recompileMethodsAccessingAny:addedNames.
claus
parents: 1
diff changeset
   366
                ] ifFalse:[
claus
parents: 1
diff changeset
   367
                    "find set of changed instvars"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   368
2
claus
parents: 1
diff changeset
   369
                    offset := 0. oldOffsets := Dictionary new.
10
claus
parents: 5
diff changeset
   370
                    oldInstVars do:[:nm | offset := offset + 1. oldOffsets at:nm put:offset].
2
claus
parents: 1
diff changeset
   371
                    offset := 0. newOffsets := Dictionary new.
10
claus
parents: 5
diff changeset
   372
                    newInstVars do:[:nm | offset := offset + 1. newOffsets at:nm put:offset].
2
claus
parents: 1
diff changeset
   373
claus
parents: 1
diff changeset
   374
                    oldOffsets associationsDo:[:a |
claus
parents: 1
diff changeset
   375
                        |k|
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   376
2
claus
parents: 1
diff changeset
   377
                        k := a key.
claus
parents: 1
diff changeset
   378
                        (newOffsets includesKey:k) ifFalse:[
claus
parents: 1
diff changeset
   379
                            changeSet2 add:k
claus
parents: 1
diff changeset
   380
                        ] ifTrue:[
claus
parents: 1
diff changeset
   381
                            (a value ~~ (newOffsets at:k)) ifTrue:[
claus
parents: 1
diff changeset
   382
                                changeSet2 add:k
claus
parents: 1
diff changeset
   383
                            ]
claus
parents: 1
diff changeset
   384
                        ]
claus
parents: 1
diff changeset
   385
                    ].
claus
parents: 1
diff changeset
   386
                    newOffsets associationsDo:[:a |
claus
parents: 1
diff changeset
   387
                        |k|
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   388
2
claus
parents: 1
diff changeset
   389
                        k := a key.
claus
parents: 1
diff changeset
   390
                        (oldOffsets includesKey:k) ifFalse:[
claus
parents: 1
diff changeset
   391
                            changeSet2 add:k
claus
parents: 1
diff changeset
   392
                        ] ifTrue:[
claus
parents: 1
diff changeset
   393
                            (a value ~~ (oldOffsets at:k)) ifTrue:[
claus
parents: 1
diff changeset
   394
                                changeSet2 add:k
claus
parents: 1
diff changeset
   395
                            ]
claus
parents: 1
diff changeset
   396
                        ]
claus
parents: 1
diff changeset
   397
                    ].
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   398
2
claus
parents: 1
diff changeset
   399
                    changeSet1 do:[:nm | changeSet2 add:nm].
claus
parents: 1
diff changeset
   400
" "
claus
parents: 1
diff changeset
   401
                    Transcript showCr:'recompiling instance methods accessing ' , changeSet2 printString , ' ...'.
claus
parents: 1
diff changeset
   402
" "
claus
parents: 1
diff changeset
   403
                    self copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:changeSet2.
claus
parents: 1
diff changeset
   404
                    newClass recompileInvalidatedMethods.
claus
parents: 1
diff changeset
   405
claus
parents: 1
diff changeset
   406
                ].
claus
parents: 1
diff changeset
   407
            ].
claus
parents: 1
diff changeset
   408
        ].
claus
parents: 1
diff changeset
   409
    ].
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   410
2
claus
parents: 1
diff changeset
   411
    "get list of all subclasses - do before superclass is changed"
claus
parents: 1
diff changeset
   412
claus
parents: 1
diff changeset
   413
    allSubclasses := oldClass allSubclasses.
claus
parents: 1
diff changeset
   414
claus
parents: 1
diff changeset
   415
    "update superclass of immediate subclasses - this forces recompilation if needed"
claus
parents: 1
diff changeset
   416
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   417
    "dont update change file for the subclass changes"
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   418
    upd := Class updateChanges:false.
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   419
    [
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   420
        oldClass subclassesDo:[:aClass |
2
claus
parents: 1
diff changeset
   421
" "
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   422
            Transcript showCr:'changing superclass of:' , aClass name.
2
claus
parents: 1
diff changeset
   423
" "
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   424
            aClass superclass:newClass
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   425
        ]
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   426
    ] valueNowOrOnUnwindDo:[
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   427
        Class updateChanges:upd.
2
claus
parents: 1
diff changeset
   428
    ].
claus
parents: 1
diff changeset
   429
claus
parents: 1
diff changeset
   430
    aSystemDictionary at:classSymbol put:newClass.
claus
parents: 1
diff changeset
   431
    ObjectMemory flushCaches.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   432
    ^ newClass
a27a279701f8 Initial revision
claus
parents:
diff changeset
   433
!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   434
a27a279701f8 Initial revision
claus
parents:
diff changeset
   435
new
2
claus
parents: 1
diff changeset
   436
    "create & return a new metaclass (a classes class)"
claus
parents: 1
diff changeset
   437
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   438
    |newClass|
a27a279701f8 Initial revision
claus
parents:
diff changeset
   439
a27a279701f8 Initial revision
claus
parents:
diff changeset
   440
    newClass := self basicNew.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   441
    newClass setSuperclass:(Object class)
a27a279701f8 Initial revision
claus
parents:
diff changeset
   442
                 selectors:(Array new:0)
a27a279701f8 Initial revision
claus
parents:
diff changeset
   443
                   methods:(Array new:0)
a27a279701f8 Initial revision
claus
parents:
diff changeset
   444
                  instSize:0
a27a279701f8 Initial revision
claus
parents:
diff changeset
   445
                     flags:0.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   446
    newClass setComment:(self comment) category:(self category).
a27a279701f8 Initial revision
claus
parents:
diff changeset
   447
    ^ newClass
a27a279701f8 Initial revision
claus
parents:
diff changeset
   448
! !
a27a279701f8 Initial revision
claus
parents:
diff changeset
   449
a27a279701f8 Initial revision
claus
parents:
diff changeset
   450
!Metaclass methodsFor:'class instance variables'!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   451
a27a279701f8 Initial revision
claus
parents:
diff changeset
   452
instanceVariableNames:aString
a27a279701f8 Initial revision
claus
parents:
diff changeset
   453
    "changing / adding class-inst vars -
2
claus
parents: 1
diff changeset
   454
     this actually creates a new metaclass and class."
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   455
a27a279701f8 Initial revision
claus
parents:
diff changeset
   456
    |newClass newMetaclass nClassInstVars oldClass 
2
claus
parents: 1
diff changeset
   457
     allSubclasses t oldVars
claus
parents: 1
diff changeset
   458
     oldNames newNames addedNames
claus
parents: 1
diff changeset
   459
     oldOffsets newOffsets offset changeSet delta
claus
parents: 1
diff changeset
   460
     oldToNew newSubMeta newSub oldSubMeta oldSuper|
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   461
a27a279701f8 Initial revision
claus
parents:
diff changeset
   462
    oldVars := self instanceVariableString.
2
claus
parents: 1
diff changeset
   463
    aString = oldVars ifTrue:[
claus
parents: 1
diff changeset
   464
"
claus
parents: 1
diff changeset
   465
        Transcript showCr:'no change (', oldVars , ') -> (', aString , ')'.
claus
parents: 1
diff changeset
   466
"
claus
parents: 1
diff changeset
   467
        ^ self
claus
parents: 1
diff changeset
   468
    ].
claus
parents: 1
diff changeset
   469
claus
parents: 1
diff changeset
   470
    oldNames := oldVars asCollectionOfWords.
claus
parents: 1
diff changeset
   471
    newNames := aString asCollectionOfWords.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   472
2
claus
parents: 1
diff changeset
   473
    oldNames = newNames ifTrue:[
claus
parents: 1
diff changeset
   474
"
claus
parents: 1
diff changeset
   475
        Transcript showCr:'no real change'.
claus
parents: 1
diff changeset
   476
"
claus
parents: 1
diff changeset
   477
        "no real change (just formatting)"
claus
parents: 1
diff changeset
   478
        self instanceVariableString:aString.
claus
parents: 1
diff changeset
   479
        ^ self
claus
parents: 1
diff changeset
   480
    ]. 
claus
parents: 1
diff changeset
   481
claus
parents: 1
diff changeset
   482
    nClassInstVars := newNames size.
claus
parents: 1
diff changeset
   483
claus
parents: 1
diff changeset
   484
"
claus
parents: 1
diff changeset
   485
    Transcript showCr:'create new class/metaclass'.
claus
parents: 1
diff changeset
   486
"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   487
a27a279701f8 Initial revision
claus
parents:
diff changeset
   488
    "create the new metaclass"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   489
    newMetaclass := Metaclass new.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   490
    newMetaclass setSuperclass:superclass.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   491
    newMetaclass instSize:(superclass instSize + nClassInstVars).
a27a279701f8 Initial revision
claus
parents:
diff changeset
   492
    (nClassInstVars ~~ 0) ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   493
        newMetaclass instanceVariableString:aString
a27a279701f8 Initial revision
claus
parents:
diff changeset
   494
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   495
    newMetaclass flags:0.            "not indexed"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   496
    newMetaclass setName:name.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   497
    newMetaclass classVariableString:classvars.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   498
    newMetaclass category:category.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   499
    newMetaclass setComment:comment.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   500
a27a279701f8 Initial revision
claus
parents:
diff changeset
   501
    "find the class which is my sole instance"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   502
a27a279701f8 Initial revision
claus
parents:
diff changeset
   503
    t := Smalltalk allClasses select:[:element | element class == self].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   504
    (t size ~~ 1) ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   505
        self error:'oops - I should have exactly one instance'.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   506
        ^ nil
a27a279701f8 Initial revision
claus
parents:
diff changeset
   507
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   508
    oldClass := t anElement.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   509
a27a279701f8 Initial revision
claus
parents:
diff changeset
   510
    "create a new class"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   511
    newClass := newMetaclass new.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   512
    newClass setSuperclass:(oldClass superclass).
a27a279701f8 Initial revision
claus
parents:
diff changeset
   513
    newClass instSize:(oldClass instSize).
a27a279701f8 Initial revision
claus
parents:
diff changeset
   514
    newClass flags:(oldClass flags).
a27a279701f8 Initial revision
claus
parents:
diff changeset
   515
    newClass setName:(oldClass name).
a27a279701f8 Initial revision
claus
parents:
diff changeset
   516
    newClass instanceVariableString:(oldClass instanceVariableString).
a27a279701f8 Initial revision
claus
parents:
diff changeset
   517
    newClass classVariableString:(oldClass classVariableString).
2
claus
parents: 1
diff changeset
   518
    newClass setComment:(oldClass comment).
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   519
    newClass category:(oldClass category).
a27a279701f8 Initial revision
claus
parents:
diff changeset
   520
2
claus
parents: 1
diff changeset
   521
    offset := 0. oldOffsets := Dictionary new.
claus
parents: 1
diff changeset
   522
    oldNames do:[:nm | offset := offset + 1. oldOffsets at:nm put:offset].
claus
parents: 1
diff changeset
   523
    offset := 0. newOffsets := Dictionary new.
claus
parents: 1
diff changeset
   524
    newNames do:[:nm | offset := offset + 1. newOffsets at:nm put:offset].
claus
parents: 1
diff changeset
   525
    changeSet := Set new.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   526
2
claus
parents: 1
diff changeset
   527
    oldOffsets associationsDo:[:a |
10
claus
parents: 5
diff changeset
   528
        |k|
claus
parents: 5
diff changeset
   529
claus
parents: 5
diff changeset
   530
        k := a key.
claus
parents: 5
diff changeset
   531
        (newOffsets includesKey:k) ifFalse:[
claus
parents: 5
diff changeset
   532
            changeSet add:k
2
claus
parents: 1
diff changeset
   533
        ] ifTrue:[
10
claus
parents: 5
diff changeset
   534
            (a value ~~ (newOffsets at:k)) ifTrue:[
claus
parents: 5
diff changeset
   535
                changeSet add:k
2
claus
parents: 1
diff changeset
   536
            ]
claus
parents: 1
diff changeset
   537
        ]
claus
parents: 1
diff changeset
   538
    ].
claus
parents: 1
diff changeset
   539
    newOffsets associationsDo:[:a |
10
claus
parents: 5
diff changeset
   540
        |k|
claus
parents: 5
diff changeset
   541
claus
parents: 5
diff changeset
   542
        k := a key.
claus
parents: 5
diff changeset
   543
        (oldOffsets includesKey:k) ifFalse:[
claus
parents: 5
diff changeset
   544
            changeSet add:k
2
claus
parents: 1
diff changeset
   545
        ] ifTrue:[
10
claus
parents: 5
diff changeset
   546
            (a value ~~ (oldOffsets at:k)) ifTrue:[
claus
parents: 5
diff changeset
   547
                changeSet add:k
2
claus
parents: 1
diff changeset
   548
            ]
claus
parents: 1
diff changeset
   549
        ]
claus
parents: 1
diff changeset
   550
    ].
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   551
2
claus
parents: 1
diff changeset
   552
    ((oldNames size == 0) 
claus
parents: 1
diff changeset
   553
    or:[newNames startsWith:oldNames]) ifTrue:[
claus
parents: 1
diff changeset
   554
        "new variable(s) has/have been added - old methods still work"
claus
parents: 1
diff changeset
   555
claus
parents: 1
diff changeset
   556
        Transcript showCr:'copying methods ...'.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   557
        self copyMethodsFrom:self for:newMetaclass.
2
claus
parents: 1
diff changeset
   558
        self copyMethodsFrom:oldClass for:newClass.
claus
parents: 1
diff changeset
   559
claus
parents: 1
diff changeset
   560
        "but have to recompile methods accessing stuff now defined
claus
parents: 1
diff changeset
   561
         (it might have been a global before ...)"
claus
parents: 1
diff changeset
   562
claus
parents: 1
diff changeset
   563
        addedNames := newNames select:[:nm | (oldNames includes:nm) not].
claus
parents: 1
diff changeset
   564
"
claus
parents: 1
diff changeset
   565
        Transcript showCr:'recompiling methods accessing ' , 
claus
parents: 1
diff changeset
   566
                          addedNames printString ,  '...'.
claus
parents: 1
diff changeset
   567
"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   568
        "recompile class-methods"
2
claus
parents: 1
diff changeset
   569
        newMetaclass recompileMethodsAccessingAny:addedNames.
claus
parents: 1
diff changeset
   570
    ] ifFalse:[
claus
parents: 1
diff changeset
   571
"
claus
parents: 1
diff changeset
   572
        Transcript showCr:'recompiling methods accessing ' ,
claus
parents: 1
diff changeset
   573
                          changeSet printString , ' ...'.
claus
parents: 1
diff changeset
   574
"
claus
parents: 1
diff changeset
   575
        "recompile class-methods"
claus
parents: 1
diff changeset
   576
        self copyInvalidatedMethodsFrom:self for:newMetaclass accessingAny:changeSet.
claus
parents: 1
diff changeset
   577
        newMetaclass recompileInvalidatedMethods.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   578
2
claus
parents: 1
diff changeset
   579
        self copyMethodsFrom:oldClass for:newClass.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   580
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   581
2
claus
parents: 1
diff changeset
   582
    delta := newNames size - oldNames size.
claus
parents: 1
diff changeset
   583
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   584
    "get list of all subclasses - do before superclass is changed"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   585
a27a279701f8 Initial revision
claus
parents:
diff changeset
   586
    allSubclasses := oldClass allSubclasses.
2
claus
parents: 1
diff changeset
   587
    allSubclasses := allSubclasses asSortedCollection:[:a :b |
claus
parents: 1
diff changeset
   588
                                b isSubclassOf:a
claus
parents: 1
diff changeset
   589
                     ].
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   590
2
claus
parents: 1
diff changeset
   591
    oldToNew := IdentityDictionary new.
claus
parents: 1
diff changeset
   592
claus
parents: 1
diff changeset
   593
    "create a new class tree, based on new version"
claus
parents: 1
diff changeset
   594
claus
parents: 1
diff changeset
   595
    allSubclasses do:[:aSubclass |
claus
parents: 1
diff changeset
   596
        oldSuper := aSubclass superclass.
claus
parents: 1
diff changeset
   597
        oldSubMeta := aSubclass class.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   598
2
claus
parents: 1
diff changeset
   599
        newSubMeta := Metaclass new.
claus
parents: 1
diff changeset
   600
        oldSuper == oldClass ifTrue:[
claus
parents: 1
diff changeset
   601
            newSubMeta setSuperclass:newMetaclass.
claus
parents: 1
diff changeset
   602
        ] ifFalse:[
claus
parents: 1
diff changeset
   603
            newSubMeta setSuperclass:(oldToNew at:oldSuper) class.
claus
parents: 1
diff changeset
   604
        ].
claus
parents: 1
diff changeset
   605
        newSubMeta instSize:(oldSubMeta instSize + delta).
claus
parents: 1
diff changeset
   606
        newSubMeta flags:(oldSubMeta flags).
claus
parents: 1
diff changeset
   607
        newSubMeta setName:(oldSubMeta name).
claus
parents: 1
diff changeset
   608
        newSubMeta classVariableString:(oldSubMeta classVariableString).
claus
parents: 1
diff changeset
   609
        newSubMeta setComment:(oldSubMeta comment).
claus
parents: 1
diff changeset
   610
        newSubMeta category:(oldSubMeta category).
claus
parents: 1
diff changeset
   611
claus
parents: 1
diff changeset
   612
        newSub := newSubMeta new.
claus
parents: 1
diff changeset
   613
        oldSuper == oldClass ifTrue:[
claus
parents: 1
diff changeset
   614
            newSub setSuperclass:newClass.
claus
parents: 1
diff changeset
   615
        ] ifFalse:[
claus
parents: 1
diff changeset
   616
            newSub setSuperclass:(oldToNew at:oldSuper).
claus
parents: 1
diff changeset
   617
        ].
claus
parents: 1
diff changeset
   618
        newSub setSelectors:(aSubclass selectors).
claus
parents: 1
diff changeset
   619
        newSub setMethodDictionary:(aSubclass methodDictionary).
claus
parents: 1
diff changeset
   620
        newSub setName:(aSubclass name).
claus
parents: 1
diff changeset
   621
        newSub classVariableString:(aSubclass classVariableString).
claus
parents: 1
diff changeset
   622
        newSub setComment:(aSubclass comment).
claus
parents: 1
diff changeset
   623
        newSub category:(aSubclass category).
claus
parents: 1
diff changeset
   624
claus
parents: 1
diff changeset
   625
        oldToNew at:aSubclass put:newSub.
claus
parents: 1
diff changeset
   626
claus
parents: 1
diff changeset
   627
        aSubclass setName:(aSubclass name , '-old').
claus
parents: 1
diff changeset
   628
        aSubclass category:'obsolete classes'
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   629
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   630
2
claus
parents: 1
diff changeset
   631
    "recompile what needs to be"
claus
parents: 1
diff changeset
   632
claus
parents: 1
diff changeset
   633
    delta == 0 ifTrue:[
claus
parents: 1
diff changeset
   634
        "only have to recompile class methods accessing 
claus
parents: 1
diff changeset
   635
         class instvars from changeset"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   636
2
claus
parents: 1
diff changeset
   637
        allSubclasses do:[:aClass |
claus
parents: 1
diff changeset
   638
            aClass class recompileMethodsAccessingAny:changeSet.
claus
parents: 1
diff changeset
   639
        ]
claus
parents: 1
diff changeset
   640
    ] ifFalse:[
claus
parents: 1
diff changeset
   641
        "have to recompile all class methods accessing class instvars"
claus
parents: 1
diff changeset
   642
claus
parents: 1
diff changeset
   643
        allSubclasses do:[:aClass |
claus
parents: 1
diff changeset
   644
            |classInstVars|
claus
parents: 1
diff changeset
   645
claus
parents: 1
diff changeset
   646
            classInstVars := aClass class allInstVarNames.
claus
parents: 1
diff changeset
   647
            aClass class recompileMethodsAccessingAny:classInstVars.
claus
parents: 1
diff changeset
   648
        ]
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   649
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   650
2
claus
parents: 1
diff changeset
   651
    self addChangeRecordForClassInstvars:newClass.
claus
parents: 1
diff changeset
   652
claus
parents: 1
diff changeset
   653
    "install all new classes"
claus
parents: 1
diff changeset
   654
claus
parents: 1
diff changeset
   655
    Smalltalk at:(oldClass name asSymbol) put:newClass.
claus
parents: 1
diff changeset
   656
    ObjectMemory flushCachesFor:oldClass.
claus
parents: 1
diff changeset
   657
    allSubclasses do:[:aClass |
claus
parents: 1
diff changeset
   658
        Smalltalk at:(oldToNew at:aClass) name asSymbol put:(oldToNew at:aClass).
claus
parents: 1
diff changeset
   659
        ObjectMemory flushCachesFor:aClass.
claus
parents: 1
diff changeset
   660
    ].
claus
parents: 1
diff changeset
   661
10
claus
parents: 5
diff changeset
   662
    "tell dependents of class ..."
claus
parents: 5
diff changeset
   663
2
claus
parents: 1
diff changeset
   664
    oldClass changed.
claus
parents: 1
diff changeset
   665
    self changed.
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   666
    ^ newMetaclass
a27a279701f8 Initial revision
claus
parents:
diff changeset
   667
! !
a27a279701f8 Initial revision
claus
parents:
diff changeset
   668
a27a279701f8 Initial revision
claus
parents:
diff changeset
   669
!Metaclass methodsFor:'queries'!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   670
a27a279701f8 Initial revision
claus
parents:
diff changeset
   671
isMeta
a27a279701f8 Initial revision
claus
parents:
diff changeset
   672
    "return true, if the receiver is some kind of metaclass;
a27a279701f8 Initial revision
claus
parents:
diff changeset
   673
     true is returned here. Redefines isMeta in Object"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   674
a27a279701f8 Initial revision
claus
parents:
diff changeset
   675
    ^ true
a27a279701f8 Initial revision
claus
parents:
diff changeset
   676
! !
a27a279701f8 Initial revision
claus
parents:
diff changeset
   677
a27a279701f8 Initial revision
claus
parents:
diff changeset
   678
!Metaclass methodsFor:'private'!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   679
a27a279701f8 Initial revision
claus
parents:
diff changeset
   680
copyMethodsFrom:oldClass for:newClass
a27a279701f8 Initial revision
claus
parents:
diff changeset
   681
    "when a class has changed, but metaclass is unaffected (i.e. classVars
a27a279701f8 Initial revision
claus
parents:
diff changeset
   682
     have not changed) there is no need to recompile them"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   683
2
claus
parents: 1
diff changeset
   684
    newClass selectors:(oldClass selectors copy) methods:(oldClass methodDictionary copy)
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   685
!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   686
a27a279701f8 Initial revision
claus
parents:
diff changeset
   687
copyInvalidatedMethodsFrom:oldClass for:newClass
a27a279701f8 Initial revision
claus
parents:
diff changeset
   688
    "when a class has been changed, copy all old methods into the new class
a27a279701f8 Initial revision
claus
parents:
diff changeset
   689
     - changing code to a trap method giving an error message;
a27a279701f8 Initial revision
claus
parents:
diff changeset
   690
     this allows us to keep the source while trapping uncompilable (due to
a27a279701f8 Initial revision
claus
parents:
diff changeset
   691
     now undefined instvars) methods"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   692
2
claus
parents: 1
diff changeset
   693
    |trap trapCode trapByteCode newMethod oldMethodArray newMethodArray|
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   694
a27a279701f8 Initial revision
claus
parents:
diff changeset
   695
    trap := Method compiledMethodAt:#invalidMethod.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   696
    trapCode := trap code.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   697
    trapByteCode := trap byteCode.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   698
2
claus
parents: 1
diff changeset
   699
    oldMethodArray := oldClass methodDictionary.
claus
parents: 1
diff changeset
   700
    newMethodArray := Array new:(oldMethodArray size).
claus
parents: 1
diff changeset
   701
    newClass selectors:(oldClass selectors copy) methods:newMethodArray.
claus
parents: 1
diff changeset
   702
    1 to:oldMethodArray size do:[:i |
claus
parents: 1
diff changeset
   703
        newMethod := (oldMethodArray at:i) copy.
claus
parents: 1
diff changeset
   704
        newMethod code:trapCode.
claus
parents: 1
diff changeset
   705
        newMethod literals:nil.
claus
parents: 1
diff changeset
   706
        newMethod byteCode:trapByteCode.
claus
parents: 1
diff changeset
   707
        newMethodArray at:i put:newMethod
claus
parents: 1
diff changeset
   708
    ]
claus
parents: 1
diff changeset
   709
!
claus
parents: 1
diff changeset
   710
claus
parents: 1
diff changeset
   711
copyInvalidatedMethodsFrom:oldClass for:newClass accessingAny:setOfNames
claus
parents: 1
diff changeset
   712
    "copy all methods from oldClass to newClass. Those methods accessing
claus
parents: 1
diff changeset
   713
     a variable in setOfNames will be copied as invalid method, leading to
claus
parents: 1
diff changeset
   714
     a trap when its executed."
claus
parents: 1
diff changeset
   715
claus
parents: 1
diff changeset
   716
    |trap trapCode trapByteCode p oldMethod newMethod oldMethodArray newMethodArray|
claus
parents: 1
diff changeset
   717
claus
parents: 1
diff changeset
   718
    trap := Method compiledMethodAt:#invalidMethod.
claus
parents: 1
diff changeset
   719
    trapCode := trap code.
claus
parents: 1
diff changeset
   720
    trapByteCode := trap byteCode.
claus
parents: 1
diff changeset
   721
claus
parents: 1
diff changeset
   722
    oldMethodArray := oldClass methodDictionary.
claus
parents: 1
diff changeset
   723
    newMethodArray := Array new:(oldMethodArray size).
claus
parents: 1
diff changeset
   724
    newClass selectors:(oldClass selectors copy) methods:newMethodArray.
claus
parents: 1
diff changeset
   725
    1 to:oldMethodArray size do:[:i |
claus
parents: 1
diff changeset
   726
        oldMethod := oldMethodArray at:i.
claus
parents: 1
diff changeset
   727
        p := Parser parseMethod:(oldMethod source) in:newClass.
claus
parents: 1
diff changeset
   728
        (p isNil or:[p usedVars notNil and:[p usedVars includesAny:setOfNames]]) ifTrue:[
claus
parents: 1
diff changeset
   729
            newMethod := oldMethod copy.
claus
parents: 1
diff changeset
   730
            newMethod code:trapCode.
claus
parents: 1
diff changeset
   731
            newMethod literals:nil.
claus
parents: 1
diff changeset
   732
            newMethod byteCode:trapByteCode
claus
parents: 1
diff changeset
   733
        ] ifFalse:[
claus
parents: 1
diff changeset
   734
            newMethod := oldMethod.
claus
parents: 1
diff changeset
   735
        ].
claus
parents: 1
diff changeset
   736
        newMethodArray at:i put:newMethod
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   737
    ]
a27a279701f8 Initial revision
claus
parents:
diff changeset
   738
!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   739
a27a279701f8 Initial revision
claus
parents:
diff changeset
   740
anyInvalidatedMethodsIn:aClass
a27a279701f8 Initial revision
claus
parents:
diff changeset
   741
    "return true, if aClass has any invalidated methods in it"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   742
a27a279701f8 Initial revision
claus
parents:
diff changeset
   743
    |trap trapCode trapByteCode|
a27a279701f8 Initial revision
claus
parents:
diff changeset
   744
a27a279701f8 Initial revision
claus
parents:
diff changeset
   745
    trap := Method compiledMethodAt:#invalidMethod.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   746
    trapCode := trap code.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   747
    trapByteCode := trap byteCode.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   748
a27a279701f8 Initial revision
claus
parents:
diff changeset
   749
    aClass methodDictionary do:[:aMethod |
a27a279701f8 Initial revision
claus
parents:
diff changeset
   750
        trapCode notNil ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   751
            (aMethod code == trapCode) ifTrue:[^ true]
a27a279701f8 Initial revision
claus
parents:
diff changeset
   752
        ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   753
        trapByteCode notNil ifTrue:[
a27a279701f8 Initial revision
claus
parents:
diff changeset
   754
            (aMethod byteCode == trapByteCode) ifTrue:[^ true]
a27a279701f8 Initial revision
claus
parents:
diff changeset
   755
        ]
a27a279701f8 Initial revision
claus
parents:
diff changeset
   756
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   757
    ^ false
a27a279701f8 Initial revision
claus
parents:
diff changeset
   758
! !