< prev index next >

src/hotspot/share/ci/ciInstanceKlass.cpp

Print this page
*** 22,10 ***
--- 22,11 ---
   *
   */
  
  #include "precompiled.hpp"
  #include "ci/ciField.hpp"
+ #include "ci/ciInlineKlass.hpp"
  #include "ci/ciInstance.hpp"
  #include "ci/ciInstanceKlass.hpp"
  #include "ci/ciUtilities.inline.hpp"
  #include "classfile/javaClasses.hpp"
  #include "classfile/systemDictionary.hpp"

*** 35,10 ***
--- 36,11 ---
  #include "memory/resourceArea.hpp"
  #include "oops/instanceKlass.inline.hpp"
  #include "oops/klass.inline.hpp"
  #include "oops/oop.inline.hpp"
  #include "oops/fieldStreams.inline.hpp"
+ #include "oops/inlineKlass.inline.hpp"
  #include "runtime/fieldDescriptor.inline.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/jniHandles.inline.hpp"
  
  // ciInstanceKlass

*** 116,18 ***
    _field_cache = NULL;
  }
  
  // Version for unloaded classes:
  ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
!                                  jobject loader, jobject protection_domain)
!   : ciKlass(name, T_OBJECT)
  {
    assert(name->char_at(0) != JVM_SIGNATURE_ARRAY, "not an instance klass");
    _init_state = (InstanceKlass::ClassState)0;
    _nonstatic_field_size = -1;
    _has_nonstatic_fields = false;
!   _nonstatic_fields = NULL;
    _has_injected_fields = -1;
    _is_hidden = false;
    _is_record = false;
    _loader = loader;
    _protection_domain = protection_domain;
--- 118,19 ---
    _field_cache = NULL;
  }
  
  // Version for unloaded classes:
  ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
!                                  jobject loader, jobject protection_domain,
!                                  BasicType bt)
+   : ciKlass(name, bt)
  {
    assert(name->char_at(0) != JVM_SIGNATURE_ARRAY, "not an instance klass");
    _init_state = (InstanceKlass::ClassState)0;
    _nonstatic_field_size = -1;
    _has_nonstatic_fields = false;
!   _nonstatic_fields = NULL;            // initialized lazily by compute_nonstatic_fields
    _has_injected_fields = -1;
    _is_hidden = false;
    _is_record = false;
    _loader = loader;
    _protection_domain = protection_domain;

*** 359,15 ***
                bool_to_str(is_initialized()),
                bool_to_str(has_finalizer()),
                bool_to_str(has_subklass()),
                layout_helper());
  
!     _flags.print_klass_flags();
  
      if (_super) {
        st->print(" super=");
!       _super->print_name();
      }
      if (_java_mirror) {
        st->print(" mirror=PRESENT");
      }
    } else {
--- 362,15 ---
                bool_to_str(is_initialized()),
                bool_to_str(has_finalizer()),
                bool_to_str(has_subklass()),
                layout_helper());
  
!     _flags.print_klass_flags(st);
  
      if (_super) {
        st->print(" super=");
!       _super->print_name_on(st);
      }
      if (_java_mirror) {
        st->print(" mirror=PRESENT");
      }
    } else {

*** 459,10 ***
--- 462,33 ---
    }
    ciField* field = new (CURRENT_THREAD_ENV->arena()) ciField(&fd);
    return field;
  }
  
+ ciField* ciInstanceKlass::get_non_flattened_field_by_offset(int field_offset) {
+   if (super() != NULL && super()->has_nonstatic_fields()) {
+     ciField* f = super()->get_non_flattened_field_by_offset(field_offset);
+     if (f != NULL) {
+       return f;
+     }
+   }
+ 
+   VM_ENTRY_MARK;
+   InstanceKlass* k = get_instanceKlass();
+   Arena* arena = CURRENT_ENV->arena();
+   for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
+     if (fs.access_flags().is_static())  continue;
+     fieldDescriptor& fd = fs.field_descriptor();
+     if (fd.offset() == field_offset) {
+       ciField* f = new (arena) ciField(&fd);
+       return f;
+     }
+   }
+ 
+   return NULL;
+ }
+ 
  // ------------------------------------------------------------------
  // ciInstanceKlass::get_field_by_name
  ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static) {
    VM_ENTRY_MARK;
    InstanceKlass* k = get_instanceKlass();

*** 520,22 ***
      } else {
        return 0;
      }
    }
  
