src/share/vm/classfile/classFileParser.cpp

Print this page
rev 3 : [mq]: anonk.patch

@@ -165,15 +165,27 @@
           u1* utf8_buffer = cfs->get_u1_buffer();
           assert(utf8_buffer != NULL, "null utf8 buffer");
           // Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward.
           cfs->guarantee_more(utf8_length+1, CHECK);  // utf8 string, tag/access_flags
           cfs->skip_u1_fast(utf8_length);
+
           // Before storing the symbol, make sure it's legal
           if (_need_verify) {
             verify_legal_utf8((unsigned char*)utf8_buffer, utf8_length, CHECK);
           }
 
+          if (has_cp_patch_at(index)) {
+            Handle patch = clear_cp_patch_at(index);
+            guarantee_property(java_lang_String::is_instance(patch()),
+                               "Illegal utf8 patch at %d in class file %s",
+                               index, CHECK);
+            char* str = java_lang_String::as_utf8_string(patch());
+            // (could use java_lang_String::as_symbol instead, but might as well batch them)
+            utf8_buffer = (u1*) str;
+            utf8_length = strlen(str);
+          }
+
           unsigned int hash;
           symbolOop result = SymbolTable::lookup_only((char*)utf8_buffer, utf8_length, hash);
           if (result == NULL) {
             names[names_count] = (char*)utf8_buffer;
             lengths[names_count] = utf8_length;

@@ -298,12 +310,18 @@
           check_property(
             valid_cp_range(class_index, length) &&
               cp->tag_at(class_index).is_utf8(),
             "Invalid constant pool index %u in class file %s",
             class_index, CHECK_(nullHandle));
-          cp->unresolved_klass_at_put(index, cp->symbol_at(class_index));
+          symbolOop name = cp->symbol_at(class_index);
+          klassOop  wkk  = SystemDictionary::find_well_known_klass(name);
+          if (wkk != NULL) {
+            cp->klass_at_put(index, wkk); // eagerly resolve
+          } else {
+            cp->unresolved_klass_at_put(index, name);
         }
+        }
         break;
       case JVM_CONSTANT_UnresolvedString :
         ShouldNotReachHere();     // Only JVM_CONSTANT_StringIndex should be present
         break;
       case JVM_CONSTANT_StringIndex :

@@ -323,20 +341,49 @@
         ShouldNotReachHere();
         break;
     } // end of switch
   } // end of for
 
+  if (_cp_patches != NULL) {
+    // need to treat this_class specially...
+    int this_class_index;
+    {
+      cfs->guarantee_more(8, CHECK_(nullHandle));  // flags, this_class, super_class, infs_len
+      u1* mark = cfs->current();
+      u2 flags         = cfs->get_u2_fast();
+      this_class_index = cfs->get_u2_fast();
+      cfs->set_current(mark);  // revert to mark
+    }
+
+    for (index = 1; index < length; index++) {          // Index 0 is unused
+      if (has_cp_patch_at(index)) {
+        guarantee_property(index != this_class_index,
+                           "Illegal constant pool patch to self at %d in class file %s",
+                           index, CHECK_(nullHandle));
+        patch_constant_pool(cp, index, cp_patch_at(index), CHECK_(nullHandle));
+      }
+    }
+    // Ensure that all the patches have been used.
+    for (index = 0; index < _cp_patches->length(); index++) {
+      guarantee_property(!has_cp_patch_at(index),
+                         "Unused constant pool patch at %d in class file %s",
+                         index, CHECK_(nullHandle));
+    }
+  }
+
   if (!_need_verify) {
     return cp;
   }
 
   // second verification pass - checks the strings are of the right format.
