1 | /* |
2 | * Copyright (c) 2011, 2019, 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/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 { |
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_OOPS_FIELDINFO_HPP |
258 | |