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