< prev index next >

src/hotspot/share/classfile/verificationType.hpp

Print this page

        

@@ -67,25 +67,28 @@
       ITEM_Long_2nd, ITEM_Double_2nd
     };
 
     // Enum for the _data field
     enum {
-      // Bottom two bits determine if the type is a reference, primitive,
-      // uninitialized or a query-type.
-      TypeMask           = 0x00000003,
+      // Bottom three bits determine if the type is a reference, value type,
+      // primitive, uninitialized or a query-type.
+      TypeMask           = 0x00000007,
 
       // Topmost types encoding
-      Reference          = 0x0,        // _sym contains the name
+      Reference          = 0x0,        // _sym contains the name of an object
       Primitive          = 0x1,        // see below for primitive list
       Uninitialized      = 0x2,        // 0x00ffff00 contains bci
       TypeQuery          = 0x3,        // Meta-types used for category testing
+      ValueType          = 0x4,        // _sym contains the name of a value type
 
       // Utility flags
       ReferenceFlag      = 0x00,       // For reference query types
       Category1Flag      = 0x01,       // One-word values
       Category2Flag      = 0x02,       // First word of a two-word value
       Category2_2ndFlag  = 0x04,       // Second word of a two-word value
+      ValueTypeFlag      = 0x08,       // For value type query types
+      NonScalarFlag      = 0x10,       // For either value type or reference queries
 
       // special reference values
       Null               = 0x00000000, // A reference with a 0 sym is null
 
       // Primitives categories (the second byte determines the category)

@@ -113,11 +116,13 @@
 
       // Query values
       ReferenceQuery     = (ReferenceFlag     << 1 * BitsPerByte) | TypeQuery,
       Category1Query     = (Category1Flag     << 1 * BitsPerByte) | TypeQuery,
       Category2Query     = (Category2Flag     << 1 * BitsPerByte) | TypeQuery,
-      Category2_2ndQuery = (Category2_2ndFlag << 1 * BitsPerByte) | TypeQuery
+      Category2_2ndQuery = (Category2_2ndFlag << 1 * BitsPerByte) | TypeQuery,
+      ValueTypeQuery     = (ValueTypeFlag     << 1 * BitsPerByte) | TypeQuery,
+      NonScalarQuery     = (NonScalarFlag     << 1 * BitsPerByte) | TypeQuery
     };
 
   VerificationType(uintptr_t raw_data) {
     _u._data = raw_data;
   }

@@ -146,30 +151,45 @@
   // to anything, but the specified types are assignable to a "check".  For
   // example, any category1 primitive is assignable to category1_check and
   // any reference is assignable to reference_check.
   static VerificationType reference_check()
     { return VerificationType(ReferenceQuery); }
+  static VerificationType valuetype_check()
+    { return VerificationType(ValueTypeQuery); }
   static VerificationType category1_check()
     { return VerificationType(Category1Query); }
   static VerificationType category2_check()
     { return VerificationType(Category2Query); }
   static VerificationType category2_2nd_check()
     { return VerificationType(Category2_2ndQuery); }
+  static VerificationType nonscalar_check()
+    { return VerificationType(NonScalarQuery); }
 
   // For reference types, store the actual Symbol
   static VerificationType reference_type(Symbol* sh) {
-      assert(((uintptr_t)sh & 0x3) == 0, "Symbols must be aligned");
+      assert(((uintptr_t)sh & TypeMask) == 0, "Symbols must be aligned");
       // If the above assert fails in the future because oop* isn't aligned,
       // then this type encoding system will have to change to have a tag value
       // to descriminate between oops and primitives.
       return VerificationType((uintptr_t)sh);
   }
   static VerificationType uninitialized_type(u2 bci)
     { return VerificationType(bci << 1 * BitsPerByte | Uninitialized); }
   static VerificationType uninitialized_this_type()
     { return uninitialized_type(BciForThis); }
 
+  // For value types, store the actual Symbol* and set the 3rd bit.
+  // Provides a way for a value type to be distinguished from a reference type.
+  static VerificationType valuetype_type(Symbol* sh) {
+      assert(((uintptr_t)sh & TypeMask) == 0, "Symbols must be aligned");
+      assert((uintptr_t)sh != 0, "Null is not a valid value type");
+      // If the above assert fails in the future because oop* isn't aligned,
+      // then this type encoding system will have to change to have a tag value
+      // to descriminate between oops and primitives.
+      return VerificationType((uintptr_t)sh | ValueType);
+  }
+
   // Create based on u1 read from classfile
   static VerificationType from_tag(u1 tag);
 
   bool is_bogus() const     { return (_u._data == Bogus); }
   bool is_null() const      { return (_u._data == Null); }

@@ -181,15 +201,16 @@
   bool is_long() const      { return (_u._data == Long); }
   bool is_float() const     { return (_u._data == Float); }
   bool is_double() const    { return (_u._data == Double); }
   bool is_long2() const     { return (_u._data == Long_2nd); }
   bool is_double2() const   { return (_u._data == Double_2nd); }
