--- old/src/share/vm/ci/ciInstanceKlass.cpp 2017-03-09 09:43:58.286633083 +0100 +++ new/src/share/vm/ci/ciInstanceKlass.cpp 2017-03-09 09:43:54.909635208 +0100 @@ -33,6 +33,7 @@ #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/fieldStreams.hpp" +#include "oops/valueKlass.hpp" #include "runtime/fieldDescriptor.hpp" // ciInstanceKlass @@ -655,77 +656,122 @@ // 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(); + InstanceKlass* holder = fd->field_holder(); + oop mirror = 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: { - oop value = mirror->obj_field_acquire(fd->offset()); - if (value == NULL) { - _out->print_cr("null"); - } else { - 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(); - } - break; - } - case T_OBJECT: { - oop value = mirror->obj_field_acquire(fd->offset()); - if (value == NULL) { - _out->print_cr("null"); - } else if (value->is_instance()) { - if (value->is_a(SystemDictionary::String_klass())) { - _out->print("\""); - _out->print_raw(java_lang_String::as_quoted_ascii(value)); - _out->print_cr("\""); - } else { - const char* klass_name = value->klass()->name()->as_quoted_ascii(); - _out->print_cr("%s", klass_name); - } - } else { - ShouldNotReachHere(); - } - break; - } - default: - ShouldNotReachHere(); - } + 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) { + switch (fd->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: { + oop value = mirror->obj_field_acquire(fd->offset()); + if (value == NULL) { + _out->print("null"); + } else { + 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); + } + } + break; + } + case T_OBJECT: { + oop value = mirror->obj_field_acquire(fd->offset()); + if (value == NULL) { + _out->print("null"); + } else if (value->is_instance()) { + if (value->is_a(SystemDictionary::String_klass())) { + _out->print("\""); + _out->print_raw(java_lang_String::as_quoted_ascii(value)); + _out->print("\""); + } else { + const char* klass_name = value->klass()->name()->as_quoted_ascii(); + _out->print("%s", klass_name); + } + } 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(holder->class_loader()), Handle(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) { ResourceMark rm; --- old/src/share/vm/ci/ciReplay.cpp 2017-03-09 09:44:01.927630792 +0100 +++ new/src/share/vm/ci/ciReplay.cpp 2017-03-09 09:43:58.568632906 +0100 @@ -32,6 +32,7 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" +#include "oops/valueKlass.hpp" #include "utilities/copy.hpp" #include "utilities/macros.hpp" @@ -737,6 +738,84 @@ } } + class ValueTypeFieldInitializer : public FieldClosure { + oop _vt; + CompileReplay* _replay; + public: + ValueTypeFieldInitializer(oop vt, CompileReplay* replay) + : _vt(vt), _replay(replay) {} + + void do_field(fieldDescriptor* fd) { + BasicType bt = fd->field_type(); + const char* string_value = bt != T_VALUETYPE ? _replay->parse_escaped_string() : NULL; + switch (bt) { + case T_BYTE: { + int value = atoi(string_value); + _vt->byte_field_put(fd->offset(), value); + break; + } + case T_BOOLEAN: { + int value = atoi(string_value); + _vt->bool_field_put(fd->offset(), value); + break; + } + case T_SHORT: { + int value = atoi(string_value); + _vt->short_field_put(fd->offset(), value); + break; + } + case T_CHAR: { + int value = atoi(string_value); + _vt->char_field_put(fd->offset(), value); + break; + } + case T_INT: { + int value = atoi(string_value); + _vt->int_field_put(fd->offset(), value); + break; + } + case T_LONG: { + jlong value; + if (sscanf(string_value, JLONG_FORMAT, &value) != 1) { + fprintf(stderr, "Error parsing long: %s\n", string_value); + break; + } + _vt->long_field_put(fd->offset(), value); + break; + } + case T_FLOAT: { + float value = atof(string_value); + _vt->float_field_put(fd->offset(), value); + break; + } + case T_DOUBLE: { + double value = atof(string_value); + _vt->double_field_put(fd->offset(), value); + break; + } + case T_ARRAY: + _replay->report_error("Array in value type unsupported"); + break; + case T_OBJECT: + _replay->report_error("Object in value type unsupported"); + break; + case T_VALUETYPE: { + Thread* THREAD = Thread::current(); + SignatureStream ss(fd->signature(), false); + InstanceKlass* holder = fd->field_holder(); + Klass* k = ss.as_klass(Handle(holder->class_loader()), Handle(holder->protection_domain()), SignatureStream::ReturnNull, THREAD); + assert(k != NULL && !HAS_PENDING_EXCEPTION, "can resolve klass?"); + ValueKlass* vk = ValueKlass::cast(k); + int field_offset = fd->offset() - vk->first_field_offset(); + oop obj = (oop)((address)_vt + field_offset); + ValueTypeFieldInitializer init_fields(obj, _replay); + vk->do_nonstatic_fields(&init_fields); + break; + } + } + } + }; + // Initialize a class and fill in the value for a static field. // This is useful when the compile was dependent on the value of // static fields but it's impossible to properly rerun the static @@ -751,7 +830,7 @@ assert(k->is_initialized(), "must be"); - const char* field_name = parse_escaped_string();; + const char* field_name = parse_escaped_string(); const char* field_signature = parse_string(); fieldDescriptor fd; Symbol* name = SymbolTable::lookup(field_name, (int)strlen(field_name), CHECK); @@ -807,7 +886,7 @@ } java_mirror->obj_field_put(fd.offset(), value); } else { - const char* string_value = parse_escaped_string(); + const char* string_value = field_signature[0] != 'Q' ? parse_escaped_string() : NULL; if (strcmp(field_signature, "I") == 0) { int value = atoi(string_value); java_mirror->int_field_put(fd.offset(), value); @@ -844,6 +923,14 @@ KlassHandle kelem = resolve_klass(field_signature, CHECK); oop value = InstanceKlass::cast(kelem())->allocate_instance(CHECK); java_mirror->obj_field_put(fd.offset(), value); + } else if (field_signature[0] == 'Q') { + Symbol* klass_name = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK); + KlassHandle kelem = resolve_klass(field_signature, CHECK); + ValueKlass* vk = ValueKlass::cast(kelem()); + oop value = vk->allocate_instance(CHECK); + ValueTypeFieldInitializer init_fields(value, this); + vk->do_nonstatic_fields(&init_fields); + java_mirror->obj_field_put(fd.offset(), value); } else { report_error("unhandled staticfield"); } --- old/src/share/vm/opto/callnode.cpp 2017-03-09 09:44:05.560628507 +0100 +++ new/src/share/vm/opto/callnode.cpp 2017-03-09 09:44:02.216630611 +0100 @@ -39,6 +39,7 @@ #include "opto/regmask.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" +#include "opto/valuetypenode.hpp" // Portions of code courtesy of Clifford Click @@ -1138,7 +1139,31 @@ //------------------------------Ideal------------------------------------------ // Skip over any collapsed Regions Node *SafePointNode::Ideal(PhaseGVN *phase, bool can_reshape) { - return remove_dead_region(phase, can_reshape) ? this : NULL; + if (remove_dead_region(phase, can_reshape)) { + return this; + } + if (jvms() != NULL) { + bool progress = false; + // A ValueTypeNode with a valid object input in the debug info? + // Reference the object directly. Helps removal of useless value + // type allocations with incremental inlining. + for (uint i = jvms()->debug_start(); i < jvms()->debug_end(); i++) { + Node *arg = in(i); + if (arg->is_ValueType()) { + ValueTypeNode* vt = arg->as_ValueType(); + Node* in_oop = vt->get_oop(); + const Type* oop_type = phase->type(in_oop); + if (oop_type->meet(TypePtr::NULL_PTR) != oop_type) { + set_req(i, in_oop); + progress = true; + } + } + } + if (progress) { + return this; + } + } + return NULL; } //------------------------------Identity--------------------------------------- @@ -1377,7 +1402,10 @@ //============================================================================= Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if (remove_dead_region(phase, can_reshape)) return this; + Node* res = SafePointNode::Ideal(phase, can_reshape); + if (res != NULL) { + return res; + } // Don't bother trying to transform a dead node if (in(0) && in(0)->is_top()) return NULL; --- old/src/share/vm/opto/escape.cpp 2017-03-09 09:44:09.592625970 +0100 +++ new/src/share/vm/opto/escape.cpp 2017-03-09 09:44:05.870628312 +0100 @@ -2064,8 +2064,8 @@ } } } else if (offset != oopDesc::klass_offset_in_bytes()) { - if (adr_type->isa_instptr()) { - ciField* field = _compile->alias_type(adr_type->isa_instptr())->field(); + if (adr_type->isa_instptr() || adr_type->isa_valuetypeptr()) { + ciField* field = _compile->alias_type(adr_type->is_ptr())->field(); if (field != NULL) { bt = field->layout_type(); } else { @@ -2994,7 +2994,7 @@ n->raise_bottom_type(tinst); igvn->hash_insert(n); record_for_optimizer(n); - if (alloc->is_Allocate() && (t->isa_instptr() || t->isa_aryptr())) { + if (alloc->is_Allocate() && (t->isa_instptr() || t->isa_aryptr() || t->isa_valuetypeptr())) { // First, put on the worklist all Field edges from Connection Graph // which is more accurate than putting immediate users from Ideal Graph. --- old/src/share/vm/opto/macro.cpp 2017-03-09 09:44:13.771623341 +0100 +++ new/src/share/vm/opto/macro.cpp 2017-03-09 09:44:09.874625793 +0100 @@ -831,8 +831,7 @@ if (res != NULL) { klass = res_type->klass(); // Value types are only allocated on demand - assert(!klass->is_valuetype(), "value type allocations should not be scalar replaceable"); - if (res_type->isa_instptr()) { + if (res_type->isa_instptr() || res_type->isa_valuetypeptr()) { // find the fields of the class which will be needed for safepoint debug information assert(klass->is_instance_klass(), "must be an instance klass."); iklass = klass->as_instance_klass(); --- old/src/share/vm/opto/valuetypenode.cpp 2017-03-09 09:44:18.050620649 +0100 +++ new/src/share/vm/opto/valuetypenode.cpp 2017-03-09 09:44:14.026623180 +0100 @@ -347,31 +347,26 @@ JVMState* jvms = sfpt->jvms(); int start = jvms->debug_start(); int end = jvms->debug_end(); - if (oop_type->meet(TypePtr::NULL_PTR) != oop_type) { - // Replace safepoint edge by oop - int nb = sfpt->replace_edges_in_range(this, in_oop, start, end); - --i; imax -= nb; - } else { - // Replace safepoint edge by SafePointScalarObjectNode and add field values - assert(jvms != NULL, "missing JVMS"); - uint first_ind = (sfpt->req() - jvms->scloff()); - SafePointScalarObjectNode* sobj = new SafePointScalarObjectNode(res_type, + assert(oop_type->meet(TypePtr::NULL_PTR) == oop_type, "already available object should be linked directly"); + // Replace safepoint edge by SafePointScalarObjectNode and add field values + assert(jvms != NULL, "missing JVMS"); + uint first_ind = (sfpt->req() - jvms->scloff()); + SafePointScalarObjectNode* sobj = new SafePointScalarObjectNode(res_type, #ifdef ASSERT - NULL, + NULL, #endif - first_ind, nfields); - sobj->init_req(0, C->root()); - // Iterate over the value type fields in order of increasing - // offset and add the field values to the safepoint. - for (uint j = 0; j < nfields; ++j) { - int offset = vk->nonstatic_field_at(j)->offset(); - Node* value = field_value_by_offset(offset, true /* include flattened value type fields */); - sfpt->add_req(value); - } - jvms->set_endoff(sfpt->req()); - int nb = sfpt->replace_edges_in_range(this, sobj, start, end); - --i; imax -= nb; + first_ind, nfields); + sobj->init_req(0, C->root()); + // Iterate over the value type fields in order of increasing + // offset and add the field values to the safepoint. + for (uint j = 0; j < nfields; ++j) { + int offset = vk->nonstatic_field_at(j)->offset(); + Node* value = field_value_by_offset(offset, true /* include flattened value type fields */); + sfpt->add_req(value); } + jvms->set_endoff(sfpt->req()); + int nb = sfpt->replace_edges_in_range(this, sobj, start, end); + --i; imax -= nb; } } } --- old/test/compiler/valhalla/valuetypes/ValueTypeTestBench.java 2017-03-09 09:44:26.748615177 +0100 +++ new/test/compiler/valhalla/valuetypes/ValueTypeTestBench.java 2017-03-09 09:44:18.266620513 +0100 @@ -36,11 +36,7 @@ * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs -XX:-ValueArrayFlatten * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench - */ - -// TODO Enable this -/* - * run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UnlockExperimentalVMOptions -XX:+ValueTypePassFieldsAsArgs -XX:+AlwaysIncrementalInline -XX:+ValueArrayFlatten * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench */