< prev index next >

src/hotspot/share/classfile/verifier.cpp

Print this page

        

@@ -56,10 +56,11 @@
 #include "utilities/bytes.hpp"
 
 #define NOFAILOVER_MAJOR_VERSION                       51
 #define NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION  51
 #define STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION       52
+#define VALUETYPE_MAJOR_VERSION                        56
 #define MAX_ARRAY_DIMENSIONS 255
 
 // Access to external entry for VerifyClassCodes - old byte code verifier
 
 extern "C" {

@@ -240,11 +241,11 @@
   bool is_reflect = refl_magic_klass != NULL && klass->is_subtype_of(refl_magic_klass);
 
   return (should_verify_for(klass->class_loader(), should_verify_class) &&
     // return if the class is a bootstrapping class
     // or defineClass specified not to verify by default (flags override passed arg)
-    // We need to skip the following four for bootstraping
+    // We need to skip the following four for bootstrapping
     name != vmSymbols::java_lang_Object() &&
     name != vmSymbols::java_lang_Class() &&
     name != vmSymbols::java_lang_String() &&
     name != vmSymbols::java_lang_Throwable() &&
 

@@ -471,10 +472,17 @@
       ss->print("Expected stackmap frame at this location.");
       break;
     case BAD_STACKMAP:
       ss->print("Invalid stackmap specification.");
       break;
+    case WRONG_VALUE_TYPE:
+      ss->print("Type ");
+      _type.details(ss);
+      ss->print(" and type ");
+      _expected.details(ss);
+      ss->print(" must be identical value types.");
+      break;
     case UNKNOWN:
     default:
       ShouldNotReachHere();
       ss->print_cr("Unknown");
   }

@@ -565,14 +573,22 @@
   }
 }
 
 // Methods in ClassVerifier
 