-   int flen = fields->length();
- 
-   // Now sort them by offset, ascending.
-   // (In principle, they could mix with superclass fields.)
-   fields->sort(sort_field_by_offset);
    _nonstatic_fields = fields;
!   return flen;
  }
  
! GrowableArray<ciField*>*
- ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray<ciField*>*
-                                                super_fields) {
    ASSERT_IN_VM;
    Arena* arena = CURRENT_ENV->arena();
    int flen = 0;
    GrowableArray<ciField*>* fields = NULL;
    InstanceKlass* k = get_instanceKlass();
--- 546,15 ---
      } else {
        return 0;
      }
    }
  
    _nonstatic_fields = fields;
!   return fields->length();
  }
  
! GrowableArray<ciField*>* ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray<ciField*>* super_fields, bool flatten) {
    ASSERT_IN_VM;
    Arena* arena = CURRENT_ENV->arena();
    int flen = 0;
    GrowableArray<ciField*>* fields = NULL;
    InstanceKlass* k = get_instanceKlass();

*** 549,22 ***
      return NULL;  // return nothing if none are locally declared
    }
    if (super_fields != NULL) {
      flen += super_fields->length();
    }
    fields = new (arena) GrowableArray<ciField*>(arena, flen, 0, NULL);
    if (super_fields != NULL) {
      fields->appendAll(super_fields);
    }
  
    for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
      if (fs.access_flags().is_static())  continue;
      fieldDescriptor& fd = fs.field_descriptor();
!     ciField* field = new (arena) ciField(&fd);
!     fields->append(field);
    }
    assert(fields->length() == flen, "sanity");
    return fields;
  }
  
  bool ciInstanceKlass::compute_injected_fields_helper() {
    ASSERT_IN_VM;
--- 568,46 ---
      return NULL;  // return nothing if none are locally declared
    }
    if (super_fields != NULL) {
      flen += super_fields->length();
    }
+ 
    fields = new (arena) GrowableArray<ciField*>(arena, flen, 0, NULL);
    if (super_fields != NULL) {
      fields->appendAll(super_fields);
    }
  
    for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
      if (fs.access_flags().is_static())  continue;
      fieldDescriptor& fd = fs.field_descriptor();
!     if (fd.is_inlined() && flatten) {
!       // Inline type fields are embedded
+       int field_offset = fd.offset();
+       // Get InlineKlass and adjust number of fields
+       Klass* k = get_instanceKlass()->get_inline_type_field_klass(fd.index());
+       ciInlineKlass* vk = CURRENT_ENV->get_klass(k)->as_inline_klass();
+       flen += vk->nof_nonstatic_fields() - 1;
+       // Iterate over fields of the flattened inline type and copy them to 'this'
+       for (int i = 0; i < vk->nof_nonstatic_fields(); ++i) {
+         ciField* flattened_field = vk->nonstatic_field_at(i);
+         // Adjust offset to account for missing oop header
+         int offset = field_offset + (flattened_field->offset() - vk->first_field_offset());
+         // A flattened field can be treated as final if the non-flattened
+         // field is declared final or the holder klass is an inline type itself.
+         bool is_final = fd.is_final() || is_inlinetype();
+         ciField* field = new (arena) ciField(flattened_field, this, offset, is_final);
+         fields->append(field);
+       }
+     } else {
+       ciField* field = new (arena) ciField(&fd);
+       fields->append(field);
+     }
    }
    assert(fields->length() == flen, "sanity");
+   // Now sort them by offset, ascending.
+   // (In principle, they could mix with superclass fields.)
+   fields->sort(sort_field_by_offset);
    return fields;
  }
  
  bool ciInstanceKlass::compute_injected_fields_helper() {
    ASSERT_IN_VM;

*** 658,82 ***
      }
    }
    return impl;
  }
  
  // Utility class for printing of the contents of the static fields for
  // use by compilation replay.  It only prints out the information that
  // could be consumed by the compiler, so for primitive types it prints
  // out the actual value.  For Strings it's the actual string value.
  // For array types it it's first level array size since that's the
  // only value which statically unchangeable.  For all other reference
  // types it simply prints out the dynamic type.
  
