8243302: Advanced class supports

Fri, 16 Oct 2020 23:17:14 +0100

author
dcherepanov
date
Fri, 16 Oct 2020 23:17:14 +0100
changeset 10013
7ab1cd9c7843
parent 10012
73d58f4c918a
child 10014
6b836efa38fe

8243302: Advanced class supports
Reviewed-by: mbalao, andrew

src/share/vm/classfile/classFileParser.cpp file | annotate | diff | comparison | revisions
src/share/vm/classfile/classFileParser.hpp file | annotate | diff | comparison | revisions
src/share/vm/oops/constantPool.cpp file | annotate | diff | comparison | revisions
src/share/vm/oops/constantPool.hpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/classfile/classFileParser.cpp	Fri Oct 16 19:25:10 2020 +0100
     1.2 +++ b/src/share/vm/classfile/classFileParser.cpp	Fri Oct 16 23:17:14 2020 +0100
     1.3 @@ -2691,8 +2691,83 @@
     1.4  // Inner classes can be static, private or protected (classic VM does this)
     1.5  #define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC)
     1.6  
     1.7 +// Find index of the InnerClasses entry for the specified inner_class_info_index.
     1.8 +// Return -1 if none is found.
     1.9 +static int inner_classes_find_index(const Array<u2>* inner_classes, int inner, const ConstantPool* cp, int length) {
    1.10 +  Symbol* cp_klass_name =  cp->klass_name_at(inner);
    1.11 +  for (int idx = 0; idx < length; idx += InstanceKlass::inner_class_next_offset) {
    1.12 +    int idx_inner = inner_classes->at(idx + InstanceKlass::inner_class_inner_class_info_offset);
    1.13 +    if (cp->klass_name_at(idx_inner) == cp_klass_name) {
    1.14 +      return idx;
    1.15 +    }
    1.16 +  }
    1.17 +  return -1;
    1.18 +}
    1.19 +
    1.20 +// Return the outer_class_info_index for the InnerClasses entry containing the
    1.21 +// specified inner_class_info_index.  Return -1 if no InnerClasses entry is found.
    1.22 +static int inner_classes_jump_to_outer(const Array<u2>* inner_classes, int inner, const ConstantPool* cp, int length) {
    1.23 +  if (inner == 0) return -1;
    1.24 +  int idx = inner_classes_find_index(inner_classes, inner, cp, length);
    1.25 +  if (idx == -1) return -1;
    1.26 +  int result = inner_classes->at(idx + InstanceKlass::inner_class_outer_class_info_offset);
    1.27 +  return result;
    1.28 +}
    1.29 +
    1.30 +// Return true if circularity is found, false if no circularity is found.
    1.31 +// Use Floyd's cycle finding algorithm.
    1.32 +static bool inner_classes_check_loop_through_outer(const Array<u2>* inner_classes, int idx, const ConstantPool* cp, int length) {
    1.33 +  int slow = inner_classes->at(idx + InstanceKlass::inner_class_inner_class_info_offset);
    1.34 +  int fast = inner_classes->at(idx + InstanceKlass::inner_class_outer_class_info_offset);
    1.35 +  while (fast != -1 && fast != 0) {
    1.36 +    if (slow != 0 && (cp->klass_name_at(slow) == cp->klass_name_at(fast))) {
    1.37 +      return true;  // found a circularity
    1.38 +    }
    1.39 +    fast = inner_classes_jump_to_outer(inner_classes, fast, cp, length);
    1.40 +    if (fast == -1) return false;
    1.41 +    fast = inner_classes_jump_to_outer(inner_classes, fast, cp, length);
    1.42 +    if (fast == -1) return false;
    1.43 +    slow = inner_classes_jump_to_outer(inner_classes, slow, cp, length);
    1.44 +    assert(slow != -1, "sanity check");
    1.45 +  }
    1.46 +  return false;
    1.47 +}
    1.48 +
    1.49 +// Loop through each InnerClasses entry checking for circularities and duplications
    1.50 +// with other entries.  If duplicate entries are found then throw CFE.  Otherwise,
    1.51 +// return true if a circularity or entries with duplicate inner_class_info_indexes
    1.52 +// are found.
    1.53 +bool ClassFileParser::check_inner_classes_circularity(const ConstantPool* cp, int length, TRAPS) {
    1.54 +  // Loop through each InnerClasses entry.
    1.55 +  for (int idx = 0; idx < length; idx += InstanceKlass::inner_class_next_offset) {
    1.56 +    // Return true if there are circular entries.
    1.57 +    if (inner_classes_check_loop_through_outer(_inner_classes, idx, cp, length)) {
    1.58 +      return true;
    1.59 +    }
    1.60 +    // Check if there are duplicate entries or entries with the same inner_class_info_index.
    1.61 +    for (int y = idx + InstanceKlass::inner_class_next_offset; y < length;
    1.62 +         y += InstanceKlass::inner_class_next_offset) {
    1.63 +
    1.64 +      // To maintain compatibility, throw an exception if duplicate inner classes
    1.65 +      // entries are found.
    1.66 +      guarantee_property((_inner_classes->at(idx) != _inner_classes->at(y) ||
    1.67 +                          _inner_classes->at(idx+1) != _inner_classes->at(y+1) ||
    1.68 +                          _inner_classes->at(idx+2) != _inner_classes->at(y+2) ||
    1.69 +                          _inner_classes->at(idx+3) != _inner_classes->at(y+3)),
    1.70 +                         "Duplicate entry in InnerClasses attribute in class file %s",
    1.71 +                         CHECK_(true));
    1.72 +      // Return true if there are two entries with the same inner_class_info_index.
    1.73 +      if (_inner_classes->at(y) == _inner_classes->at(idx)) {
    1.74 +        return true;
    1.75 +      }
    1.76 +    }
    1.77 +  }
    1.78 +  return false;
    1.79 +}
    1.80 +
    1.81  // Return number of classes in the inner classes attribute table
    1.82 -u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start,
    1.83 +u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ConstantPool* cp,
    1.84 +                                                            u1* inner_classes_attribute_start,
    1.85                                                              bool parsed_enclosingmethod_attribute,
    1.86                                                              u2 enclosing_method_class_index,
    1.87                                                              u2 enclosing_method_method_index,
    1.88 @@ -2764,25 +2839,28 @@
    1.89    }
    1.90  
    1.91    // 4347400: make sure there's no duplicate entry in the classes array
    1.92 +  // Also, check for circular entries.
    1.93 +  bool has_circularity = false;
    1.94    if (_need_verify && _major_version >= JAVA_1_5_VERSION) {
    1.95 -    for(int i = 0; i < length * 4; i += 4) {
    1.96 -      for(int j = i + 4; j < length * 4; j += 4) {
    1.97 -        guarantee_property((inner_classes->at(i)   != inner_classes->at(j) ||
    1.98 -                            inner_classes->at(i+1) != inner_classes->at(j+1) ||
    1.99 -                            inner_classes->at(i+2) != inner_classes->at(j+2) ||
   1.100 -                            inner_classes->at(i+3) != inner_classes->at(j+3)),
   1.101 -                            "Duplicate entry in InnerClasses in class file %s",
   1.102 -                            CHECK_0);
   1.103 +    has_circularity = check_inner_classes_circularity(cp, length * 4, CHECK_0);
   1.104 +    if (has_circularity) {
   1.105 +      // If circularity check failed then ignore InnerClasses attribute.
   1.106 +      MetadataFactory::free_array<u2>(_loader_data, _inner_classes);
   1.107 +      index = 0;
   1.108 +      if (parsed_enclosingmethod_attribute) {
   1.109 +        inner_classes = MetadataFactory::new_array<u2>(_loader_data, 2, CHECK_0);
   1.110 +        _inner_classes = inner_classes;
   1.111 +      } else {
   1.112 +        _inner_classes = Universe::the_empty_short_array();
   1.113        }
   1.114      }
   1.115    }
   1.116 -
   1.117    // Set EnclosingMethod class and method indexes.
   1.118    if (parsed_enclosingmethod_attribute) {
   1.119      inner_classes->at_put(index++, enclosing_method_class_index);
   1.120      inner_classes->at_put(index++, enclosing_method_method_index);
   1.121    }
   1.122 -  assert(index == size, "wrong size");
   1.123 +  assert(index == size || has_circularity, "wrong size");
   1.124  
   1.125    // Restore buffer's current position.
   1.126    cfs->set_current(current_mark);
   1.127 @@ -3051,6 +3129,7 @@
   1.128  
   1.129    if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) {
   1.130      u2 num_of_classes = parse_classfile_inner_classes_attribute(
   1.131 +                            _cp,
   1.132                              inner_classes_attribute_start,
   1.133                              parsed_innerclasses_attribute,
   1.134                              enclosing_method_class_index,
     2.1 --- a/src/share/vm/classfile/classFileParser.hpp	Fri Oct 16 19:25:10 2020 +0100
     2.2 +++ b/src/share/vm/classfile/classFileParser.hpp	Fri Oct 16 23:17:14 2020 +0100
     2.3 @@ -275,7 +275,12 @@
     2.4    u2 parse_generic_signature_attribute(TRAPS);
     2.5    void parse_classfile_sourcefile_attribute(TRAPS);
     2.6    void parse_classfile_source_debug_extension_attribute(int length, TRAPS);
     2.7 -  u2   parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start,
     2.8 +
     2.9 +  // Check for circularity in InnerClasses attribute.
    2.10 +  bool check_inner_classes_circularity(const ConstantPool* cp, int length, TRAPS);
    2.11 +
    2.12 +  u2   parse_classfile_inner_classes_attribute(const ConstantPool* cp,
    2.13 +                                               u1* inner_classes_attribute_start,
    2.14                                                 bool parsed_enclosingmethod_attribute,
    2.15                                                 u2 enclosing_method_class_index,
    2.16                                                 u2 enclosing_method_method_index,
     3.1 --- a/src/share/vm/oops/constantPool.cpp	Fri Oct 16 19:25:10 2020 +0100
     3.2 +++ b/src/share/vm/oops/constantPool.cpp	Fri Oct 16 23:17:14 2020 +0100
     3.3 @@ -504,7 +504,7 @@
     3.4  }
     3.5  
     3.6  
     3.7 -Symbol* ConstantPool::klass_name_at(int which) {
     3.8 +Symbol* ConstantPool::klass_name_at(int which) const {
     3.9    assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(),
    3.10           "Corrupted constant pool");
    3.11    // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
     4.1 --- a/src/share/vm/oops/constantPool.hpp	Fri Oct 16 19:25:10 2020 +0100
     4.2 +++ b/src/share/vm/oops/constantPool.hpp	Fri Oct 16 23:17:14 2020 +0100
     4.3 @@ -125,7 +125,7 @@
     4.4   private:
     4.5    intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); }
     4.6  
     4.7 -  CPSlot slot_at(int which) {
     4.8 +  CPSlot slot_at(int which) const {
     4.9      assert(is_within_bounds(which), "index out of bounds");
    4.10      // Uses volatile because the klass slot changes without a lock.
    4.11      volatile intptr_t adr = (intptr_t)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which));
    4.12 @@ -353,7 +353,7 @@
    4.13      return klass_at_impl(h_this, which, CHECK_NULL);
    4.14    }
    4.15  
    4.16 -  Symbol* klass_name_at(int which);  // Returns the name, w/o resolving.
    4.17 +  Symbol* klass_name_at(int which) const;  // Returns the name, w/o resolving.
    4.18  
    4.19    Klass* resolved_klass_at(int which) const {  // Used by Compiler
    4.20      guarantee(tag_at(which).is_klass(), "Corrupted constant pool");

mercurial