+VerificationType reference_or_valuetype(InstanceKlass* klass) {
+  if (klass->is_value()) {
+    return VerificationType::valuetype_type(klass->name());
+  } else {
+    return VerificationType::reference_type(klass->name());
+  }
+}
+
 ClassVerifier::ClassVerifier(
     InstanceKlass* klass, TRAPS)
     : _thread(THREAD), _exception_type(NULL), _message(NULL), _klass(klass) {
-  _this_type = VerificationType::reference_type(klass->name());
+  _this_type = reference_or_valuetype(klass);
   // Create list to hold symbols in reference area.
   _symbols = new GrowableArray<Symbol*>(100, 0, NULL);
 }
 
 ClassVerifier::~ClassVerifier() {

@@ -958,11 +974,11 @@
         case Bytecodes::_aaload : {
           type = current_frame.pop_stack(
             VerificationType::integer_type(), CHECK_VERIFY(this));
           atype = current_frame.pop_stack(
             VerificationType::reference_check(), CHECK_VERIFY(this));
-          if (!atype.is_reference_array()) {
+          if (!atype.is_nonscalar_array()) {
             verify_error(ErrorContext::bad_type(bci,
                 current_frame.stack_top_ctx(),
                 TypeOrigin::implicit(VerificationType::reference_check())),
                 bad_type_msg, "aaload");
             return;

@@ -1132,11 +1148,11 @@
           type2 = current_frame.pop_stack(
             VerificationType::integer_type(), CHECK_VERIFY(this));
           atype = current_frame.pop_stack(
             VerificationType::reference_check(), CHECK_VERIFY(this));
           // more type-checking is done at runtime
-          if (!atype.is_reference_array()) {
+          if (!atype.is_nonscalar_array()) {
             verify_error(ErrorContext::bad_type(bci,
                 current_frame.stack_top_ctx(),
                 TypeOrigin::implicit(VerificationType::reference_check())),
                 bad_type_msg, "aastore");
             return;

@@ -1532,16 +1548,16 @@
             &current_frame, target, CHECK_VERIFY(this));
           no_control_flow = false; break;
         case Bytecodes::_if_acmpeq :
         case Bytecodes::_if_acmpne :
           current_frame.pop_stack(
-            VerificationType::reference_check(), CHECK_VERIFY(this));
+            VerificationType::nonscalar_check(), CHECK_VERIFY(this));
           // fall through
         case Bytecodes::_ifnull :
         case Bytecodes::_ifnonnull :
           current_frame.pop_stack(
-            VerificationType::reference_check(), CHECK_VERIFY(this));
+            VerificationType::nonscalar_check(), CHECK_VERIFY(this));
           target = bcs.dest();
           stackmap_table.check_jump_target
             (&current_frame, target, CHECK_VERIFY(this));
           no_control_flow = false; break;
         case Bytecodes::_goto :

@@ -1588,11 +1604,11 @@
           verify_return_value(return_type, type, bci,
                               &current_frame, CHECK_VERIFY(this));
           no_control_flow = true; break;
         case Bytecodes::_areturn :
           type = current_frame.pop_stack(
-            VerificationType::reference_check(), CHECK_VERIFY(this));
+            VerificationType::nonscalar_check(), CHECK_VERIFY(this));
           verify_return_value(return_type, type, bci,
                               &current_frame, CHECK_VERIFY(this));
           no_control_flow = true; break;
         case Bytecodes::_return :
           if (return_type != VerificationType::bogus_type()) {

@@ -1620,10 +1636,21 @@
         case Bytecodes::_putfield :
           // pass FALSE, operand can't be an array type for getfield/putfield.
           verify_field_instructions(
             &bcs, &current_frame, cp, false, CHECK_VERIFY(this));
           no_control_flow = false; break;
+        case Bytecodes::_withfield :
+          if (_klass->major_version() < VALUETYPE_MAJOR_VERSION) {
+            class_format_error(
+              "withfield not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          // pass FALSE, operand can't be an array type for withfield.
+          verify_field_instructions(
+            &bcs, &current_frame, cp, false, CHECK_VERIFY(this));
+          no_control_flow = false; break;
         case Bytecodes::_invokevirtual :
         case Bytecodes::_invokespecial :
         case Bytecodes::_invokestatic :
           verify_invoke_instructions(
             &bcs, code_length, &current_frame, (bci >= ex_min && bci < ex_max),

@@ -1649,10 +1676,32 @@
           }
           type = VerificationType::uninitialized_type(bci);
           current_frame.push_stack(type, CHECK_VERIFY(this));
           no_control_flow = false; break;
         }
+        case Bytecodes::_defaultvalue :
+        {
+          if (_klass->major_version() < VALUETYPE_MAJOR_VERSION) {
+            class_format_error(
+              "defaultvalue not supported by this class file version (%d.%d), class %s",
+              _klass->major_version(), _klass->minor_version(), _klass->external_name());
+            return;
+          }
+          index = bcs.get_index_u2();
+          verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
+          VerificationType ref_type = cp_index_to_type(index, cp, CHECK_VERIFY(this));
+          if (!ref_type.is_object()) {
+            verify_error(ErrorContext::bad_type(bci,
+                TypeOrigin::cp(index, ref_type)),
+                "Illegal defaultvalue instruction");
+            return;
+          }
+          VerificationType value_type =
+            VerificationType::change_ref_to_valuetype(ref_type);
+          current_frame.push_stack(value_type, CHECK_VERIFY(this));
+          no_control_flow = false; break;
+        }
         case Bytecodes::_newarray :
           type = get_newarray_type(bcs.get_index(), bci, CHECK_VERIFY(this));
           current_frame.pop_stack(
             VerificationType::integer_type(),  CHECK_VERIFY(this));
           current_frame.push_stack(type, CHECK_VERIFY(this));

@@ -1689,14 +1738,15 @@
           current_frame.push_stack(
             VerificationType::integer_type(), CHECK_VERIFY(this));
           no_control_flow = false; break;
         }
         case Bytecodes::_monitorenter :
-        case Bytecodes::_monitorexit :
-          current_frame.pop_stack(
+        case Bytecodes::_monitorexit : {
+          VerificationType ref = current_frame.pop_stack(
             VerificationType::reference_check(), CHECK_VERIFY(this));
           no_control_flow = false; break;
+        }
         case Bytecodes::_multianewarray :
         {
           index = bcs.get_index_u2();
           u2 dim = *(bcs.bcp()+3);
           verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));

@@ -1951,10 +2001,11 @@
   // We must check was_recursively_verified() before we get here.
   guarantee(cp->cache() == NULL, "not rewritten yet");
 
   verify_cp_index(bci, cp, index, CHECK_VERIFY(this));
   unsigned int tag = cp->tag_at(index).value();
+
   if ((types & (1 << tag)) == 0) {
     verify_error(ErrorContext::bad_cp_index(bci, index),
       "Illegal type at constant pool entry %d in class %s",
       index, cp->pool_holder()->external_name());
     return;

@@ -2251,10 +2302,11 @@
         TypeOrigin::cp(index, ref_class_type)),
         "Expecting reference to class in class %s at constant pool index %d",
         _klass->external_name(), index);
     return;
   }
+
   VerificationType target_class_type = ref_class_type;
 
   assert(sizeof(VerificationType) == sizeof(uintptr_t),
         "buffer type must match VerificationType size");
   uintptr_t field_type_buffer[2];

@@ -2281,10 +2333,29 @@
       for (int i = n - 1; i >= 0; i--) {
         current_frame->pop_stack(field_type[i], CHECK_VERIFY(this));
       }
       break;
     }
