diff --git a/src/cpu/ppc/vm/globals_ppc.hpp b/src/cpu/ppc/vm/globals_ppc.hpp index 2dd4b1df1675aaada73c1ea99c0fcfa1c08fb83c..b39151004c9f014a6fca64765b6d8dae76e2f776 100644 --- a/src/cpu/ppc/vm/globals_ppc.hpp +++ b/src/cpu/ppc/vm/globals_ppc.hpp @@ -92,7 +92,7 @@ define_pd_global(uintx, TypeProfileLevel, 0); /* Trap based checks use the ppc trap instructions to check certain */ \ /* conditions. This instruction raises a SIGTRAP caught by the */ \ /* exception handler of the VM. */ \ - product(bool, UseSIGTRAP, false, \ + product(bool, UseSIGTRAP, true, \ "Allow trap instructions that make use of SIGTRAP. Use this to " \ "switch off all optimizations requiring SIGTRAP.") \ product(bool, TrapBasedICMissChecks, true, \ diff --git a/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/src/cpu/ppc/vm/macroAssembler_ppc.cpp index eb716b5b84e8f014fb035419ecd5e7b2fdbb3d6e..f4b7c5e7652ca9953387dca94d5ba06a7baed40a 100644 --- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -2433,7 +2433,7 @@ void MacroAssembler::load_klass(Register dst, Register src) { } void MacroAssembler::load_klass_with_trap_null_check(Register dst, Register src) { - if (false NOT_LINUX(|| true) /*!os::zero_page_read_protected()*/) { + if (!os::zero_page_read_protected()) { if (TrapBasedNullChecks) { trap_null_check(src); } diff --git a/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp b/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp index d80e4ec445967c7555bd6959c583cad002ceba0e..529f82468ef7444b71e050727f26558d68d7dad5 100644 --- a/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp +++ b/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp @@ -269,7 +269,7 @@ inline void MacroAssembler::trap_ic_miss_check(Register a, Register b) { // No support for compressed oops (base page of heap). Does not distinguish // loads and stores. inline void MacroAssembler::null_check_throw(Register a, int offset, Register temp_reg, address exception_entry) { - if (!ImplicitNullChecks || needs_explicit_null_check(offset) NOT_LINUX(|| true) /*!os::zero_page_read_protected()*/) { + if (!ImplicitNullChecks || needs_explicit_null_check(offset) || !os::zero_page_read_protected()) { if (TrapBasedNullChecks) { assert(UseSIGTRAP, "sanity"); trap_null_check(a); @@ -286,7 +286,7 @@ inline void MacroAssembler::null_check_throw(Register a, int offset, Register te } inline void MacroAssembler::ld_with_trap_null_check(Register d, int si16, Register s1) { - if ( NOT_LINUX(true) LINUX_ONLY(false)/*!os::zero_page_read_protected()*/) { + if (!os::zero_page_read_protected()) { if (TrapBasedNullChecks) { trap_null_check(s1); } @@ -297,7 +297,7 @@ inline void MacroAssembler::ld_with_trap_null_check(Register d, int si16, Regist // Attention: No null check for loaded uncompressed OOP. Can be used for loading klass field. inline void MacroAssembler::load_heap_oop_with_trap_null_check(Register d, RegisterOrConstant si16, Register s1) { - if ( NOT_LINUX(true)LINUX_ONLY(false) /*!os::zero_page_read_protected()*/) { + if ( !os::zero_page_read_protected()) { if (TrapBasedNullChecks) { trap_null_check(s1); } diff --git a/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index e9d217601306efa50e753c7747039eb5603a9151..c2a971118cf05b9e08b9de3eaa7b16df4ddf705e 100644 --- a/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -1128,7 +1128,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), "klass offset should reach into any page"); // Check for NULL argument if we don't have implicit null checks. - if (!ImplicitNullChecks NOT_LINUX(|| true) /*!os::zero_page_read_protected()*/) { + if (!ImplicitNullChecks || !os::zero_page_read_protected()) { if (TrapBasedNullChecks) { __ trap_null_check(R3_ARG1); } else { diff --git a/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp b/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp index 5323e4ae59ed5efd3d57dbe26e8aacd89a7b983d..6a608e93262339864170c7f0657559ae7b6b4479 100644 --- a/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp +++ b/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp @@ -221,7 +221,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { // Must do an explicit check if implicit checks are disabled. assert(!MacroAssembler::needs_explicit_null_check(in_bytes(Method::from_compiled_offset())), "sanity"); - if (!ImplicitNullChecks NOT_LINUX(|| true) /*!os::zero_page_read_protected()*/) { + if (!ImplicitNullChecks || !os::zero_page_read_protected()) { if (TrapBasedNullChecks) { __ trap_null_check(R19_method); } else { diff --git a/src/os/bsd/vm/os_bsd.hpp b/src/os/bsd/vm/os_bsd.hpp index a906a30e97fd888a3d35f88a7beb67aa9e95b860..c33968a0ab3fc279b662353e938473e65d38c717 100644 --- a/src/os/bsd/vm/os_bsd.hpp +++ b/src/os/bsd/vm/os_bsd.hpp @@ -27,6 +27,9 @@ // Bsd_OS defines the interface to Bsd operating systems +// Information about the protection of the page at address '0' on this os. +static bool zero_page_read_protected() { return true; } + /* pthread_getattr_np comes with BsdThreads-0.9-7 on RedHat 7.1 */ typedef int (*pthread_getattr_func_type) (pthread_t, pthread_attr_t *); diff --git a/src/os/linux/vm/os_linux.hpp b/src/os/linux/vm/os_linux.hpp index 5eed54f8c1e1176ba016f692b6c4fd3debcc82f1..829852f91950e6696be91e8808b5e7a3445d0698 100644 --- a/src/os/linux/vm/os_linux.hpp +++ b/src/os/linux/vm/os_linux.hpp @@ -30,6 +30,9 @@ /* pthread_getattr_np comes with LinuxThreads-0.9-7 on RedHat 7.1 */ typedef int (*pthread_getattr_func_type) (pthread_t, pthread_attr_t *); +// Information about the protection of the page at address '0' on this os. +static bool zero_page_read_protected() { return true; } + class Linux { friend class os; friend class TestReserveMemorySpecial; diff --git a/src/os/solaris/vm/os_solaris.hpp b/src/os/solaris/vm/os_solaris.hpp index 330d4fbc5914166a062330be4aab5d0e7bca90e2..0485346914a53f1a4cd929562a6ac4a796fb3e99 100644 --- a/src/os/solaris/vm/os_solaris.hpp +++ b/src/os/solaris/vm/os_solaris.hpp @@ -27,6 +27,9 @@ // Solaris_OS defines the interface to Solaris operating systems +// Information about the protection of the page at address '0' on this os. +static bool zero_page_read_protected() { return true; } + class Solaris { friend class os; diff --git a/src/os/windows/vm/os_windows.hpp b/src/os/windows/vm/os_windows.hpp index 67ed8a4af7c4edd1c61ba2499c62c3400a58117e..c9c4840bb6cfca416495690496c7be67f6c594ae 100644 --- a/src/os/windows/vm/os_windows.hpp +++ b/src/os/windows/vm/os_windows.hpp @@ -26,6 +26,9 @@ #define OS_WINDOWS_VM_OS_WINDOWS_HPP // Win32_OS defines the interface to windows operating systems +// Information about the protection of the page at address '0' on this os. +static bool zero_page_read_protected() { return true; } + class win32 { friend class os; diff --git a/src/share/vm/opto/callGenerator.cpp b/src/share/vm/opto/callGenerator.cpp index adc27ac02e4e143005b802ffcd61e57f6c3d3b68..22807e2c7006846f85dff9de62e82f72387f0f7f 100644 --- a/src/share/vm/opto/callGenerator.cpp +++ b/src/share/vm/opto/callGenerator.cpp @@ -201,7 +201,7 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms, Parse* parent_parser) { // Block::implicit_null_check() only looks for loads and stores, not calls. ciMethod *caller = kit.method(); ciMethodData *caller_md = (caller == NULL) ? NULL : caller->method_data(); - if (!UseInlineCaches || !ImplicitNullChecks || + if (!UseInlineCaches || !ImplicitNullChecks || !os::zero_page_read_protected() || ((ImplicitNullCheckThreshold > 0) && caller_md && (caller_md->trap_count(Deoptimization::Reason_null_check) >= (uint)ImplicitNullCheckThreshold))) { diff --git a/src/share/vm/opto/lcm.cpp b/src/share/vm/opto/lcm.cpp index 8c4f339cd3fb264548be3d5e9c98474f90cface3..dfdc663a2cb3915153fd7be41543f89523a3dd6c 100644 --- a/src/share/vm/opto/lcm.cpp +++ b/src/share/vm/opto/lcm.cpp @@ -54,6 +54,43 @@ // Optimization - Graph Style +// Check whether val is not-null-decoded compressed oop, +// i.e. will grab into the base of the heap if it represents NULL. +static bool accesses_heap_base_zone(Node *val) { + if (Universe::narrow_oop_base() > 0) { // Implies UseCompressedOops. + if (val && val->is_Mach()) { + if (val->as_Mach()->ideal_Opcode() == Op_DecodeN) { + // This assumes all Decodes with TypePtr::NotNull are matched to nodes that + // decode NULL to point to the heap base (Decode_NN). + if (val->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull) { + return true; + } + } + // Must recognize load operation with Decode matched in memory operand. + // We should not reach here exept for PPC/AIX, as os::zero_page_read_protected() + // returns true everywhere else. On PPC, no such memory operands + // exist, therefore we did not yet implement a check for such operands. + NOT_AIX(Unimplemented()); + } + } + return false; +} + +static bool needs_explicit_null_check_for_read(Node *val) { + // On some OSes (AIX) the page at address 0 is only write protected. + // If so, only Store operations will trap. + if (os::zero_page_read_protected()) { + return false; // Implicit null check will work. + } + // Also a read accessing the base of a heap-based compressed heap will trap. + if (accesses_heap_base_zone(val) && // Hits the base zone page. + Universe::narrow_oop_use_implicit_null_checks()) { // Base zone page is protected. + return false; + } + + return true; +} + //------------------------------implicit_null_check---------------------------- // Detect implicit-null-check opportunities. Basically, find NULL checks // with suitable memory ops nearby. Use the memory op to do the NULL check. @@ -209,6 +246,14 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo } break; } + + // On some OSes (AIX) the page at address 0 is only write protected. + // If so, only Store operations will trap. + // But a read accessing the base of a heap-based compressed heap will trap. + if (!was_store && needs_explicit_null_check_for_read(val)) { + continue; + } + // check if the offset is not too high for implicit exception { intptr_t offset = 0;