1 /*
  2  * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #ifndef SHARE_OOPS_FIELDINFO_HPP
 26 #define SHARE_OOPS_FIELDINFO_HPP
 27 
 28 #include "oops/constantPool.hpp"
 29 #include "oops/symbol.hpp"
 30 #include "oops/typeArrayOop.hpp"
 31 #include "utilities/vmEnums.hpp"
 32 
 33 // This class represents the field information contained in the fields
 34 // array of an InstanceKlass.  Currently it's laid on top an array of
 35 // Java shorts but in the future it could simply be used as a real
 36 // array type.  FieldInfo generally shouldn't be used directly.
 37 // Fields should be queried either through InstanceKlass or through
 38 // the various FieldStreams.
 39 class FieldInfo {
 40   friend class fieldDescriptor;
 41   friend class JavaFieldStream;
 42   friend class ClassFileParser;
 43 
 44  public:
 45   // fields
 46   // Field info extracted from the class file and stored
 47   // as an array of 6 shorts.
 48 
 49 #define FIELDINFO_TAG_SIZE             3
 50 #define FIELDINFO_TAG_OFFSET           1 << 0
 51 #define FIELDINFO_TAG_CONTENDED        1 << 1
 52 #define FIELDINFO_TAG_INLINED          1 << 2
 53 
 54   // Packed field has the tag, and can be either of:
 55   //    hi bits <--------------------------- lo bits
 56   //   |---------high---------|---------low---------|
 57   //    ..........................................CO
 58   //    ..........................................00  - non-contended field
 59   //    [--contention_group--]...................I10  - contended field with contention group
 60   //    [------------------offset---------------]I01  - real field offset
 61 
 62   // Bit O indicates if the packed field contains an offset (O=1) or not (O=0)
 63   // Bit C indicates if the field is contended (C=1) or not (C=0)
 64   //       (if it is contended, the high packed field contains the contention group)
 65   // Bit I indicates if the field has been inlined  (I=1) or not (I=0)
 66 
 67   enum FieldOffset {
 68     access_flags_offset      = 0,
 69     name_index_offset        = 1,
 70     signature_index_offset   = 2,
 71     initval_index_offset     = 3,
 72     low_packed_offset        = 4,
 73     high_packed_offset       = 5,
 74     field_slots              = 6
 75   };
 76 
 77  private:
 78   u2 _shorts[field_slots];
 79 
 80   void set_name_index(u2 val)                    { _shorts[name_index_offset] = val;         }
 81   void set_signature_index(u2 val)               { _shorts[signature_index_offset] = val;    }
 82   void set_initval_index(u2 val)                 { _shorts[initval_index_offset] = val;      }
 83 
 84   u2 name_index() const                          { return _shorts[name_index_offset];        }
 85   u2 signature_index() const                     { return _shorts[signature_index_offset];   }
 86   u2 initval_index() const                       { return _shorts[initval_index_offset];     }
 87 
 88  public:
 89   static FieldInfo* from_field_array(Array<u2>* fields, int index) {
 90     return ((FieldInfo*)fields->adr_at(index * field_slots));
 91   }
 92   static FieldInfo* from_field_array(u2* fields, int index) {
 93     return ((FieldInfo*)(fields + index * field_slots));
 94   }
 95 
 96   void initialize(u2 access_flags,
 97                   u2 name_index,
 98                   u2 signature_index,
 99                   u2 initval_index) {
100     _shorts[access_flags_offset] = access_flags;
101     _shorts[name_index_offset] = name_index;
102     _shorts[signature_index_offset] = signature_index;
103     _shorts[initval_index_offset] = initval_index;
104     _shorts[low_packed_offset] = 0;
105     _shorts[high_packed_offset] = 0;
106   }
107 
108   u2 access_flags() const                        { return _shorts[access_flags_offset];            }
109   u4 offset() const {
110     assert((_shorts[low_packed_offset] & FIELDINFO_TAG_OFFSET) != 0, "Offset must have been set");
111     return build_int_from_shorts(_shorts[low_packed_offset], _shorts[high_packed_offset]) >> FIELDINFO_TAG_SIZE;
112   }
113 
114   bool is_contended() const {
115     return (_shorts[low_packed_offset] & FIELDINFO_TAG_CONTENDED) != 0;
116   }
117 
118   u2 contended_group() const {
119     assert((_shorts[low_packed_offset] & FIELDINFO_TAG_OFFSET) == 0, "Offset must not have been set");
120     assert((_shorts[low_packed_offset] & FIELDINFO_TAG_CONTENDED) != 0, "Field must be contended");
121     return _shorts[high_packed_offset];
122  }
123 
124   bool is_offset_set() const {
125     return (_shorts[low_packed_offset] & FIELDINFO_TAG_OFFSET)!= 0;
126   }
127 
128   Symbol* name(ConstantPool* cp) const {
129     int index = name_index();
130     if (is_internal()) {
131       return lookup_symbol(index);
132     }
133     return cp->symbol_at(index);
134   }
135 
136   Symbol* signature(ConstantPool* cp) const {
137     int index = signature_index();
138     if (is_internal()) {
139       return lookup_symbol(index);
140     }
141     return cp->symbol_at(index);
142   }
143 
144   void set_access_flags(u2 val)                  { _shorts[access_flags_offset] = val;             }
145   void set_offset(u4 val)                        {
146     val = val << FIELDINFO_TAG_SIZE; // make room for tag
147     bool inlined = is_inlined();
148     _shorts[low_packed_offset] = extract_low_short_from_int(val) | FIELDINFO_TAG_OFFSET;
149     if (inlined) set_inlined(true);
150     _shorts[high_packed_offset] = extract_high_short_from_int(val);
151     assert(is_inlined() || !inlined, "just checking");
152   }
153 
154   void set_inlined(bool b) {
155     if (b) {
156       _shorts[low_packed_offset] |= FIELDINFO_TAG_INLINED;
157     } else {
158       _shorts[low_packed_offset] &= ~FIELDINFO_TAG_INLINED;
159     }
160   }
161 
162   bool is_inlined() {
163     return (_shorts[low_packed_offset] & FIELDINFO_TAG_INLINED) != 0;
164   }
165 
166   void set_contended_group(u2 val) {
167     assert((_shorts[low_packed_offset] & FIELDINFO_TAG_OFFSET) == 0, "Offset must not have been set");
168     assert((_shorts[low_packed_offset] & FIELDINFO_TAG_CONTENDED) == 0, "Overwritting contended group");
169     _shorts[low_packed_offset] |= FIELDINFO_TAG_CONTENDED;
170     _shorts[high_packed_offset] = val;
171   }
172 
173   bool is_internal() const {
174     return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0;
175   }
176 
177   bool is_stable() const {
178     return (access_flags() & JVM_ACC_FIELD_STABLE) != 0;
179   }
180   void set_stable(bool z) {
181     if (z) _shorts[access_flags_offset] |=  JVM_ACC_FIELD_STABLE;
182     else   _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE;
183   }
184 
185   Symbol* lookup_symbol(int symbol_index) const {
186     assert(is_internal(), "only internal fields");
187     return Symbol::vm_symbol_at(static_cast<vmSymbolID>(symbol_index));
188   }
189 };
190 
191 #endif // SHARE_OOPS_FIELDINFO_HPP