< 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 >