! class StaticFinalFieldPrinter : public FieldClosure {
    outputStream* _out;
    const char*   _holder;
   public:
    StaticFinalFieldPrinter(outputStream* out, const char* holder) :
!     _out(out),
-     _holder(holder) {
    }
    void do_field(fieldDescriptor* fd) {
      if (fd->is_final() && !fd->has_initial_value()) {
        ResourceMark rm;
!       oop mirror = fd->field_holder()->java_mirror();
!       _out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii());
!       switch (fd->field_type()) {
!         case T_BYTE:    _out->print_cr("%d", mirror->byte_field(fd->offset()));   break;
!         case T_BOOLEAN: _out->print_cr("%d", mirror->bool_field(fd->offset()));   break;
!         case T_SHORT:   _out->print_cr("%d", mirror->short_field(fd->offset()));  break;
!         case T_CHAR:    _out->print_cr("%d", mirror->char_field(fd->offset()));   break;
!         case T_INT:     _out->print_cr("%d", mirror->int_field(fd->offset()));    break;
!         case T_LONG:    _out->print_cr(INT64_FORMAT, (int64_t)(mirror->long_field(fd->offset())));   break;
!         case T_FLOAT: {
!           float f = mirror->float_field(fd->offset());
!           _out->print_cr("%d", *(int*)&f);
!           break;
!         }
!         case T_DOUBLE: {
!           double d = mirror->double_field(fd->offset());
!           _out->print_cr(INT64_FORMAT, *(int64_t*)&d);
!           break;
!         }
!         case T_ARRAY:  // fall-through
!         case T_OBJECT: {
!           oop value =  mirror->obj_field_acquire(fd->offset());
!           if (value == NULL) {
!             _out->print_cr("null");
!           } else if (value->is_instance()) {
!             assert(fd->field_type() == T_OBJECT, "");
!             if (value->is_a(vmClasses::String_klass())) {
!               const char* ascii_value = java_lang_String::as_quoted_ascii(value);
!               _out->print("\"%s\"", (ascii_value != NULL) ? ascii_value : "");
!             } else {
!               const char* klass_name  = value->klass()->name()->as_quoted_ascii();
!               _out->print_cr("%s", klass_name);
!             }
!           } else if (value->is_array()) {
!             typeArrayOop ta = (typeArrayOop)value;
!             _out->print("%d", ta->length());
!             if (value->is_objArray()) {
!               objArrayOop oa = (objArrayOop)value;
!               const char* klass_name  = value->klass()->name()->as_quoted_ascii();
!               _out->print(" %s", klass_name);
!             }
!             _out->cr();
!           } else {
!             ShouldNotReachHere();
!           }
!           break;
          }
!         default:
!           ShouldNotReachHere();
          }
      }
    }
! };
  
  const char *ciInstanceKlass::replay_name() const {
    return CURRENT_ENV->replay_name(get_instanceKlass());
  }
  
--- 701,152 ---
      }
    }
    return impl;
  }
  
+ bool ciInstanceKlass::can_be_inline_klass(bool is_exact) {
+   if (!EnableValhalla) {
+     return false;
+   }
+   if (!is_loaded() || is_inlinetype()) {
+     // Not loaded or known to be an inline klass
+     return true;
+   }
+   if (!is_exact) {
+     // Not exact, check if this is a valid super for an inline klass
+     VM_ENTRY_MARK;
+     return !get_instanceKlass()->invalid_inline_super();
+   }
+   return false;
+ }
+ 
  // Utility class for printing of the contents of the static fields for
  // use by compilation replay.  It only prints out the information that
  // could be consumed by the compiler, so for primitive types it prints
  // out the actual value.  For Strings it's the actual string value.
  // For array types it it's first level array size since that's the
  // only value which statically unchangeable.  For all other reference
  // types it simply prints out the dynamic type.
  
