aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/classfile/verificationType.hpp
blob: db3a8097002cd9c755beed87c733f1180960e48d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/*
 * Copyright (c) 2003, 2006, 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.
 *
 */

enum {
  // As specifed in the JVM spec
  ITEM_Top = 0,
  ITEM_Integer = 1,
  ITEM_Float = 2,
  ITEM_Double = 3,
  ITEM_Long = 4,
  ITEM_Null = 5,
  ITEM_UninitializedThis = 6,
  ITEM_Object = 7,
  ITEM_Uninitialized = 8,
  ITEM_Bogus = (uint)-1
};

class VerificationType VALUE_OBJ_CLASS_SPEC {
  private:
    // Least significant bits of _handle are always 0, so we use these as
    // the indicator that the _handle is valid.  Otherwise, the _data field
    // contains encoded data (as specified below).  Should the VM change
    // and the lower bits on oops aren't 0, the assert in the constructor
    // will catch this and we'll have to add a descriminator tag to this
    // structure.
    union {
      symbolOop* _handle;
      uintptr_t _data;
    } _u;

    enum {
      // These rest are not found in classfiles, but used by the verifier
      ITEM_Boolean = 9, ITEM_Byte, ITEM_Short, ITEM_Char,
      ITEM_Long_2nd, ITEM_Double_2nd
    };

    // Enum for the _data field
    enum {
      // Bottom two bits determine if the type is a reference, primitive,
      // uninitialized or a query-type.
      TypeMask           = 0x00000003,

      // Topmost types encoding
      Reference          = 0x0,        // _handle contains the name
      Primitive          = 0x1,        // see below for primitive list
      Uninitialized      = 0x2,        // 0x00ffff00 contains bci
      TypeQuery          = 0x3,        // Meta-types used for category testing

      // Utility flags
      ReferenceFlag      = 0x00,       // For reference query types
      Category1Flag      = 0x01,       // One-word values
      Category2Flag      = 0x02,       // First word of a two-word value
      Category2_2ndFlag  = 0x04,       // Second word of a two-word value

      // special reference values
      Null               = 0x00000000, // A reference with a 0 handle is null

      // Primitives categories (the second byte determines the category)
      Category1          = (Category1Flag     << 1 * BitsPerByte) | Primitive,
      Category2          = (Category2Flag     << 1 * BitsPerByte) | Primitive,
      Category2_2nd      = (Category2_2ndFlag << 1 * BitsPerByte) | Primitive,

      // Primitive values (type descriminator stored in most-signifcant bytes)
      Bogus              = (ITEM_Bogus      << 2 * BitsPerByte) | Category1,
      Boolean            = (ITEM_Boolean    << 2 * BitsPerByte) | Category1,
      Byte               = (ITEM_Byte       << 2 * BitsPerByte) | Category1,
      Short              = (ITEM_Short      << 2 * BitsPerByte) | Category1,
      Char               = (ITEM_Char       << 2 * BitsPerByte) | Category1,
      Integer            = (ITEM_Integer    << 2 * BitsPerByte) | Category1,
      Float              = (ITEM_Float      << 2 * BitsPerByte) | Category1,
      Long               = (ITEM_Long       << 2 * BitsPerByte) | Category2,
      Double             = (ITEM_Double     << 2 * BitsPerByte) | Category2,
      Long_2nd           = (ITEM_Long_2nd   << 2 * BitsPerByte) | Category2_2nd,
      Double_2nd         = (ITEM_Double_2nd << 2 * BitsPerByte) | Category2_2nd,

      // Used by Uninitialized (second and third bytes hold the bci)
      BciMask            = 0xffff << 1 * BitsPerByte,
      BciForThis         = ((u2)-1),   // A bci of -1 is an Unintialized-This

      // Query values
      ReferenceQuery     = (ReferenceFlag     << 1 * BitsPerByte) | TypeQuery,
      Category1Query     = (Category1Flag     << 1 * BitsPerByte) | TypeQuery,
      Category2Query     = (Category2Flag     << 1 * BitsPerByte) | TypeQuery,
      Category2_2ndQuery = (Category2_2ndFlag << 1 * BitsPerByte) | TypeQuery
    };

