# HG changeset patch # User iklam # Date 1542393535 28800 # Fri Nov 16 10:38:55 2018 -0800 # Branch lworld # Node ID d75e908878490dac5b045be13a83798ce21986ed # Parent 221983ae9e6b1f4b8a4da7b854a89c3abb8de531 [mq]: c1 diff --git a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp --- a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp +++ b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp @@ -50,7 +50,7 @@ #else opr = as_long_opr(reg2, reg); #endif // _LP64 - } else if (type == T_OBJECT || type == T_ARRAY) { + } else if (type == T_OBJECT || type == T_ARRAY || type == T_VALUETYPE) { opr = as_oop_opr(reg); } else if (type == T_METADATA) { opr = as_metadata_opr(reg); diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -200,7 +200,7 @@ __ push_addr(frame_map()->address_for_slot(opr->single_stack_ix())); } else if (opr->is_constant()) { LIR_Const* const_opr = opr->as_constant_ptr(); - if (const_opr->type() == T_OBJECT) { + if (const_opr->type() == T_OBJECT || const_opr->type() == T_VALUETYPE) { __ push_oop(const_opr->as_jobject()); } else if (const_opr->type() == T_INT) { __ push_jint(const_opr->as_jint()); @@ -630,6 +630,7 @@ break; } + case T_VALUETYPE: // Fall through case T_OBJECT: { if (patch_code != lir_patch_none) { jobject2reg_with_patching(dest->as_register(), info); @@ -712,6 +713,7 @@ __ movptr(frame_map()->address_for_slot(dest->single_stack_ix()), c->as_jint_bits()); break; + case T_VALUETYPE: // Fall through case T_OBJECT: __ movoop(frame_map()->address_for_slot(dest->single_stack_ix()), c->as_jobject()); break; @@ -751,6 +753,7 @@ __ movptr(as_Address(addr), c->as_jint_bits()); break; + case T_VALUETYPE: // fall through case T_OBJECT: // fall through case T_ARRAY: if (c->as_jobject() == NULL) { @@ -839,14 +842,14 @@ } #endif assert(src->is_single_cpu(), "must match"); - if (src->type() == T_OBJECT) { + if (src->type() == T_OBJECT || src->type() == T_VALUETYPE) { __ verify_oop(src->as_register()); } move_regs(src->as_register(), dest->as_register()); } else if (dest->is_double_cpu()) { #ifdef _LP64 - if (src->type() == T_OBJECT || src->type() == T_ARRAY) { + if (src->type() == T_OBJECT || src->type() == T_ARRAY || src->type() == T_VALUETYPE) { // Surprising to me but we can see move of a long to t_object __ verify_oop(src->as_register()); move_regs(src->as_register(), dest->as_register_lo()); @@ -917,7 +920,7 @@ if (src->is_single_cpu()) { Address dst = frame_map()->address_for_slot(dest->single_stack_ix()); - if (type == T_OBJECT || type == T_ARRAY) { + if (type == T_OBJECT || type == T_ARRAY || type == T_VALUETYPE) { __ verify_oop(src->as_register()); __ movptr (dst, src->as_register()); } else if (type == T_METADATA) { @@ -963,7 +966,7 @@ PatchingStub* patch = NULL; Register compressed_src = rscratch1; - if (type == T_ARRAY || type == T_OBJECT) { + if (type == T_ARRAY || type == T_OBJECT || type == T_VALUETYPE) { __ verify_oop(src->as_register()); #ifdef _LP64 if (UseCompressedOops && !wide) { @@ -1008,6 +1011,7 @@ break; } + case T_VALUETYPE: // fall through case T_ARRAY: // fall through case T_OBJECT: // fall through if (UseCompressedOops && !wide) { @@ -1098,7 +1102,7 @@ assert(dest->is_register(), "should not call otherwise"); if (dest->is_single_cpu()) { - if (type == T_ARRAY || type == T_OBJECT) { + if (type == T_ARRAY || type == T_OBJECT || type == T_VALUETYPE) { __ movptr(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix())); __ verify_oop(dest->as_register()); } else if (type == T_METADATA) { @@ -1139,7 +1143,7 @@ void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { if (src->is_single_stack()) { - if (type == T_OBJECT || type == T_ARRAY) { + if (type == T_OBJECT || type == T_ARRAY || type == T_VALUETYPE) { __ pushptr(frame_map()->address_for_slot(src ->single_stack_ix())); __ popptr (frame_map()->address_for_slot(dest->single_stack_ix())); } else { @@ -1178,7 +1182,7 @@ LIR_Address* addr = src->as_address_ptr(); Address from_addr = as_Address(addr); - if (addr->base()->type() == T_OBJECT) { + if (addr->base()->type() == T_OBJECT || addr->base()->type() == T_VALUETYPE) { __ verify_oop(addr->base()->as_pointer_register()); } @@ -1231,6 +1235,7 @@ break; } + case T_VALUETYPE: // fall through case T_OBJECT: // fall through case T_ARRAY: // fall through if (UseCompressedOops && !wide) { @@ -1340,7 +1345,7 @@ patching_epilog(patch, patch_code, addr->base()->as_register(), info); } - if (type == T_ARRAY || type == T_OBJECT) { + if (type == T_ARRAY || type == T_OBJECT || type == T_VALUETYPE) { #ifdef _LP64 if (UseCompressedOops && !wide) { __ decode_heap_oop(dest->as_register()); @@ -1577,7 +1582,7 @@ Register len = op->len()->as_register(); LP64_ONLY( __ movslq(len, len); ) - if (UseSlowPath || + if (UseSlowPath || op->type() == T_VALUETYPE || (!UseFastNewObjectArray && (op->type() == T_OBJECT || op->type() == T_ARRAY)) || (!UseFastNewTypeArray && (op->type() != T_OBJECT && op->type() != T_ARRAY))) { __ jmp(*op->stub()->entry()); @@ -2498,7 +2503,7 @@ } else { #ifdef _LP64 Register r_lo; - if (right->type() == T_OBJECT || right->type() == T_ARRAY) { + if (right->type() == T_OBJECT || right->type() == T_ARRAY || right->type() == T_VALUETYPE) { r_lo = right->as_register(); } else { r_lo = right->as_register_lo(); @@ -2611,15 +2616,15 @@ Register reg1 = opr1->as_register(); if (opr2->is_single_cpu()) { // cpu register - cpu register - if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY) { + if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY || opr1->type() == T_VALUETYPE) { __ cmpoop(reg1, opr2->as_register()); } else { - assert(opr2->type() != T_OBJECT && opr2->type() != T_ARRAY, "cmp int, oop?"); + assert(opr2->type() != T_OBJECT && opr2->type() != T_ARRAY && opr2->type() != T_VALUETYPE, "cmp int, oop?"); __ cmpl(reg1, opr2->as_register()); } } else if (opr2->is_stack()) { // cpu register - stack - if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY) { + if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY || opr1->type() == T_VALUETYPE) { __ cmpoop(reg1, frame_map()->address_for_slot(opr2->single_stack_ix())); } else { __ cmpl(reg1, frame_map()->address_for_slot(opr2->single_stack_ix())); @@ -2629,7 +2634,7 @@ LIR_Const* c = opr2->as_constant_ptr(); if (c->type() == T_INT) { __ cmpl(reg1, c->as_jint()); - } else if (c->type() == T_OBJECT || c->type() == T_ARRAY) { + } else if (c->type() == T_OBJECT || c->type() == T_ARRAY || c->type() == T_VALUETYPE) { // In 64bit oops are single register jobject o = c->as_jobject(); if (o == NULL) { @@ -2729,7 +2734,7 @@ } else if (opr1->is_address() && opr2->is_constant()) { LIR_Const* c = opr2->as_constant_ptr(); #ifdef _LP64 - if (c->type() == T_OBJECT || c->type() == T_ARRAY) { + if (c->type() == T_OBJECT || c->type() == T_ARRAY || c->type() == T_VALUETYPE) { assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "need to reverse"); __ movoop(rscratch1, c->as_jobject()); } @@ -2741,7 +2746,7 @@ LIR_Address* addr = opr1->as_address_ptr(); if (c->type() == T_INT) { __ cmpl(as_Address(addr), c->as_jint()); - } else if (c->type() == T_OBJECT || c->type() == T_ARRAY) { + } else if (c->type() == T_OBJECT || c->type() == T_ARRAY || c->type() == T_VALUETYPE) { #ifdef _LP64 // %%% Make this explode if addr isn't reachable until we figure out a // better strategy by giving noreg as the temp for as_Address diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -33,6 +33,7 @@ #include "ci/ciArray.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "gc/shared/c1/barrierSetC1.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" @@ -1198,6 +1199,21 @@ __ move(reg, result); } +void LIRGenerator::do_NewValueTypeInstance (NewValueTypeInstance* x) { + // Mapping to do_NewInstance (same code) + CodeEmitInfo* info = state_for(x, x->state()); + x->set_to_object_type(); + LIR_Opr reg = result_register_for(x->type()); + new_instance(reg, x->klass(), x->is_unresolved(), + FrameMap::rcx_oop_opr, + FrameMap::rdi_oop_opr, + FrameMap::rsi_oop_opr, + LIR_OprFact::illegalOpr, + FrameMap::rdx_metadata_opr, info); + LIR_Opr result = rlock_result(x); + __ move(reg, result); + +} void LIRGenerator::do_NewTypeArray(NewTypeArray* x) { CodeEmitInfo* info = state_for(x, x->state()); diff --git a/src/hotspot/cpu/x86/c1_globals_x86.hpp b/src/hotspot/cpu/x86/c1_globals_x86.hpp --- a/src/hotspot/cpu/x86/c1_globals_x86.hpp +++ b/src/hotspot/cpu/x86/c1_globals_x86.hpp @@ -39,7 +39,7 @@ define_pd_global(bool, PreferInterpreterNativeStubs, false); define_pd_global(bool, ProfileTraps, false); define_pd_global(bool, UseOnStackReplacement, true ); -define_pd_global(bool, TieredCompilation, false); +define_pd_global(bool, TieredCompilation, true); define_pd_global(intx, CompileThreshold, 1500 ); define_pd_global(intx, OnStackReplacePercentage, 933 ); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -490,6 +490,7 @@ case T_OBJECT: case T_ARRAY: case T_ADDRESS: + case T_VALUETYPE: case T_VALUETYPEPTR: if (int_args < Argument::n_int_register_parameters_j) { regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); diff --git a/src/hotspot/share/c1/c1_Canonicalizer.cpp b/src/hotspot/share/c1/c1_Canonicalizer.cpp --- a/src/hotspot/share/c1/c1_Canonicalizer.cpp +++ b/src/hotspot/share/c1/c1_Canonicalizer.cpp @@ -644,6 +644,7 @@ void Canonicalizer::do_TypeCast (TypeCast* x) {} void Canonicalizer::do_Invoke (Invoke* x) {} void Canonicalizer::do_NewInstance (NewInstance* x) {} +void Canonicalizer::do_NewValueTypeInstance(NewValueTypeInstance* x) {} void Canonicalizer::do_NewTypeArray (NewTypeArray* x) {} void Canonicalizer::do_NewObjectArray (NewObjectArray* x) {} void Canonicalizer::do_NewMultiArray (NewMultiArray* x) {} diff --git a/src/hotspot/share/c1/c1_Canonicalizer.hpp b/src/hotspot/share/c1/c1_Canonicalizer.hpp --- a/src/hotspot/share/c1/c1_Canonicalizer.hpp +++ b/src/hotspot/share/c1/c1_Canonicalizer.hpp @@ -81,6 +81,7 @@ virtual void do_TypeCast (TypeCast* x); virtual void do_Invoke (Invoke* x); virtual void do_NewInstance (NewInstance* x); + virtual void do_NewValueTypeInstance(NewValueTypeInstance* x); virtual void do_NewTypeArray (NewTypeArray* x); virtual void do_NewObjectArray (NewObjectArray* x); virtual void do_NewMultiArray (NewMultiArray* x); diff --git a/src/hotspot/share/c1/c1_FrameMap.cpp b/src/hotspot/share/c1/c1_FrameMap.cpp --- a/src/hotspot/share/c1/c1_FrameMap.cpp +++ b/src/hotspot/share/c1/c1_FrameMap.cpp @@ -41,7 +41,7 @@ for (int i = 0; i < sig->count(); i++) { ciType* type = sig->type_at(i); BasicType t = type->basic_type(); - if (t == T_ARRAY) { + if (t == T_ARRAY || t == T_VALUETYPE) { t = T_OBJECT; } sta->append(t); diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -33,6 +33,7 @@ #include "ci/ciKlass.hpp" #include "ci/ciMemberName.hpp" #include "ci/ciUtilities.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/bytecode.hpp" #include "jfr/jfrEvents.hpp" @@ -648,6 +649,17 @@ } } + // Record this newly allocated object + void new_instance(NewValueTypeInstance* object) { + int index = _newobjects.length(); + _newobjects.append(object); + if (_fields.at_grow(index, NULL) == NULL) { + _fields.at_put(index, new FieldBuffer()); + } else { + _fields.at(index)->kill(); + } + } + void store_value(Value value) { int index = _newobjects.find(value); if (index != -1) { @@ -979,7 +991,19 @@ (array->as_NewArray() && array->as_NewArray()->length() && array->as_NewArray()->length()->type()->is_constant())) { length = append(new ArrayLength(array, state_before)); } - push(as_ValueType(type), append(new LoadIndexed(array, index, length, type, state_before))); + + if (array->is_flattened_array()) { + ciType* array_type = array->declared_type(); + ciValueKlass* elem_klass = array_type->as_value_array_klass()->element_klass()->as_value_klass(); + NewValueTypeInstance* new_instance = new NewValueTypeInstance(elem_klass, state_before, false); + _memory->new_instance(new_instance); + apush(append_split(new_instance)); + LoadIndexed* load_indexed = new LoadIndexed(array, index, length, type, state_before); + load_indexed->set_vt(new_instance); + append(load_indexed); + } else { + push(as_ValueType(type), append(new LoadIndexed(array, index, length, type, state_before))); + } } @@ -1700,7 +1724,7 @@ Value constant = NULL; obj = apop(); ObjectType* obj_type = obj->type()->as_ObjectType(); - if (field->is_constant() && obj_type->is_constant() && !PatchALot) { + if (field->is_constant() && !field->is_flattened() && obj_type->is_constant() && !PatchALot) { ciObject* const_oop = obj_type->constant_value(); if (!const_oop->is_null_object() && const_oop->is_loaded()) { ciConstant field_value = field->constant_value_of(const_oop); @@ -1723,13 +1747,35 @@ if (state_before == NULL) { state_before = copy_state_for_exception(); } - LoadField* load = new LoadField(obj, offset, field, false, state_before, needs_patching); - Value replacement = !needs_patching ? _memory->load(load) : load; - if (replacement != load) { - assert(replacement->is_linked() || !replacement->can_be_linked(), "should already by linked"); - push(type, replacement); - } else { - push(type, append(load)); + // Pb with test below, is_flattened() can return true for fields that are not value types + // (initialization issue of ciField?) + if (!(field->type()->is_valuetype() && field->is_flattened())) { + LoadField* load = new LoadField(obj, offset, field, false, state_before, needs_patching); + Value replacement = !needs_patching ? _memory->load(load) : load; + if (replacement != load) { + assert(replacement->is_linked() || !replacement->can_be_linked(), "should already by linked"); + push(type, replacement); + } else { + push(type, append(load)); + } + } else { // flattened field, not optimized solution: re-instantiate the flattened value + ciValueKlass* value_klass = field->type()->as_value_klass(); + int flattening_offset = field->offset() - value_klass->first_field_offset(); + assert(field->type()->is_valuetype(), "Sanity check"); + scope()->set_wrote_final(); + scope()->set_wrote_fields(); + NewValueTypeInstance* new_instance = new NewValueTypeInstance(value_klass, state_before, false); + _memory->new_instance(new_instance); + apush(append_split(new_instance)); + for (int i = 0; i < holder->nof_nonstatic_fields(); i++) { + ciField* inner_field = holder->nonstatic_field_at(i); + int off = inner_field->offset(); + // Only load those fields who are not modified + LoadField* load = new LoadField(obj, off + flattening_offset, inner_field, false, state_before, needs_patching); + Value replacement = append(load); + StoreField* store = new StoreField(new_instance, off, inner_field, replacement, false, state_before, needs_patching); + append(store); + } } } break; @@ -1744,10 +1790,27 @@ Value mask = append(new Constant(new IntConstant(1))); val = append(new LogicOp(Bytecodes::_iand, val, mask)); } - StoreField* store = new StoreField(obj, offset, field, val, false, state_before, needs_patching); - if (!needs_patching) store = _memory->store(store); - if (store != NULL) { - append(store); + // Pb with test below, is_flattened() can return true for fields that are not value types + // (initialization issue of ciField?) + if (!(field->type()->is_valuetype() && field->is_flattened())) { + StoreField* store = new StoreField(obj, offset, field, val, false, state_before, needs_patching); + if (!needs_patching) store = _memory->store(store); + if (store != NULL) { + append(store); + } + } else { + ciValueKlass* value_klass = field->type()->as_value_klass(); + int flattening_offset = field->offset() - value_klass->first_field_offset(); + for (int i = 0; i < holder->nof_nonstatic_fields(); i++) { + ciField* inner_field = holder->nonstatic_field_at(i); + int off = inner_field->offset(); + // Only load those fields who are not modified + // LoadField* load = new LoadField(obj, off + flattening_offset, inner_field, false, state_before, needs_patching); + LoadField* load = new LoadField(val, off, inner_field, false, state_before, needs_patching); + Value replacement = append(load); + StoreField* store = new StoreField(obj, off + flattening_offset, inner_field, replacement, false, state_before, needs_patching); + append(store); + } } break; } @@ -1757,6 +1820,57 @@ } } +// Baseline version of withfield, allocate every time +void GraphBuilder::withfield(int field_index) +{ + bool will_link; + ciField* field_modify = stream()->get_field(will_link); + ciInstanceKlass* holder = field_modify->holder(); + assert(holder->is_valuetype(), "must be a value klass"); + BasicType field_type = field_modify->type()->basic_type(); + ValueType* type = as_ValueType(field_type); + + // call will_link again to determine if the field is valid. + const bool needs_patching = !holder->is_loaded() || + !field_modify->will_link(method(), Bytecodes::_withfield) || + PatchALot; + + + scope()->set_wrote_final(); + scope()->set_wrote_fields(); + + const int offset = !needs_patching ? field_modify->offset() : -1; + Value val = pop(type); + Value obj = apop(); + + ValueStack* state_before = copy_state_for_exception(); + + NewValueTypeInstance* new_instance = new NewValueTypeInstance(holder->as_value_klass(), state_before, false); + _memory->new_instance(new_instance); + apush(append_split(new_instance)); + + for (int i = 0; i < holder->nof_nonstatic_fields(); i++) { + ciField* field = holder->nonstatic_field_at(i); + int off = field->offset(); + + if (field->offset() != offset) { + // Only load those fields who are not modified + LoadField* load = new LoadField(obj, off, field, false, state_before, needs_patching); + Value replacement = append(load); + + StoreField* store = new StoreField(new_instance, off, field, replacement, false, state_before, needs_patching); + append(store); + } + } + + // Field to modify + if (field_modify->type()->basic_type() == T_BOOLEAN) { + Value mask = append(new Constant(new IntConstant(1))); + val = append(new LogicOp(Bytecodes::_iand, val, mask)); + } + StoreField* store = new StoreField(new_instance, offset, field_modify, val, false, state_before, needs_patching); + append(store); +} Dependencies* GraphBuilder::dependency_recorder() const { assert(DeoptC1, "need debug information"); @@ -2144,11 +2258,22 @@ bool will_link; ciKlass* klass = stream()->get_klass(will_link); assert(klass->is_instance_klass(), "must be an instance klass"); + assert(!klass->is_valuetype(), "must not be a value klass"); NewInstance* new_instance = new NewInstance(klass->as_instance_klass(), state_before, stream()->is_unresolved_klass()); _memory->new_instance(new_instance); apush(append_split(new_instance)); } +void GraphBuilder::new_value_type_instance(int klass_index) { + ValueStack* state_before = copy_state_exhandling(); + bool will_link; + ciKlass* klass = stream()->get_klass(will_link); + assert(klass->is_valuetype(), "must be a value klass"); + NewValueTypeInstance* new_instance = new NewValueTypeInstance(klass->as_value_klass(), + state_before, stream()->is_unresolved_klass()); + _memory->new_instance(new_instance); + apush(append_split(new_instance)); +} void GraphBuilder::new_type_array() { ValueStack* state_before = copy_state_exhandling(); @@ -2883,6 +3008,8 @@ case Bytecodes::_ifnonnull : if_null(objectType, If::neq); break; case Bytecodes::_goto_w : _goto(s.cur_bci(), s.get_far_dest()); break; case Bytecodes::_jsr_w : jsr(s.get_far_dest()); break; + case Bytecodes::_defaultvalue : new_value_type_instance(s.get_index_u2()); break; + case Bytecodes::_withfield : withfield(s.get_index_u2()); break; case Bytecodes::_breakpoint : BAILOUT_("concurrent setting of breakpoint", NULL); default : ShouldNotReachHere(); break; } @@ -3178,7 +3305,7 @@ ciType* type = sig->type_at(i); BasicType basic_type = type->basic_type(); // don't allow T_ARRAY to propagate into locals types - if (basic_type == T_ARRAY) basic_type = T_OBJECT; + if (basic_type == T_ARRAY || basic_type == T_VALUETYPE) basic_type = T_OBJECT; ValueType* vt = as_ValueType(basic_type); state->store_local(idx, new Local(type, vt, idx, false)); idx += type->size(); diff --git a/src/hotspot/share/c1/c1_GraphBuilder.hpp b/src/hotspot/share/c1/c1_GraphBuilder.hpp --- a/src/hotspot/share/c1/c1_GraphBuilder.hpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.hpp @@ -267,6 +267,10 @@ void throw_op(int bci); Value round_fp(Value fp_value); + // value types + void new_value_type_instance(int klass_index); + void withfield(int field_index); + // stack/code manipulation helpers Instruction* append_with_bci(Instruction* instr, int bci); Instruction* append(Instruction* instr); diff --git a/src/hotspot/share/c1/c1_Instruction.cpp b/src/hotspot/share/c1/c1_Instruction.cpp --- a/src/hotspot/share/c1/c1_Instruction.cpp +++ b/src/hotspot/share/c1/c1_Instruction.cpp @@ -29,6 +29,8 @@ #include "c1/c1_ValueStack.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeArrayKlass.hpp" +#include "ci/ciValueArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" // Implementation of Instruction @@ -112,6 +114,18 @@ return NULL; } +bool Instruction::is_flattened_array() const { + if (ValueArrayFlatten) { + ciType* type = declared_type(); + if (type != NULL && + type->is_value_array_klass() && + type->as_value_array_klass()->element_klass()->as_value_klass()->flatten_array()) { + return true; + } + } + + return false; +} #ifndef PRODUCT void Instruction::check_state(ValueStack* state) { @@ -223,6 +237,23 @@ return exact_type(); } +Value NewValueTypeInstance::depends_on() { + if (_depends_on != this) { + if (_depends_on->as_NewValueTypeInstance() != NULL) { + return _depends_on->as_NewValueTypeInstance()->depends_on(); + } + } + return _depends_on; +} + +ciType* NewValueTypeInstance::exact_type() const { + return klass(); +} + +ciType* NewValueTypeInstance::declared_type() const { + return exact_type(); +} + ciType* CheckCast::declared_type() const { return klass(); } diff --git a/src/hotspot/share/c1/c1_Instruction.hpp b/src/hotspot/share/c1/c1_Instruction.hpp --- a/src/hotspot/share/c1/c1_Instruction.hpp +++ b/src/hotspot/share/c1/c1_Instruction.hpp @@ -72,6 +72,7 @@ class StateSplit; class Invoke; class NewInstance; +class NewValueTypeInstance; class NewArray; class NewTypeArray; class NewObjectArray; @@ -177,6 +178,7 @@ virtual void do_TypeCast (TypeCast* x) = 0; virtual void do_Invoke (Invoke* x) = 0; virtual void do_NewInstance (NewInstance* x) = 0; + virtual void do_NewValueTypeInstance(NewValueTypeInstance* x) = 0; virtual void do_NewTypeArray (NewTypeArray* x) = 0; virtual void do_NewObjectArray (NewObjectArray* x) = 0; virtual void do_NewMultiArray (NewMultiArray* x) = 0; @@ -503,6 +505,8 @@ return _next; } + bool is_flattened_array() const; + Instruction *insert_after_same_bci(Instruction *i) { #ifndef PRODUCT i->set_printable_bci(printable_bci()); @@ -550,6 +554,7 @@ virtual StateSplit* as_StateSplit() { return NULL; } virtual Invoke* as_Invoke() { return NULL; } virtual NewInstance* as_NewInstance() { return NULL; } + virtual NewValueTypeInstance* as_NewValueTypeInstance() { return NULL; } virtual NewArray* as_NewArray() { return NULL; } virtual NewTypeArray* as_NewTypeArray() { return NULL; } virtual NewObjectArray* as_NewObjectArray() { return NULL; } @@ -947,6 +952,7 @@ LEAF(LoadIndexed, AccessIndexed) private: NullCheck* _explicit_null_check; // For explicit null check elimination + NewValueTypeInstance* _vt; public: // creation @@ -964,6 +970,9 @@ ciType* exact_type() const; ciType* declared_type() const; + NewValueTypeInstance* vt() { return _vt; } + void set_vt(NewValueTypeInstance* vt) { _vt = vt; } + // generic HASHING2(LoadIndexed, true, array()->subst(), index()->subst()) }; @@ -1315,6 +1324,42 @@ ciType* declared_type() const; }; +LEAF(NewValueTypeInstance, StateSplit) + bool _is_unresolved; + ciValueKlass* _klass; + Value _depends_on; // Link to instance on with withfield was called on + +public: + + // Default creation, always allocated for now + NewValueTypeInstance(ciValueKlass* klass, ValueStack* state_before, bool is_unresolved, Value depends_on = NULL) + : StateSplit(instanceType, state_before) + , _is_unresolved(is_unresolved) + , _klass(klass) + { + if (depends_on == NULL) { + _depends_on = this; + } else { + _depends_on = depends_on; + } + } + + // accessors + bool is_unresolved() const { return _is_unresolved; } + Value depends_on(); + + ciValueKlass* klass() const { return _klass; } + + virtual bool needs_exception_state() const { return false; } + + // generic + virtual bool can_trap() const { return true; } + ciType* exact_type() const; + ciType* declared_type() const; + + // Only done in LIR Generator -> map everything to object + void set_to_object_type() { set_type(instanceType); } +}; BASE(NewArray, StateSplit) private: diff --git a/src/hotspot/share/c1/c1_InstructionPrinter.cpp b/src/hotspot/share/c1/c1_InstructionPrinter.cpp --- a/src/hotspot/share/c1/c1_InstructionPrinter.cpp +++ b/src/hotspot/share/c1/c1_InstructionPrinter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "ci/ciArray.hpp" #include "ci/ciInstance.hpp" #include "ci/ciObject.hpp" +#include "ci/ciValueKlass.hpp" #ifndef PRODUCT @@ -44,6 +45,7 @@ case T_DOUBLE : return "double"; case T_ARRAY : return "array"; case T_OBJECT : return "object"; + case T_VALUETYPE : return "value type"; default : return "???"; } } @@ -516,6 +518,10 @@ output()->put(']'); } +void InstructionPrinter::do_NewValueTypeInstance(NewValueTypeInstance* x) { + output()->print("new value type instance "); + print_klass(x->klass()); +} void InstructionPrinter::do_NewObjectArray(NewObjectArray* x) { output()->print("new object array ["); diff --git a/src/hotspot/share/c1/c1_InstructionPrinter.hpp b/src/hotspot/share/c1/c1_InstructionPrinter.hpp --- a/src/hotspot/share/c1/c1_InstructionPrinter.hpp +++ b/src/hotspot/share/c1/c1_InstructionPrinter.hpp @@ -104,6 +104,7 @@ virtual void do_TypeCast (TypeCast* x); virtual void do_Invoke (Invoke* x); virtual void do_NewInstance (NewInstance* x); + virtual void do_NewValueTypeInstance(NewValueTypeInstance* x); virtual void do_NewTypeArray (NewTypeArray* x); virtual void do_NewObjectArray (NewObjectArray* x); virtual void do_NewMultiArray (NewMultiArray* x); diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -107,6 +107,7 @@ char LIR_OprDesc::type_char(BasicType t) { switch (t) { case T_ARRAY: + case T_VALUETYPE: t = T_OBJECT; case T_BOOLEAN: case T_CHAR: @@ -165,6 +166,7 @@ case T_OBJECT: case T_METADATA: case T_ARRAY: + case T_VALUETYPE: assert((kindfield == cpu_register || kindfield == stack_value) && size_field() == single_size, "must match"); break; diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -316,6 +316,7 @@ case T_INT: case T_ADDRESS: case T_OBJECT: + case T_VALUETYPE: case T_ARRAY: case T_METADATA: return single_size; @@ -466,6 +467,7 @@ case T_FLOAT: return LIR_OprDesc::float_type; case T_DOUBLE: return LIR_OprDesc::double_type; case T_OBJECT: + case T_VALUETYPE: case T_ARRAY: return LIR_OprDesc::object_type; case T_ADDRESS: return LIR_OprDesc::address_type; case T_METADATA: return LIR_OprDesc::metadata_type; @@ -651,6 +653,7 @@ LIR_Opr res; switch (type) { case T_OBJECT: // fall through + case T_VALUETYPE: // fall through case T_ARRAY: res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::object_type | @@ -756,6 +759,7 @@ static LIR_Opr stack(int index, BasicType type) { LIR_Opr res; switch (type) { + case T_VALUETYPE: // fall through case T_OBJECT: // fall through case T_ARRAY: res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -59,6 +59,7 @@ } else if (patch->id() == PatchingStub::load_klass_id) { switch (code) { case Bytecodes::_new: + case Bytecodes::_defaultvalue: case Bytecodes::_anewarray: case Bytecodes::_multianewarray: case Bytecodes::_instanceof: diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -34,6 +34,8 @@ #include "ci/ciInstance.hpp" #include "ci/ciObjArray.hpp" #include "ci/ciUtilities.hpp" +#include "ci/ciValueArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/c1/barrierSetC1.hpp" #include "runtime/arguments.hpp" @@ -1548,12 +1550,85 @@ value.result(), info != NULL ? new CodeEmitInfo(info) : NULL, info); } +// FIXME -- I can't find any other way to pass an address to access_load_at(). +class TempResolvedAddress: public Instruction { + public: + TempResolvedAddress(ValueType* type, LIR_Opr addr) : Instruction(type) { + set_operand(addr); + } + virtual void input_values_do(ValueVisitor*) {} + virtual void visit(InstructionVisitor* v) {} + virtual const char* name() const { return "TempResolvedAddress"; } +}; + +void LIRGenerator::access_flattened_array(bool is_load, LIRItem& array, LIRItem& index, LIRItem& obj_item) { + // Find the starting address of the source (inside the array) + ciType* array_type = array.value()->declared_type(); + ciValueArrayKlass* value_array_klass = array_type->as_value_array_klass(); + ciValueKlass* elem_klass = value_array_klass->element_klass()->as_value_klass(); + int array_header_size = value_array_klass->array_header_in_bytes(); + +#ifndef _LP64 + LIR_Opr index_op = index.result(); +#else + LIR_Opr index_op = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index.result(), index_op); +#endif + // Need to shift manually, as LIR_Address can scale only up to 3. + __ shift_left(index_op, value_array_klass->log2_element_size(), index_op); + + LIR_Opr elm_op = new_pointer_register(); + LIR_Address* elm_address = new LIR_Address(array.result(), index_op, array_header_size, T_ADDRESS); + __ leal(LIR_OprFact::address(elm_address), elm_op); + + for (int i = 0; i < elem_klass->nof_nonstatic_fields(); i++) { + ciField* inner_field = elem_klass->nonstatic_field_at(i); + int obj_offset = inner_field->offset(); + int elm_offset = obj_offset - elem_klass->first_field_offset(); // object header is not stored in array. + + BasicType field_type = inner_field->type()->basic_type(); + switch (field_type) { + case T_BYTE: + case T_BOOLEAN: + case T_SHORT: + case T_CHAR: + field_type = T_INT; + break; + default: + break; + } + + LIR_Opr temp = new_register(field_type); + TempResolvedAddress* elm_resolved_addr = new TempResolvedAddress(as_ValueType(field_type), elm_op); + LIRItem elm_item(elm_resolved_addr, this); + + DecoratorSet decorators = IN_HEAP; + if (is_load) { + access_load_at(decorators, field_type, + elm_item, LIR_OprFact::intConst(elm_offset), temp, + NULL, NULL); + access_store_at(decorators, field_type, + obj_item, LIR_OprFact::intConst(obj_offset), temp, + NULL, NULL); + } else { + access_load_at(decorators, field_type, + obj_item, LIR_OprFact::intConst(obj_offset), temp, + NULL, NULL); + access_store_at(decorators, field_type, + elm_item, LIR_OprFact::intConst(elm_offset), temp, + NULL, NULL); + } + } +} + void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { assert(x->is_pinned(),""); + bool is_flattened = x->array()->is_flattened_array(); bool needs_range_check = x->compute_needs_range_check(); bool use_length = x->length() != NULL; bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; - bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || + bool needs_store_check = obj_store && !is_flattened && + (x->value()->as_Constant() == NULL || !get_jobject_constant(x->value())->is_null_object() || x->should_profile()); @@ -1570,7 +1645,8 @@ length.load_item(); } - if (needs_store_check || x->check_boolean()) { + + if (needs_store_check || x->check_boolean() || is_flattened) { value.load_item(); } else { value.load_for_store(x->elt_type()); @@ -1603,13 +1679,18 @@ array_store_check(value.result(), array.result(), store_check_info, x->profiled_method(), x->profiled_bci()); } - DecoratorSet decorators = IN_HEAP | IS_ARRAY; - if (x->check_boolean()) { - decorators |= C1_MASK_BOOLEAN; + if (is_flattened) { + index.load_item(); + access_flattened_array(false, array, index, value); + } else { + DecoratorSet decorators = IN_HEAP | IS_ARRAY; + if (x->check_boolean()) { + decorators |= C1_MASK_BOOLEAN; + } + + access_store_at(decorators, x->elt_type(), array, index.result(), value.result(), + NULL, null_check_info); } - - access_store_at(decorators, x->elt_type(), array, index.result(), value.result(), - NULL, null_check_info); } void LIRGenerator::access_load_at(DecoratorSet decorators, BasicType type, @@ -1870,12 +1951,20 @@ } } - DecoratorSet decorators = IN_HEAP | IS_ARRAY; - - LIR_Opr result = rlock_result(x, x->elt_type()); - access_load_at(decorators, x->elt_type(), - array, index.result(), result, - NULL, null_check_info); + if (x->array()->is_flattened_array()) { + // Find the destination address (of the NewValueTypeInstance) + LIR_Opr obj = x->vt()->operand(); + LIRItem obj_item(x->vt(), this); + + access_flattened_array(true, array, index, obj_item); + set_no_result(x); + } else { + DecoratorSet decorators = IN_HEAP | IS_ARRAY; + LIR_Opr result = rlock_result(x, x->elt_type()); + access_load_at(decorators, x->elt_type(), + array, index.result(), result, + NULL, null_check_info); + } } @@ -2735,6 +2824,7 @@ } else { LIR_Address* addr = loc->as_address_ptr(); param->load_for_store(addr->type()); + assert(addr->type() != T_VALUETYPE, "not supported yet"); if (addr->type() == T_OBJECT) { __ move_wide(param->result(), addr); } else diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp --- a/src/hotspot/share/c1/c1_LIRGenerator.hpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp @@ -266,6 +266,8 @@ void do_update_CRC32C(Intrinsic* x); void do_vectorizedMismatch(Intrinsic* x); + void access_flattened_array(bool is_load, LIRItem& array, LIRItem& index, LIRItem& obj_item); + public: LIR_Opr call_runtime(BasicTypeArray* signature, LIRItemList* args, address entry, ValueType* result_type, CodeEmitInfo* info); LIR_Opr call_runtime(BasicTypeArray* signature, LIR_OprList* args, address entry, ValueType* result_type, CodeEmitInfo* info); @@ -565,6 +567,7 @@ virtual void do_TypeCast (TypeCast* x); virtual void do_Invoke (Invoke* x); virtual void do_NewInstance (NewInstance* x); + virtual void do_NewValueTypeInstance(NewValueTypeInstance* x); virtual void do_NewTypeArray (NewTypeArray* x); virtual void do_NewObjectArray (NewObjectArray* x); virtual void do_NewMultiArray (NewMultiArray* x); diff --git a/src/hotspot/share/c1/c1_Optimizer.cpp b/src/hotspot/share/c1/c1_Optimizer.cpp --- a/src/hotspot/share/c1/c1_Optimizer.cpp +++ b/src/hotspot/share/c1/c1_Optimizer.cpp @@ -502,6 +502,7 @@ void do_TypeCast (TypeCast* x); void do_Invoke (Invoke* x); void do_NewInstance (NewInstance* x); + void do_NewValueTypeInstance(NewValueTypeInstance* x); void do_NewTypeArray (NewTypeArray* x); void do_NewObjectArray (NewObjectArray* x); void do_NewMultiArray (NewMultiArray* x); @@ -650,6 +651,7 @@ void handle_NullCheck (NullCheck* x); void handle_Invoke (Invoke* x); void handle_NewInstance (NewInstance* x); + void handle_NewValueTypeInstance(NewValueTypeInstance* x); void handle_NewArray (NewArray* x); void handle_AccessMonitor (AccessMonitor* x); void handle_Intrinsic (Intrinsic* x); @@ -688,6 +690,7 @@ void NullCheckVisitor::do_TypeCast (TypeCast* x) {} void NullCheckVisitor::do_Invoke (Invoke* x) { nce()->handle_Invoke(x); } void NullCheckVisitor::do_NewInstance (NewInstance* x) { nce()->handle_NewInstance(x); } +void NullCheckVisitor::do_NewValueTypeInstance(NewValueTypeInstance* x) { nce()->handle_NewValueTypeInstance(x); } void NullCheckVisitor::do_NewTypeArray (NewTypeArray* x) { nce()->handle_NewArray(x); } void NullCheckVisitor::do_NewObjectArray (NewObjectArray* x) { nce()->handle_NewArray(x); } void NullCheckVisitor::do_NewMultiArray (NewMultiArray* x) { nce()->handle_NewArray(x); } @@ -862,7 +865,7 @@ if (field->is_constant()) { ciConstant field_val = field->constant_value(); BasicType field_type = field_val.basic_type(); - if (field_type == T_OBJECT || field_type == T_ARRAY) { + if (field_type == T_OBJECT || field_type == T_ARRAY || field_type == T_VALUETYPE) { ciObject* obj_val = field_val.as_object(); if (!obj_val->is_null_object()) { if (PrintNullCheckElimination) { @@ -1040,6 +1043,13 @@ } } +void NullCheckEliminator::handle_NewValueTypeInstance(NewValueTypeInstance* x) { + set_put(x); + if (PrintNullCheckElimination) { + tty->print_cr("NewValueTypeInstance %d is non-null", x->id()); + } +} + void NullCheckEliminator::handle_NewArray(NewArray* x) { set_put(x); diff --git a/src/hotspot/share/c1/c1_RangeCheckElimination.hpp b/src/hotspot/share/c1/c1_RangeCheckElimination.hpp --- a/src/hotspot/share/c1/c1_RangeCheckElimination.hpp +++ b/src/hotspot/share/c1/c1_RangeCheckElimination.hpp @@ -143,6 +143,7 @@ void do_NullCheck (NullCheck* x) { /* nothing to do */ }; void do_TypeCast (TypeCast* x) { /* nothing to do */ }; void do_NewInstance (NewInstance* x) { /* nothing to do */ }; + void do_NewValueTypeInstance (NewValueTypeInstance* x) { /* nothing to do */ }; void do_NewTypeArray (NewTypeArray* x) { /* nothing to do */ }; void do_NewObjectArray (NewObjectArray* x) { /* nothing to do */ }; void do_NewMultiArray (NewMultiArray* x) { /* nothing to do */ }; diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -932,6 +932,11 @@ k = caller_method->constants()->klass_at(bnew.index(), CHECK); } break; + case Bytecodes::_defaultvalue: + { Bytecode_defaultvalue bdefaultvalue(caller_method(), caller_method->bcp_from(bci)); + k = caller_method->constants()->klass_at(bdefaultvalue.index(), CHECK); + } + break; case Bytecodes::_multianewarray: { Bytecode_multianewarray mna(caller_method(), caller_method->bcp_from(bci)); k = caller_method->constants()->klass_at(mna.index(), CHECK); diff --git a/src/hotspot/share/c1/c1_ValueMap.hpp b/src/hotspot/share/c1/c1_ValueMap.hpp --- a/src/hotspot/share/c1/c1_ValueMap.hpp +++ b/src/hotspot/share/c1/c1_ValueMap.hpp @@ -186,6 +186,7 @@ void do_NullCheck (NullCheck* x) { /* nothing to do */ } void do_TypeCast (TypeCast* x) { /* nothing to do */ } void do_NewInstance (NewInstance* x) { /* nothing to do */ } + void do_NewValueTypeInstance (NewValueTypeInstance* x) { /* nothing to do */ } void do_NewTypeArray (NewTypeArray* x) { /* nothing to do */ } void do_NewObjectArray (NewObjectArray* x) { /* nothing to do */ } void do_NewMultiArray (NewMultiArray* x) { /* nothing to do */ } diff --git a/src/hotspot/share/c1/c1_ValueType.cpp b/src/hotspot/share/c1/c1_ValueType.cpp --- a/src/hotspot/share/c1/c1_ValueType.cpp +++ b/src/hotspot/share/c1/c1_ValueType.cpp @@ -135,6 +135,7 @@ case T_DOUBLE : return doubleType; case T_ARRAY : return arrayType; case T_OBJECT : return objectType; + case T_VALUETYPE: return objectType; case T_ADDRESS: return addressType; case T_ILLEGAL: return illegalType; default : ShouldNotReachHere(); @@ -154,6 +155,7 @@ case T_FLOAT : return new FloatConstant (value.as_float ()); case T_DOUBLE : return new DoubleConstant(value.as_double()); case T_ARRAY : // fall through (ciConstant doesn't have an array accessor) + case T_VALUETYPE: // fall through case T_OBJECT : { // TODO: Common the code with GraphBuilder::load_constant? ciObject* obj = value.as_object(); diff --git a/src/hotspot/share/ci/ciArrayKlass.cpp b/src/hotspot/share/ci/ciArrayKlass.cpp --- a/src/hotspot/share/ci/ciArrayKlass.cpp +++ b/src/hotspot/share/ci/ciArrayKlass.cpp @@ -109,3 +109,7 @@ return ciObjArrayKlass::make(element_type->as_klass()); } } + +int ciArrayKlass::array_header_in_bytes() { + return get_ArrayKlass()->array_header_in_bytes(); +} diff --git a/src/hotspot/share/ci/ciArrayKlass.hpp b/src/hotspot/share/ci/ciArrayKlass.hpp --- a/src/hotspot/share/ci/ciArrayKlass.hpp +++ b/src/hotspot/share/ci/ciArrayKlass.hpp @@ -60,6 +60,8 @@ virtual ciKlass* element_klass() { return NULL; } static ciArrayKlass* make(ciType* element_type); + + int array_header_in_bytes(); }; #endif // SHARE_VM_CI_CIARRAYKLASS_HPP diff --git a/src/hotspot/share/interpreter/bytecode.hpp b/src/hotspot/share/interpreter/bytecode.hpp --- a/src/hotspot/share/interpreter/bytecode.hpp +++ b/src/hotspot/share/interpreter/bytecode.hpp @@ -293,6 +293,15 @@ long index() const { return get_index_u2(Bytecodes::_new); }; }; +class Bytecode_defaultvalue: public Bytecode { + public: + Bytecode_defaultvalue(Method* method, address bcp): Bytecode(method, bcp) { verify(); } + void verify() const { assert(java_code() == Bytecodes::_defaultvalue, "check defaultvalue"); } + + // Returns index + long index() const { return get_index_u2(Bytecodes::_defaultvalue); }; +}; + class Bytecode_multianewarray: public Bytecode { public: Bytecode_multianewarray(Method* method, address bcp): Bytecode(method, bcp) { verify(); } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -2098,11 +2098,18 @@ } if (EnableValhalla) { - // C1 has no support for value types - if (!FLAG_IS_DEFAULT(TieredCompilation)) { - warning("TieredCompilation disabled because value types are not supported by C1"); + if (!EnableValhallaC1) { + // C1 support for value types is incomplete. Don't use it by default. + if (!FLAG_IS_DEFAULT(TieredCompilation)) { + warning("TieredCompilation disabled because value types are not supported by C1"); + } + FLAG_SET_CMDLINE(bool, TieredCompilation, false); + } else { + if (TieredStopAtLevel > 1) { + warning("C1 doesn't work with C2 yet. Forcing TieredStopAtLevel=1"); + FLAG_SET_CMDLINE(intx, TieredStopAtLevel, 1); + } } - FLAG_SET_CMDLINE(bool, TieredCompilation, false); } else { FLAG_SET_CMDLINE(bool, ValueArrayFlatten, false); } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -2647,6 +2647,9 @@ product(bool, EnableValhalla, false, \ "Enable experimental Valhalla features") \ \ + product(bool, EnableValhallaC1, false, \ + "Enable C1 compiler for Valhalla") \ + \ product_pd(bool, ValueTypePassFieldsAsArgs, \ "Pass each value type field as an argument at calls") \ \ diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java --- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java @@ -84,6 +84,9 @@ } public abstract class ValueTypeTest { + // Run "jtreg -Dtest.c1=true" to enable experimental C1 testing. + static final boolean TEST_C1 = Boolean.getBoolean("test.c1"); + // Random test values public static final int rI = Utils.getRandomInstance().nextInt() % 1000; public static final long rL = Utils.getRandomInstance().nextLong() % 1000; @@ -91,7 +94,7 @@ // User defined settings private static final boolean PRINT_GRAPH = true; private static final boolean PRINT_TIMES = Boolean.parseBoolean(System.getProperty("PrintTimes", "false")); - private static boolean VERIFY_IR = Boolean.parseBoolean(System.getProperty("VerifyIR", "true")); + private static final boolean VERIFY_IR = Boolean.parseBoolean(System.getProperty("VerifyIR", "true")) && (!TEST_C1) private static final boolean VERIFY_VM = Boolean.parseBoolean(System.getProperty("VerifyVM", "false")); private static final String SCENARIOS = System.getProperty("Scenarios", ""); private static final String TESTLIST = System.getProperty("Testlist", ""); @@ -125,7 +128,7 @@ protected static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields"); protected static final boolean NullableValueTypes = (Boolean)WHITE_BOX.getVMFlag("NullableValueTypes"); protected static final int COMP_LEVEL_ANY = -2; - protected static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; + protected static final int COMP_LEVEL_FULL_OPTIMIZATION = TEST_C1 ? 1 : 4; protected static final Hashtable tests = new Hashtable(); protected static final boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); protected static final boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal"); @@ -170,7 +173,11 @@ * the 5 built-in scenarios */ public int getNumScenarios() { - return 5; + if (TEST_C1) { + return 1; + } else { + return 5; + } } /** @@ -178,6 +185,12 @@ * extra parameters for (some of) these scenarios, override getExtraVMParameters(). */ public String[] getVMParameters(int scenario) { + if (TEST_C1) { + return new String[] { + "-XX:+EnableValhallaC1", + }; + } + switch (scenario) { case 0: return new String[] { "-XX:+AlwaysIncrementalInline",