! class StaticFieldPrinter : public FieldClosure {
+ protected:
    outputStream* _out;
+ public:
+   StaticFieldPrinter(outputStream* out) :
+     _out(out) {
+   }
+   void do_field_helper(fieldDescriptor* fd, oop obj, bool flattened);
+ };
+ 
+ class StaticFinalFieldPrinter : public StaticFieldPrinter {
    const char*   _holder;
   public:
    StaticFinalFieldPrinter(outputStream* out, const char* holder) :
!     StaticFieldPrinter(out), _holder(holder) {
    }
    void do_field(fieldDescriptor* fd) {
      if (fd->is_final() && !fd->has_initial_value()) {
        ResourceMark rm;
!       InstanceKlass* holder = fd->field_holder();
!       oop mirror = holder->java_mirror();
!       _out->print("staticfield %s %s ", _holder, fd->name()->as_quoted_ascii());
!       BasicType bt = fd->field_type();
!       if (bt != T_OBJECT && bt != T_ARRAY) {
!         _out->print("%s ", fd->signature()->as_quoted_ascii());
!       }
!       do_field_helper(fd, mirror, false);
!       _out->cr();
!     }
!   }
! };
! 
! class InlineTypeFieldPrinter : public StaticFieldPrinter {
!   oop _obj;
! public:
!   InlineTypeFieldPrinter(outputStream* out, oop obj) :
!     StaticFieldPrinter(out), _obj(obj) {
!   }
!   void do_field(fieldDescriptor* fd) {
!     do_field_helper(fd, _obj, true);
!     _out->print(" ");
!   }
! };
! 
! void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool flattened) {
!   BasicType bt = fd->field_type();
!   switch (bt) {
!     case T_BYTE:    _out->print("%d", mirror->byte_field(fd->offset()));   break;
!     case T_BOOLEAN: _out->print("%d", mirror->bool_field(fd->offset()));   break;
!     case T_SHORT:   _out->print("%d", mirror->short_field(fd->offset()));  break;
!     case T_CHAR:    _out->print("%d", mirror->char_field(fd->offset()));   break;
!     case T_INT:     _out->print("%d", mirror->int_field(fd->offset()));    break;
!     case T_LONG:    _out->print(INT64_FORMAT, (int64_t)(mirror->long_field(fd->offset())));   break;
!     case T_FLOAT: {
!       float f = mirror->float_field(fd->offset());
!       _out->print("%d", *(int*)&f);
!       break;
!     }
!     case T_DOUBLE: {
!       double d = mirror->double_field(fd->offset());
!       _out->print(INT64_FORMAT, *(int64_t*)&d);
!       break;
!     }
!     case T_ARRAY:  // fall-through
!     case T_OBJECT: {
+       _out->print("%s ", fd->signature()->as_quoted_ascii());
+       oop value =  mirror->obj_field_acquire(fd->offset());
+       if (value == NULL) {
+         _out->print_cr("null");
+       } else if (value->is_instance()) {
+         assert(fd->field_type() == T_OBJECT, "");
+         if (value->is_a(vmClasses::String_klass())) {
+           const char* ascii_value = java_lang_String::as_quoted_ascii(value);
+           _out->print("\"%s\"", (ascii_value != NULL) ? ascii_value : "");
+          } else {
+           const char* klass_name  = value->klass()->name()->as_quoted_ascii();
+           _out->print("%s", klass_name);
          }
!       } else if (value->is_array()) {
!         typeArrayOop ta = (typeArrayOop)value;
+         _out->print("%d", ta->length());
+         if (value->is_objArray() || value->is_flatArray()) {
+           objArrayOop oa = (objArrayOop)value;
+           const char* klass_name  = value->klass()->name()->as_quoted_ascii();
+           _out->print(" %s", klass_name);
          }
+       } else {
+         ShouldNotReachHere();
+       }
+       break;
      }
+     case T_INLINE_TYPE: {
+       ResetNoHandleMark rnhm;
+       Thread* THREAD = Thread::current();
+       SignatureStream ss(fd->signature(), false);
+       Symbol* name = ss.as_symbol();
+       assert(!HAS_PENDING_EXCEPTION, "can resolve klass?");
+       InstanceKlass* holder = fd->field_holder();
+       InstanceKlass* k = SystemDictionary::find_instance_klass(name,
+                                                                Handle(THREAD, holder->class_loader()),
+                                                                Handle(THREAD, holder->protection_domain()));
+       assert(k != NULL && !HAS_PENDING_EXCEPTION, "can resolve klass?");
+       InlineKlass* vk = InlineKlass::cast(k);
+       oop obj;
+       if (flattened) {
+         int field_offset = fd->offset() - vk->first_field_offset();
+         obj = cast_to_oop(cast_from_oop<address>(mirror) + field_offset);
+       } else {
+         obj = mirror->obj_field_acquire(fd->offset());
+       }
+       InlineTypeFieldPrinter print_field(_out, obj);
+       vk->do_nonstatic_fields(&print_field);
+       break;
+     }
+     default:
+       ShouldNotReachHere();
    }
! }
  
  const char *ciInstanceKlass::replay_name() const {
    return CURRENT_ENV->replay_name(get_instanceKlass());
  }
  
< prev index next >