--- old/src/hotspot/share/ci/ciInstanceKlass.cpp 2019-03-11 14:25:21.846355768 +0100 +++ new/src/hotspot/share/ci/ciInstanceKlass.cpp 2019-03-11 14:25:21.622355771 +0100 @@ -27,12 +27,14 @@ #include "ci/ciInstance.hpp" #include "ci/ciInstanceKlass.hpp" #include "ci/ciUtilities.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/systemDictionary.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/fieldStreams.hpp" +#include "oops/valueKlass.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.inline.hpp" @@ -63,8 +65,9 @@ _has_nonstatic_fields = ik->has_nonstatic_fields(); _has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods(); _is_unsafe_anonymous = ik->is_unsafe_anonymous(); - _nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields: + _nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields _has_injected_fields = -1; + _vcc_klass = NULL; _implementor = NULL; // we will fill these lazily // Ensure that the metadata wrapped by the ciMetadata is kept alive by GC. @@ -113,15 +116,17 @@ // Version for unloaded classes: ciInstanceKlass::ciInstanceKlass(ciSymbol* name, - jobject loader, jobject protection_domain) - : ciKlass(name, T_OBJECT) + jobject loader, jobject protection_domain, + BasicType bt) + : ciKlass(name, bt) { assert(name->char_at(0) != '[', "not an instance klass"); _init_state = (InstanceKlass::ClassState)0; _nonstatic_field_size = -1; _has_nonstatic_fields = false; - _nonstatic_fields = NULL; + _nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields _has_injected_fields = -1; + _vcc_klass = NULL; _is_unsafe_anonymous = false; _loader = loader; _protection_domain = protection_domain; @@ -416,6 +421,29 @@ 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) { @@ -483,18 +511,11 @@ } } - 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; + return fields->length(); } -GrowableArray* -ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray* - super_fields) { +GrowableArray* ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray* super_fields, bool flatten) { ASSERT_IN_VM; Arena* arena = CURRENT_ENV->arena(); int flen = 0; @@ -512,6 +533,7 @@ if (super_fields != NULL) { flen += super_fields->length(); } + fields = new (arena) GrowableArray(arena, flen, 0, NULL); if (super_fields != NULL) { fields->appendAll(super_fields); @@ -520,10 +542,33 @@ 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); + if (fd.is_flattened() && flatten) { + // Value type fields are embedded + int field_offset = fd.offset(); + // Get ValueKlass and adjust number of fields + Klass* k = get_instanceKlass()->get_value_field_klass(fd.index()); + ciValueKlass* vk = CURRENT_ENV->get_klass(k)->as_value_klass(); + flen += vk->nof_nonstatic_fields() - 1; + // Iterate over fields of the flattened value 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 a value type itself. + bool is_final = fd.is_final() || is_valuetype(); + 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; } @@ -631,6 +676,10 @@ return NULL; } +ciInstanceKlass* ciInstanceKlass::vcc_klass() { + return NULL; +} + // 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 @@ -639,70 +688,123 @@ // only value which statically unchangeable. For all other reference // types it simply prints out the dynamic type. -class StaticFinalFieldPrinter : public FieldClosure { +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) : - _out(out), - _holder(holder) { + StaticFieldPrinter(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(SystemDictionary::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; + 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 ValueTypeFieldPrinter : public StaticFieldPrinter { + oop _obj; +public: + ValueTypeFieldPrinter(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: { + 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(SystemDictionary::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); } - default: - ShouldNotReachHere(); + } else if (value->is_array()) { + typeArrayOop ta = (typeArrayOop)value; + _out->print("%d", ta->length()); + if (value->is_objArray() || value->is_valueArray()) { + objArrayOop oa = (objArrayOop)value; + const char* klass_name = value->klass()->name()->as_quoted_ascii(); + _out->print(" %s", klass_name); } + _out->cr(); + } else { + ShouldNotReachHere(); + } + break; + } + case T_VALUETYPE: { + ResetNoHandleMark rnhm; + Thread* THREAD = Thread::current(); + SignatureStream ss(fd->signature(), false); + Symbol* name = ss.as_symbol(THREAD); + assert(!HAS_PENDING_EXCEPTION, "can resolve klass?"); + InstanceKlass* holder = fd->field_holder(); + Klass* k = SystemDictionary::find(name, Handle(THREAD, holder->class_loader()), + Handle(THREAD, holder->protection_domain()), THREAD); + assert(k != NULL && !HAS_PENDING_EXCEPTION, "can resolve klass?"); + ValueKlass* vk = ValueKlass::cast(k); + oop obj; + if (flattened) { + int field_offset = fd->offset() - vk->first_field_offset(); + obj = (oop)((address)mirror + field_offset); + } else { + obj = mirror->obj_field_acquire(fd->offset()); + } + ValueTypeFieldPrinter print_field(_out, obj); + vk->do_nonstatic_fields(&print_field); + break; } + default: + ShouldNotReachHere(); } -}; +} void ciInstanceKlass::dump_replay_data(outputStream* out) {