duke@435: /* stefank@2314: * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #ifndef SHARE_VM_CLASSFILE_VERIFICATIONTYPE_HPP stefank@2314: #define SHARE_VM_CLASSFILE_VERIFICATIONTYPE_HPP stefank@2314: stefank@2314: #include "classfile/systemDictionary.hpp" stefank@2314: #include "memory/allocation.hpp" stefank@2314: #include "oops/instanceKlass.hpp" stefank@2314: #include "oops/oop.inline.hpp" coleenp@2497: #include "oops/symbol.hpp" stefank@2314: #include "runtime/handles.hpp" stefank@2314: #include "runtime/signature.hpp" stefank@2314: duke@435: enum { duke@435: // As specifed in the JVM spec duke@435: ITEM_Top = 0, duke@435: ITEM_Integer = 1, duke@435: ITEM_Float = 2, duke@435: ITEM_Double = 3, duke@435: ITEM_Long = 4, duke@435: ITEM_Null = 5, duke@435: ITEM_UninitializedThis = 6, duke@435: ITEM_Object = 7, duke@435: ITEM_Uninitialized = 8, duke@435: ITEM_Bogus = (uint)-1 duke@435: }; duke@435: coleenp@2497: class ClassVerifier; coleenp@2497: duke@435: class VerificationType VALUE_OBJ_CLASS_SPEC { duke@435: private: duke@435: // Least significant bits of _handle are always 0, so we use these as duke@435: // the indicator that the _handle is valid. Otherwise, the _data field duke@435: // contains encoded data (as specified below). Should the VM change duke@435: // and the lower bits on oops aren't 0, the assert in the constructor duke@435: // will catch this and we'll have to add a descriminator tag to this duke@435: // structure. duke@435: union { coleenp@2497: Symbol* _sym; duke@435: uintptr_t _data; duke@435: } _u; duke@435: duke@435: enum { duke@435: // These rest are not found in classfiles, but used by the verifier duke@435: ITEM_Boolean = 9, ITEM_Byte, ITEM_Short, ITEM_Char, duke@435: ITEM_Long_2nd, ITEM_Double_2nd duke@435: }; duke@435: duke@435: // Enum for the _data field duke@435: enum { duke@435: // Bottom two bits determine if the type is a reference, primitive, duke@435: // uninitialized or a query-type. duke@435: TypeMask = 0x00000003, duke@435: duke@435: // Topmost types encoding coleenp@2497: Reference = 0x0, // _sym contains the name duke@435: Primitive = 0x1, // see below for primitive list duke@435: Uninitialized = 0x2, // 0x00ffff00 contains bci duke@435: TypeQuery = 0x3, // Meta-types used for category testing duke@435: duke@435: // Utility flags duke@435: ReferenceFlag = 0x00, // For reference query types duke@435: Category1Flag = 0x01, // One-word values duke@435: Category2Flag = 0x02, // First word of a two-word value duke@435: Category2_2ndFlag = 0x04, // Second word of a two-word value duke@435: duke@435: // special reference values coleenp@2497: Null = 0x00000000, // A reference with a 0 sym is null duke@435: duke@435: // Primitives categories (the second byte determines the category) duke@435: Category1 = (Category1Flag << 1 * BitsPerByte) | Primitive, duke@435: Category2 = (Category2Flag << 1 * BitsPerByte) | Primitive, duke@435: Category2_2nd = (Category2_2ndFlag << 1 * BitsPerByte) | Primitive, duke@435: duke@435: // Primitive values (type descriminator stored in most-signifcant bytes) duke@435: Bogus = (ITEM_Bogus << 2 * BitsPerByte) | Category1, duke@435: Boolean = (ITEM_Boolean << 2 * BitsPerByte) | Category1, duke@435: Byte = (ITEM_Byte << 2 * BitsPerByte) | Category1, duke@435: Short = (ITEM_Short << 2 * BitsPerByte) | Category1, duke@435: Char = (ITEM_Char << 2 * BitsPerByte) | Category1, duke@435: Integer = (ITEM_Integer << 2 * BitsPerByte) | Category1, duke@435: Float = (ITEM_Float << 2 * BitsPerByte) | Category1, duke@435: Long = (ITEM_Long << 2 * BitsPerByte) | Category2, duke@435: Double = (ITEM_Double << 2 * BitsPerByte) | Category2, duke@435: Long_2nd = (ITEM_Long_2nd << 2 * BitsPerByte) | Category2_2nd, duke@435: Double_2nd = (ITEM_Double_2nd << 2 * BitsPerByte) | Category2_2nd, duke@435: duke@435: // Used by Uninitialized (second and third bytes hold the bci) duke@435: BciMask = 0xffff << 1 * BitsPerByte, duke@435: BciForThis = ((u2)-1), // A bci of -1 is an Unintialized-This duke@435: duke@435: // Query values duke@435: ReferenceQuery = (ReferenceFlag << 1 * BitsPerByte) | TypeQuery, duke@435: Category1Query = (Category1Flag << 1 * BitsPerByte) | TypeQuery, duke@435: Category2Query = (Category2Flag << 1 * BitsPerByte) | TypeQuery, duke@435: Category2_2ndQuery = (Category2_2ndFlag << 1 * BitsPerByte) | TypeQuery duke@435: }; duke@435: duke@435: VerificationType(uintptr_t raw_data) { duke@435: _u._data = raw_data; duke@435: } duke@435: duke@435: public: duke@435: duke@435: VerificationType() { *this = bogus_type(); } duke@435: duke@435: // Create verification types duke@435: static VerificationType bogus_type() { return VerificationType(Bogus); } kamg@2585: static VerificationType top_type() { return bogus_type(); } // alias duke@435: static VerificationType null_type() { return VerificationType(Null); } duke@435: static VerificationType integer_type() { return VerificationType(Integer); } duke@435: static VerificationType float_type() { return VerificationType(Float); } duke@435: static VerificationType long_type() { return VerificationType(Long); } duke@435: static VerificationType long2_type() { return VerificationType(Long_2nd); } duke@435: static VerificationType double_type() { return VerificationType(Double); } duke@435: static VerificationType boolean_type() { return VerificationType(Boolean); } duke@435: static VerificationType byte_type() { return VerificationType(Byte); } duke@435: static VerificationType char_type() { return VerificationType(Char); } duke@435: static VerificationType short_type() { return VerificationType(Short); } duke@435: static VerificationType double2_type() duke@435: { return VerificationType(Double_2nd); } duke@435: duke@435: // "check" types are used for queries. A "check" type is not assignable duke@435: // to anything, but the specified types are assignable to a "check". For duke@435: // example, any category1 primitive is assignable to category1_check and duke@435: // any reference is assignable to reference_check. duke@435: static VerificationType reference_check() duke@435: { return VerificationType(ReferenceQuery); } duke@435: static VerificationType category1_check() duke@435: { return VerificationType(Category1Query); } duke@435: static VerificationType category2_check() duke@435: { return VerificationType(Category2Query); } duke@435: static VerificationType category2_2nd_check() duke@435: { return VerificationType(Category2_2ndQuery); } duke@435: coleenp@2497: // For reference types, store the actual Symbol coleenp@2497: static VerificationType reference_type(Symbol* sh) { coleenp@2497: assert(((uintptr_t)sh & 0x3) == 0, "Oops must be aligned"); duke@435: // If the above assert fails in the future because oop* isn't aligned, duke@435: // then this type encoding system will have to change to have a tag value duke@435: // to descriminate between oops and primitives. coleenp@2497: return VerificationType((uintptr_t)sh); duke@435: } duke@435: static VerificationType uninitialized_type(u2 bci) duke@435: { return VerificationType(bci << 1 * BitsPerByte | Uninitialized); } duke@435: static VerificationType uninitialized_this_type() duke@435: { return uninitialized_type(BciForThis); } duke@435: duke@435: // Create based on u1 read from classfile duke@435: static VerificationType from_tag(u1 tag); duke@435: duke@435: bool is_bogus() const { return (_u._data == Bogus); } duke@435: bool is_null() const { return (_u._data == Null); } duke@435: bool is_boolean() const { return (_u._data == Boolean); } duke@435: bool is_byte() const { return (_u._data == Byte); } duke@435: bool is_char() const { return (_u._data == Char); } duke@435: bool is_short() const { return (_u._data == Short); } duke@435: bool is_integer() const { return (_u._data == Integer); } duke@435: bool is_long() const { return (_u._data == Long); } duke@435: bool is_float() const { return (_u._data == Float); } duke@435: bool is_double() const { return (_u._data == Double); } duke@435: bool is_long2() const { return (_u._data == Long_2nd); } duke@435: bool is_double2() const { return (_u._data == Double_2nd); } duke@435: bool is_reference() const { return ((_u._data & TypeMask) == Reference); } duke@435: bool is_category1() const { duke@435: // This should return true for all one-word types, which are category1 duke@435: // primitives, and references (including uninitialized refs). Though duke@435: // the 'query' types should technically return 'false' here, if we duke@435: // allow this to return true, we can perform the test using only duke@435: // 2 operations rather than 8 (3 masks, 3 compares and 2 logical 'ands'). duke@435: // Since noone should call this on a query type anyway, this is ok. duke@435: assert(!is_check(), "Must not be a check type (wrong value returned)"); duke@435: return ((_u._data & Category1) != Primitive); duke@435: // should only return false if it's a primitive, and the category1 flag duke@435: // is not set. duke@435: } duke@435: bool is_category2() const { return ((_u._data & Category2) == Category2); } duke@435: bool is_category2_2nd() const { duke@435: return ((_u._data & Category2_2nd) == Category2_2nd); duke@435: } duke@435: bool is_reference_check() const { return _u._data == ReferenceQuery; } duke@435: bool is_category1_check() const { return _u._data == Category1Query; } duke@435: bool is_category2_check() const { return _u._data == Category2Query; } duke@435: bool is_category2_2nd_check() const { return _u._data == Category2_2ndQuery; } duke@435: bool is_check() const { return (_u._data & TypeQuery) == TypeQuery; } duke@435: duke@435: bool is_x_array(char sig) const { duke@435: return is_null() || (is_array() && (name()->byte_at(1) == sig)); duke@435: } duke@435: bool is_int_array() const { return is_x_array('I'); } duke@435: bool is_byte_array() const { return is_x_array('B'); } duke@435: bool is_bool_array() const { return is_x_array('Z'); } duke@435: bool is_char_array() const { return is_x_array('C'); } duke@435: bool is_short_array() const { return is_x_array('S'); } duke@435: bool is_long_array() const { return is_x_array('J'); } duke@435: bool is_float_array() const { return is_x_array('F'); } duke@435: bool is_double_array() const { return is_x_array('D'); } duke@435: bool is_object_array() const { return is_x_array('L'); } duke@435: bool is_array_array() const { return is_x_array('['); } duke@435: bool is_reference_array() const duke@435: { return is_object_array() || is_array_array(); } duke@435: bool is_object() const duke@435: { return (is_reference() && !is_null() && name()->utf8_length() >= 1 && duke@435: name()->byte_at(0) != '['); } duke@435: bool is_array() const duke@435: { return (is_reference() && !is_null() && name()->utf8_length() >= 2 && duke@435: name()->byte_at(0) == '['); } duke@435: bool is_uninitialized() const duke@435: { return ((_u._data & Uninitialized) == Uninitialized); } duke@435: bool is_uninitialized_this() const duke@435: { return is_uninitialized() && bci() == BciForThis; } duke@435: duke@435: VerificationType to_category2_2nd() const { duke@435: assert(is_category2(), "Must be a double word"); duke@435: return VerificationType(is_long() ? Long_2nd : Double_2nd); duke@435: } duke@435: duke@435: u2 bci() const { duke@435: assert(is_uninitialized(), "Must be uninitialized type"); duke@435: return ((_u._data & BciMask) >> 1 * BitsPerByte); duke@435: } duke@435: coleenp@2497: Symbol* name() const { duke@435: assert(is_reference() && !is_null(), "Must be a non-null reference"); coleenp@2497: return _u._sym; duke@435: } duke@435: duke@435: bool equals(const VerificationType& t) const { duke@435: return (_u._data == t._u._data || duke@435: (is_reference() && t.is_reference() && !is_null() && !t.is_null() && duke@435: name() == t.name())); duke@435: } duke@435: duke@435: bool operator ==(const VerificationType& t) const { duke@435: return equals(t); duke@435: } duke@435: duke@435: bool operator !=(const VerificationType& t) const { duke@435: return !equals(t); duke@435: } duke@435: duke@435: // The whole point of this type system - check to see if one type duke@435: // is assignable to another. Returns true if one can assign 'from' to duke@435: // this. duke@435: bool is_assignable_from( coleenp@2497: const VerificationType& from, ClassVerifier* context, TRAPS) const { duke@435: if (equals(from) || is_bogus()) { duke@435: return true; duke@435: } else { duke@435: switch(_u._data) { duke@435: case Category1Query: duke@435: return from.is_category1(); duke@435: case Category2Query: duke@435: return from.is_category2(); duke@435: case Category2_2ndQuery: duke@435: return from.is_category2_2nd(); duke@435: case ReferenceQuery: duke@435: return from.is_reference() || from.is_uninitialized(); duke@435: case Boolean: duke@435: case Byte: duke@435: case Char: duke@435: case Short: duke@435: // An int can be assigned to boolean, byte, char or short values. duke@435: return from.is_integer(); duke@435: default: duke@435: if (is_reference() && from.is_reference()) { duke@435: return is_reference_assignable_from(from, context, CHECK_false); duke@435: } else { duke@435: return false; duke@435: } duke@435: } duke@435: } duke@435: } duke@435: coleenp@2497: VerificationType get_component(ClassVerifier* context, TRAPS) const; duke@435: duke@435: int dimensions() const { duke@435: assert(is_array(), "Must be an array"); duke@435: int index = 0; duke@435: while (name()->byte_at(index++) == '['); duke@435: return index; duke@435: } duke@435: duke@435: void print_on(outputStream* st) const PRODUCT_RETURN; duke@435: duke@435: private: duke@435: duke@435: bool is_reference_assignable_from( coleenp@2497: const VerificationType&, ClassVerifier*, TRAPS) const; duke@435: }; stefank@2314: stefank@2314: #endif // SHARE_VM_CLASSFILE_VERIFICATIONTYPE_HPP