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.
38class 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             2
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_MASK             3
54
55  // Packed field has the tag, and can be either of:
56  //    hi bits <--------------------------- lo bits
57  //   |---------high---------|---------low---------|
58  //    ..........................................00  - blank
59  //    [------------------offset----------------]01  - real field offset
60  //    ......................[-------type-------]10  - plain field with type
61  //    [--contention_group--][-------type-------]11  - contended field with type and contention group
62  enum FieldOffset {
63    access_flags_offset      = 0,
64    name_index_offset        = 1,
65    signature_index_offset   = 2,
66    initval_index_offset     = 3,
67    low_packed_offset        = 4,
68    high_packed_offset       = 5,
69    field_slots              = 6
70  };
71
72 private:
73  u2 _shorts[field_slots];
74
75  void set_name_index(u2 val)                    { _shorts[name_index_offset] = val;         }
76  void set_signature_index(u2 val)               { _shorts[signature_index_offset] = val;    }
77  void set_initval_index(u2 val)                 { _shorts[initval_index_offset] = val;      }
78
79  u2 name_index() const                          { return _shorts[name_index_offset];        }
80  u2 signature_index() const                     { return _shorts[signature_index_offset];   }
81  u2 initval_index() const                       { return _shorts[initval_index_offset];     }
82
83 public:
84  static FieldInfo* from_field_array(Array<u2>* fields, int index) {
85    return ((FieldInfo*)fields->adr_at(index * field_slots));
86  }
87  static FieldInfo* from_field_array(u2* fields, int index) {
88    return ((FieldInfo*)(fields + index * field_slots));
89  }
90
91  void initialize(u2 access_flags,
92                  u2 name_index,
93                  u2 signature_index,
94                  u2 initval_index) {
95    _shorts[access_flags_offset] = access_flags;
96    _shorts[name_index_offset] = name_index;
97    _shorts[signature_index_offset] = signature_index;
98    _shorts[initval_index_offset] = initval_index;
99    _shorts[low_packed_offset] = 0;
100    _shorts[high_packed_offset] = 0;
101  }
102
103  u2 access_flags() const                        { return _shorts[access_flags_offset];            }
104  u4 offset() const {
105    u2 lo = _shorts[low_packed_offset];
106    switch(lo & FIELDINFO_TAG_MASK) {
107      case FIELDINFO_TAG_OFFSET:
108        return build_int_from_shorts(_shorts[low_packed_offset], _shorts[high_packed_offset]) >> FIELDINFO_TAG_SIZE;
109#ifndef PRODUCT
110      case FIELDINFO_TAG_TYPE_PLAIN:
111        fatal("Asking offset for the plain type field");
112      case FIELDINFO_TAG_TYPE_CONTENDED:
113        fatal("Asking offset for the contended type field");
114      case FIELDINFO_TAG_BLANK:
115        fatal("Asking offset for the blank field");
116#endif
117    }
118    ShouldNotReachHere();
119    return 0;
120  }
121
122  bool is_contended() const {
123    u2 lo = _shorts[low_packed_offset];
124    switch(lo & FIELDINFO_TAG_MASK) {
125      case FIELDINFO_TAG_TYPE_PLAIN:
126        return false;
127      case FIELDINFO_TAG_TYPE_CONTENDED:
128        return true;
129#ifndef PRODUCT
130      case FIELDINFO_TAG_OFFSET:
131        fatal("Asking contended flag for the field with offset");
132      case FIELDINFO_TAG_BLANK:
133        fatal("Asking contended flag for the blank field");
134#endif
135    }
136    ShouldNotReachHere();
137    return false;
138  }
139
140  u2 contended_group() const {
141    u2 lo = _shorts[low_packed_offset];
142    switch(lo & FIELDINFO_TAG_MASK) {
143      case FIELDINFO_TAG_TYPE_PLAIN:
144        return 0;
145      case FIELDINFO_TAG_TYPE_CONTENDED:
146        return _shorts[high_packed_offset];
147#ifndef PRODUCT
148      case FIELDINFO_TAG_OFFSET:
149        fatal("Asking the contended group for the field with offset");
150      case FIELDINFO_TAG_BLANK:
151        fatal("Asking the contended group for the blank field");
152#endif
153    }
154    ShouldNotReachHere();
155    return 0;
156 }
157
158  u2 allocation_type() const {
159    u2 lo = _shorts[low_packed_offset];
160    switch(lo & FIELDINFO_TAG_MASK) {
161      case FIELDINFO_TAG_TYPE_PLAIN:
162      case FIELDINFO_TAG_TYPE_CONTENDED:
163        return (lo >> FIELDINFO_TAG_SIZE);
164#ifndef PRODUCT
165      case FIELDINFO_TAG_OFFSET:
166        fatal("Asking the field type for field with offset");
167      case FIELDINFO_TAG_BLANK:
168        fatal("Asking the field type for the blank field");
169#endif
170    }
171    ShouldNotReachHere();
172    return 0;
173  }
174
175  bool is_offset_set() const {
176    return (_shorts[low_packed_offset] & FIELDINFO_TAG_MASK) == FIELDINFO_TAG_OFFSET;
177  }
178
179  Symbol* name(const constantPoolHandle& cp) const {
180    int index = name_index();
181    if (is_internal()) {
182      return lookup_symbol(index);
183    }
184    return cp->symbol_at(index);
185  }
186
187  Symbol* signature(const constantPoolHandle& cp) const {
188    int index = signature_index();
189    if (is_internal()) {
190      return lookup_symbol(index);
191    }
192    return cp->symbol_at(index);
193  }
194
195  void set_access_flags(u2 val)                  { _shorts[access_flags_offset] = val;             }
196  void set_offset(u4 val)                        {
197    val = val << FIELDINFO_TAG_SIZE; // make room for tag
198    _shorts[low_packed_offset] = extract_low_short_from_int(val) | FIELDINFO_TAG_OFFSET;
199    _shorts[high_packed_offset] = extract_high_short_from_int(val);
200  }
201
202  void set_allocation_type(int type) {
203    u2 lo = _shorts[low_packed_offset];
204    switch(lo & FIELDINFO_TAG_MASK) {
205      case FIELDINFO_TAG_BLANK:
206        _shorts[low_packed_offset] = ((type << FIELDINFO_TAG_SIZE)) & 0xFFFF;
207        _shorts[low_packed_offset] &= ~FIELDINFO_TAG_MASK;
208        _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_PLAIN;
209        return;
210#ifndef PRODUCT
211      case FIELDINFO_TAG_TYPE_PLAIN:
212      case FIELDINFO_TAG_TYPE_CONTENDED:
213      case FIELDINFO_TAG_OFFSET:
214        fatal("Setting the field type with overwriting");
215#endif
216    }
217    ShouldNotReachHere();
218  }
219
220  void set_contended_group(u2 val) {
221    u2 lo = _shorts[low_packed_offset];
222    switch(lo & FIELDINFO_TAG_MASK) {
223      case FIELDINFO_TAG_TYPE_PLAIN:
224        _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_CONTENDED;
225        _shorts[high_packed_offset] = val;
226        return;
227#ifndef PRODUCT
228      case FIELDINFO_TAG_TYPE_CONTENDED:
229        fatal("Overwriting contended group");
230      case FIELDINFO_TAG_BLANK:
231        fatal("Setting contended group for the blank field");
232      case FIELDINFO_TAG_OFFSET:
233        fatal("Setting contended group for field with offset");
234#endif
235    }
236    ShouldNotReachHere();
237  }
238
239  bool is_internal() const {
240    return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0;
241  }
242
243  bool is_stable() const {
244    return (access_flags() & JVM_ACC_FIELD_STABLE) != 0;
245  }
246  void set_stable(bool z) {
247    if (z) _shorts[access_flags_offset] |=  JVM_ACC_FIELD_STABLE;
248    else   _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE;
249  }
250
251  Symbol* lookup_symbol(int symbol_index) const {
252    assert(is_internal(), "only internal fields");
253    return vmSymbols::symbol_at((vmSymbols::SID)symbol_index);
254  }
255};
256
257#endif // SHARE_VM_OOPS_FIELDINFO_HPP
258