+    case Bytecodes::_withfield: {
+      for (int i = n - 1; i >= 0; i--) {
+        current_frame->pop_stack(field_type[i], CHECK_VERIFY(this));
+      }
+      // stack_object_type and target_class_type must be the same value type.
+      stack_object_type =
+        current_frame->pop_stack(VerificationType::valuetype_check(), CHECK_VERIFY(this));
+      VerificationType target_value_type =
+        VerificationType::change_ref_to_valuetype(target_class_type);
+      if (!stack_object_type.equals(target_value_type)) {
+        verify_error(ErrorContext::bad_value_type(bci,
+            current_frame->stack_top_ctx(),
+            TypeOrigin::cp(index, target_class_type)),
+            "Invalid type on operand stack in withfield instruction");
+        return;
+      }
+      current_frame->push_stack(target_value_type, CHECK_VERIFY(this));
+      break;
+    }
     case Bytecodes::_getfield: {
       stack_object_type = current_frame->pop_stack(
         target_class_type, CHECK_VERIFY(this));
       for (int i = 0; i < n; i++) {
         current_frame->push_stack(field_type[i], CHECK_VERIFY(this));

@@ -2724,11 +2795,11 @@
       "Invalid method signature in class %s referenced "
       "from constant pool index %d", _klass->external_name(), index);
     return;
   }
 