+  // but not yet to the other entries
   for (index = 1; index < length; index++) {
     jbyte tag = cp->tag_at(index).value();
     switch (tag) {
       case JVM_CONSTANT_UnresolvedClass: {
         symbolHandle class_name(THREAD, cp->unresolved_klass_at(index));
+        // check the name, even if _cp_patches will overwrite it
         verify_legal_class_name(class_name, CHECK_(nullHandle));
         break;
       }
       case JVM_CONSTANT_Fieldref:
       case JVM_CONSTANT_Methodref:

@@ -375,10 +422,68 @@
 
   return cp;
 }
 
 
+void ClassFileParser::patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS) {
+  BasicType patch_type = T_VOID;
+  switch (cp->tag_at(index).value()) {
+
+  case JVM_CONSTANT_UnresolvedClass :
+    // Patching a class means pre-resolving it.
+    // The name in the constant pool is ignored.
+    guarantee_property(java_lang_Class::is_instance(patch())
+                       && !java_lang_Class::is_primitive(patch()),
+                       "Illegal class patch at %d in class file %s",
+                       index, CHECK);
+    cp->klass_at_put(index, java_lang_Class::as_klassOop(patch()));
+    break;
+
+  case JVM_CONSTANT_UnresolvedString :
+    // Patching a string means pre-resolving it.
+    // The spelling in the constant pool is ignored.
+    // The constant reference may be any object whatever.
+    // If it is not a real string, the constant is referred to
+    // as a "pseudo-string".
+    cp->string_at_put(index, patch());
+    break;
+
+  case JVM_CONSTANT_Integer : patch_type = T_INT;    goto patch_prim;
+  case JVM_CONSTANT_Float :   patch_type = T_FLOAT;  goto patch_prim;
+  case JVM_CONSTANT_Long :    patch_type = T_LONG;   goto patch_prim;
+  case JVM_CONSTANT_Double :  patch_type = T_DOUBLE; goto patch_prim;
+  patch_prim:
+    {
+      jvalue value;
+      BasicType value_type = java_lang_boxing_object::get_value(patch(), &value);
+      guarantee_property(value_type == patch_type,
+                         "Illegal primitive patch at %d in class file %s",
+                         index, CHECK);
+      switch (value_type) {
+      case T_INT:    cp->int_at_put(index,   value.i); break;
+      case T_FLOAT:  cp->float_at_put(index, value.f); break;
+      case T_LONG:   cp->long_at_put(index,  value.j); break;
+      case T_DOUBLE: cp->long_at_put(index,  value.d); break;
+      default:       assert(false, "");
+      }
+    }
+    break;
+
+  default:
+    // %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc.
+    guarantee_property(!has_cp_patch_at(index),
+                       "Illegal unexpected patch at %d in class file %s",
+                       index, CHECK);
+    return;
+  } 
+
+  // On fall-through, mark the patch as used.
+  clear_cp_patch_at(index);
+}
+
+
+
 class NameSigHash: public ResourceObj {
  public:
   symbolOop     _name;       // name
   symbolOop     _sig;        // signature
   NameSigHash*  _next;       // Next entry in hash table

@@ -445,15 +550,19 @@
   objArrayHandle interfaces (THREAD, interface_oop);
 
   int index;
   for (index = 0; index < length; index++) {
     u2 interface_index = cfs->get_u2(CHECK_(nullHandle));
+    KlassHandle interf;
     check_property(
       valid_cp_range(interface_index, cp->length()) &&
-        cp->tag_at(interface_index).is_unresolved_klass(),
+        cp->tag_at(interface_index).is_klass_reference(),
       "Interface name has bad constant pool index %u in class file %s",
       interface_index, CHECK_(nullHandle));
+    if (cp->tag_at(interface_index).is_klass()) {
+      interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index));
+    } else {
     symbolHandle unresolved_klass (THREAD, cp->klass_name_at(interface_index));
 
     // Don't need to check legal name because it's checked when parsing constant pool.
     // But need to make sure it's not an array type.
     guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY,

@@ -462,13 +571,16 @@
     vmtimer->suspend();  // do not count recursive loading twice
     // Call resolve_super so classcircularity is checked
     klassOop k = SystemDictionary::resolve_super_or_fail(class_name,
                   unresolved_klass, class_loader, protection_domain,
                   false, CHECK_(nullHandle));
-    KlassHandle interf (THREAD, k);
+      interf = KlassHandle(THREAD, k);
     vmtimer->resume();
 
+      cp->klass_at_put(interface_index, interf()); // eagerly resolve
+    }
+
     if (!Klass::cast(interf())->is_interface()) {
       THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", nullHandle);
     }
     interfaces->obj_at_put(index, interf());
   }

@@ -874,12 +986,11 @@
                          "Illegal exception table range in class file %s", CHECK_(nullHandle));
       guarantee_property(handler_pc < code_length,
                          "Illegal exception table handler in class file %s", CHECK_(nullHandle));
       if (catch_type_index != 0) {
         guarantee_property(valid_cp_range(catch_type_index, cp->length()) &&
-                          (cp->tag_at(catch_type_index).is_klass() ||
-                           cp->tag_at(catch_type_index).is_unresolved_klass()),
+                           cp->tag_at(catch_type_index).is_klass_reference(),
                            "Catch type in exception table has bad constant type in class file %s", CHECK_(nullHandle));
       }
     }
     exception_handlers->int_at_put(index++, start_pc);
     exception_handlers->int_at_put(index++, end_pc);

