示例#1
0
// Update child's copy of super vtable for overrides
// OR return true if a new vtable entry is required
// Only called for instanceKlass's, i.e. not for arrays
// If that changed, could not use _klass as handle for klass
bool klassVtable::update_inherited_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len,
                  bool checkconstraints, TRAPS) {
  ResourceMark rm;
  bool allocate_new = true;
  assert(klass->oop_is_instance(), "must be instanceKlass");

  // Initialize the method's vtable index to "nonvirtual".
  // If we allocate a vtable entry, we will update it to a non-negative number.
  target_method()->set_vtable_index(methodOopDesc::nonvirtual_vtable_index);

  // Static and <init> methods are never in
  if (target_method()->is_static() || target_method()->name() ==  vmSymbols::object_initializer_name()) {
    return false;
  }

  if (klass->is_final() || target_method()->is_final()) {
    // a final method never needs a new entry; final methods can be statically
    // resolved and they have to be present in the vtable only if they override
    // a super's method, in which case they re-use its entry
    allocate_new = false;
  }

  // we need a new entry if there is no superclass
  if (klass->super() == NULL) {
    return allocate_new;
  }

  // private methods always have a new entry in the vtable
  // specification interpretation since classic has
  // private methods not overriding
  if (target_method()->is_private()) {
    return allocate_new;
  }

  // search through the vtable and update overridden entries
  // Since check_signature_loaders acquires SystemDictionary_lock
  // which can block for gc, once we are in this loop, use handles
  // For classfiles built with >= jdk7, we now look for transitive overrides

  Symbol* name = target_method()->name();
  Symbol* signature = target_method()->signature();
  Handle target_loader(THREAD, _klass->class_loader());
  Symbol*  target_classname = _klass->name();
  for(int i = 0; i < super_vtable_len; i++) {
    methodOop super_method = method_at(i);
    // Check if method name matches
    if (super_method->name() == name && super_method->signature() == signature) {

      // get super_klass for method_holder for the found method
      instanceKlass* super_klass =  instanceKlass::cast(super_method->method_holder());

      if ((super_klass->is_override(super_method, target_loader, target_classname, THREAD)) ||
      ((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION)
        && ((super_klass = find_transitive_override(super_klass, target_method, i, target_loader,
             target_classname, THREAD)) != (instanceKlass*)NULL))) {
        // overriding, so no new entry
        allocate_new = false;

        if (checkconstraints) {
        // Override vtable entry if passes loader constraint check
        // if loader constraint checking requested
        // No need to visit his super, since he and his super
        // have already made any needed loader constraints.
        // Since loader constraints are transitive, it is enough
        // to link to the first super, and we get all the others.
          Handle super_loader(THREAD, super_klass->class_loader());

          if (target_loader() != super_loader()) {
            ResourceMark rm(THREAD);
            char* failed_type_name =
              SystemDictionary::check_signature_loaders(signature, target_loader,
                                                        super_loader, true,
                                                        CHECK_(false));
            if (failed_type_name != NULL) {
              const char* msg = "loader constraint violation: when resolving "
                "overridden method \"%s\" the class loader (instance"
                " of %s) of the current class, %s, and its superclass loader "
                "(instance of %s), have different Class objects for the type "
                "%s used in the signature";
              char* sig = target_method()->name_and_sig_as_C_string();
              const char* loader1 = SystemDictionary::loader_name(target_loader());
              char* current = _klass->name()->as_C_string();
              const char* loader2 = SystemDictionary::loader_name(super_loader());
              size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) +
                strlen(current) + strlen(loader2) + strlen(failed_type_name);
              char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
              jio_snprintf(buf, buflen, msg, sig, loader1, current, loader2,
                           failed_type_name);
              THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false);
            }
          }
       }

        put_method_at(target_method(), i);
        target_method()->set_vtable_index(i);
#ifndef PRODUCT
        if (PrintVtables && Verbose) {
          tty->print("overriding with %s::%s index %d, original flags: ",
           _klass->internal_name(), (target_method() != NULL) ?
           target_method()->name()->as_C_string() : "<NULL>", i);
           super_method->access_flags().print_on(tty);
           tty->print("overriders flags: ");
           target_method->access_flags().print_on(tty);
           tty->cr();
        }
#endif /*PRODUCT*/
      } else {
// Update child's copy of super vtable for overrides
// OR return true if a new vtable entry is required
// Only called for instanceKlass's, i.e. not for arrays
// If that changed, could not use _klass as handle for klass
bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS) {    
  ResourceMark rm;
  bool allocate_new = true;
  assert(klass->oop_is_instance(), "must be instanceKlass");

  // Initialize the method's vtable index to "nonvirtual".
  // If we allocate a vtable entry, we will update it to a non-negative number.
  target_method()->set_vtable_index(methodOopDesc::nonvirtual_vtable_index);

  // Static and <init> methods are never in 
  if (target_method()->is_static() || target_method()->name() ==  vmSymbols::object_initializer_name()) {
    return false;
  }

  if (klass->is_final() || target_method()->is_final()) {
    // a final method never needs a new entry; final methods can be statically
    // resolved and they have to be present in the vtable only if they override
    // a super's method, in which case they re-use its entry          
    allocate_new = false;
  }      

  // we need a new entry if there is no superclass
  if (klass->super() == NULL) {
    return allocate_new;
  }

  // private methods always have a new entry in the vtable
  if (target_method()->is_private()) {
    return allocate_new;
  }
  
  // search through the vtable and update overridden entries
  // Since check_signature_loaders acquires SystemDictionary_lock
  // which can block for gc, once we are in this loop, use handles, not
  // unhandled oops unless they are reinitialized for each loop
  // handles for name, signature, klass, target_method
  // not for match_method, holder
  
  symbolHandle name(THREAD,target_method()->name());
  symbolHandle signature(THREAD,target_method()->signature());    
  for(int i = 0; i < super_vtable_len; i++) {
    methodOop match_method = method_at(i);
    // Check if method name matches
    if (match_method->name() == name() && match_method->signature() == signature()) {
      
      instanceKlass* holder = (THREAD, instanceKlass::cast(match_method->method_holder()));

      // Check if the match_method is accessable from current class
      
      bool same_package_init = false;
      bool same_package_flag = false;
      bool simple_match = match_method->is_public()  || match_method->is_protected();
      if (!simple_match) {
        same_package_init = true;
        same_package_flag = holder->is_same_class_package(_klass->class_loader(), _klass->name());

        simple_match = match_method->is_package_private() && same_package_flag;
      }
      // match_method is the superclass' method. Note we can't override
      // and shouldn't access superclass' ACC_PRIVATE methods 
      // (although they have been copied into our vtable)
      // A simple form of this statement is:
      // if ( (match_method->is_public()  || match_method->is_protected()) ||
      //    (match_method->is_package_private() && holder->is_same_class_package(klass->class_loader(), klass->name()))) {
      //
      // The complexity is introduced it avoid recomputing 'is_same_class_package' which is expensive.
      if (simple_match) {      
        // Check if target_method and match_method has same level of accessibility. The accesibility of the
        // match method is the "most-general" visibility of all entries at it's particular vtable index for
        // all superclasses. This check must be done before we override the current entry in the vtable.
        AccessType at = vtable_accessibility_at(i);        
        bool same_access = false;

        if (  (at == acc_publicprotected && (target_method()->is_public() || target_method()->is_protected())) 
           || (at == acc_package_private && (target_method()->is_package_private() &&
                                            (( same_package_init && same_package_flag) ||
(!same_package_init&&holder->is_same_class_package(_klass->class_loader(),_klass->name())))))){
           same_access = true;
        }
        
        if (checkconstraints) {
        // Override vtable entry if passes loader constraint check
        // if loader constraint checking requested
        // No need to visit his super, since he and his super
        // have already made any needed loader constraints.
        // Since loader constraints are transitive, it is enough
        // to link to the first super, and we get all the others.
          symbolHandle signature(THREAD, target_method()->signature());
          Handle this_loader(THREAD, _klass->class_loader());
          instanceKlassHandle super_klass(THREAD, _klass->super());
          Handle super_loader(THREAD, super_klass->class_loader());

          if (this_loader() != super_loader()) {
	    ResourceMark rm(THREAD);
            char* failed_type_name = 
	      SystemDictionary::check_signature_loaders(signature, this_loader,
							super_loader, true, 
							CHECK_(false));
	    if (failed_type_name != NULL) {
	      const char* msg = "loader constraint violation: when resolving "
		"overridden method \"%s\" the class loader (instance"
		" of %s) of the current class, %s, and its superclass loader "
		"(instance of %s), have different Class objects for the type "
		"%s used in the signature";
	      char* sig = target_method()->name_and_sig_as_C_string();
	      const char* loader1 = SystemDictionary::loader_name(this_loader());
	      char* current = _klass->name()->as_C_string();
	      const char* loader2 = SystemDictionary::loader_name(super_loader());
	      size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + 
		strlen(current) + strlen(loader2) + strlen(failed_type_name);
	      char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
	      jio_snprintf(buf, buflen, msg, sig, loader1, current, loader2,
			   failed_type_name);
	      THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false);
	    }
          }
        }
        put_method_at(target_method(), i);


        if (same_access) {
          // target and match has same accessiblity - share entry  
          allocate_new = false;
          target_method()->set_vtable_index(i);
#ifndef PRODUCT
          if (PrintVtables && Verbose) {  
            AccessType targetacc; 
            if (target_method()->is_protected() || 
                 target_method()->is_public()) {
               targetacc =  acc_publicprotected;
            } else {
              targetacc = target_method()->is_package_private() ? acc_package_private : acc_private;
            }
            tty->print_cr("overriding with %s::%s index %d, original flags: %x overriders flags: %x", 
             _klass->internal_name(), (target_method() != NULL) ? 
             target_method()->name()->as_C_string() : "<NULL>", i,
             at, targetacc);
          }
#endif /*PRODUCT*/
        } else {
#ifndef PRODUCT
          if (PrintVtables && Verbose) {  
            AccessType targetacc; 
            if (target_method()->is_protected() || 
                 target_method()->is_public()) {
               targetacc =  acc_publicprotected;
            } else {
              targetacc = target_method()->is_package_private() ? acc_package_private : acc_private;
            }
            tty->print_cr("override %s %s::%s at index %d, original flags: %x overriders flags: %x", 
            allocate_new ? "+ new" : "only",
            _klass->internal_name(), (target_method() != NULL) ? 
            target_method()->name()->as_C_string() : "<NULL>", i,
            at, targetacc);
           }
#endif /*PRODUCT*/
        }
      }
    }