| /* |
| * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #ifndef SHARE_VM_OOPS_FIELDINFO_HPP |
| #define SHARE_VM_OOPS_FIELDINFO_HPP |
| |
| #include "oops/constantPool.hpp" |
| #include "oops/typeArrayOop.hpp" |
| #include "classfile/vmSymbols.hpp" |
| |
| // This class represents the field information contained in the fields |
| // array of an InstanceKlass. Currently it's laid on top an array of |
| // Java shorts but in the future it could simply be used as a real |
| // array type. FieldInfo generally shouldn't be used directly. |
| // Fields should be queried either through InstanceKlass or through |
| // the various FieldStreams. |
| class FieldInfo VALUE_OBJ_CLASS_SPEC { |
| friend class fieldDescriptor; |
| friend class JavaFieldStream; |
| friend class ClassFileParser; |
| |
| public: |
| // fields |
| // Field info extracted from the class file and stored |
| // as an array of 6 shorts. |
| |
| #define FIELDINFO_TAG_SIZE 2 |
| #define FIELDINFO_TAG_BLANK 0 |
| #define FIELDINFO_TAG_OFFSET 1 |
| #define FIELDINFO_TAG_TYPE_PLAIN 2 |
| #define FIELDINFO_TAG_TYPE_CONTENDED 3 |
| #define FIELDINFO_TAG_MASK 3 |
| |
| // Packed field has the tag, and can be either of: |
| // hi bits <--------------------------- lo bits |
| // |---------high---------|---------low---------| |
| // ..........................................00 - blank |
| // [------------------offset----------------]01 - real field offset |
| // ......................[-------type-------]10 - plain field with type |
| // [--contention_group--][-------type-------]11 - contended field with type and contention group |
| enum FieldOffset { |
| access_flags_offset = 0, |
| name_index_offset = 1, |
| signature_index_offset = 2, |
| initval_index_offset = 3, |
| low_packed_offset = 4, |
| high_packed_offset = 5, |
| field_slots = 6 |
| }; |
| |
| private: |
| u2 _shorts[field_slots]; |
| |
| void set_name_index(u2 val) { _shorts[name_index_offset] = val; } |
| void set_signature_index(u2 val) { _shorts[signature_index_offset] = val; } |
| void set_initval_index(u2 val) { _shorts[initval_index_offset] = val; } |
| |
| u2 name_index() const { return _shorts[name_index_offset]; } |
| u2 signature_index() const { return _shorts[signature_index_offset]; } |
| u2 initval_index() const { return _shorts[initval_index_offset]; } |
| |
| public: |
| static FieldInfo* from_field_array(Array<u2>* fields, int index) { |
| return ((FieldInfo*)fields->adr_at(index * field_slots)); |
| } |
| static FieldInfo* from_field_array(u2* fields, int index) { |
| return ((FieldInfo*)(fields + index * field_slots)); |
| } |
| |
| void initialize(u2 access_flags, |
| u2 name_index, |
| u2 signature_index, |
| u2 initval_index) { |
| _shorts[access_flags_offset] = access_flags; |
| _shorts[name_index_offset] = name_index; |
| _shorts[signature_index_offset] = signature_index; |
| _shorts[initval_index_offset] = initval_index; |
| _shorts[low_packed_offset] = 0; |
| _shorts[high_packed_offset] = 0; |
| } |
| |
| u2 access_flags() const { return _shorts[access_flags_offset]; } |
| u4 offset() const { |
| u2 lo = _shorts[low_packed_offset]; |
| switch(lo & FIELDINFO_TAG_MASK) { |
| case FIELDINFO_TAG_OFFSET: |
| return build_int_from_shorts(_shorts[low_packed_offset], _shorts[high_packed_offset]) >> FIELDINFO_TAG_SIZE; |
| #ifndef PRODUCT |
| case FIELDINFO_TAG_TYPE_PLAIN: |
| fatal("Asking offset for the plain type field"); |
| case FIELDINFO_TAG_TYPE_CONTENDED: |
| fatal("Asking offset for the contended type field"); |
| case FIELDINFO_TAG_BLANK: |
| fatal("Asking offset for the blank field"); |
| #endif |
| } |
| ShouldNotReachHere(); |
| return 0; |
| } |
| |
| bool is_contended() const { |
| u2 lo = _shorts[low_packed_offset]; |
| switch(lo & FIELDINFO_TAG_MASK) { |
| case FIELDINFO_TAG_TYPE_PLAIN: |
| return false; |
| case FIELDINFO_TAG_TYPE_CONTENDED: |
| return true; |
| #ifndef PRODUCT |
| case FIELDINFO_TAG_OFFSET: |
| fatal("Asking contended flag for the field with offset"); |
| case FIELDINFO_TAG_BLANK: |
| fatal("Asking contended flag for the blank field"); |
| #endif |
| } |
| ShouldNotReachHere(); |
| return false; |
| } |
| |
| u2 contended_group() const { |
| u2 lo = _shorts[low_packed_offset]; |
| switch(lo & FIELDINFO_TAG_MASK) { |
| case FIELDINFO_TAG_TYPE_PLAIN: |
| return 0; |
| case FIELDINFO_TAG_TYPE_CONTENDED: |
| return _shorts[high_packed_offset]; |
| #ifndef PRODUCT |
| case FIELDINFO_TAG_OFFSET: |
| fatal("Asking the contended group for the field with offset"); |
| case FIELDINFO_TAG_BLANK: |
| fatal("Asking the contended group for the blank field"); |
| #endif |
| } |
| ShouldNotReachHere(); |
| return 0; |
| } |
| |
| u2 allocation_type() const { |
| u2 lo = _shorts[low_packed_offset]; |
| switch(lo & FIELDINFO_TAG_MASK) { |
| case FIELDINFO_TAG_TYPE_PLAIN: |
| case FIELDINFO_TAG_TYPE_CONTENDED: |
| return (lo >> FIELDINFO_TAG_SIZE); |
| #ifndef PRODUCT |
| case FIELDINFO_TAG_OFFSET: |
| fatal("Asking the field type for field with offset"); |
| case FIELDINFO_TAG_BLANK: |
| fatal("Asking the field type for the blank field"); |
| #endif |
| } |
| ShouldNotReachHere(); |
| return 0; |
| } |
| |
| bool is_offset_set() const { |
| return (_shorts[low_packed_offset] & FIELDINFO_TAG_MASK) == FIELDINFO_TAG_OFFSET; |
| } |
| |
| Symbol* name(constantPoolHandle cp) const { |
| int index = name_index(); |
| if (is_internal()) { |
| return lookup_symbol(index); |
| } |
| return cp->symbol_at(index); |
| } |
| |
| Symbol* signature(constantPoolHandle cp) const { |
| int index = signature_index(); |
| if (is_internal()) { |
| return lookup_symbol(index); |
| } |
| return cp->symbol_at(index); |
| } |
| |
| void set_access_flags(u2 val) { _shorts[access_flags_offset] = val; } |
| void set_offset(u4 val) { |
| val = val << FIELDINFO_TAG_SIZE; // make room for tag |
| _shorts[low_packed_offset] = extract_low_short_from_int(val) | FIELDINFO_TAG_OFFSET; |
| _shorts[high_packed_offset] = extract_high_short_from_int(val); |
| } |
| |
| void set_allocation_type(int type) { |
| u2 lo = _shorts[low_packed_offset]; |
| switch(lo & FIELDINFO_TAG_MASK) { |
| case FIELDINFO_TAG_BLANK: |
| _shorts[low_packed_offset] = ((type << FIELDINFO_TAG_SIZE)) & 0xFFFF; |
| _shorts[low_packed_offset] &= ~FIELDINFO_TAG_MASK; |
| _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_PLAIN; |
| return; |
| #ifndef PRODUCT |
| case FIELDINFO_TAG_TYPE_PLAIN: |
| case FIELDINFO_TAG_TYPE_CONTENDED: |
| case FIELDINFO_TAG_OFFSET: |
| fatal("Setting the field type with overwriting"); |
| #endif |
| } |
| ShouldNotReachHere(); |
| } |
| |
| void set_contended_group(u2 val) { |
| u2 lo = _shorts[low_packed_offset]; |
| switch(lo & FIELDINFO_TAG_MASK) { |
| case FIELDINFO_TAG_TYPE_PLAIN: |
| _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_CONTENDED; |
| _shorts[high_packed_offset] = val; |
| return; |
| #ifndef PRODUCT |
| case FIELDINFO_TAG_TYPE_CONTENDED: |
| fatal("Overwriting contended group"); |
| case FIELDINFO_TAG_BLANK: |
| fatal("Setting contended group for the blank field"); |
| case FIELDINFO_TAG_OFFSET: |
| fatal("Setting contended group for field with offset"); |
| #endif |
| } |
| ShouldNotReachHere(); |
| } |
| |
| bool is_internal() const { |
| return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0; |
| } |
| |
| bool is_stable() const { |
| return (access_flags() & JVM_ACC_FIELD_STABLE) != 0; |
| } |
| void set_stable(bool z) { |
| if (z) _shorts[access_flags_offset] |= JVM_ACC_FIELD_STABLE; |
| else _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE; |
| } |
| |
| Symbol* lookup_symbol(int symbol_index) const { |
| assert(is_internal(), "only internal fields"); |
| return vmSymbols::symbol_at((vmSymbols::SID)symbol_index); |
| } |
| }; |
| |
| #endif // SHARE_VM_OOPS_FIELDINFO_HPP |