--- old/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp 2019-01-08 13:57:13.646461441 -0800 +++ new/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp 2019-01-08 13:57:13.478455193 -0800 @@ -1679,20 +1679,22 @@ assert_different_registers(obj, k_RInfo, klass_RInfo); - __ cmpptr(obj, (int32_t)NULL_WORD); - if (op->should_profile()) { - Label not_null; - __ jccb(Assembler::notEqual, not_null); - // Object is null; update MDO and exit - Register mdo = klass_RInfo; - __ mov_metadata(mdo, md->constant_encoding()); - Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset())); - int header_bits = BitData::null_seen_byte_constant(); - __ orb(data_addr, header_bits); - __ jmp(*obj_is_null); - __ bind(not_null); - } else { - __ jcc(Assembler::equal, *obj_is_null); + if (op->need_null_check()) { + __ cmpptr(obj, (int32_t)NULL_WORD); + if (op->should_profile()) { + Label not_null; + __ jccb(Assembler::notEqual, not_null); + // Object is null; update MDO and exit + Register mdo = klass_RInfo; + __ mov_metadata(mdo, md->constant_encoding()); + Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset())); + int header_bits = BitData::null_seen_byte_constant(); + __ orb(data_addr, header_bits); + __ jmp(*obj_is_null); + __ bind(not_null); + } else { + __ jcc(Assembler::equal, *obj_is_null); + } } if (!k->is_loaded()) { --- old/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp 2019-01-08 13:57:14.206482266 -0800 +++ new/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp 2019-01-08 13:57:14.038476018 -0800 @@ -1373,6 +1373,10 @@ (x->needs_exception_state() ? state_for(x) : state_for(x, x->state_before(), true /*ignore_xhandler*/)); + if (x->is_never_null()) { + __ null_check(obj.result(), new CodeEmitInfo(info_for_exception), /* deoptimize */ false); + } + CodeStub* stub; if (x->is_incompatible_class_change_check()) { assert(patching_info == NULL, "can't patch this"); @@ -1391,7 +1395,7 @@ __ checkcast(reg, obj.result(), x->klass(), new_register(objectType), new_register(objectType), tmp3, x->direct_compare(), info_for_exception, patching_info, stub, - x->profiled_method(), x->profiled_bci()); + x->profiled_method(), x->profiled_bci(), x->is_never_null()); } --- old/src/hotspot/share/c1/c1_Canonicalizer.cpp 2019-01-08 13:57:14.666499372 -0800 +++ new/src/hotspot/share/c1/c1_Canonicalizer.cpp 2019-01-08 13:57:14.490492827 -0800 @@ -649,7 +649,8 @@ void Canonicalizer::do_NewObjectArray (NewObjectArray* x) {} void Canonicalizer::do_NewMultiArray (NewMultiArray* x) {} void Canonicalizer::do_CheckCast (CheckCast* x) { - if (x->klass()->is_loaded()) { + if (x->klass()->is_loaded() && !x->is_never_null()) { + // Don't canonicalize for non-nullable types -- we need to throw NPE. Value obj = x->obj(); ciType* klass = obj->exact_type(); if (klass == NULL) { --- old/src/hotspot/share/c1/c1_GraphBuilder.cpp 2019-01-08 13:57:15.098515437 -0800 +++ new/src/hotspot/share/c1/c1_GraphBuilder.cpp 2019-01-08 13:57:14.930509189 -0800 @@ -2333,8 +2333,9 @@ void GraphBuilder::check_cast(int klass_index) { bool will_link; ciKlass* klass = stream()->get_klass(will_link); + bool never_null = stream()->is_klass_never_null(); ValueStack* state_before = !klass->is_loaded() || PatchALot ? copy_state_before() : copy_state_for_exception(); - CheckCast* c = new CheckCast(klass, apop(), state_before); + CheckCast* c = new CheckCast(klass, apop(), state_before, never_null); apush(append_split(c)); c->set_direct_compare(direct_compare(klass)); --- old/src/hotspot/share/c1/c1_Instruction.hpp 2019-01-08 13:57:15.566532841 -0800 +++ new/src/hotspot/share/c1/c1_Instruction.hpp 2019-01-08 13:57:15.394526444 -0800 @@ -1502,10 +1502,11 @@ LEAF(CheckCast, TypeCheck) + bool _is_never_null; public: // creation - CheckCast(ciKlass* klass, Value obj, ValueStack* state_before) - : TypeCheck(klass, obj, objectType, state_before) {} + CheckCast(ciKlass* klass, Value obj, ValueStack* state_before, bool never_null = false) + : TypeCheck(klass, obj, objectType, state_before), _is_never_null(never_null) {} void set_incompatible_class_change_check() { set_flag(ThrowIncompatibleClassChangeErrorFlag, true); @@ -1519,6 +1520,9 @@ bool is_invokespecial_receiver_check() const { return check_flag(InvokeSpecialReceiverCheckFlag); } + bool is_never_null() const { + return _is_never_null; + } virtual bool needs_exception_state() const { return !is_invokespecial_receiver_check(); --- old/src/hotspot/share/c1/c1_LIR.cpp 2019-01-08 13:57:16.014549500 -0800 +++ new/src/hotspot/share/c1/c1_LIR.cpp 2019-01-08 13:57:15.846543253 -0800 @@ -313,7 +313,7 @@ LIR_OpTypeCheck::LIR_OpTypeCheck(LIR_Code code, LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_exception, CodeEmitInfo* info_for_patch, - CodeStub* stub) + CodeStub* stub, bool need_null_check) : LIR_Op(code, result, NULL) , _object(object) @@ -329,6 +329,7 @@ , _profiled_method(NULL) , _profiled_bci(-1) , _should_profile(false) + , _need_null_check(need_null_check) { if (code == lir_checkcast) { assert(info_for_exception != NULL, "checkcast throws exceptions"); @@ -356,6 +357,7 @@ , _profiled_method(NULL) , _profiled_bci(-1) , _should_profile(false) + , _need_null_check(true) { if (code == lir_store_check) { _stub = new ArrayStoreExceptionStub(object, info_for_exception); @@ -1389,7 +1391,10 @@ void LIR_List::checkcast (LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_exception, CodeEmitInfo* info_for_patch, CodeStub* stub, - ciMethod* profiled_method, int profiled_bci) { + ciMethod* profiled_method, int profiled_bci, bool is_never_null) { + // If klass is non-nullable, LIRGenerator::do_CheckCast has already performed null-check + // on the object. + bool need_null_check = !is_never_null; LIR_OpTypeCheck* c = new LIR_OpTypeCheck(lir_checkcast, result, object, klass, tmp1, tmp2, tmp3, fast_check, info_for_exception, info_for_patch, stub); if (profiled_method != NULL) { --- old/src/hotspot/share/c1/c1_LIR.hpp 2019-01-08 13:57:16.466566309 -0800 +++ new/src/hotspot/share/c1/c1_LIR.hpp 2019-01-08 13:57:16.294559912 -0800 @@ -1562,11 +1562,12 @@ ciMethod* _profiled_method; int _profiled_bci; bool _should_profile; + bool _need_null_check; public: LIR_OpTypeCheck(LIR_Code code, LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, - CodeEmitInfo* info_for_exception, CodeEmitInfo* info_for_patch, CodeStub* stub); + CodeEmitInfo* info_for_exception, CodeEmitInfo* info_for_patch, CodeStub* stub, bool need_null_check = true); LIR_OpTypeCheck(LIR_Code code, LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception); @@ -1588,7 +1589,7 @@ ciMethod* profiled_method() const { return _profiled_method; } int profiled_bci() const { return _profiled_bci; } bool should_profile() const { return _should_profile; } - + bool need_null_check() const { return _need_null_check; } virtual bool is_patching() { return _info_for_patch != NULL; } virtual void emit_code(LIR_Assembler* masm); virtual LIR_OpTypeCheck* as_OpTypeCheck() { return this; } @@ -2257,7 +2258,7 @@ void checkcast (LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_exception, CodeEmitInfo* info_for_patch, CodeStub* stub, - ciMethod* profiled_method, int profiled_bci); + ciMethod* profiled_method, int profiled_bci, bool is_never_null); // MethodData* profiling void profile_call(ciMethod* method, int bci, ciMethod* callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* cha_klass) { append(new LIR_OpProfileCall(method, bci, callee, mdo, recv, t1, cha_klass)); --- old/src/hotspot/share/ci/ciEnv.cpp 2019-01-08 13:57:16.910582820 -0800 +++ new/src/hotspot/share/ci/ciEnv.cpp 2019-01-08 13:57:16.742576572 -0800 @@ -607,20 +607,20 @@ } // ------------------------------------------------------------------ -// ciEnv::get_never_null_impl +// ciEnv::is_klass_never_null_impl // -// Implementation of get_never_null. -bool ciEnv::get_never_null_impl(const constantPoolHandle& cpool, int index) { +// Implementation of is_klass_never_null. +bool ciEnv::is_klass_never_null_impl(const constantPoolHandle& cpool, int index) { Symbol* klass_name = cpool->klass_name_at(index); return klass_name->is_Q_signature(); } // ------------------------------------------------------------------ -// ciEnv::get_never_null +// ciEnv::is_klass_never_null // // Get information about nullability from the constant pool. -bool ciEnv::get_never_null(const constantPoolHandle& cpool, int index) { - GUARDED_VM_ENTRY(return get_never_null_impl(cpool, index);) +bool ciEnv::is_klass_never_null(const constantPoolHandle& cpool, int index) { + GUARDED_VM_ENTRY(return is_klass_never_null_impl(cpool, index);) } // ------------------------------------------------------------------ --- old/src/hotspot/share/ci/ciEnv.hpp 2019-01-08 13:57:17.342598885 -0800 +++ new/src/hotspot/share/ci/ciEnv.hpp 2019-01-08 13:57:17.178592786 -0800 @@ -132,8 +132,8 @@ ciMethod* get_method_by_index(const constantPoolHandle& cpool, int method_index, Bytecodes::Code bc, ciInstanceKlass* loading_klass); - bool get_never_null(const constantPoolHandle& cpool, - int klass_index); + bool is_klass_never_null(const constantPoolHandle& cpool, + int klass_index); // Implementation methods for loading and constant pool access. ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass, @@ -153,8 +153,8 @@ ciMethod* get_method_by_index_impl(const constantPoolHandle& cpool, int method_index, Bytecodes::Code bc, ciInstanceKlass* loading_klass); - bool get_never_null_impl(const constantPoolHandle& cpool, - int klass_index); + bool is_klass_never_null_impl(const constantPoolHandle& cpool, + int klass_index); // Helper methods bool check_klass_accessibility(ciKlass* accessing_klass, --- old/src/hotspot/share/ci/ciStreams.cpp 2019-01-08 13:57:17.770614801 -0800 +++ new/src/hotspot/share/ci/ciStreams.cpp 2019-01-08 13:57:17.602608553 -0800 @@ -192,13 +192,13 @@ } // ------------------------------------------------------------------ -// ciBytecodeStream::get_never_null +// ciBytecodeStream::is_klass_never_null // // Get information about nullability from the constant pool. -bool ciBytecodeStream::get_never_null() const { +bool ciBytecodeStream::is_klass_never_null() const { VM_ENTRY_MARK; constantPoolHandle cpool(_method->get_Method()->constants()); - return CURRENT_ENV->get_never_null(cpool, get_klass_index()); + return CURRENT_ENV->is_klass_never_null(cpool, get_klass_index()); } // ------------------------------------------------------------------ --- old/src/hotspot/share/ci/ciStreams.hpp 2019-01-08 13:57:18.194630568 -0800 +++ new/src/hotspot/share/ci/ciStreams.hpp 2019-01-08 13:57:18.026624321 -0800 @@ -235,7 +235,7 @@ // or checkcast, get the referenced klass. ciKlass* get_klass(bool& will_link); int get_klass_index() const; - bool get_never_null() const; + bool is_klass_never_null() const; // If this bytecode is one of the ldc variants, get the referenced // constant. Do not attempt to resolve it, since that would require --- old/src/hotspot/share/ci/ciTypeFlow.cpp 2019-01-08 13:57:18.622646484 -0800 +++ new/src/hotspot/share/ci/ciTypeFlow.cpp 2019-01-08 13:57:18.454640237 -0800 @@ -629,7 +629,7 @@ do_null_assert(klass); } else { pop_object(); - if (str->get_never_null()) { + if (str->is_klass_never_null()) { // Casting to a Q-Type contains a NULL check assert(klass->is_valuetype(), "must be a value type"); push(outer()->mark_as_never_null(klass)); --- old/src/hotspot/share/opto/parseHelper.cpp 2019-01-08 13:57:19.082663590 -0800 +++ new/src/hotspot/share/opto/parseHelper.cpp 2019-01-08 13:57:18.910657195 -0800 @@ -68,7 +68,7 @@ void Parse::do_checkcast() { bool will_link; ciKlass* klass = iter().get_klass(will_link); - bool never_null = iter().get_never_null(); + bool never_null = iter().is_klass_never_null(); Node *obj = peek();