< prev index next > src/hotspot/share/ci/ciInstanceKlass.cpp
Print this page
*
*/
#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"
#include "classfile/vmClasses.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#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
_field_cache = nullptr;
}
// 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;
_has_nonstatic_fields = false;
! _nonstatic_fields = nullptr;
_has_injected_fields = -1;
_is_hidden = false;
_is_record = false;
_loader = loader;
_protection_domain = protection_domain;
_field_cache = nullptr;
}
// 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;
_has_nonstatic_fields = false;
! _nonstatic_fields = nullptr; // initialized lazily by compute_nonstatic_fields
_has_injected_fields = -1;
_is_hidden = false;
_is_record = false;
_loader = loader;
_protection_domain = protection_domain;
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");
}
}
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");
}
}
}
ciField* field = new (CURRENT_THREAD_ENV->arena()) ciField(&fd);
return field;
}
+ ciField* ciInstanceKlass::get_non_flat_field_by_offset(int field_offset) {
+ if (super() != nullptr && super()->has_nonstatic_fields()) {
+ ciField* f = super()->get_non_flat_field_by_offset(field_offset);
+ if (f != nullptr) {
+ 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 nullptr;
+ }
+
// ------------------------------------------------------------------
// 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();
} 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 = nullptr;
InstanceKlass* k = get_instanceKlass();
} else {
return 0;
}
}
_nonstatic_fields = fields;
! return fields->length();
}
! GrowableArray<ciField*>* ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray<ciField*>* super_fields, bool is_flat) {
ASSERT_IN_VM;
Arena* arena = CURRENT_ENV->arena();
int flen = 0;
GrowableArray<ciField*>* fields = nullptr;
InstanceKlass* k = get_instanceKlass();
}
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;
}
for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) continue;
fieldDescriptor& fd = fs.field_descriptor();
! if (fd.is_flat() && is_flat) {
! // 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 flat inline type and copy them to 'this'
+ for (int i = 0; i < vk->nof_nonstatic_fields(); ++i) {
+ ciField* flat_field = vk->nonstatic_field_at(i);
+ // Adjust offset to account for missing oop header
+ int offset = field_offset + (flat_field->offset_in_bytes() - vk->first_field_offset());
+ // A flat field can be treated as final if the non-flat
+ // 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(flat_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;
_implementor = impl;
}
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());
! BasicType field_type = fd->field_type();
! switch (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 == nullptr) {
! if (field_type == T_ARRAY) {
! _out->print("%d", -1);
! }
! _out->cr();
! } else if (value->is_instance()) {
! assert(field_type == T_OBJECT, "");
! if (value->is_a(vmClasses::String_klass())) {
! const char* ascii_value = java_lang_String::as_quoted_ascii(value);
! _out->print_cr("\"%s\"", (ascii_value != nullptr) ? 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());
}
_implementor = impl;
}
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()->access_flags().is_identity_class() || is_java_lang_Object() ;
+ }
+ 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 is_flat);
+ };
+
+ 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 is_flat) {
! BasicType field_type = fd->field_type();
! switch (field_type) {
! 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:
+ if (!fd->is_null_free_inline_type()) {
+ _out->print("%s ", fd->signature()->as_quoted_ascii());
+ oop value = mirror->obj_field_acquire(fd->offset());
+ if (value == nullptr) {
+ if (field_type == T_ARRAY) {
+ _out->print("%d", -1);
+ }
+ _out->cr();
+ } else if (value->is_instance()) {
+ assert(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 != nullptr) ? 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;
+ } else {
+ // handling of null free 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(THREAD, name,
+ Handle(THREAD, holder->class_loader()),
+ Handle(THREAD, holder->protection_domain()));
+ assert(k != nullptr && !HAS_PENDING_EXCEPTION, "can resolve klass?");
+ InlineKlass* vk = InlineKlass::cast(k);
+ oop obj;
+ if (is_flat) {
+ 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 >