@@ -1114,11 +1225,11 @@
     if (tag == ITEM_Long || tag == ITEM_Double) {
       index++;
     } else if (tag == ITEM_Object) {
       u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK);
       guarantee_property(valid_cp_range(class_index, cp->length()) &&
-                         cp->tag_at(class_index).is_unresolved_klass(),
+                         cp->tag_at(class_index).is_klass_reference(),
                          "Bad class index %u in StackMap in class file %s",
                          class_index, CHECK);
     } else if (tag == ITEM_Uninitialized) {
       u2 offset = u2_array[i2++] = cfs->get_u2(CHECK);
       guarantee_property(

@@ -2337,10 +2448,11 @@
 
 
 instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
                                                     Handle class_loader,
                                                     Handle protection_domain,
+                                                    GrowableArray<Handle>* cp_patches,
                                                     symbolHandle& parsed_name,
                                                     TRAPS) {
   // So that JVMTI can cache class file in the state before retransformable agents
   // have modified it
   unsigned char *cached_class_file_bytes = NULL;

@@ -2368,10 +2480,11 @@
       cfs = new ClassFileStream(ptr, end_ptr - ptr, cfs->source());
       set_stream(cfs);
     }
   }
 
+  _cp_patches = cp_patches;
 
   instanceKlassHandle nullHandle;
 
   // Figure out whether we can skip format checking (matching classic VM behavior)
   _need_verify = Verifier::should_verify_for(class_loader());

@@ -2498,18 +2611,26 @@
                      "Invalid superclass index %u in class file %s",
                      super_class_index,
                      CHECK_(nullHandle));
     } else {
       check_property(valid_cp_range(super_class_index, cp_size) &&
-                     cp->tag_at(super_class_index).is_unresolved_klass(),
+                     cp->tag_at(super_class_index).is_klass_reference(),
                      "Invalid superclass index %u in class file %s",
                      super_class_index,
                      CHECK_(nullHandle));
       // The class name should be legal because it is checked when parsing constant pool.
       // However, make sure it is not an array type.
+      bool is_array = false;
+      if (cp->tag_at(super_class_index).is_klass()) {
+        super_klass = instanceKlassHandle(THREAD, cp->resolved_klass_at(super_class_index));
+        if (_need_verify)
+          is_array = super_klass->oop_is_array();
+      } else if (_need_verify) {
+        is_array = (cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY);
+      }
       if (_need_verify) {
-        guarantee_property(cp->unresolved_klass_at(super_class_index)->byte_at(0) != JVM_SIGNATURE_ARRAY,
+        guarantee_property(!is_array,
                           "Bad superclass name in class file %s", CHECK_(nullHandle));
       }
     }
 
     // Interfaces

@@ -2545,11 +2666,11 @@
     objArrayHandle methods_annotations(THREAD, methods_annotations_oop);
     objArrayHandle methods_parameter_annotations(THREAD, methods_parameter_annotations_oop);
     objArrayHandle methods_default_annotations(THREAD, methods_default_annotations_oop);
 
     // We check super class after class file is parsed and format is checked
-    if (super_class_index > 0) {
+    if (super_class_index > 0 && super_klass.is_null()) {
       symbolHandle sk (THREAD, cp->klass_name_at(super_class_index));
       if (access_flags.is_interface()) {
         // Before attempting to resolve the superclass, check for class format
         // errors not checked yet.
         guarantee_property(sk() == vmSymbols::java_lang_Object(),

@@ -2562,10 +2683,13 @@
                                                            protection_domain,
                                                            true,
                                                            CHECK_(nullHandle));
       KlassHandle kh (THREAD, k);
       super_klass = instanceKlassHandle(THREAD, kh());
+      cp->klass_at_put(super_class_index, super_klass()); // eagerly resolve
+    }
+    if (super_klass.not_null()) {
       if (super_klass->is_interface()) {
         ResourceMark rm(THREAD);
         Exceptions::fthrow(
           THREAD_AND_LOCATION,
           vmSymbolHandles::java_lang_IncompatibleClassChangeError(),

@@ -2971,10 +3095,11 @@
       this_klass->set_has_final_method();
     }
     this_klass->set_method_ordering(method_ordering());
     this_klass->set_initial_method_idnum(methods->length());
     this_klass->set_name(cp->klass_name_at(this_class_index));
+    cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
     this_klass->set_protection_domain(protection_domain());
     this_klass->set_fields_annotations(fields_annotations());
     this_klass->set_methods_annotations(methods_annotations());
     this_klass->set_methods_parameter_annotations(methods_parameter_annotations());
     this_klass->set_methods_default_annotations(methods_default_annotations());