-  // Get referenced class type
+  // Get referenced class
   VerificationType ref_class_type;
   if (opcode == Bytecodes::_invokedynamic) {
     if (_klass->major_version() < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
       class_format_error(
         "invokedynamic instructions not supported by this class file version (%d), class %s",

@@ -2816,26 +2887,26 @@
       return;
     }
   } else if (opcode == Bytecodes::_invokespecial
              && !is_same_or_direct_interface(current_class(), current_type(), ref_class_type)
              && !ref_class_type.equals(VerificationType::reference_type(
-                  current_class()->super()->name()))) {
+                  current_class()->super()->name()))) { // super() can never be a value_type.
     bool subtype = false;
     bool have_imr_indirect = cp->tag_at(index).value() == JVM_CONSTANT_InterfaceMethodref;
     if (!current_class()->is_unsafe_anonymous()) {
       subtype = ref_class_type.is_assignable_from(
                  current_type(), this, false, CHECK_VERIFY(this));
     } else {
-      VerificationType unsafe_anonymous_host_type =
-                        VerificationType::reference_type(current_class()->unsafe_anonymous_host()->name());
+      InstanceKlass* unsafe_host = current_class()->unsafe_anonymous_host();
+      VerificationType unsafe_anonymous_host_type = reference_or_valuetype(unsafe_host);
       subtype = ref_class_type.is_assignable_from(unsafe_anonymous_host_type, this, false, CHECK_VERIFY(this));
 
       // If invokespecial of IMR, need to recheck for same or
       // direct interface relative to the host class
       have_imr_indirect = (have_imr_indirect &&
                            !is_same_or_direct_interface(
-                             current_class()->unsafe_anonymous_host(),
+                             unsafe_host,
                              unsafe_anonymous_host_type, ref_class_type));
     }
     if (!subtype) {
       verify_error(ErrorContext::bad_code(bci),
           "Bad invokespecial instruction: "

@@ -2869,13 +2940,14 @@
         } else {
           // anonymous class invokespecial calls: check if the
           // objectref is a subtype of the unsafe_anonymous_host of the current class
           // to allow an anonymous class to reference methods in the unsafe_anonymous_host
           VerificationType top = current_frame->pop_stack(CHECK_VERIFY(this));
-          VerificationType hosttype =
-            VerificationType::reference_type(current_class()->unsafe_anonymous_host()->name());
-          bool subtype = hosttype.is_assignable_from(top, this, false, CHECK_VERIFY(this));
+
+          InstanceKlass* unsafe_host = current_class()->unsafe_anonymous_host();
+          VerificationType host_type = reference_or_valuetype(unsafe_host);
+          bool subtype = host_type.is_assignable_from(top, this, false, CHECK_VERIFY(this));
           if (!subtype) {
             verify_error( ErrorContext::bad_type(current_frame->offset(),
               current_frame->stack_top_ctx(),
               TypeOrigin::implicit(top)),
               "Bad type on operand stack");

@@ -2984,14 +3056,15 @@
     arr_sig_str = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, length + 1);
     int n = os::snprintf(arr_sig_str, length + 1, "[%s", component_name);
     assert(n == length, "Unexpected number of characters in string");
   } else {         // it's an object or interface
     const char* component_name = component_type.name()->as_utf8();
-    // add one dimension to component with 'L' prepended and ';' postpended.
+    char Q_or_L = component_type.is_valuetype() ? 'Q' : 'L';
+    // add one dimension to component with 'L' or 'Q' prepended and ';' appended.
     length = (int)strlen(component_name) + 3;
     arr_sig_str = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, length + 1);
-    int n = os::snprintf(arr_sig_str, length + 1, "[L%s;", component_name);
+    int n = os::snprintf(arr_sig_str, length + 1, "[%c%s;", Q_or_L, component_name);
     assert(n == length, "Unexpected number of characters in string");
   }
   Symbol* arr_sig = create_temporary_symbol(
     arr_sig_str, length, CHECK_VERIFY(this));
   VerificationType new_array_type = VerificationType::reference_type(arr_sig);

@@ -3030,11 +3103,11 @@
     VerificationType::double2_type(), CHECK_VERIFY(this));
 }
 
 void ClassVerifier::verify_aload(u2 index, StackMapFrame* current_frame, TRAPS) {
   VerificationType type = current_frame->get_local(
-    index, VerificationType::reference_check(), CHECK_VERIFY(this));
+    index, VerificationType::nonscalar_check(), CHECK_VERIFY(this));
   current_frame->push_stack(type, CHECK_VERIFY(this));
 }
 
 void ClassVerifier::verify_istore(u2 index, StackMapFrame* current_frame, TRAPS) {
   current_frame->pop_stack(

@@ -3067,11 +3140,11 @@
     VerificationType::double2_type(), CHECK_VERIFY(this));
 }
 
 void ClassVerifier::verify_astore(u2 index, StackMapFrame* current_frame, TRAPS) {
   VerificationType type = current_frame->pop_stack(
-    VerificationType::reference_check(), CHECK_VERIFY(this));
+    VerificationType::nonscalar_check(), CHECK_VERIFY(this));
   current_frame->set_local(index, type, CHECK_VERIFY(this));
 }
 
 void ClassVerifier::verify_iinc(u2 index, StackMapFrame* current_frame, TRAPS) {
   VerificationType type = current_frame->get_local(
< prev index next >