  VerificationType(uintptr_t raw_data) {
    _u._data = raw_data;
  }

 public:

  VerificationType() { *this = bogus_type(); }

  // Create verification types
  static VerificationType bogus_type() { return VerificationType(Bogus); }
  static VerificationType null_type() { return VerificationType(Null); }
  static VerificationType integer_type() { return VerificationType(Integer); }
  static VerificationType float_type() { return VerificationType(Float); }
  static VerificationType long_type() { return VerificationType(Long); }
  static VerificationType long2_type() { return VerificationType(Long_2nd); }
  static VerificationType double_type() { return VerificationType(Double); }
  static VerificationType boolean_type() { return VerificationType(Boolean); }
  static VerificationType byte_type() { return VerificationType(Byte); }
  static VerificationType char_type() { return VerificationType(Char); }
  static VerificationType short_type() { return VerificationType(Short); }
  static VerificationType double2_type()
    { return VerificationType(Double_2nd); }

  // "check" types are used for queries.  A "check" type is not assignable
  // to anything, but the specified types are assignable to a "check".  For
  // example, any category1 primitive is assignable to category1_check and
  // any reference is assignable to reference_check.
  static VerificationType reference_check()
    { return VerificationType(ReferenceQuery); }
  static VerificationType category1_check()
    { return VerificationType(Category1Query); }
  static VerificationType category2_check()
    { return VerificationType(Category2Query); }
  static VerificationType category2_2nd_check()
    { return VerificationType(Category2_2ndQuery); }

  // For reference types, store the actual oop* handle
  static VerificationType reference_type(symbolHandle sh) {
      assert(((uintptr_t)sh.raw_value() & 0x3) == 0, "Oops must be aligned");
      // If the above assert fails in the future because oop* isn't aligned,
      // then this type encoding system will have to change to have a tag value
      // to descriminate between oops and primitives.
      return VerificationType((uintptr_t)((symbolOop*)sh.raw_value()));
  }
  static VerificationType reference_type(symbolOop s, TRAPS)
    { return reference_type(symbolHandle(THREAD, s)); }

  static VerificationType uninitialized_type(u2 bci)
    { return VerificationType(bci << 1 * BitsPerByte | Uninitialized); }
  static VerificationType uninitialized_this_type()
    { return uninitialized_type(BciForThis); }

  // Create based on u1 read from classfile
  static VerificationType from_tag(u1 tag);

  bool is_bogus() const     { return (_u._data == Bogus); }
  bool is_null() const      { return (_u._data == Null); }
  bool is_boolean() const   { return (_u._data == Boolean); }
  bool is_byte() const      { return (_u._data == Byte); }
  bool is_char() const      { return (_u._data == Char); }
  bool is_short() const     { return (_u._data == Short); }
  bool is_integer() const   { return (_u._data == Integer); }
  bool is_long() const      { return (_u._data == Long); }
  bool is_float() const     { return (_u._data == Float); }
  bool is_double() const    { return (_u._data == Double); }
  bool is_long2() const     { return (_u._data == Long_2nd); }
  bool is_double2() const   { return (_u._data == Double_2nd); }
  bool is_reference() const { return ((_u._data & TypeMask) == Reference); }
  bool is_category1() const {
    // This should return true for all one-word types, which are category1
    // primitives, and references (including uninitialized refs).  Though
    // the 'query' types should technically return 'false' here, if we
    // allow this to return true, we can perform the test using only
    // 2 operations rather than 8 (3 masks, 3 compares and 2 logical 'ands').
    // Since noone should call this on a query type anyway, this is ok.
    assert(!is_check(), "Must not be a check type (wrong value returned)");
    return ((_u._data & Category1) != Primitive);
    // should only return false if it's a primitive, and the category1 flag
    // is not set.
  }
  bool is_category2() const { return ((_u._data & Category2) == Category2); }
  bool is_category2_2nd() const {
    return ((_u._data & Category2_2nd) == Category2_2nd);
  }
  bool is_reference_check() const { return _u._data == ReferenceQuery; }
  bool is_category1_check() const { return _u._data == Category1Query; }
  bool is_category2_check() const { return _u._data == Category2Query; }
  bool is_category2_2nd_check() const { return _u._data == Category2_2ndQuery; }
  bool is_check() const { return (_u._data & TypeQuery) == TypeQuery; }

