1 /*
   2  * Copyright (c) 2011, 2015, 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_VM_OOPS_FIELDINFO_HPP
  26 #define SHARE_VM_OOPS_FIELDINFO_HPP
  27 
  28 #include "oops/constantPool.hpp"
  29 #include "oops/typeArrayOop.hpp"
  30 #include "classfile/vmSymbols.hpp"
  31 
  32 // This class represents the field information contained in the fields
  33 // array of an InstanceKlass.  Currently it's laid on top an array of
  34 // Java shorts but in the future it could simply be used as a real
  35 // array type.  FieldInfo generally shouldn't be used directly.
  36 // Fields should be queried either through InstanceKlass or through
  37 // the various FieldStreams.
  38 class FieldInfo VALUE_OBJ_CLASS_SPEC {
  39   friend class fieldDescriptor;
  40   friend class JavaFieldStream;
  41   friend class ClassFileParser;
  42 
  43  public:
  44   // fields
  45   // Field info extracted from the class file and stored
  46   // as an array of 6 shorts.
  47 
  48 #define FIELDINFO_TAG_SIZE             3
  49 #define FIELDINFO_TAG_BLANK            0
  50 #define FIELDINFO_TAG_OFFSET           1
  51 #define FIELDINFO_TAG_TYPE_PLAIN       2
  52 #define FIELDINFO_TAG_TYPE_CONTENDED   3
  53 #define FIELDINFO_TAG_TYPE_MASK        3
  54 #define FIELDINFO_TAG_MASK             7
  55 #define FIELDINFO_FLATTENING_OFFSET    2
  56 
  57   // Packed field has the tag, and can be either of:
  58   //    hi bits <--------------------------- lo bits
  59   //   |---------high---------|---------low---------|
  60   //    ..........................................00  - blank
  61   //    [------------------offset----------------]01  - real field offset
  62   //    ......................[-------type-------]10  - plain field with type
  63   //    [--contention_group--][-------type-------]11  - contended field with type and contention group
  64   enum FieldOffset {
  65     access_flags_offset      = 0,
  66     name_index_offset        = 1,
  67     signature_index_offset   = 2,
  68     initval_index_offset     = 3,
  69     low_packed_offset        = 4,
  70     high_packed_offset       = 5,
  71     field_slots              = 6
  72   };
  73 
  74  private:
  75   u2 _shorts[field_slots];
  76 
  77   void set_name_index(u2 val)                    { _shorts[name_index_offset] = val;         }
  78   void set_signature_index(u2 val)               { _shorts[signature_index_offset] = val;    }
  79   void set_initval_index(u2 val)                 { _shorts[initval_index_offset] = val;      }
  80 
  81   u2 name_index() const                          { return _shorts[name_index_offset];        }
  82   u2 signature_index() const                     { return _shorts[signature_index_offset];   }
  83   u2 initval_index() const                       { return _shorts[initval_index_offset];     }
  84 
  85  public:
  86   static FieldInfo* from_field_array(Array<u2>* fields, int index) {
  87     return ((FieldInfo*)fields->adr_at(index * field_slots));
  88   }
  89   static FieldInfo* from_field_array(u2* fields, int index) {
  90     return ((FieldInfo*)(fields + index * field_slots));
  91   }
  92 
  93   void initialize(u2 access_flags,
  94                   u2 name_index,
  95                   u2 signature_index,
  96                   u2 initval_index) {
  97     _shorts[access_flags_offset] = access_flags;
  98     _shorts[name_index_offset] = name_index;
  99     _shorts[signature_index_offset] = signature_index;
 100     _shorts[initval_index_offset] = initval_index;
 101     _shorts[low_packed_offset] = 0;
 102     _shorts[high_packed_offset] = 0;
 103   }
 104 
 105   u2 access_flags() const                        { return _shorts[access_flags_offset];            }
 106   u4 offset() const {
 107     u2 lo = _shorts[low_packed_offset];
 108     switch(lo & FIELDINFO_TAG_TYPE_MASK) {
 109       case FIELDINFO_TAG_OFFSET:
 110         return build_int_from_shorts(_shorts[low_packed_offset], _shorts[high_packed_offset]) >> FIELDINFO_TAG_SIZE;
 111 #ifndef PRODUCT
 112       case FIELDINFO_TAG_TYPE_PLAIN:
 113         fatal("Asking offset for the plain type field");
 114       case FIELDINFO_TAG_TYPE_CONTENDED:
 115         fatal("Asking offset for the contended type field");
 116       case FIELDINFO_TAG_BLANK:
 117         fatal("Asking offset for the blank field");
 118 #endif
 119     }
 120     ShouldNotReachHere();
 121     return 0;
 122   }
 123 
 124   bool is_contended() const {
 125     u2 lo = _shorts[low_packed_offset];
 126     switch(lo & FIELDINFO_TAG_TYPE_MASK) {
 127       case FIELDINFO_TAG_TYPE_PLAIN:
 128         return false;
 129       case FIELDINFO_TAG_TYPE_CONTENDED:
 130         return true;
 131 #ifndef PRODUCT
 132       case FIELDINFO_TAG_OFFSET:
 133         fatal("Asking contended flag for the field with offset");
 134       case FIELDINFO_TAG_BLANK:
 135         fatal("Asking contended flag for the blank field");
 136 #endif
 137     }
 138     ShouldNotReachHere();
 139     return false;
 140   }
 141 
 142   u2 contended_group() const {
 143     u2 lo = _shorts[low_packed_offset];
 144     switch(lo & FIELDINFO_TAG_TYPE_MASK) {
 145       case FIELDINFO_TAG_TYPE_PLAIN:
 146         return 0;
 147       case FIELDINFO_TAG_TYPE_CONTENDED:
 148         return _shorts[high_packed_offset];
 149 #ifndef PRODUCT
 150       case FIELDINFO_TAG_OFFSET:
 151         fatal("Asking the contended group for the field with offset");
 152       case FIELDINFO_TAG_BLANK:
 153         fatal("Asking the contended group for the blank field");
 154 #endif
 155     }
 156     ShouldNotReachHere();
 157     return 0;
 158  }
 159 
 160   u2 allocation_type() const {
 161     u2 lo = _shorts[low_packed_offset];
 162     switch(lo & FIELDINFO_TAG_TYPE_MASK) {
 163       case FIELDINFO_TAG_TYPE_PLAIN:
 164       case FIELDINFO_TAG_TYPE_CONTENDED:
 165         return (lo >> FIELDINFO_TAG_SIZE);
 166 #ifndef PRODUCT
 167       case FIELDINFO_TAG_OFFSET:
 168         fatal("Asking the field type for field with offset");
 169       case FIELDINFO_TAG_BLANK:
 170         fatal("Asking the field type for the blank field");
 171 #endif
 172     }
 173     ShouldNotReachHere();
 174     return 0;
 175   }
 176 
 177   bool is_offset_set() const {
 178     return (_shorts[low_packed_offset] & FIELDINFO_TAG_TYPE_MASK) == FIELDINFO_TAG_OFFSET;
 179   }
 180 
 181   Symbol* name(const constantPoolHandle& cp) const {
 182     int index = name_index();
 183     if (is_internal()) {
 184       return lookup_symbol(index);
 185     }
 186     return cp->symbol_at(index);
 187   }
 188 
 189   Symbol* signature(const constantPoolHandle& cp) const {
 190     int index = signature_index();
 191     if (is_internal()) {
 192       return lookup_symbol(index);
 193     }
 194     return cp->symbol_at(index);
 195   }
 196 
 197   void set_access_flags(u2 val)                  { _shorts[access_flags_offset] = val;             }
 198   void set_offset(u4 val)                        {
 199     val = val << FIELDINFO_TAG_SIZE; // make room for tag
 200     bool flatten = is_flatten();
 201     _shorts[low_packed_offset] = extract_low_short_from_int(val) | FIELDINFO_TAG_OFFSET;
 202     if (flatten) set_flattening(true);
 203     _shorts[high_packed_offset] = extract_high_short_from_int(val);
 204     assert(is_flatten() || !flatten, "just checking");
 205   }
 206 
 207   void set_allocation_type(int type) {
 208     bool b = is_flatten();
 209     u2 lo = _shorts[low_packed_offset];
 210     switch(lo & FIELDINFO_TAG_TYPE_MASK) {
 211       case FIELDINFO_TAG_BLANK:
 212         _shorts[low_packed_offset] |= ((type << FIELDINFO_TAG_SIZE)) & 0xFFFF;
 213         _shorts[low_packed_offset] &= ~FIELDINFO_TAG_TYPE_MASK;
 214         _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_PLAIN;
 215         assert(is_flatten() || !b, "Just checking");
 216         return;
 217 #ifndef PRODUCT
 218       case FIELDINFO_TAG_TYPE_PLAIN:
 219       case FIELDINFO_TAG_TYPE_CONTENDED:
 220       case FIELDINFO_TAG_OFFSET:
 221         fatal("Setting the field type with overwriting");
 222 #endif
 223     }
 224     ShouldNotReachHere();
 225   }
 226 
 227   void set_flattening(bool b) {
 228     if (b) {
 229       _shorts[low_packed_offset] |= 1 << FIELDINFO_FLATTENING_OFFSET;
 230     } else {
 231       _shorts[low_packed_offset] &= ~(1 << FIELDINFO_FLATTENING_OFFSET);
 232     }
 233   }
 234 
 235   bool is_flatten() {
 236     return ((_shorts[low_packed_offset] >> FIELDINFO_FLATTENING_OFFSET) & 1) != 0;
 237   }
 238 
 239   void set_contended_group(u2 val) {
 240     u2 lo = _shorts[low_packed_offset];
 241     switch(lo & FIELDINFO_TAG_TYPE_MASK) {
 242       case FIELDINFO_TAG_TYPE_PLAIN:
 243         _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_CONTENDED;
 244         _shorts[high_packed_offset] = val;
 245         return;
 246 #ifndef PRODUCT
 247       case FIELDINFO_TAG_TYPE_CONTENDED:
 248         fatal("Overwriting contended group");
 249       case FIELDINFO_TAG_BLANK:
 250         fatal("Setting contended group for the blank field");
 251       case FIELDINFO_TAG_OFFSET:
 252         fatal("Setting contended group for field with offset");
 253 #endif
 254     }
 255     ShouldNotReachHere();
 256   }
 257 
 258   bool is_internal() const {
 259     return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0;
 260   }
 261 
 262   bool is_stable() const {
 263     return (access_flags() & JVM_ACC_FIELD_STABLE) != 0;
 264   }
 265   void set_stable(bool z) {
 266     if (z) _shorts[access_flags_offset] |=  JVM_ACC_FIELD_STABLE;
 267     else   _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE;
 268   }
 269 
 270   Symbol* lookup_symbol(int symbol_index) const {
 271     assert(is_internal(), "only internal fields");
 272     return vmSymbols::symbol_at((vmSymbols::SID)symbol_index);
 273   }
 274 };
 275 
 276 #endif // SHARE_VM_OOPS_FIELDINFO_HPP