src/share/vm/oops/klassVtable.cpp

changeset 1087
4aaa9f5e02a8
parent 1045
70998f2e05ef
child 1111
d3676b4cb78c
     1.1 --- a/src/share/vm/oops/klassVtable.cpp	Mon Mar 16 08:50:53 2009 -0400
     1.2 +++ b/src/share/vm/oops/klassVtable.cpp	Wed Mar 18 17:20:57 2009 -0400
     1.3 @@ -45,9 +45,10 @@
     1.4                                                         klassOop super,
     1.5                                                         objArrayOop methods,
     1.6                                                         AccessFlags class_flags,
     1.7 -                                                       oop classloader,
     1.8 -                                                       symbolOop classname,
     1.9 -                                                       objArrayOop local_interfaces
    1.10 +                                                       Handle classloader,
    1.11 +                                                       symbolHandle classname,
    1.12 +                                                       objArrayOop local_interfaces,
    1.13 +                                                       TRAPS
    1.14                                                         ) {
    1.15  
    1.16    No_Safepoint_Verifier nsv;
    1.17 @@ -64,9 +65,9 @@
    1.18    int len = methods->length();
    1.19    for (int i = 0; i < len; i++) {
    1.20      assert(methods->obj_at(i)->is_method(), "must be a methodOop");
    1.21 -    methodOop m = methodOop(methods->obj_at(i));
    1.22 +    methodHandle mh(THREAD, methodOop(methods->obj_at(i)));
    1.23  
    1.24 -    if (needs_new_vtable_entry(m, super, classloader, classname, class_flags)) {
    1.25 +    if (needs_new_vtable_entry(mh, super, classloader, classname, class_flags, THREAD)) {
    1.26        vtable_length += vtableEntry::size(); // we need a new entry
    1.27      }
    1.28    }
    1.29 @@ -117,6 +118,7 @@
    1.30      superVtable->copy_vtable_to(table());
    1.31  #ifndef PRODUCT
    1.32      if (PrintVtables && Verbose) {
    1.33 +      ResourceMark rm;
    1.34        tty->print_cr("copy vtable from %s to %s size %d", sk->internal_name(), klass()->internal_name(), _length);
    1.35      }
    1.36  #endif
    1.37 @@ -159,13 +161,13 @@
    1.38      int len = methods()->length();
    1.39      int initialized = super_vtable_len;
    1.40  
    1.41 -    // update_super_vtable can stop for gc - ensure using handles
    1.42 +    // update_inherited_vtable can stop for gc - ensure using handles
    1.43      for (int i = 0; i < len; i++) {
    1.44        HandleMark hm(THREAD);
    1.45        assert(methods()->obj_at(i)->is_method(), "must be a methodOop");
    1.46        methodHandle mh(THREAD, (methodOop)methods()->obj_at(i));
    1.47  
    1.48 -      bool needs_new_entry = update_super_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK);
    1.49 +      bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK);
    1.50  
    1.51        if (needs_new_entry) {
    1.52          put_method_at(mh(), initialized);
    1.53 @@ -177,7 +179,7 @@
    1.54      // add miranda methods; it will also update the value of initialized
    1.55      fill_in_mirandas(initialized);
    1.56  
    1.57 -    // In class hierachieswhere the accesibility is not increasing (i.e., going from private ->
    1.58 +    // In class hierarchies where the accessibility is not increasing (i.e., going from private ->
    1.59      // package_private -> publicprotected), the vtable might actually be smaller than our initial
    1.60      // calculation.
    1.61      assert(initialized <= _length, "vtable initialization failed");
    1.62 @@ -188,26 +190,49 @@
    1.63    }
    1.64  }
    1.65  
    1.66 -// Interates through the vtables to find the broadest access level. This
    1.67 -// will always be monotomic for valid Java programs - but not neccesarily
    1.68 -// for incompatible class files.
    1.69 -klassVtable::AccessType klassVtable::vtable_accessibility_at(int i) {
    1.70 -  // This vtable is not implementing the specific method
    1.71 -  if (i >= length()) return acc_private;
    1.72 +// Called for cases where a method does not override its superclass' vtable entry
    1.73 +// For bytecodes not produced by javac together it is possible that a method does not override
    1.74 +// the superclass's method, but might indirectly override a super-super class's vtable entry
    1.75 +// If none found, return a null superk, else return the superk of the method this does override
    1.76 +instanceKlass* klassVtable::find_transitive_override(instanceKlass* initialsuper, methodHandle target_method,
    1.77 +                            int vtable_index, Handle target_loader, symbolHandle target_classname, Thread * THREAD) {
    1.78 +  instanceKlass* superk = initialsuper;
    1.79 +  while (superk != NULL && superk->super() != NULL) {
    1.80 +    instanceKlass* supersuperklass = instanceKlass::cast(superk->super());
    1.81 +    klassVtable* ssVtable = supersuperklass->vtable();
    1.82 +    if (vtable_index < ssVtable->length()) {
    1.83 +      methodOop super_method = ssVtable->method_at(vtable_index);
    1.84 +#ifndef PRODUCT
    1.85 +      symbolHandle name(THREAD,target_method()->name());
    1.86 +      symbolHandle signature(THREAD,target_method()->signature());
    1.87 +      assert(super_method->name() == name() && super_method->signature() == signature(), "vtable entry name/sig mismatch");
    1.88 +#endif
    1.89 +      if (supersuperklass->is_override(super_method, target_loader, target_classname, THREAD)) {
    1.90 +#ifndef PRODUCT
    1.91 +        if (PrintVtables && Verbose) {
    1.92 +          ResourceMark rm(THREAD);
    1.93 +          tty->print("transitive overriding superclass %s with %s::%s index %d, original flags: ",
    1.94 +           supersuperklass->internal_name(),
    1.95 +           _klass->internal_name(), (target_method() != NULL) ?
    1.96 +           target_method()->name()->as_C_string() : "<NULL>", vtable_index);
    1.97 +           super_method->access_flags().print_on(tty);
    1.98 +           tty->print("overriders flags: ");
    1.99 +           target_method->access_flags().print_on(tty);
   1.100 +           tty->cr();
   1.101 +        }
   1.102 +#endif /*PRODUCT*/
   1.103 +        break; // return found superk
   1.104 +      }
   1.105 +    } else  {
   1.106 +      // super class has no vtable entry here, stop transitive search
   1.107 +      superk = (instanceKlass*)NULL;
   1.108 +      break;
   1.109 +    }
   1.110 +    // if no override found yet, continue to search up
   1.111 +    superk = instanceKlass::cast(superk->super());
   1.112 +  }
   1.113  
   1.114 -  // Compute AccessType for current method. public or protected we are done.
   1.115 -  methodOop m = method_at(i);
   1.116 -  if (m->is_protected() || m->is_public()) return acc_publicprotected;
   1.117 -
   1.118 -  AccessType acc = m->is_package_private() ? acc_package_private : acc_private;
   1.119 -
   1.120 -  // Compute AccessType for method in super classes
   1.121 -  klassOop super = klass()->super();
   1.122 -  AccessType super_acc = (super != NULL) ? instanceKlass::cast(klass()->super())->vtable()->vtable_accessibility_at(i)
   1.123 -                                         : acc_private;
   1.124 -
   1.125 -  // Merge
   1.126 -  return (AccessType)MAX2((int)acc, (int)super_acc);
   1.127 +  return superk;
   1.128  }
   1.129  
   1.130  
   1.131 @@ -215,7 +240,8 @@
   1.132  // OR return true if a new vtable entry is required
   1.133  // Only called for instanceKlass's, i.e. not for arrays
   1.134  // If that changed, could not use _klass as handle for klass
   1.135 -bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS) {
   1.136 +bool klassVtable::update_inherited_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len,
   1.137 +                  bool checkconstraints, TRAPS) {
   1.138    ResourceMark rm;
   1.139    bool allocate_new = true;
   1.140    assert(klass->oop_is_instance(), "must be instanceKlass");
   1.141 @@ -242,58 +268,35 @@
   1.142    }
   1.143  
   1.144    // private methods always have a new entry in the vtable
   1.145 +  // specification interpretation since classic has
   1.146 +  // private methods not overriding
   1.147    if (target_method()->is_private()) {
   1.148      return allocate_new;
   1.149    }
   1.150  
   1.151    // search through the vtable and update overridden entries
   1.152    // Since check_signature_loaders acquires SystemDictionary_lock
   1.153 -  // which can block for gc, once we are in this loop, use handles, not
   1.154 -  // unhandled oops unless they are reinitialized for each loop
   1.155 -  // handles for name, signature, klass, target_method
   1.156 -  // not for match_method, holder
   1.157 +  // which can block for gc, once we are in this loop, use handles
   1.158 +  // For classfiles built with >= jdk7, we now look for transitive overrides
   1.159  
   1.160    symbolHandle name(THREAD,target_method()->name());
   1.161    symbolHandle signature(THREAD,target_method()->signature());
   1.162 +  Handle target_loader(THREAD, _klass->class_loader());
   1.163 +  symbolHandle target_classname(THREAD, _klass->name());
   1.164    for(int i = 0; i < super_vtable_len; i++) {
   1.165 -    methodOop match_method = method_at(i);
   1.166 +    methodOop super_method = method_at(i);
   1.167      // Check if method name matches
   1.168 -    if (match_method->name() == name() && match_method->signature() == signature()) {
   1.169 +    if (super_method->name() == name() && super_method->signature() == signature()) {
   1.170  
   1.171 -      instanceKlass* holder = (THREAD, instanceKlass::cast(match_method->method_holder()));
   1.172 +      // get super_klass for method_holder for the found method
   1.173 +      instanceKlass* super_klass =  instanceKlass::cast(super_method->method_holder());
   1.174  
   1.175 -      // Check if the match_method is accessable from current class
   1.176 -
   1.177 -      bool same_package_init = false;
   1.178 -      bool same_package_flag = false;
   1.179 -      bool simple_match = match_method->is_public()  || match_method->is_protected();
   1.180 -      if (!simple_match) {
   1.181 -        same_package_init = true;
   1.182 -        same_package_flag = holder->is_same_class_package(_klass->class_loader(), _klass->name());
   1.183 -
   1.184 -        simple_match = match_method->is_package_private() && same_package_flag;
   1.185 -      }
   1.186 -      // match_method is the superclass' method. Note we can't override
   1.187 -      // and shouldn't access superclass' ACC_PRIVATE methods
   1.188 -      // (although they have been copied into our vtable)
   1.189 -      // A simple form of this statement is:
   1.190 -      // if ( (match_method->is_public()  || match_method->is_protected()) ||
   1.191 -      //    (match_method->is_package_private() && holder->is_same_class_package(klass->class_loader(), klass->name()))) {
   1.192 -      //
   1.193 -      // The complexity is introduced it avoid recomputing 'is_same_class_package' which is expensive.
   1.194 -      if (simple_match) {
   1.195 -        // Check if target_method and match_method has same level of accessibility. The accesibility of the
   1.196 -        // match method is the "most-general" visibility of all entries at it's particular vtable index for
   1.197 -        // all superclasses. This check must be done before we override the current entry in the vtable.
   1.198 -        AccessType at = vtable_accessibility_at(i);
   1.199 -        bool same_access = false;
   1.200 -
   1.201 -        if (  (at == acc_publicprotected && (target_method()->is_public() || target_method()->is_protected())
   1.202 -           || (at == acc_package_private && (target_method()->is_package_private() &&
   1.203 -                                            (( same_package_init && same_package_flag) ||
   1.204 -                                             (!same_package_init && holder->is_same_class_package(_klass->class_loader(), _klass->name()))))))) {
   1.205 -           same_access = true;
   1.206 -        }
   1.207 +      if ((super_klass->is_override(super_method, target_loader, target_classname, THREAD)) ||
   1.208 +      ((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION)
   1.209 +        && ((super_klass = find_transitive_override(super_klass, target_method, i, target_loader,
   1.210 +             target_classname, THREAD)) != (instanceKlass*)NULL))) {
   1.211 +        // overriding, so no new entry
   1.212 +        allocate_new = false;
   1.213  
   1.214          if (checkconstraints) {
   1.215          // Override vtable entry if passes loader constraint check
   1.216 @@ -302,15 +305,12 @@
   1.217          // have already made any needed loader constraints.
   1.218          // Since loader constraints are transitive, it is enough
   1.219          // to link to the first super, and we get all the others.
   1.220 -          symbolHandle signature(THREAD, target_method()->signature());
   1.221 -          Handle this_loader(THREAD, _klass->class_loader());
   1.222 -          instanceKlassHandle super_klass(THREAD, _klass->super());
   1.223            Handle super_loader(THREAD, super_klass->class_loader());
   1.224  
   1.225 -          if (this_loader() != super_loader()) {
   1.226 +          if (target_loader() != super_loader()) {
   1.227              ResourceMark rm(THREAD);
   1.228              char* failed_type_name =
   1.229 -              SystemDictionary::check_signature_loaders(signature, this_loader,
   1.230 +              SystemDictionary::check_signature_loaders(signature, target_loader,
   1.231                                                          super_loader, true,
   1.232                                                          CHECK_(false));
   1.233              if (failed_type_name != NULL) {
   1.234 @@ -320,7 +320,7 @@
   1.235                  "(instance of %s), have different Class objects for the type "
   1.236                  "%s used in the signature";
   1.237                char* sig = target_method()->name_and_sig_as_C_string();
   1.238 -              const char* loader1 = SystemDictionary::loader_name(this_loader());
   1.239 +              const char* loader1 = SystemDictionary::loader_name(target_loader());
   1.240                char* current = _klass->name()->as_C_string();
   1.241                const char* loader2 = SystemDictionary::loader_name(super_loader());
   1.242                size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) +
   1.243 @@ -331,59 +331,46 @@
   1.244                THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false);
   1.245              }
   1.246            }
   1.247 +       }
   1.248 +
   1.249 +        put_method_at(target_method(), i);
   1.250 +        target_method()->set_vtable_index(i);
   1.251 +#ifndef PRODUCT
   1.252 +        if (PrintVtables && Verbose) {
   1.253 +          tty->print("overriding with %s::%s index %d, original flags: ",
   1.254 +           _klass->internal_name(), (target_method() != NULL) ?
   1.255 +           target_method()->name()->as_C_string() : "<NULL>", i);
   1.256 +           super_method->access_flags().print_on(tty);
   1.257 +           tty->print("overriders flags: ");
   1.258 +           target_method->access_flags().print_on(tty);
   1.259 +           tty->cr();
   1.260          }
   1.261 -        put_method_at(target_method(), i);
   1.262 -
   1.263 -
   1.264 -        if (same_access) {
   1.265 -          // target and match has same accessiblity - share entry
   1.266 -          allocate_new = false;
   1.267 -          target_method()->set_vtable_index(i);
   1.268 +#endif /*PRODUCT*/
   1.269 +      } else {
   1.270 +        // allocate_new = true; default. We might override one entry,
   1.271 +        // but not override another. Once we override one, not need new
   1.272  #ifndef PRODUCT
   1.273 -          if (PrintVtables && Verbose) {
   1.274 -            AccessType targetacc;
   1.275 -            if (target_method()->is_protected() ||
   1.276 -                 target_method()->is_public()) {
   1.277 -               targetacc =  acc_publicprotected;
   1.278 -            } else {
   1.279 -              targetacc = target_method()->is_package_private() ? acc_package_private : acc_private;
   1.280 -            }
   1.281 -            tty->print_cr("overriding with %s::%s index %d, original flags: %x overriders flags: %x",
   1.282 -             _klass->internal_name(), (target_method() != NULL) ?
   1.283 -             target_method()->name()->as_C_string() : "<NULL>", i,
   1.284 -             at, targetacc);
   1.285 -          }
   1.286 +        if (PrintVtables && Verbose) {
   1.287 +          tty->print("NOT overriding with %s::%s index %d, original flags: ",
   1.288 +           _klass->internal_name(), (target_method() != NULL) ?
   1.289 +           target_method()->name()->as_C_string() : "<NULL>", i);
   1.290 +           super_method->access_flags().print_on(tty);
   1.291 +           tty->print("overriders flags: ");
   1.292 +           target_method->access_flags().print_on(tty);
   1.293 +           tty->cr();
   1.294 +        }
   1.295  #endif /*PRODUCT*/
   1.296 -        } else {
   1.297 -#ifndef PRODUCT
   1.298 -          if (PrintVtables && Verbose) {
   1.299 -            AccessType targetacc;
   1.300 -            if (target_method()->is_protected() ||
   1.301 -                 target_method()->is_public()) {
   1.302 -               targetacc =  acc_publicprotected;
   1.303 -            } else {
   1.304 -              targetacc = target_method()->is_package_private() ? acc_package_private : acc_private;
   1.305 -            }
   1.306 -            tty->print_cr("override %s %s::%s at index %d, original flags: %x overriders flags: %x",
   1.307 -            allocate_new ? "+ new" : "only",
   1.308 -            _klass->internal_name(), (target_method() != NULL) ?
   1.309 -            target_method()->name()->as_C_string() : "<NULL>", i,
   1.310 -            at, targetacc);
   1.311 -           }
   1.312 -#endif /*PRODUCT*/
   1.313 -        }
   1.314        }
   1.315      }
   1.316    }
   1.317    return allocate_new;
   1.318  }
   1.319  
   1.320 -
   1.321 -
   1.322  void klassVtable::put_method_at(methodOop m, int index) {
   1.323    assert(m->is_oop_or_null(), "Not an oop or null");
   1.324  #ifndef PRODUCT
   1.325    if (PrintVtables && Verbose) {
   1.326 +    ResourceMark rm;
   1.327      tty->print_cr("adding %s::%s at index %d", _klass->internal_name(),
   1.328        (m != NULL) ? m->name()->as_C_string() : "<NULL>", index);
   1.329    }
   1.330 @@ -397,19 +384,23 @@
   1.331  // by "classloader" and "classname".
   1.332  // NOTE: The logic used here is very similar to the one used for computing
   1.333  // the vtables indices for a method. We cannot directly use that function because,
   1.334 -// when the Universe is boostrapping, a super's vtable might not be initialized.
   1.335 -bool klassVtable::needs_new_vtable_entry(methodOop target_method,
   1.336 +// we allocate the instanceKlass at load time, and that requires that the
   1.337 +// superclass has been loaded.
   1.338 +// However, the vtable entries are filled in at link time, and therefore
   1.339 +// the superclass' vtable may not yet have been filled in.
   1.340 +bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
   1.341                                           klassOop super,
   1.342 -                                         oop classloader,
   1.343 -                                         symbolOop classname,
   1.344 -                                         AccessFlags class_flags) {
   1.345 -  if ((class_flags.is_final() || target_method->is_final()) ||
   1.346 +                                         Handle classloader,
   1.347 +                                         symbolHandle classname,
   1.348 +                                         AccessFlags class_flags,
   1.349 +                                         TRAPS) {
   1.350 +  if ((class_flags.is_final() || target_method()->is_final()) ||
   1.351        // a final method never needs a new entry; final methods can be statically
   1.352        // resolved and they have to be present in the vtable only if they override
   1.353        // a super's method, in which case they re-use its entry
   1.354 -      (target_method->is_static()) ||
   1.355 +      (target_method()->is_static()) ||
   1.356        // static methods don't need to be in vtable
   1.357 -      (target_method->name() ==  vmSymbols::object_initializer_name())
   1.358 +      (target_method()->name() ==  vmSymbols::object_initializer_name())
   1.359        // <init> is never called dynamically-bound
   1.360        ) {
   1.361      return false;
   1.362 @@ -421,55 +412,58 @@
   1.363    }
   1.364  
   1.365    // private methods always have a new entry in the vtable
   1.366 -  if (target_method->is_private()) {
   1.367 +  // specification interpretation since classic has
   1.368 +  // private methods not overriding
   1.369 +  if (target_method()->is_private()) {
   1.370      return true;
   1.371    }
   1.372  
   1.373    // search through the super class hierarchy to see if we need
   1.374    // a new entry
   1.375 -  symbolOop name = target_method->name();
   1.376 -  symbolOop signature = target_method->signature();
   1.377 +  ResourceMark rm;
   1.378 +  symbolOop name = target_method()->name();
   1.379 +  symbolOop signature = target_method()->signature();
   1.380    klassOop k = super;
   1.381 -  methodOop match_method = NULL;
   1.382 +  methodOop super_method = NULL;
   1.383    instanceKlass *holder = NULL;
   1.384 +  methodOop recheck_method =  NULL;
   1.385    while (k != NULL) {
   1.386      // lookup through the hierarchy for a method with matching name and sign.
   1.387 -    match_method = instanceKlass::cast(k)->lookup_method(name, signature);
   1.388 -    if (match_method == NULL) {
   1.389 +    super_method = instanceKlass::cast(k)->lookup_method(name, signature);
   1.390 +    if (super_method == NULL) {
   1.391        break; // we still have to search for a matching miranda method
   1.392      }
   1.393      // get the class holding the matching method
   1.394 -    holder = instanceKlass::cast(match_method->method_holder());
   1.395 -
   1.396 -    if (!match_method->is_static()) { // we want only instance method matches
   1.397 -      if ((target_method->is_public() || target_method->is_protected()) &&
   1.398 -          (match_method->is_public()  || match_method->is_protected())) {
   1.399 -        // target and match are public/protected; we do not need a new entry
   1.400 +    // make sure you use that class for is_override
   1.401 +    instanceKlass* superk = instanceKlass::cast(super_method->method_holder());
   1.402 +    // we want only instance method matches
   1.403 +    // pretend private methods are not in the super vtable
   1.404 +    // since we do override around them: e.g. a.m pub/b.m private/c.m pub,
   1.405 +    // ignore private, c.m pub does override a.m pub
   1.406 +    // For classes that were not javac'd together, we also do transitive overriding around
   1.407 +    // methods that have less accessibility
   1.408 +    if ((!super_method->is_static()) &&
   1.409 +       (!super_method->is_private())) {
   1.410 +      if (superk->is_override(super_method, classloader, classname, THREAD)) {
   1.411          return false;
   1.412 -      }
   1.413 -
   1.414 -      if (target_method->is_package_private() &&
   1.415 -          match_method->is_package_private() &&
   1.416 -          holder->is_same_class_package(classloader, classname)) {
   1.417 -        // target and match are P private; we do not need a new entry
   1.418 -        return false;
   1.419 +      // else keep looking for transitive overrides
   1.420        }
   1.421      }
   1.422  
   1.423 -    k = holder->super(); // haven't found a match yet; continue to look
   1.424 +    // Start with lookup result and continue to search up
   1.425 +    k = superk->super(); // haven't found an override match yet; continue to look
   1.426    }
   1.427  
   1.428    // if the target method is public or protected it may have a matching
   1.429    // miranda method in the super, whose entry it should re-use.
   1.430 -  if (target_method->is_public() || target_method->is_protected()) {
   1.431 -    instanceKlass *sk = instanceKlass::cast(super);
   1.432 -    if (sk->has_miranda_methods()) {
   1.433 -      if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) {
   1.434 -        return false;  // found a matching miranda; we do not need a new entry
   1.435 -      }
   1.436 +  // Actually, to handle cases that javac would not generate, we need
   1.437 +  // this check for all access permissions.
   1.438 +  instanceKlass *sk = instanceKlass::cast(super);
   1.439 +  if (sk->has_miranda_methods()) {
   1.440 +    if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) {
   1.441 +      return false;  // found a matching miranda; we do not need a new entry
   1.442      }
   1.443    }
   1.444 -
   1.445    return true; // found no match; we need a new entry
   1.446  }
   1.447  
   1.448 @@ -884,7 +878,7 @@
   1.449                                      _klass->name()->as_C_string());
   1.450  
   1.451  
   1.452 -    // Interate through all interfaces
   1.453 +    // Iterate through all interfaces
   1.454      int i;
   1.455      for(i = 0; i < num_interfaces; i++) {
   1.456        itableOffsetEntry* ioe = offset_entry(i);
   1.457 @@ -1012,6 +1006,7 @@
   1.458              new_method->name()->as_C_string(),
   1.459              new_method->signature()->as_C_string()));
   1.460          }
   1.461 +        break;
   1.462        }
   1.463        ime++;
   1.464      }

mercurial