reflection.cpp

Go to the documentation of this file.
00001 /* Copyright 1994, 1995 LongView Technologies L.L.C. $Revision: 1.21 $ */
00002 /* Copyright (c) 2006, Sun Microsystems, Inc.
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
00006 following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
00010           disclaimer in the documentation and/or other materials provided with the distribution.
00011     * Neither the name of Sun Microsystems nor the names of its contributors may be used to endorse or promote products derived 
00012           from this software without specific prior written permission.
00013 
00014 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 
00015 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
00016 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
00017 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00018 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
00019 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00020 
00021 
00022 */
00023 
00024 
00025 # include "incls/_precompiled.incl"
00026 # include "incls/_reflection.cpp.incl"
00027 
00028 // Converter hierarchy:
00029 // - memConverter
00030 //   - byteArrayConverter
00031 //   - doubleByteArrayConverter
00032 //   - doubleValueArrayConverter
00033 //   - klassConverter
00034 //   - mixinConverter
00035 //   - objArrayConverter
00036 //   - processConverter
00037 //   - proxyConverter
00038 
00039 class memConverter: public ResourceObj {
00040  protected:
00041   klassOop old_klass;
00042   klassOop new_klass;
00043   GrowableArray<int>* mapping;
00044 
00045   void compute_mapping() {
00046     mapping = new GrowableArray<int>(20);
00047     int old_header_size = old_klass->klass_part()->oop_header_size();
00048     int new_header_size = new_klass->klass_part()->oop_header_size();
00049     int n               = old_klass->klass_part()->number_of_instance_variables();
00050     for (int old_index = 0; old_index < n; old_index++) {
00051       symbolOop name = old_klass->klass_part()->inst_var_name_at(old_index + old_header_size);
00052       assert(name->is_symbol(), "instance variable name must be symbol");
00053       int new_index = new_klass->klass_part()->lookup_inst_var(name);
00054       if (new_index > 0) {
00055         if (TraceApplyChange) {
00056           std->print("map ");
00057           name->print_symbol_on(std);
00058           std->print_cr(" %d -> %d", old_index + old_header_size, new_index);
00059         }
00060         // We found a match between a old and new class
00061         mapping->push(old_index + old_header_size);
00062         mapping->push(new_index);
00063       }
00064     }
00065   }
00066 
00067  public:
00068   memConverter(klassOop old_klass, klassOop new_klass) {
00069     this->old_klass = old_klass;
00070     this->new_klass = new_klass;
00071     compute_mapping();
00072   }
00073 
00074   memOop convert(memOop src) {
00075     memOop dst = allocate(src);
00076     // Transfer contents from src to dst
00077     transfer(src, dst);
00078     Reflection::forward(src, dst);
00079     return dst;
00080   }
00081 
00082   virtual void transfer(memOop src, memOop dst) {
00083     // header information
00084     if (src->mark()->is_near_death())
00085       dst->mark_as_dying();
00086     dst->set_identity_hash(src->identity_hash());
00087     // Instance variables
00088     for (int index = 0; index < mapping->length(); index += 2) {
00089       int from = mapping->at(index);
00090       int to   = mapping->at(index+1);
00091       dst->raw_at_put(to, src->raw_at(from));
00092     }
00093   }
00094 
00095   virtual memOop allocate(memOop src) {
00096     return memOop(new_klass->klass_part()->allocateObject());
00097   }
00098 };
00099 
00100 class proxyConverter: public memConverter {
00101  private:
00102   bool source_is_proxy;
00103  public:
00104   proxyConverter(klassOop old_klass, klassOop new_klass)
00105   : memConverter(old_klass, new_klass){
00106     assert(new_klass->klass_part()->oop_is_proxy(), "new_klass must be a proxy klass");
00107     source_is_proxy = old_klass->klass_part()->oop_is_proxy();
00108   }
00109 
00110   void transfer(memOop src, memOop dst) {
00111     if (source_is_proxy) 
00112       proxyOop(dst)->set_pointer(proxyOop(src)->get_pointer());
00113     memConverter::transfer(src, dst);
00114   }
00115 };
00116 
00117 class processConverter: public memConverter {
00118  private:
00119   bool source_is_process;
00120  public:
00121   processConverter(klassOop old_klass, klassOop new_klass)
00122   : memConverter(old_klass, new_klass){
00123     assert(new_klass->klass_part()->oop_is_process(), "new_klass must be a process klass");
00124     source_is_process = old_klass->klass_part()->oop_is_process();
00125   }
00126 
00127   void transfer(memOop src, memOop dst) {
00128     if (source_is_process) 
00129       processOop(dst)->set_process(processOop(src)->process());
00130     memConverter::transfer(src, dst);
00131   }
00132 };
00133 
00134 class byteArrayConverter: public memConverter {
00135  private:
00136   bool source_is_byte_array;
00137  public:
00138   byteArrayConverter(klassOop old_klass, klassOop new_klass)
00139   : memConverter(old_klass, new_klass){
00140     assert(new_klass->klass_part()->oop_is_byteArray(), "new_klass must be a byteArray klass");
00141     source_is_byte_array = old_klass->klass_part()->oop_is_byteArray();
00142   }
00143 
00144   void transfer(memOop src, memOop dst) {
00145     memConverter::transfer(src, dst);
00146     if (source_is_byte_array) {
00147       int length = byteArrayOop(src)->length();
00148       for (int index = 1; index <= length; index++)
00149         byteArrayOop(dst)->byte_at_put(index, byteArrayOop(src)->byte_at(index));
00150     }
00151   }
00152 
00153   memOop allocate(memOop src) {
00154     int len = source_is_byte_array ? byteArrayOop(src)->length() : 0;
00155     return memOop(new_klass->klass_part()->allocateObjectSize(len));
00156   }
00157 };
00158 
00159 class doubleByteArrayConverter: public memConverter {
00160  private:
00161   bool source_is_doubleByte_array;
00162  public:
00163   doubleByteArrayConverter(klassOop old_klass, klassOop new_klass)
00164   : memConverter(old_klass, new_klass){
00165     assert(new_klass->klass_part()->oop_is_doubleByteArray(), "new_klass must be a byteArray klass");
00166     source_is_doubleByte_array = old_klass->klass_part()->oop_is_doubleByteArray();
00167   }
00168 
00169   void transfer(memOop src, memOop dst) {
00170     memConverter::transfer(src, dst);
00171     if (source_is_doubleByte_array) {
00172       int length = doubleByteArrayOop(src)->length();
00173       for (int index = 1; index <= length; index++)
00174         doubleByteArrayOop(dst)->doubleByte_at_put(index, doubleByteArrayOop(src)->doubleByte_at(index));
00175     }
00176   }
00177 
00178   memOop allocate(memOop src) {
00179     int len = source_is_doubleByte_array ? doubleByteArrayOop(src)->length() : 0;
00180     return memOop(new_klass->klass_part()->allocateObjectSize(len));
00181   }
00182 };
00183 
00184 class objArrayConverter: public memConverter {
00185  private:
00186   bool source_is_obj_array;
00187  public:
00188   objArrayConverter(klassOop old_klass, klassOop new_klass)
00189   : memConverter(old_klass, new_klass){
00190     assert(new_klass->klass_part()->oop_is_objArray(), "new_klass must be a objArray klass");
00191     source_is_obj_array = old_klass->klass_part()->oop_is_objArray();
00192   }
00193 
00194   void transfer(memOop src, memOop dst) {
00195     memConverter::transfer(src, dst);
00196     if (source_is_obj_array) {
00197       int length = objArrayOop(src)->length();
00198       for (int index = 1; index <= length; index++)
00199         objArrayOop(dst)->obj_at_put(index, objArrayOop(src)->obj_at(index));
00200     }
00201   }
00202 
00203   memOop allocate(memOop src) {
00204     int len = source_is_obj_array ? objArrayOop(src)->length() : 0;
00205     return memOop(new_klass->klass_part()->allocateObjectSize(len));
00206   }
00207 };
00208 
00209 class doubleValueArrayConverter: public memConverter {
00210  private:
00211   bool source_is_obj_array;
00212  public:
00213   doubleValueArrayConverter(klassOop old_klass, klassOop new_klass)
00214   : memConverter(old_klass, new_klass){
00215     assert(new_klass->klass_part()->oop_is_doubleValueArray(), "new_klass must be a doubleValueArray klass");
00216     source_is_obj_array = old_klass->klass_part()->oop_is_doubleValueArray();
00217   }
00218 
00219   void transfer(memOop src, memOop dst) {
00220     memConverter::transfer(src, dst);
00221     if (source_is_obj_array) {
00222       int length = doubleValueArrayOop(src)->length();
00223       for (int index = 1; index <= length; index++)
00224         doubleValueArrayOop(dst)->double_at_put(index, doubleValueArrayOop(src)->double_at(index));
00225     }
00226   }
00227 
00228   memOop allocate(memOop src) {
00229     int len = source_is_obj_array ? doubleValueArrayOop(src)->length() : 0;
00230     return memOop(new_klass->klass_part()->allocateObjectSize(len));
00231   }
00232 };
00233 
00234 class klassConverter: public memConverter {
00235  public:
00236   klassConverter(klassOop old_klass, klassOop new_klass)
00237   : memConverter(old_klass, new_klass){
00238     assert(old_klass->klass_part()->oop_is_klass(), "new_klass must be a klass klass");
00239     assert(new_klass->klass_part()->oop_is_klass(), "new_klass must be a klass klass");
00240   }
00241 
00242   void transfer(memOop src, memOop dst) {
00243     memConverter::transfer(src, dst);
00244   }
00245 
00246   memOop allocate(memOop src) {
00247     Unimplemented();
00248     return NULL;
00249   }
00250 };
00251 
00252 class mixinConverter: public memConverter {
00253  public:
00254   mixinConverter(klassOop old_klass, klassOop new_klass)
00255   : memConverter(old_klass, new_klass){
00256     assert(old_klass->klass_part()->oop_is_mixin(), "new_klass must be a mixin klass");
00257     assert(new_klass->klass_part()->oop_is_mixin(), "new_klass must be a mixin klass");
00258   }
00259 
00260   void transfer(memOop src, memOop dst) {
00261     Unimplemented();
00262     memConverter::transfer(src, dst);
00263   }
00264 };
00265 
00266 // Static variables in Reflection
00267 GrowableArray<ClassChange*>*  Reflection::class_changes = NULL;
00268 GrowableArray<memOop>*        Reflection::converted   = NULL;
00269 
00270 class ConvertClosure : public OopClosure {
00271   void do_oop(oop* o) {
00272     Reflection::convert(o);
00273   }
00274 };
00275 
00276 class ConvertOopClosure : public ObjectClosure {
00277  public:
00278   void do_object(memOop obj) {
00279     if (obj->klass()->klass_part()->is_marked_for_schema_change()) return;
00280     ConvertClosure blk;
00281     obj->oop_iterate(&blk);
00282   }
00283 };
00284 
00285 class ClassChange: public ResourceObj {
00286  private:
00287   klassOop      _old_klass;
00288   mixinOop      _new_mixin;
00289   Klass::Format _new_format;
00290   klassOop      _new_klass;
00291   klassOop      _new_super;
00292   memConverter* _converter;
00293   ClassChange*  _super_change;
00294   bool          _is_schema_change_computed;
00295   bool          _needs_schema_change;
00296   char*         _reason_for_schema_change;
00297 
00298  public:
00299   ClassChange(klassOop old_klass, mixinOop new_mixin, Klass::Format new_format, klassOop new_super) {
00300     _old_klass    = old_klass;
00301     _new_mixin    = new_mixin;
00302     _new_format   = new_format;
00303     _new_super    = new_super;
00304     _new_klass    = NULL;
00305     _converter    = NULL;
00306     _super_change = NULL;
00307     _is_schema_change_computed = false;
00308     _reason_for_schema_change = "";
00309   }
00310 
00311   ClassChange(klassOop old_klass, Klass::Format new_format) {
00312     _old_klass    = old_klass;
00313     _new_mixin    = old_klass->klass_part()->mixin();
00314     _new_format   = new_format;
00315     _new_super    = NULL;
00316     _new_klass    = NULL;
00317     _converter    = NULL;
00318     _super_change = NULL;
00319     _is_schema_change_computed = false;
00320     _reason_for_schema_change = "";
00321   }
00322   klassOop      old_klass()    const { return _old_klass;    }
00323   mixinOop      new_mixin()    const { return _new_mixin;    }
00324   Klass::Format new_format()   const { return _new_format;   }
00325   klassOop      new_klass()    const { return _new_klass;    }
00326   klassOop      new_super()    const { return _new_super;    }
00327   memConverter* converter()    const { return _converter;    }
00328   ClassChange*  super_change() const { return _super_change; }
00329   mixinOop      old_mixin()    const { return _old_klass->klass_part()->mixin(); }
00330 
00331 
00332   char* reason_for_schema_change()             { return _reason_for_schema_change; }
00333   void set_reason_for_schema_change(char* msg) { _reason_for_schema_change = msg; }
00334 
00335   void set_super_change(ClassChange* change) { 
00336     _super_change = change;
00337   }
00338 
00339   void setup_schema_change();
00340   void recustomize_methods();
00341 
00342   bool compute_needed_schema_change();
00343   bool needs_schema_change() {
00344     if (!_is_schema_change_computed)
00345       _needs_schema_change = compute_needed_schema_change(); 
00346     return _needs_schema_change;
00347   }
00348 
00349   klassOop new_class_from(klassOop      old_klass,
00350                                  klassOop      new_super_klass,
00351                                  mixinOop      new_mixin,
00352                                  Klass::Format new_format,
00353                                  mixinOop      old_mixin);
00354 
00355   memConverter* create_converter_for(klassOop old_class, klassOop new_class);
00356 
00357   void transfer_misc(memOop src, memOop dst);
00358 
00359   // Updating if no schema change is needed
00360   void update_class(bool class_vars_changed,
00361                     bool instance_methods_changed,
00362                     bool class_methods_changed);
00363 
00364   void update_class_vars();
00365   void update_methods(bool instance_side);
00366 };
00367 
00368 
00369 void ClassChange::recustomize_methods() {
00370   new_mixin()->customize_for(new_klass());
00371   new_mixin()->class_mixin()->customize_for(new_klass()->klass());
00372 }
00373 
00374 klassOop ClassChange::new_class_from(klassOop      old_klass,
00375                                      klassOop      new_super_klass,
00376                                      mixinOop      new_mixin,
00377                                      Klass::Format new_format,
00378                                      mixinOop      old_mixin) {
00379 
00380   Klass::Format format = (new_format != Klass::special_klass)
00381                        ?  new_format
00382                        :  old_klass->klass_part()->format();
00383 
00384   klassOop result = new_super_klass->klass_part()->create_subclass(new_mixin, format);
00385   if (result == NULL) {
00386     fatal("class creation failed - internal error");
00387   }
00388 
00389   // %cleanup code
00390   _new_klass = result;
00391 
00392   if (old_klass->klass_part()->mixin()->primary_invocation() == old_klass) {
00393     recustomize_methods();
00394     new_mixin->set_primary_invocation(result);
00395     new_mixin->class_mixin()->set_primary_invocation(result->klass());
00396   }
00397 
00398   new_mixin->set_installed(trueObj);
00399   new_mixin->class_mixin()->set_installed(trueObj);
00400 
00401   transfer_misc(old_klass,          result);
00402   transfer_misc(old_klass->klass(), result->klass());
00403 
00404   // Copy the class variables
00405   for (int index = old_klass->klass_part()->number_of_classVars(); index > 0; index--) {
00406     associationOop old_assoc = old_klass->klass_part()->classVar_at(index);
00407     associationOop new_assoc = result->klass_part()->local_lookup_class_var(old_assoc->key());
00408     if (new_assoc) {
00409       new_assoc->set_value(old_assoc->value());
00410     }
00411   }
00412   return result;
00413 }
00414 
00415 
00416 void ClassChange::transfer_misc(memOop  src, memOop dst) {
00417   memConverter* c = new memConverter(src->klass(), dst->klass());
00418   c->transfer(src, dst);
00419 }
00420 
00421 memConverter* ClassChange::create_converter_for(klassOop old_class, klassOop new_class) {
00422   switch (new_class->klass_part()->format()) {
00423   case Klass::mem_klass:              return new              memConverter(old_class, new_class);
00424   case Klass::byteArray_klass:        return new        byteArrayConverter(old_class, new_class);
00425   case Klass::doubleByteArray_klass:  return new  doubleByteArrayConverter(old_class, new_class);
00426   case Klass::doubleValueArray_klass: return new doubleValueArrayConverter(old_class, new_class);
00427   case Klass::klass_klass:            return new            klassConverter(old_class, new_class);
00428   case Klass::mixin_klass:            return new            mixinConverter(old_class, new_class);
00429   case Klass::objArray_klass:         return new         objArrayConverter(old_class, new_class);
00430   case Klass::weakArray_klass:        return new         objArrayConverter(old_class, new_class);
00431   case Klass::process_klass:          return new          processConverter(old_class, new_class);
00432   case Klass::proxy_klass:            return new            proxyConverter(old_class, new_class);
00433   }
00434   fatal("cannot create converter for type");
00435   return NULL;
00436 }
00437 
00438 void ClassChange::update_class_vars() {
00439   if (TraceApplyChange) {
00440     std->print(" - updating class variables for: ");
00441     old_klass()->print_value();
00442     std->cr();
00443   }
00444 
00445   Klass* k = old_klass()->klass_part();
00446 
00447   // Remove the dead entries
00448   for (int index = k->number_of_classVars(); index > 0; index--) {
00449     associationOop assoc = k->classVar_at(index);
00450     if (!new_mixin()->includes_classVar(assoc->key())) {
00451       k->remove_classVar_at(index);
00452     }
00453   }
00454   // Add the new ones
00455   for (index = new_mixin()->number_of_classVars(); index > 0; index--) {
00456     symbolOop name = new_mixin()->classVar_at(index);
00457     if (!k->includes_classVar(name)) {
00458       k->add_classVar(oopFactory::new_association(name, nilObj, false));
00459     }
00460   }
00461 
00462   // Make fhe Class side enherit the Instance side class variables
00463   old_klass()->klass()->klass_part()->set_classVars(k->classVars());
00464 
00465   old_mixin()->set_classVars(new_mixin()->classVars());
00466   old_mixin()->class_mixin()->set_classVars(new_mixin()->classVars());
00467 }
00468 
00469 void ClassChange::update_methods(bool instance_side) {
00470   if (TraceApplyChange) {
00471     std->print(" updating %s-side methods for: ", instance_side ? "instance" : "class");
00472     old_klass()->print_value();
00473     std->cr();
00474   }
00475 
00476   if (instance_side) {
00477     old_klass()->klass_part()->flush_methods();
00478     old_mixin()->set_methods(new_mixin()->methods());
00479   } else {
00480     old_klass()->klass()->klass_part()->flush_methods();
00481     old_mixin()->class_mixin()->set_methods(new_mixin()->class_mixin()->methods());
00482   }
00483 }
00484 
00485 void ClassChange::update_class(bool class_vars_changed,
00486                                bool instance_methods_changed,
00487                                bool class_methods_changed) {
00488   // The format has not changed which means we can patch the existing classes and mixins
00489   // We only have to change classes using the old_mixin
00490   if (old_mixin() == new_mixin()) return;
00491 
00492   // This is an invocation 
00493   if (class_vars_changed)
00494     update_class_vars();
00495   if (instance_methods_changed)
00496     update_methods(true);
00497   if (class_methods_changed)
00498     update_methods(false);
00499 
00500   if (old_klass()->klass_part()->superKlass() != new_super()) {
00501     old_klass()->klass_part()->set_superKlass(new_super());
00502   }
00503 }
00504 
00505 void ClassChange::setup_schema_change() {
00506 
00507   // Setup the new super class if we have super change
00508   if (_super_change) {
00509     _new_super = super_change()->new_klass();
00510     assert(_new_super != NULL, "super class must exist");
00511   }
00512 
00513   // Create new class
00514   _new_klass = new_class_from(old_klass(), new_super(), new_mixin(), new_format(), old_mixin());
00515 
00516   // Create the converter
00517   _converter = create_converter_for(old_klass(), new_klass());
00518 
00519   // Set forward pointer in old_class
00520   Reflection::forward(old_klass(), new_klass());
00521 
00522   // Set forward pointer in old_class class
00523   Reflection::forward(old_klass()->klass(), new_klass()->klass());
00524 
00525   // Set forward pointer in mixin
00526   Reflection::forward(old_klass()->klass_part()->mixin(), new_klass()->klass_part()->mixin());
00527 
00528   // Set forward pointer in mixinClass
00529   Reflection::forward(old_klass()->klass()->klass_part()->mixin(), new_klass()->klass()->klass_part()->mixin());
00530 }
00531 
00532 bool ClassChange::compute_needed_schema_change() {
00533   // Be dependent on the super change 
00534   if (   new_super()->is_klass()
00535       && !new_super()->klass_part()->has_same_layout_as(old_klass()->klass_part()->superKlass())) {
00536     set_reason_for_schema_change("super class has changed");
00537     return true;
00538   }
00539 
00540   // Has the format changed
00541   if (   new_format() != Klass::special_klass
00542       && new_format() != old_klass()->klass_part()->format()) {
00543     set_reason_for_schema_change("format of class has changed");
00544     return true;
00545   }
00546 
00547   // Check if we've changed the of instance variables
00548   if (new_mixin()->number_of_instVars() != old_mixin()->number_of_instVars()) {
00549     set_reason_for_schema_change("number of instance variables have changed");
00550     return true;
00551   }
00552 
00553   for (int index = new_mixin()->number_of_instVars(); index > 0; index--) {
00554     if (new_mixin()->instVar_at(index) != old_mixin()->instVar_at(index)) {
00555       set_reason_for_schema_change("instance variables have changed");
00556       return true;
00557     }
00558   }
00559   return false;
00560 }
00561 
00562 bool Reflection::needs_schema_change() {
00563   bool result = false;
00564   for (int index = 0; index < class_changes->length(); index++) {
00565     bool sub_result = class_changes->at(index)->needs_schema_change();
00566     if (TraceApplyChange && sub_result) {
00567       class_changes->at(index)->old_klass()->print_value();
00568       std->cr();
00569       std->print_cr("  needs schema change because: %s.", class_changes->at(index)->reason_for_schema_change());
00570     }
00571     result = result || sub_result;
00572   }
00573   return result;
00574 }
00575 
00576 void Reflection::forward(memOop old_obj, memOop new_obj) {
00577   if (old_obj == new_obj) return;
00578   if (old_obj->is_forwarded()) {
00579     if (old_obj->forwardee() != new_obj) {
00580       fatal("inconsistent forwarding");
00581     }
00582     return;
00583   }
00584   old_obj->forward_to(new_obj);
00585   converted->append(old_obj);
00586 }
00587 
00588 bool Reflection::has_methods_changed(mixinOop new_mixin, mixinOop old_mixin) {
00589   if (new_mixin->number_of_methods() != old_mixin->number_of_methods())
00590     return true;
00591   
00592   for (int index = 1; index <= new_mixin->number_of_methods(); index++) {
00593     if (!old_mixin->includes_method(new_mixin->method_at(index))) 
00594       return true;
00595   }
00596   return false;
00597 }
00598 
00599 bool Reflection::has_class_vars_changed(mixinOop new_mixin, mixinOop old_mixin) {
00600   if (new_mixin->number_of_classVars() != old_mixin->number_of_classVars())
00601     return true;
00602   
00603   for (int index = 1; index <= new_mixin->number_of_classVars(); index++) {
00604     if (!old_mixin->includes_classVar(new_mixin->classVar_at(index))) 
00605       return true;
00606   }
00607   return false;
00608 }
00609 
00610 
00611 ClassChange* Reflection::find_change_for(klassOop klass) {
00612   for (int index = 0; index < class_changes->length(); index++) {
00613     ClassChange* e = class_changes->at(index);
00614     if (e->old_klass() == klass) return e;
00615   }
00616   return NULL;
00617 }
00618 
00619 void Reflection::register_class_changes(mixinOop    new_mixin,
00620                                         objArrayOop invocations) {
00621 
00622   class_changes = new GrowableArray<ClassChange*>(100);
00623   int length = invocations->length();
00624   for (int index = invocations_offset(); index <= length; index++) {
00625     objArrayOop invocation = objArrayOop(invocations->obj_at(index));
00626     assert(invocation->is_objArray(), "type check");
00627 
00628 
00629     ClassChange* change = new ClassChange(klassOop(invocation->obj_at(1)),
00630                                           new_mixin,
00631                                           Klass::format_from_symbol(symbolOop(invocation->obj_at(2))),
00632                                           klassOop(invocation->obj_at(3)));
00633     change->set_super_change(find_change_for(change->old_klass()->klass_part()->superKlass()));
00634     class_changes->append(change);
00635 
00636     for (int j = 4; j <= invocation->length() - 1; j += 2) {
00637       klassOop old_klass = klassOop(invocation->obj_at(j));
00638       change = new ClassChange(old_klass,
00639                         Klass::format_from_symbol(symbolOop(invocation->obj_at(j+1))));
00640       change->set_super_change(find_change_for(old_klass->klass_part()->superKlass()));
00641       class_changes->append(change);
00642     }
00643   }
00644 }
00645 
00646 void Reflection::invalidate_classes(bool value) {
00647   for (int index = 0; index < class_changes->length(); index++) {
00648     klassOop old_klass = class_changes->at(index)->old_klass();
00649     old_klass->set_invalid(value);
00650     old_klass->klass()->set_invalid(value);
00651   }
00652 }
00653 
00654 void Reflection::update_classes(bool class_vars_changed, bool instance_methods_changed, bool class_methods_changed) {
00655   for (int index = 0; index < class_changes->length(); index++) {
00656     class_changes->at(index)->update_class(class_vars_changed, instance_methods_changed, class_methods_changed);
00657   }
00658 }
00659 
00660 void Reflection::setup_schema_change() {
00661   for (int index = 0; index < class_changes->length(); index++) {
00662     class_changes->at(index)->setup_schema_change();
00663   }
00664   for (index = 0; index < class_changes->length(); index++) {
00665     // Mark old class for schema change
00666     class_changes->at(index)->old_klass()->klass_part()->mark_for_schema_change();
00667   }
00668 }
00669 
00670 void Reflection::apply_change(mixinOop    new_mixin,
00671                               mixinOop    old_mixin,
00672                               objArrayOop invocations) {
00673   ResourceMark rm;
00674   if (TraceApplyChange) {
00675     std->print("Reflective change");
00676     std->print_cr("[new]"); 
00677     new_mixin->print();
00678     std->print_cr("[old]"); 
00679     old_mixin->print();
00680     std->print_cr("[invocations]"); 
00681     invocations->print();
00682     Universe::verify();
00683   }
00684 
00685   register_class_changes(new_mixin, invocations);
00686 
00687   invalidate_classes(true);
00688 
00689   // Invalidate compiled code
00690   Universe::code->mark_dependents_for_deoptimization();
00691   Processes::deoptimized_wrt_marked_nmethods();
00692   Universe::code->make_marked_nmethods_zombies();
00693 
00694   // check for change mixin format too
00695   bool format_changed = needs_schema_change();
00696 
00697   bool class_vars_changed       = has_class_vars_changed(new_mixin, old_mixin);
00698   bool instance_methods_changed = has_methods_changed(new_mixin,    old_mixin);
00699   bool class_methods_changed    = has_methods_changed(new_mixin->class_mixin(), old_mixin->class_mixin());
00700 
00701   if (format_changed) {
00702     if (TraceApplyChange) {
00703       std->print_cr(" - schema change is needed");
00704     }
00705 
00706     converted = new GrowableArray<memOop> (100);
00707 
00708     setup_schema_change();
00709     
00710     // Do the transformation
00711     ConvertOopClosure blk;
00712     ConvertClosure    bl;
00713     Universe::roots_do(&convert);
00714     Processes::oop_iterate(&bl);
00715 
00716     // Save top of to_space and old_gen
00717     NewWaterMark eden_mark = Universe::new_gen.eden()->top_mark();
00718     OldWaterMark old_mark  = Universe::old_gen.top_mark();
00719 
00720     Universe::new_gen.object_iterate(&blk);
00721     Universe::old_gen.object_iterate(&blk);
00722 
00723     while (   eden_mark != Universe::new_gen.eden()->top_mark()
00724            || old_mark  != Universe::old_gen.top_mark()) {
00725       Universe::new_gen.eden()->object_iterate_from(&eden_mark, &blk);
00726       Universe::old_gen.object_iterate_from(&old_mark, &blk);
00727     }
00728 
00729     // NotificationQueue::oops_do(&follow_root);
00730 
00731     // Reset the marks for the converted objects
00732     for (int j = 0; j < converted->length(); j++) {
00733       memOop obj = converted->at(j);
00734       if (TraceApplyChange) {
00735         std->print_cr("Old: 0x%lx, 0x%lx", obj,              obj->mark());
00736         std->print_cr("New: 0x%lx, 0x%lx", obj->forwardee(), obj->forwardee()->mark());
00737       }
00738       obj->set_mark(obj->forwardee()->mark());
00739     }
00740 
00741     // Clear the static variables
00742     converted = NULL;
00743 
00744   } else {
00745     if (TraceApplyChange) {
00746       std->print_cr(" - no schema change (%s%s%s)",
00747         class_vars_changed        ? "class variables "  : "",
00748         instance_methods_changed  ? "instance methods " : "",
00749         class_methods_changed     ? "class methods "    : "");
00750     }
00751     update_classes(class_vars_changed, instance_methods_changed, class_methods_changed);
00752   }
00753 
00754   invalidate_classes(false);
00755   class_changes = NULL;
00756 
00757   // Clear inline caches
00758   Universe::flush_inline_caches_in_methods();
00759   Universe::code->clear_inline_caches();
00760 
00761   lookupCache::flush();
00762   DeltaCallCache::clearAll();
00763 
00764   if (TraceApplyChange) 
00765     Universe::verify();
00766 }
00767 
00768 oop Reflection::apply_change(objArrayOop change) {
00769    TraceTime t("ApplyChange", TraceApplyChange);
00770   
00771   // [1]     = new-mixin   <Mixin>
00772   // [2]     = old-mixin   <Mixin>
00773   // [3 - n] = invocations <Array>
00774 
00775   // Check array format
00776   int length = change->length();
00777 
00778   if (length < 3)
00779     return markSymbol(vmSymbols::argument_is_invalid());
00780 
00781   mixinOop new_mixin = mixinOop(change->obj_at(1));
00782   if (!new_mixin->is_mixin()) 
00783     return markSymbol(vmSymbols::argument_is_invalid());
00784 
00785   mixinOop old_mixin = mixinOop(change->obj_at(2));
00786   if (!old_mixin->is_mixin()) 
00787     return markSymbol(vmSymbols::argument_is_invalid());
00788 
00789   for (int index = 3; index <= length; index++) {
00790     objArrayOop array = objArrayOop(change->obj_at(index));
00791 
00792     if (!array->is_objArray())
00793       return markSymbol(vmSymbols::argument_is_invalid());
00794 
00795     if (array->length() < 3)      
00796       return markSymbol(vmSymbols::argument_is_invalid());
00797 
00798     if (!array->obj_at(1)->is_klass()) 
00799       return markSymbol(vmSymbols::argument_is_invalid());
00800 
00801     if (!array->obj_at(2)->is_symbol()) 
00802       return markSymbol(vmSymbols::argument_is_invalid());
00803 
00804     if (!array->obj_at(3)->is_klass() && array->obj_at(3) != nilObj) 
00805       return markSymbol(vmSymbols::argument_is_invalid());
00806 
00807     for (int j = 4; j <= array->length() - 1; j += 2) {
00808      if (!array->obj_at(j)->is_klass()) 
00809        return markSymbol(vmSymbols::argument_is_invalid());
00810      if (!array->obj_at(j+1)->is_symbol()) 
00811       return markSymbol(vmSymbols::argument_is_invalid());
00812     }
00813   }
00814 
00815   apply_change(new_mixin, old_mixin, change);
00816   return trueObj;
00817 }
00818 
00819 void Reflection::convert(oop* p) {
00820   oop obj = *p;
00821 
00822   if (!obj->is_mem())
00823     return;
00824 
00825   if (memOop(obj)->is_forwarded()) {
00826     Universe::store(p, memOop(obj)->forwardee());
00827     return;
00828   }
00829 
00830   if (memOop(obj)->klass()->klass_part()->is_marked_for_schema_change()) {
00831     Universe::store(p, convert_object(memOop(obj)));
00832   }
00833 }
00834 
00835 memOop Reflection::convert_object(memOop obj) {
00836   assert(obj->klass()->klass_part()->is_marked_for_schema_change(), "just checking");
00837   ClassChange* change = find_change_for(obj->klass());
00838   assert(change, "change must be present");
00839   return change->converter()->convert(obj);
00840 }

Generated on Mon Oct 9 13:37:25 2006 for Strongtalk VM by  doxygen 1.4.7