--- old/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp 2019-02-13 17:02:35.763571976 -0800 +++ new/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp 2019-02-13 17:02:35.547563821 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, 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 @@ -161,17 +161,9 @@ _array = array; _index = index; _result = result; - _info = new CodeEmitInfo(info); -} - -void LoadFlattenedArrayStub::visit(LIR_OpVisitState* visitor) { - visitor->do_slow_case(_info); - visitor->do_input(_array); - visitor->do_input(_index); - visitor->do_output(_result); - // Tell the register allocator that the runtime call will scratch rax. - visitor->do_output(FrameMap::rax_oop_opr); + _scratch_reg = FrameMap::rax_oop_opr; + _info = new CodeEmitInfo(info); } void LoadFlattenedArrayStub::emit_code(LIR_Assembler* ce) { --- old/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp 2019-02-13 17:02:36.367594780 -0800 +++ new/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp 2019-02-13 17:02:36.147586474 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -1905,6 +1905,26 @@ } +void LIR_Assembler::emit_opFlattenedStoreCheck(LIR_OpFlattenedStoreCheck* op) { + Klass* k = (Klass*)(op->element_klass()->constant_encoding()); + assert(k->is_klass(), "must be a loaded klass"); + add_debug_info_for_null_check_here(op->info_for_exception()); + +#ifdef _LP64 + if (UseCompressedClassPointers) { + __ movl(op->tmp1()->as_register(), Address(op->object()->as_register(), oopDesc::klass_offset_in_bytes())); + __ cmp_narrow_klass(op->tmp1()->as_register(), k); + } else { + __ movq(op->tmp1()->as_register(), Address(op->object()->as_register(), oopDesc::klass_offset_in_bytes())); + __ cmpq(op->tmp1()->as_register(), op->tmp2()->as_register()); + } +#else + Unimplemented(); // FIXME +#endif + + __ jcc(Assembler::notEqual, *op->stub()->entry()); + __ bind(*op->stub()->continuation()); +} void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { if (LP64_ONLY(false &&) op->code() == lir_cas_long && VM_Version::supports_cx8()) { --- old/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp 2019-02-13 17:02:36.999618641 -0800 +++ new/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp 2019-02-13 17:02:36.783610485 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, 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 @@ -271,6 +271,20 @@ __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci); } +void LIRGenerator::flattened_array_store_check(LIR_Opr value, ciKlass* element_klass, CodeEmitInfo* store_check_info) { + LIR_Opr tmp1 = new_register(T_METADATA); + LIR_Opr tmp2 = LIR_OprFact::illegalOpr; + +#ifdef _LP64 + if (!UseCompressedClassPointers) { + tmp2 = new_register(T_METADATA); + __ metadata2reg(element_klass->constant_encoding(), tmp2); + } +#endif + + __ flattened_store_check(value, element_klass, tmp1, tmp2, store_check_info); +} + //---------------------------------------------------------------------- // visitor functions //---------------------------------------------------------------------- --- old/src/hotspot/share/c1/c1_CodeStubs.hpp 2019-02-13 17:02:37.611641746 -0800 +++ new/src/hotspot/share/c1/c1_CodeStubs.hpp 2019-02-13 17:02:37.395633591 -0800 @@ -237,13 +237,26 @@ LIR_Opr _array; LIR_Opr _index; LIR_Opr _result; + LIR_Opr _scratch_reg; CodeEmitInfo* _info; public: LoadFlattenedArrayStub(LIR_Opr array, LIR_Opr index, LIR_Opr result, CodeEmitInfo* info); virtual void emit_code(LIR_Assembler* e); virtual CodeEmitInfo* info() const { return _info; } - virtual void visit(LIR_OpVisitState* visitor); + virtual void visit(LIR_OpVisitState* visitor) { + visitor->do_slow_case(_info); + visitor->do_input(_array); + visitor->do_input(_index); + visitor->do_output(_result); + if (_scratch_reg != LIR_OprFact::illegalOpr) { + visitor->do_temp(_scratch_reg); + } + // Tell the register allocator that the runtime call will scratch rax. + visitor->do_output(FrameMap::rax_oop_opr); +} + + #ifndef PRODUCT virtual void print_name(outputStream* out) const { out->print("LoadFlattenedArrayStub"); } #endif // PRODUCT --- old/src/hotspot/share/c1/c1_Instruction.cpp 2019-02-13 17:02:38.207664247 -0800 +++ new/src/hotspot/share/c1/c1_Instruction.cpp 2019-02-13 17:02:37.991656092 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, 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 @@ -257,6 +257,16 @@ return ak->element_type(); } +bool StoreIndexed::is_exact_flattened_array_store() const { + if (array()->is_loaded_flattened_array() && value()->as_Constant() == NULL) { + ciKlass* element_klass = array()->declared_type()->as_value_array_klass()->element_klass(); + ciKlass* actual_klass = value()->declared_type()->as_klass(); + if (element_klass == actual_klass) { + return true; + } + } + return false; +} ciType* LoadField::declared_type() const { return field()->type(); --- old/src/hotspot/share/c1/c1_Instruction.hpp 2019-02-13 17:02:38.811687051 -0800 +++ new/src/hotspot/share/c1/c1_Instruction.hpp 2019-02-13 17:02:38.595678896 -0800 @@ -1031,6 +1031,8 @@ bool should_profile() const { return check_flag(ProfileMDOFlag); } ciMethod* profiled_method() const { return _profiled_method; } int profiled_bci() const { return _profiled_bci; } + // Flattened array support + bool is_exact_flattened_array_store() const; // generic virtual void input_values_do(ValueVisitor* f) { AccessIndexed::input_values_do(f); f->visit(&_value); } }; --- old/src/hotspot/share/c1/c1_LIR.cpp 2019-02-13 17:02:39.431710458 -0800 +++ new/src/hotspot/share/c1/c1_LIR.cpp 2019-02-13 17:02:39.211702152 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -367,6 +367,18 @@ } } +LIR_OpFlattenedStoreCheck::LIR_OpFlattenedStoreCheck(LIR_Opr object, ciKlass* element_klass, + LIR_Opr tmp1, LIR_Opr tmp2, + CodeEmitInfo* info_for_exception) + : LIR_Op(lir_flattened_store_check, LIR_OprFact::illegalOpr, NULL) + , _object(object) + , _element_klass(element_klass) + , _tmp1(tmp1) + , _tmp2(tmp2) + , _info_for_exception(info_for_exception) +{ + _stub = new ArrayStoreExceptionStub(object, info_for_exception); +} LIR_OpArrayCopy::LIR_OpArrayCopy(LIR_Opr src, LIR_Opr src_pos, LIR_Opr dst, LIR_Opr dst_pos, LIR_Opr length, LIR_Opr tmp, ciArrayKlass* expected_type, int flags, CodeEmitInfo* info) @@ -858,6 +870,19 @@ break; } +// LIR_OpFlattenedStoreCheck + case lir_flattened_store_check: { + assert(op->as_OpFlattenedStoreCheck() != NULL, "must be"); + LIR_OpFlattenedStoreCheck* opFlattenedStoreCheck = (LIR_OpFlattenedStoreCheck*)op; + + if (opFlattenedStoreCheck->_info_for_exception) do_info(opFlattenedStoreCheck->_info_for_exception); + if (opFlattenedStoreCheck->_object->is_valid()) do_temp(opFlattenedStoreCheck->_object); + if (opFlattenedStoreCheck->_tmp1->is_valid()) do_temp(opFlattenedStoreCheck->_tmp1); + if (opFlattenedStoreCheck->_tmp2->is_valid()) do_temp(opFlattenedStoreCheck->_tmp2); + do_stub(opFlattenedStoreCheck->_stub); + break; + } + // LIR_OpCompareAndSwap case lir_cas_long: case lir_cas_obj: @@ -1045,6 +1070,13 @@ } } +void LIR_OpFlattenedStoreCheck::emit_code(LIR_Assembler* masm) { + masm->emit_opFlattenedStoreCheck(this); + if (stub()) { + masm->append_code_stub(stub()); + } +} + void LIR_OpCompareAndSwap::emit_code(LIR_Assembler* masm) { masm->emit_compare_and_swap(this); } @@ -1444,6 +1476,13 @@ } } +void LIR_List::flattened_store_check(LIR_Opr object, ciKlass* element_klass, + LIR_Opr tmp1, LIR_Opr tmp2, + CodeEmitInfo* info_for_exception) { + LIR_OpFlattenedStoreCheck* c = new LIR_OpFlattenedStoreCheck(object, element_klass, tmp1, tmp2, info_for_exception); + append(c); +} + void LIR_List::cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, LIR_Opr t1, LIR_Opr t2, LIR_Opr result) { append(new LIR_OpCompareAndSwap(lir_cas_long, addr, cmp_value, new_value, t1, t2, result)); @@ -1736,6 +1775,8 @@ case lir_instanceof: s = "instanceof"; break; case lir_checkcast: s = "checkcast"; break; case lir_store_check: s = "store_check"; break; + // LIR_OpFlattenedStoreCheck + case lir_flattened_store_check: s = "flattened_store_check"; break; // LIR_OpCompareAndSwap case lir_cas_long: s = "cas_long"; break; case lir_cas_obj: s = "cas_obj"; break; @@ -1981,6 +2022,14 @@ if (info_for_exception() != NULL) out->print(" [bci:%d]", info_for_exception()->stack()->bci()); } +void LIR_OpFlattenedStoreCheck::print_instr(outputStream* out) const { + object()->print(out); out->print(" "); + element_klass()->print_name_on(out); out->print(" "); + tmp1()->print(out); out->print(" "); + tmp2()->print(out); out->print(" "); + if (info_for_exception() != NULL) out->print(" [bci:%d]", info_for_exception()->stack()->bci()); +} + // LIR_Op3 void LIR_Op3::print_instr(outputStream* out) const { --- old/src/hotspot/share/c1/c1_LIR.hpp 2019-02-13 17:02:40.051733866 -0800 +++ new/src/hotspot/share/c1/c1_LIR.hpp 2019-02-13 17:02:39.831725560 -0800 @@ -873,6 +873,7 @@ class LIR_OpUpdateCRC32; class LIR_OpLock; class LIR_OpTypeCheck; +class LIR_OpFlattenedStoreCheck; class LIR_OpCompareAndSwap; class LIR_OpProfileCall; class LIR_OpProfileType; @@ -987,6 +988,9 @@ , lir_checkcast , lir_store_check , end_opTypeCheck + , begin_opFlattenedStoreCheck + , lir_flattened_store_check + , end_opFlattenedStoreCheck , begin_opCompareAndSwap , lir_cas_long , lir_cas_obj @@ -1137,6 +1141,7 @@ virtual LIR_OpArrayCopy* as_OpArrayCopy() { return NULL; } virtual LIR_OpUpdateCRC32* as_OpUpdateCRC32() { return NULL; } virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; } + virtual LIR_OpFlattenedStoreCheck* as_OpFlattenedStoreCheck() { return NULL; } virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; } virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; } virtual LIR_OpProfileType* as_OpProfileType() { return NULL; } @@ -1595,6 +1600,34 @@ void print_instr(outputStream* out) const PRODUCT_RETURN; }; +// LIR_OpFlattenedStoreCheck +class LIR_OpFlattenedStoreCheck: public LIR_Op { + friend class LIR_OpVisitState; + + private: + LIR_Opr _object; + ciKlass* _element_klass; + LIR_Opr _tmp1; + LIR_Opr _tmp2; + CodeEmitInfo* _info_for_exception; + CodeStub* _stub; + +public: + LIR_OpFlattenedStoreCheck(LIR_Opr object, ciKlass* element_klass, LIR_Opr tmp1, LIR_Opr tmp2, + CodeEmitInfo* info_for_exception); + + LIR_Opr object() const { return _object; } + LIR_Opr tmp1() const { return _tmp1; } + LIR_Opr tmp2() const { return _tmp2; } + ciKlass* element_klass() const { return _element_klass; } + CodeEmitInfo* info_for_exception() const { return _info_for_exception; } + CodeStub* stub() const { return _stub; } + + virtual void emit_code(LIR_Assembler* masm); + virtual LIR_OpFlattenedStoreCheck* as_OpFlattenedStoreCheck() { return this; } + virtual void print_instr(outputStream* out) const PRODUCT_RETURN; +}; + // LIR_Op2 class LIR_Op2: public LIR_Op { friend class LIR_OpVisitState; @@ -2252,6 +2285,7 @@ void instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch, ciMethod* profiled_method, int profiled_bci); void store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception, ciMethod* profiled_method, int profiled_bci); + void flattened_store_check(LIR_Opr object, ciKlass* element_klass, LIR_Opr tmp1, LIR_Opr tmp2, CodeEmitInfo* info_for_exception); void checkcast (LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, --- old/src/hotspot/share/c1/c1_LIRAssembler.hpp 2019-02-13 17:02:40.671757273 -0800 +++ new/src/hotspot/share/c1/c1_LIRAssembler.hpp 2019-02-13 17:02:40.455749118 -0800 @@ -198,6 +198,7 @@ void emit_alloc_obj(LIR_OpAllocObj* op); void emit_alloc_array(LIR_OpAllocArray* op); void emit_opTypeCheck(LIR_OpTypeCheck* op); + void emit_opFlattenedStoreCheck(LIR_OpFlattenedStoreCheck* op); void emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null); void emit_compare_and_swap(LIR_OpCompareAndSwap* op); void emit_lock(LIR_OpLock* op); --- old/src/hotspot/share/c1/c1_LIRGenerator.cpp 2019-02-13 17:02:41.259779473 -0800 +++ new/src/hotspot/share/c1/c1_LIRGenerator.cpp 2019-02-13 17:02:41.043771318 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, 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 @@ -1718,7 +1718,11 @@ } if (is_loaded_flattened_array) { - index.load_item(); + if (!x->is_exact_flattened_array_store()) { + CodeEmitInfo* info = new CodeEmitInfo(range_check_info); + ciKlass* element_klass = x->array()->declared_type()->as_value_array_klass()->element_klass(); + flattened_array_store_check(value.result(), element_klass, info); + } access_flattened_array(false, array, index, value); } else { StoreFlattenedArrayStub* slow_path = NULL; @@ -1991,8 +1995,7 @@ } array.load_item(); - if (index.is_constant() && can_inline_as_constant(x->index()) - && !x->array()->maybe_flattened_array()) { + if (index.is_constant() && can_inline_as_constant(x->index())) { // let it be a constant index.dont_load_item(); } else { @@ -2042,6 +2045,7 @@ LoadFlattenedArrayStub* slow_path = NULL; if (x->array()->maybe_flattened_array()) { + index.load_item(); // Check if we indeed have a flattened array slow_path = new LoadFlattenedArrayStub(array.result(), index.result(), result, state_for(x)); check_flattened_array(array, slow_path); --- old/src/hotspot/share/c1/c1_LIRGenerator.hpp 2019-02-13 17:02:41.891803333 -0800 +++ new/src/hotspot/share/c1/c1_LIRGenerator.hpp 2019-02-13 17:02:41.675795178 -0800 @@ -317,6 +317,7 @@ // specific implementations void array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci); + void flattened_array_store_check(LIR_Opr value, ciKlass* element_klass, CodeEmitInfo* store_check_info); static LIR_Opr result_register_for(ValueType* type, bool callee = false); --- old/src/hotspot/share/c1/c1_Runtime1.cpp 2019-02-13 17:02:42.487825834 -0800 +++ new/src/hotspot/share/c1/c1_Runtime1.cpp 2019-02-13 17:02:42.271817680 -0800 @@ -429,9 +429,10 @@ // We have a non-empty flattened array, so the element type must have been initialized. assert(vklass->is_initialized(), "must be"); Handle holder(THREAD, vklass->klass_holder()); // keep the vklass alive + valueArrayHandle ha(THREAD, array); oop obj = vklass->allocate_instance(CHECK); - void* src = array->value_at_addr(index, vaklass->layout_helper()); + void* src = ha()->value_at_addr(index, vaklass->layout_helper()); vklass->value_store(src, vklass->data_for_oop(obj), vaklass->element_byte_size(), true, false); thread->set_vm_result(obj); --- old/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnresolvedValueClass.java 2019-02-13 17:02:43.103849091 -0800 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnresolvedValueClass.java 2019-02-13 17:02:42.887840936 -0800 @@ -26,6 +26,7 @@ * @bug 8187679 * @summary The VM should exit gracefully when unable to resolve a value type argument * @library /test/lib + * @build SimpleValueType * @run main/othervm -XX:+EnableValhalla TestUnresolvedValueClass */ --- old/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java 2019-02-13 17:02:43.707871894 -0800 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypeTest.java 2019-02-13 17:02:43.487863588 -0800 @@ -286,15 +286,42 @@ } } + // To exclude test cases, use -DExclude=,,... + // Each case can be just the method name, or can be .. The latter form is useful + // when you are running several tests at the same time. + // + // jtreg -DExclude=test12 TestArrays.java + // jtreg -DExclude=test34 TestLWorld.java + // -- or -- + // jtreg -DExclude=TestArrays.test12,TestLWorld.test34 TestArrays.java TestLWorld.java + // + private List buildExcludeList() { + List exclude = null; + String classPrefix = getClass().getSimpleName() + "."; + if (!EXCLUDELIST.isEmpty()) { + exclude = new ArrayList(Arrays.asList(EXCLUDELIST.split(","))); + for (int i = exclude.size() - 1; i >= 0; i--) { + String ex = exclude.get(i); + if (ex.indexOf(".") > 0) { + if (ex.startsWith(classPrefix)) { + ex = ex.substring(classPrefix.length()); + exclude.set(i, ex); + } else { + exclude.remove(i); + } + } + } + } + return exclude; + } + protected ValueTypeTest() { List list = null; - List exclude = null; if (!TESTLIST.isEmpty()) { list = Arrays.asList(TESTLIST.split(",")); } - if (!EXCLUDELIST.isEmpty()) { - exclude = Arrays.asList(EXCLUDELIST.split(",")); - } + List exclude = buildExcludeList(); + // Gather all test methods and put them in Hashtable for (Method m : getClass().getDeclaredMethods()) { Test[] annos = m.getAnnotationsByType(Test.class);