-  bool is_reference() const { return ((_u._data & TypeMask) == Reference); }
+  bool is_reference() const { return (((_u._data & TypeMask) == Reference) && !is_valuetype_check()); }
+  bool is_valuetype() const { return ((_u._data & TypeMask) == ValueType); }
   bool is_category1() const {
     // This should return true for all one-word types, which are category1
-    // primitives, and references (including uninitialized refs).  Though
-    // the 'query' types should technically return 'false' here, if we
+    // primitives, references (including uninitialized refs) and value types.
+    // Though the 'query' types should technically return 'false' here, if we
     // allow this to return true, we can perform the test using only
     // 2 operations rather than 8 (3 masks, 3 compares and 2 logical 'ands').
     // Since noone should call this on a query type anyway, this is ok.
     assert(!is_check(), "Must not be a check type (wrong value returned)");
     return ((_u._data & Category1) != Primitive);

@@ -199,10 +220,12 @@
   bool is_category2() const { return ((_u._data & Category2) == Category2); }
   bool is_category2_2nd() const {
     return ((_u._data & Category2_2nd) == Category2_2nd);
   }
   bool is_reference_check() const { return _u._data == ReferenceQuery; }
+  bool is_valuetype_check() const { return _u._data == ValueTypeQuery; }
+  bool is_nonscalar_check() const { return _u._data == NonScalarQuery; }
   bool is_category1_check() const { return _u._data == Category1Query; }
   bool is_category2_check() const { return _u._data == Category2Query; }
   bool is_category2_2nd_check() const { return _u._data == Category2_2ndQuery; }
   bool is_check() const { return (_u._data & TypeQuery) == TypeQuery; }
 

@@ -216,13 +239,16 @@
   bool is_short_array() const { return is_x_array('S'); }
   bool is_long_array() const { return is_x_array('J'); }
   bool is_float_array() const { return is_x_array('F'); }
   bool is_double_array() const { return is_x_array('D'); }
   bool is_object_array() const { return is_x_array('L'); }
+  bool is_value_array() const { return is_x_array('Q'); }
   bool is_array_array() const { return is_x_array('['); }
   bool is_reference_array() const
     { return is_object_array() || is_array_array(); }
+  bool is_nonscalar_array() const
+    { return is_object_array() || is_array_array() || is_value_array(); }
   bool is_object() const
     { return (is_reference() && !is_null() && name()->utf8_length() >= 1 &&
               name()->char_at(0) != '['); }
   bool is_array() const
     { return (is_reference() && !is_null() && name()->utf8_length() >= 2 &&

@@ -235,24 +261,32 @@
   VerificationType to_category2_2nd() const {
     assert(is_category2(), "Must be a double word");
     return VerificationType(is_long() ? Long_2nd : Double_2nd);
   }
 
+  static VerificationType change_ref_to_valuetype(VerificationType ref) {
+    assert(ref.is_reference(), "Bad arg");
+    assert(!ref.is_null(), "Unexpected NULL");
+    return valuetype_type(ref.name());
+  }
+
   u2 bci() const {
     assert(is_uninitialized(), "Must be uninitialized type");
     return ((_u._data & BciMask) >> 1 * BitsPerByte);
   }
 
   Symbol* name() const {
-    assert(is_reference() && !is_null(), "Must be a non-null reference");
-    return _u._sym;
+    assert(!is_null() && (is_reference() || is_valuetype()), "Must be a non-null reference or a value type");
+    return (is_reference() ? _u._sym : ((Symbol*)(_u._data & ~(uintptr_t)ValueType)));
   }
 
   bool equals(const VerificationType& t) const {
     return (_u._data == t._u._data ||
-      (is_reference() && t.is_reference() && !is_null() && !t.is_null() &&
-       name() == t.name()));
+            (((is_reference() && t.is_reference()) ||
+             (is_valuetype() && t.is_valuetype())) &&
+              !is_null() && !t.is_null() && name() == t.name()));
+
   }
 
   bool operator ==(const VerificationType& t) const {
     return equals(t);
   }

@@ -277,18 +311,27 @@
           return from.is_category2();
         case Category2_2ndQuery:
           return from.is_category2_2nd();
         case ReferenceQuery:
           return from.is_reference() || from.is_uninitialized();
+        case NonScalarQuery:
+          return from.is_reference() || from.is_uninitialized() ||
+                 from.is_valuetype();
+        case ValueTypeQuery:
+          return from.is_valuetype();
         case Boolean:
         case Byte:
         case Char:
         case Short:
           // An int can be assigned to boolean, byte, char or short values.
           return from.is_integer();
         default:
-          if (is_reference() && from.is_reference()) {
+          if (is_valuetype()) {
+            return is_valuetype_assignable_from(from);
+          } else if (is_reference() && from.is_valuetype()) {
+            return is_ref_assignable_from_value_type(from, context, THREAD);
+          } else if (is_reference() && from.is_reference()) {
             return is_reference_assignable_from(from, context,
                                                 from_field_is_protected,
                                                 THREAD);
           } else {
             return false;

@@ -332,10 +375,15 @@
 
   bool is_reference_assignable_from(
     const VerificationType&, ClassVerifier*, bool from_field_is_protected,
     TRAPS) const;
 
+  bool is_valuetype_assignable_from(const VerificationType& from) const;
+
+  bool is_ref_assignable_from_value_type(const VerificationType& from, ClassVerifier* context, TRAPS) const;
+
+
  public:
   static bool resolve_and_check_assignability(InstanceKlass* klass, Symbol* name,
                                               Symbol* from_name, bool from_field_is_protected,
                                               bool from_is_array, bool from_is_object,
                                               TRAPS);
< prev index next >