< prev index next >

src/hotspot/share/prims/jvmtiRedefineClasses.cpp

Print this page

        

@@ -681,10 +681,17 @@
   _operands_index_map_p = NULL;
   _operands_cur_length = 0;
   _operands_index_map_count = 0;
 } // end finalize_operands_merge()
 
+// Symbol* comparator for qsort
+// The caller must have an active ResourceMark.
+static int symcmp(const void* a, const void* b) {
+  char* astr = (*(Symbol**)a)->as_C_string();
+  char* bstr = (*(Symbol**)b)->as_C_string();
+  return strcmp(astr, bstr);
+}
 
 jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
              InstanceKlass* the_class,
              InstanceKlass* scratch_class) {
   int i;

@@ -723,10 +730,104 @@
   if (the_class->is_in_error_state()) {
     // TBD #5057930: special error code is needed in 1.6
     return JVMTI_ERROR_INVALID_CLASS;
   }
 
+  // Check whether the class NestHost attribute has been changed.
+  {
+    Thread* thread = Thread::current();
+    ResourceMark rm(thread);
+    JvmtiThreadState *state = JvmtiThreadState::state_for((JavaThread*)thread);
+    RedefineVerifyMark rvm(the_class, scratch_class, state);
+    u2 the_nest_host_idx = the_class->nest_host_index();
+    u2 scr_nest_host_idx = scratch_class->nest_host_index();
+
+    if (the_nest_host_idx != 0 && scr_nest_host_idx != 0) {
+      Symbol* the_sym = the_class->constants()->klass_name_at(the_nest_host_idx);
+      Symbol* scr_sym = scratch_class->constants()->klass_name_at(scr_nest_host_idx);
+      if (the_sym != scr_sym) {
+        log_trace(redefine, class, nestmates)
+          ("redefined class %s attribute change error: NestHost class: %s replaced with: %s",
+           the_class->external_name(), the_sym->as_C_string(), scr_sym->as_C_string());
+        return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
+      }
+    } else if ((the_nest_host_idx == 0) ^ (scr_nest_host_idx == 0)) {
+      const char* action_str = (the_nest_host_idx != 0) ? "removed" : "added";
+      log_trace(redefine, class, nestmates)
+        ("redefined class %s attribute change error: NestHost attribute %s",
+         the_class->external_name(), action_str);
+      return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
+    }
+
+    // Check whether the class NestMembers attribute has been changed.
+    Array<u2>* the_nest_members = the_class->nest_members();
+    Array<u2>* scr_nest_members = scratch_class->nest_members();
+    bool the_members_exists = the_nest_members != Universe::the_empty_short_array();
+    bool scr_members_exists = scr_nest_members != Universe::the_empty_short_array();
+
+    int members_len = the_nest_members->length();
+    if (the_members_exists && scr_members_exists) {
+      if (members_len != scr_nest_members->length()) {
+        log_trace(redefine, class, nestmates)
+          ("redefined class %s attribute change error: NestMember len=%d changed to len=%d",
+           the_class->external_name(), members_len, scr_nest_members->length());
+        return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
+      }
+
+      // The order of entries in the NestMembers array is not specified so we
+      // have to explicitly check for the same contents. We do this by copying
+      // the referenced symbols into their own arrays, sorting them and then
+      // comparing each element pair.
+
+      Symbol** the_syms = NEW_RESOURCE_ARRAY_RETURN_NULL(Symbol*, members_len);
+      Symbol** scr_syms = NEW_RESOURCE_ARRAY_RETURN_NULL(Symbol*, members_len);
+
+      if (the_syms == NULL || scr_syms == NULL) {
+        return JVMTI_ERROR_OUT_OF_MEMORY;
+      }
+
+      for (int i = 0; i < members_len; i++) {
+        int the_cp_index = the_nest_members->at(i);
+        int scr_cp_index = scr_nest_members->at(i);
+        the_syms[i] = the_class->constants()->klass_name_at(the_cp_index);
+        scr_syms[i] = scratch_class->constants()->klass_name_at(scr_cp_index);
+      }
+
+      qsort(the_syms, members_len, sizeof(Symbol*), symcmp);
+      qsort(scr_syms, members_len, sizeof(Symbol*), symcmp);
+
+      for (int i = 0; i < members_len; i++) {
+        if (the_syms[i] != scr_syms[i]) {
+          log_trace(redefine, class, nestmates)
+            ("redefined class %s attribute change error: NestMembers[%d]: %s changed to %s",
+             the_class->external_name(), i, the_syms[i]->as_C_string(), scr_syms[i]->as_C_string());
+          return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
+        }
+      }
+      /*
+      for (int i = 0; i < members_len; i++) {
+        int the_cp_index = the_nest_members->at(i);
+        int scr_cp_index = scr_nest_members->at(i);
+        Symbol* the_sym = the_class->constants()->klass_name_at(the_cp_index);
+        Symbol* scr_sym = scratch_class->constants()->klass_name_at(scr_cp_index);
+        if (the_sym != scr_sym) {
+          log_trace(redefine, class, nestmates)
+            ("redefined class %s attribute change error: NestMembers[%d]: %s changed to %s",
+             the_class->external_name(), i, the_sym->as_C_string(), scr_sym->as_C_string());
+          return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
+        }
+      }
+      */
+    } else if (the_members_exists ^ scr_members_exists) {
+      const char* action_str = (the_members_exists) ? "removed" : "added";
+      log_trace(redefine, class, nestmates)
+        ("redefined class %s attribute change error: NestMembers attribute %s",
+         the_class->external_name(), action_str);
+      return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
+    }
+  }
+
   // Check whether class modifiers are the same.
   jushort old_flags = (jushort) the_class->access_flags().get_flags();
   jushort new_flags = (jushort) scratch_class->access_flags().get_flags();
   if (old_flags != new_flags) {
     return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED;

@@ -1596,10 +1697,16 @@
 
 // Rewrite constant pool references in klass scratch_class.
 bool VM_RedefineClasses::rewrite_cp_refs(InstanceKlass* scratch_class,
        TRAPS) {
 
+  // rewrite constant pool references in the nest attributes:
+  if (!rewrite_cp_refs_in_nest_attributes(scratch_class)) {
+    // propagate failure back to caller
+    return false;
+  }
+
   // rewrite constant pool references in the methods:
   if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) {
     // propagate failure back to caller
     return false;
   }

@@ -1678,10 +1785,26 @@
   }
 
   return true;
 } // end rewrite_cp_refs()
 
+// Rewrite constant pool references in the NestHost and NestMembers attributes.
+bool VM_RedefineClasses::rewrite_cp_refs_in_nest_attributes(
+       InstanceKlass* scratch_class) {
+
+  u2 cp_index = scratch_class->nest_host_index();
+  if (cp_index != 0) {
+    scratch_class->set_nest_host_index(find_new_index(cp_index));
+  }
+  Array<u2>* nest_members = scratch_class->nest_members();
+  for (int i = 0; i < nest_members->length(); i++) {
+    u2 cp_index = nest_members->at(i);
+    nest_members->at_put(i, find_new_index(cp_index));
+  }
+  return true;
+}
+
 // Rewrite constant pool references in the methods.
 bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
        InstanceKlass* scratch_class, TRAPS) {
 
   Array<Method*>* methods = scratch_class->methods();
< prev index next >