  bool is_x_array(char sig) const {
    return is_null() || (is_array() && (name()->byte_at(1) == sig));
  }
  bool is_int_array() const { return is_x_array('I'); }
  bool is_byte_array() const { return is_x_array('B'); }
  bool is_bool_array() const { return is_x_array('Z'); }
  bool is_char_array() const { return is_x_array('C'); }
  bool is_short_array() const { return is_x_array('S'); }
  bool is_long_array() const { return is_x_array('J'); }
  bool is_float_array() const { return is_x_array('F'); }
  bool is_double_array() const { return is_x_array('D'); }
  bool is_object_array() const { return is_x_array('L'); }
  bool is_array_array() const { return is_x_array('['); }
  bool is_reference_array() const
    { return is_object_array() || is_array_array(); }
  bool is_object() const
    { return (is_reference() && !is_null() && name()->utf8_length() >= 1 &&
              name()->byte_at(0) != '['); }
  bool is_array() const
    { return (is_reference() && !is_null() && name()->utf8_length() >= 2 &&
              name()->byte_at(0) == '['); }
  bool is_uninitialized() const
    { return ((_u._data & Uninitialized) == Uninitialized); }
  bool is_uninitialized_this() const
    { return is_uninitialized() && bci() == BciForThis; }

  VerificationType to_category2_2nd() const {
    assert(is_category2(), "Must be a double word");
    return VerificationType(is_long() ? Long_2nd : Double_2nd);
  }

  u2 bci() const {
    assert(is_uninitialized(), "Must be uninitialized type");
    return ((_u._data & BciMask) >> 1 * BitsPerByte);
  }

  symbolHandle name_handle() const {
    assert(is_reference() && !is_null(), "Must be a non-null reference");
    return symbolHandle(_u._handle, true);
  }
  symbolOop name() const {
    assert(is_reference() && !is_null(), "Must be a non-null reference");
    return *(_u._handle);
  }

  bool equals(const VerificationType& t) const {
    return (_u._data == t._u._data ||
      (is_reference() && t.is_reference() && !is_null() && !t.is_null() &&
       name() == t.name()));
  }

  bool operator ==(const VerificationType& t) const {
    return equals(t);
  }

  bool operator !=(const VerificationType& t) const {
    return !equals(t);
  }

  // The whole point of this type system - check to see if one type
  // is assignable to another.  Returns true if one can assign 'from' to
  // this.
  bool is_assignable_from(
      const VerificationType& from, instanceKlassHandle context, TRAPS) const {
    if (equals(from) || is_bogus()) {
      return true;
    } else {
      switch(_u._data) {
        case Category1Query:
          return from.is_category1();
        case Category2Query:
          return from.is_category2();
        case Category2_2ndQuery:
          return from.is_category2_2nd();
        case ReferenceQuery:
          return from.is_reference() || from.is_uninitialized();
        case Boolean:
        case Byte:
        case Char:
        case Short:
          // An int can be assigned to boolean, byte, char or short values.
          return from.is_integer();
        default:
          if (is_reference() && from.is_reference()) {
            return is_reference_assignable_from(from, context, CHECK_false);
          } else {
            return false;
          }
      }
    }
  }

  VerificationType get_component(TRAPS) const;

  int dimensions() const {
    assert(is_array(), "Must be an array");
    int index = 0;
    while (name()->byte_at(index++) == '[');
    return index;
  }

  void print_on(outputStream* st) const PRODUCT_RETURN;

 private:

  bool is_reference_assignable_from(
    const VerificationType&, instanceKlassHandle, TRAPS) const;
};