--- old/make/bsd/makefiles/compiler1.make 2015-09-16 15:17:13.000000000 -0700 +++ new/make/bsd/makefiles/compiler1.make 2015-09-16 15:17:12.000000000 -0700 @@ -28,4 +28,7 @@ VM_SUBDIR = client +# We don't support the JVMCI in a client VM. +INCLUDE_JVMCI := false + CFLAGS += -DCOMPILER1 --- old/make/bsd/makefiles/gcc.make 2015-09-16 15:17:13.000000000 -0700 +++ new/make/bsd/makefiles/gcc.make 2015-09-16 15:17:13.000000000 -0700 @@ -149,6 +149,7 @@ PCH_FLAG/sharedRuntimeTrig.o = $(PCH_FLAG/NO_PCH) PCH_FLAG/sharedRuntimeTrans.o = $(PCH_FLAG/NO_PCH) PCH_FLAG/unsafe.o = $(PCH_FLAG/NO_PCH) + PCH_FLAG/jvmciCompilerToVM.o = $(PCH_FLAG/NO_PCH) endif else # ($(USE_CLANG), true) --- old/make/bsd/makefiles/minimal1.make 2015-09-16 15:17:14.000000000 -0700 +++ new/make/bsd/makefiles/minimal1.make 2015-09-16 15:17:14.000000000 -0700 @@ -38,6 +38,7 @@ INCLUDE_NMT := false INCLUDE_TRACE := false INCLUDE_CDS := false +INCLUDE_JVMCI := false CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" CFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" --- old/make/excludeSrc.make 2015-09-16 15:17:15.000000000 -0700 +++ new/make/excludeSrc.make 2015-09-16 15:17:14.000000000 -0700 @@ -106,6 +106,25 @@ memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp endif +ifneq (,$(findstring $(Platform_arch_model), x86_64, sparc)) + # JVMCI is supported only on x86_64 and SPARC. +else + INCLUDE_JVMCI := false +endif + +ifeq ($(INCLUDE_JVMCI), false) + CXXFLAGS += -DINCLUDE_JVMCI=0 + CFLAGS += -DINCLUDE_JVMCI=0 + + jvmci_dir := $(HS_COMMON_SRC)/share/vm/jvmci + jvmci_dir_alt := $(HS_ALT_SRC)/share/vm/jvmci + jvmci_exclude := $(notdir $(wildcard $(jvmci_dir)/*.cpp)) \ + $(notdir $(wildcard $(jvmci_dir_alt)/*.cpp)) + Src_Files_EXCLUDE += $(jvmci_exclude) \ + jvmciCodeInstaller_aarch64.cpp jvmciCodeInstaller_ppc.cpp jvmciCodeInstaller_sparc.cpp \ + jvmciCodeInstaller_x86.cpp +endif + -include $(HS_ALT_MAKE)/excludeSrc.make .PHONY: $(HS_ALT_MAKE)/excludeSrc.make --- old/make/linux/makefiles/compiler1.make 2015-09-16 15:17:15.000000000 -0700 +++ new/make/linux/makefiles/compiler1.make 2015-09-16 15:17:15.000000000 -0700 @@ -28,4 +28,7 @@ VM_SUBDIR = client +# We don't support the JVMCI in a client VM. +INCLUDE_JVMCI := false + CFLAGS += -DCOMPILER1 --- old/make/linux/makefiles/gcc.make 2015-09-16 15:17:16.000000000 -0700 +++ new/make/linux/makefiles/gcc.make 2015-09-16 15:17:16.000000000 -0700 @@ -205,6 +205,7 @@ WARNINGS_ARE_ERRORS += -Wno-switch -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare WARNINGS_ARE_ERRORS += -Wno-delete-non-virtual-dtor -Wno-deprecated -Wno-format -Wno-dynamic-class-memaccess WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body + WARNINGS_ARE_ERRORS += -Wno-undefined-bool-conversion endif WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wunused-value -Wformat=2 -Wreturn-type -Woverloaded-virtual --- old/make/linux/makefiles/minimal1.make 2015-09-16 15:17:17.000000000 -0700 +++ new/make/linux/makefiles/minimal1.make 2015-09-16 15:17:16.000000000 -0700 @@ -38,6 +38,7 @@ INCLUDE_NMT := false INCLUDE_TRACE := false INCLUDE_CDS := false +INCLUDE_JVMCI := false CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" CFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" --- old/make/solaris/makefiles/compiler1.make 2015-09-16 15:17:17.000000000 -0700 +++ new/make/solaris/makefiles/compiler1.make 2015-09-16 15:17:17.000000000 -0700 @@ -28,4 +28,7 @@ VM_SUBDIR = client +# We don't support the JVMCI in a client VM. +INCLUDE_JVMCI := false + CFLAGS += -DCOMPILER1 --- old/make/windows/build_vm_def.sh 2015-09-16 15:17:18.000000000 -0700 +++ new/make/windows/build_vm_def.sh 2015-09-16 15:17:18.000000000 -0700 @@ -52,6 +52,7 @@ CAT="$MKS_HOME/cat.exe" RM="$MKS_HOME/rm.exe" DUMPBIN="link.exe /dump" +export VS_UNICODE_OUTPUT= if [ "$1" = "-nosa" ]; then echo EXPORTS > vm.def --- old/make/windows/create_obj_files.sh 2015-09-16 15:17:19.000000000 -0700 +++ new/make/windows/create_obj_files.sh 2015-09-16 15:17:18.000000000 -0700 @@ -111,6 +111,7 @@ COMPILER2_SPECIFIC_FILES="opto libadt bcEscapeAnalyzer.cpp c2_* runtime_*" COMPILER1_SPECIFIC_FILES="c1_*" +JVMCI_SPECIFIC_FILES="*jvmci* *JVMCI*" SHARK_SPECIFIC_FILES="shark" ZERO_SPECIFIC_FILES="zero" @@ -119,11 +120,11 @@ # Exclude per type. case "${TYPE}" in - "compiler1") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; + "compiler1") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; "compiler2") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;; "tiered") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;; - "zero") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; - "shark") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES}" ;; + "zero") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; + "shark") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES}" ;; esac # Special handling of arch model. --- old/make/windows/makefiles/projectcreator.make 2015-09-16 15:17:19.000000000 -0700 +++ new/make/windows/makefiles/projectcreator.make 2015-09-16 15:17:19.000000000 -0700 @@ -145,6 +145,10 @@ -ignorePath_TARGET tiered \ -ignorePath_TARGET c1_ +ProjectCreatorIDEOptionsIgnoreJVMCI=\ + -ignorePath_TARGET src/share/vm/jvmci \ + -ignorePath_TARGET vm/jvmci + ProjectCreatorIDEOptionsIgnoreCompiler2=\ -ignorePath_TARGET compiler2 \ -ignorePath_TARGET tiered \ @@ -165,6 +169,8 @@ ################################################## ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ -define_compiler1 COMPILER1 \ + -define_compiler1 INCLUDE_JVMCI=0 \ +$(ProjectCreatorIDEOptionsIgnoreJVMCI:TARGET=compiler1) \ $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=compiler1) ################################################## --- old/make/windows/makefiles/vm.make 2015-09-16 15:17:20.000000000 -0700 +++ new/make/windows/makefiles/vm.make 2015-09-16 15:17:20.000000000 -0700 @@ -40,7 +40,7 @@ !endif !if "$(Variant)" == "compiler1" -CXX_FLAGS=$(CXX_FLAGS) /D "COMPILER1" +CXX_FLAGS=$(CXX_FLAGS) /D "COMPILER1" /D INCLUDE_JVMCI=0 !endif !if "$(Variant)" == "compiler2" @@ -152,6 +152,7 @@ VM_PATH=$(VM_PATH);../generated/jvmtifiles VM_PATH=$(VM_PATH);../generated/tracefiles VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/c1 +VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/jvmci VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/compiler VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/code VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/interpreter @@ -232,6 +233,9 @@ {$(COMMONSRC)\share\vm\classfile}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{$(COMMONSRC)\share\vm\jvmci}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + {$(COMMONSRC)\share\vm\gc\parallel}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< --- old/src/cpu/aarch64/vm/compiledIC_aarch64.cpp 2015-09-16 15:17:21.000000000 -0700 +++ new/src/cpu/aarch64/vm/compiledIC_aarch64.cpp 2015-09-16 15:17:21.000000000 -0700 @@ -51,13 +51,15 @@ // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from // calling compiled code to calling interpreted code. // mov rmethod, 0 // jmp -4 # to self - address mark = cbuf.insts_mark(); // Get mark within main instrs section. + if (mark == NULL) { + mark = cbuf.insts_mark(); // Get mark within main instrs section. + } // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a stub. --- old/src/cpu/aarch64/vm/cppInterpreterGenerator_aarch64.hpp 2015-09-16 15:17:22.000000000 -0700 +++ new/src/cpu/aarch64/vm/cppInterpreterGenerator_aarch64.hpp 2015-09-16 15:17:21.000000000 -0700 @@ -30,5 +30,6 @@ void generate_more_monitors(); void generate_deopt_handling(); + void lock_method(void); #endif // CPU_AARCH64_VM_CPPINTERPRETERGENERATOR_AARCH64_HPP --- old/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp 2015-09-16 15:17:22.000000000 -0700 +++ new/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp 2015-09-16 15:17:22.000000000 -0700 @@ -48,7 +48,6 @@ address generate_Reference_get_entry(); address generate_CRC32_update_entry(); address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); - void lock_method(void); void generate_stack_overflow_check(void); void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); --- old/src/cpu/aarch64/vm/relocInfo_aarch64.cpp 2015-09-16 15:17:23.000000000 -0700 +++ new/src/cpu/aarch64/vm/relocInfo_aarch64.cpp 2015-09-16 15:17:23.000000000 -0700 @@ -102,12 +102,5 @@ } } -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { - if (NativeInstruction::maybe_cpool_ref(addr())) { - address old_addr = old_addr_for(addr(), src, dest); - MacroAssembler::pd_patch_instruction(addr(), MacroAssembler::target_addr_for_insn(old_addr)); - } -} - void metadata_Relocation::pd_fix_value(address x) { } --- old/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp 2015-09-16 15:17:24.000000000 -0700 +++ new/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp 2015-09-16 15:17:24.000000000 -0700 @@ -460,11 +460,11 @@ } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Note: r13 contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled --- old/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp 2015-09-16 15:17:25.000000000 -0700 +++ new/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp 2015-09-16 15:17:24.000000000 -0700 @@ -535,7 +535,7 @@ // r0 // c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs) // rscratch1, rscratch2 (scratch regs) -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { // synchronize method const Address access_flags(rmethod, Method::access_flags_offset()); const Address monitor_block_top( --- old/src/cpu/ppc/vm/compiledIC_ppc.cpp 2015-09-16 15:17:25.000000000 -0700 +++ new/src/cpu/ppc/vm/compiledIC_ppc.cpp 2015-09-16 15:17:25.000000000 -0700 @@ -94,10 +94,12 @@ const int IC_pos_in_java_to_interp_stub = 8; #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* = NULL*/) { #ifdef COMPILER2 - // Get the mark within main instrs section which is set to the address of the call. - address call_addr = cbuf.insts_mark(); + if (mark == NULL) { + // Get the mark within main instrs section which is set to the address of the call. + mark = cbuf.insts_mark(); + } // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a stub. @@ -117,7 +119,7 @@ // Create a static stub relocation which relates this stub // with the call instruction at insts_call_instruction_offset in the // instructions code-section. - __ relocate(static_stub_Relocation::spec(call_addr)); + __ relocate(static_stub_Relocation::spec(mark)); const int stub_start_offset = __ offset(); // Now, create the stub's code: --- old/src/cpu/ppc/vm/relocInfo_ppc.cpp 2015-09-16 15:17:26.000000000 -0700 +++ new/src/cpu/ppc/vm/relocInfo_ppc.cpp 2015-09-16 15:17:26.000000000 -0700 @@ -125,8 +125,5 @@ void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { -} - void metadata_Relocation::pd_fix_value(address x) { } --- old/src/cpu/ppc/vm/sharedRuntime_ppc.cpp 2015-09-16 15:17:27.000000000 -0700 +++ new/src/cpu/ppc/vm/sharedRuntime_ppc.cpp 2015-09-16 15:17:26.000000000 -0700 @@ -957,11 +957,11 @@ return c2i_entrypoint; } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Load method's entry-point from method. __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); --- old/src/cpu/sparc/vm/compiledIC_sparc.cpp 2015-09-16 15:17:27.000000000 -0700 +++ new/src/cpu/sparc/vm/compiledIC_sparc.cpp 2015-09-16 15:17:27.000000000 -0700 @@ -53,14 +53,15 @@ // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { -#ifdef COMPILER2 +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from calling // compiled code to calling interpreted code. // set (empty), G5 // jmp -1 - address mark = cbuf.insts_mark(); // Get mark within main instrs section. + if (mark == NULL) { + mark = cbuf.insts_mark(); // Get mark within main instrs section. + } MacroAssembler _masm(&cbuf); @@ -80,12 +81,11 @@ __ delayed()->nop(); + assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size"); + // Update current stubs pointer and restore code_end. __ end_a_stub(); return base; -#else - ShouldNotReachHere(); -#endif } #undef __ --- old/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp 2015-09-16 15:17:28.000000000 -0700 +++ new/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp 2015-09-16 15:17:28.000000000 -0700 @@ -31,6 +31,7 @@ void generate_more_monitors(); void generate_deopt_handling(); + void lock_method(void); void adjust_callers_stack(Register args); void generate_compute_interpreter_state(const Register state, const Register prev_state, --- old/src/cpu/sparc/vm/cppInterpreter_sparc.cpp 2015-09-16 15:17:29.000000000 -0700 +++ new/src/cpu/sparc/vm/cppInterpreter_sparc.cpp 2015-09-16 15:17:29.000000000 -0700 @@ -1164,7 +1164,7 @@ } // Find preallocated monitor and lock method (C++ interpreter) // -void InterpreterGenerator::lock_method(void) { +void InterpreterGenerator::lock_method() { // Lock the current method. // Destroys registers L2_scratch, L3_scratch, O0 // --- old/src/cpu/sparc/vm/interp_masm_sparc.cpp 2015-09-16 15:17:30.000000000 -0700 +++ new/src/cpu/sparc/vm/interp_masm_sparc.cpp 2015-09-16 15:17:29.000000000 -0700 @@ -1643,26 +1643,73 @@ bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. +#if INCLUDE_JVMCI + if (MethodProfileWidth == 0) { + update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); + } +#else update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); - bind (profile_continue); +#endif + bind(profile_continue); + } +} + +#if INCLUDE_JVMCI +void InterpreterMacroAssembler::profile_called_method(Register method, Register scratch) { + assert_different_registers(method, scratch); + if (ProfileInterpreter && MethodProfileWidth > 0) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + Label done; + record_item_in_profile_helper(method, scratch, 0, done, MethodProfileWidth, + &VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset())); + bind(done); + + update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); + bind(profile_continue); } } +#endif // INCLUDE_JVMCI -void InterpreterMacroAssembler::record_klass_in_profile_helper( - Register receiver, Register scratch, - int start_row, Label& done, bool is_virtual_call) { +void InterpreterMacroAssembler::record_klass_in_profile_helper(Register receiver, Register scratch, + Label& done, bool is_virtual_call) { if (TypeProfileWidth == 0) { if (is_virtual_call) { increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); } - return; +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + increment_mdp_data_at(in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()), scratch); + } +#endif + } else { + int non_profiled_offset = -1; + if (is_virtual_call) { + non_profiled_offset = in_bytes(CounterData::count_offset()); + } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()); + } +#endif + + record_item_in_profile_helper(receiver, scratch, 0, done, TypeProfileWidth, + &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); } +} - int last_row = VirtualCallData::row_limit() - 1; +void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, + Register scratch, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset) { + int last_row = total_rows - 1; assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the receiver and for null. + // Test this row for both the item and for null. // Take any of three different outcomes: - // 1. found receiver => increment count and goto done + // 1. found item => increment count and goto done // 2. found null => keep looking for case 1, maybe allocate this cell // 3. found something else => keep looking for cases 1 and 2 // Case 3 is handled by a recursive call. @@ -1670,28 +1717,28 @@ Label next_test; bool test_for_null_also = (row == start_row); - // See if the receiver is receiver[n]. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); - test_mdp_data_at(recvr_offset, receiver, next_test, scratch); + // See if the item is item[n]. + int item_offset = in_bytes(item_offset_fn(row)); + test_mdp_data_at(item_offset, item, next_test, scratch); // delayed()->tst(scratch); - // The receiver is receiver[n]. Increment count[n]. - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); + // The receiver is item[n]. Increment count[n]. + int count_offset = in_bytes(item_count_offset_fn(row)); increment_mdp_data_at(count_offset, scratch); ba_short(done); bind(next_test); if (test_for_null_also) { Label found_null; - // Failed the equality check on receiver[n]... Test for null. + // Failed the equality check on item[n]... Test for null. if (start_row == last_row) { // The only thing left to do is handle the null case. - if (is_virtual_call) { + if (non_profiled_offset >= 0) { brx(Assembler::zero, false, Assembler::pn, found_null); delayed()->nop(); - // Receiver did not match any saved receiver and there is no empty row for it. + // Item did not match any saved item and there is no empty row for it. // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); + increment_mdp_data_at(non_profiled_offset, scratch); ba_short(done); bind(found_null); } else { @@ -1705,21 +1752,22 @@ delayed()->nop(); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, scratch, start_row + 1, done, is_virtual_call); + record_item_in_profile_helper(item, scratch, start_row + 1, done, total_rows, + item_offset_fn, item_count_offset_fn, non_profiled_offset); - // Found a null. Keep searching for a matching receiver, + // Found a null. Keep searching for a matching item, // but remember that this is an empty (unused) slot. bind(found_null); } } - // In the fall-through case, we found no matching receiver, but we - // observed the receiver[start_row] is NULL. + // In the fall-through case, we found no matching item, but we + // observed the item[start_row] is NULL. - // Fill in the receiver field and increment the count. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); - set_mdp_data_at(recvr_offset, receiver); - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); + // Fill in the item field and increment the count. + int item_offset = in_bytes(item_offset_fn(start_row)); + set_mdp_data_at(item_offset, item); + int count_offset = in_bytes(item_count_offset_fn(start_row)); mov(DataLayout::counter_increment, scratch); set_mdp_data_at(count_offset, scratch); if (start_row > 0) { @@ -1732,7 +1780,7 @@ assert(ProfileInterpreter, "must be profiling"); Label done; - record_klass_in_profile_helper(receiver, scratch, 0, done, is_virtual_call); + record_klass_in_profile_helper(receiver, scratch, done, is_virtual_call); bind (done); } @@ -1788,7 +1836,7 @@ // The method data pointer needs to be updated. int mdp_delta = in_bytes(BitData::bit_data_size()); if (TypeProfileCasts) { - mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size()); } update_mdp_by_constant(mdp_delta); @@ -1806,7 +1854,7 @@ int mdp_delta = in_bytes(BitData::bit_data_size()); if (TypeProfileCasts) { - mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size()); // Record the object type. record_klass_in_profile(klass, scratch, false); @@ -1828,7 +1876,7 @@ int count_offset = in_bytes(CounterData::count_offset()); // Back up the address, since we have already bumped the mdp. - count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); + count_offset -= in_bytes(ReceiverTypeData::receiver_type_data_size()); // *Decrement* the counter. We expect to see zero or small negatives. increment_mdp_data_at(count_offset, scratch, true); --- old/src/cpu/sparc/vm/interp_masm_sparc.hpp 2015-09-16 15:17:30.000000000 -0700 +++ new/src/cpu/sparc/vm/interp_masm_sparc.hpp 2015-09-16 15:17:30.000000000 -0700 @@ -30,6 +30,8 @@ // This file specializes the assember with interpreter-specific macros +typedef ByteSize (*OffsetFunction)(uint); + REGISTER_DECLARATION( Register, Otos_i , O0); // tos for ints, etc REGISTER_DECLARATION( Register, Otos_l , O0); // for longs REGISTER_DECLARATION( Register, Otos_l1, O0); // for 1st part of longs @@ -299,7 +301,11 @@ void record_klass_in_profile(Register receiver, Register scratch, bool is_virtual_call); void record_klass_in_profile_helper(Register receiver, Register scratch, - int start_row, Label& done, bool is_virtual_call); + Label& done, bool is_virtual_call); + void record_item_in_profile_helper(Register item, + Register scratch, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset); void update_mdp_by_offset(int offset_of_disp, Register scratch); void update_mdp_by_offset(Register reg, int offset_of_disp, @@ -312,6 +318,7 @@ void profile_call(Register scratch); void profile_final_call(Register scratch); void profile_virtual_call(Register receiver, Register scratch, bool receiver_can_be_null = false); + void profile_called_method(Register method, Register scratch); void profile_ret(TosState state, Register return_bci, Register scratch); void profile_null_seen(Register scratch); void profile_typecheck(Register klass, Register scratch); --- old/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp 2015-09-16 15:17:31.000000000 -0700 +++ new/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp 2015-09-16 15:17:31.000000000 -0700 @@ -38,7 +38,6 @@ address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } address generate_Reference_get_entry(void); - void lock_method(void); void save_native_result(void); void restore_native_result(void); --- old/src/cpu/sparc/vm/nativeInst_sparc.hpp 2015-09-16 15:17:32.000000000 -0700 +++ new/src/cpu/sparc/vm/nativeInst_sparc.hpp 2015-09-16 15:17:31.000000000 -0700 @@ -53,6 +53,7 @@ bool is_nop() { return long_at(0) == nop_instruction(); } bool is_call() { return is_op(long_at(0), Assembler::call_op); } + bool is_call_reg() { return is_op(long_at(0), Assembler::arith_op); } bool is_sethi() { return (is_op2(long_at(0), Assembler::sethi_op2) && inv_rd(long_at(0)) != G0); } @@ -415,6 +416,19 @@ return call; } +class NativeCallReg: public NativeInstruction { + public: + enum Sparc_specific_constants { + instruction_size = 8, + return_address_offset = 8, + instruction_offset = 0 + }; + + address next_instruction_address() const { + return addr_at(instruction_size); + } +}; + // The NativeFarCall is an abstraction for accessing/manipulating native call-anywhere // instructions in the sparcv9 vm. Used to call native methods which may be loaded // anywhere in the address space, possibly out of reach of a call instruction. --- old/src/cpu/sparc/vm/relocInfo_sparc.cpp 2015-09-16 15:17:32.000000000 -0700 +++ new/src/cpu/sparc/vm/relocInfo_sparc.cpp 2015-09-16 15:17:32.000000000 -0700 @@ -197,8 +197,5 @@ void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { -} - void metadata_Relocation::pd_fix_value(address x) { } --- old/src/cpu/sparc/vm/sharedRuntime_sparc.cpp 2015-09-16 15:17:33.000000000 -0700 +++ new/src/cpu/sparc/vm/sharedRuntime_sparc.cpp 2015-09-16 15:17:33.000000000 -0700 @@ -43,6 +43,9 @@ #include "compiler/compileBroker.hpp" #include "shark/sharkCompiler.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif #define __ masm-> @@ -513,10 +516,10 @@ const VMRegPair *regs, Label& skip_fixup); void gen_i2c_adapter(int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs); + // VMReg max_arg, + int comp_args_on_stack, // VMRegStackSlots + const BasicType *sig_bt, + const VMRegPair *regs); AdapterGenerator(MacroAssembler *_masm) : masm(_masm) {} }; @@ -760,13 +763,11 @@ __ bind(L_fail); } -void AdapterGenerator::gen_i2c_adapter( - int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs) { - +void AdapterGenerator::gen_i2c_adapter(int total_args_passed, + // VMReg max_arg, + int comp_args_on_stack, // VMRegStackSlots + const BasicType *sig_bt, + const VMRegPair *regs) { // Generate an I2C adapter: adjust the I-frame to make space for the C-frame // layout. Lesp was saved by the calling I-frame and will be restored on // return. Meanwhile, outgoing arg space is all owned by the callee @@ -990,6 +991,21 @@ // Jump to the compiled code just as if compiled code was doing it. __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // check if this call should be routed towards a specific entry point + __ ld(Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), G1); + __ cmp(G0, G1); + Label no_alternative_target; + __ br(Assembler::equal, false, Assembler::pn, no_alternative_target); + __ delayed()->nop(); + + __ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()), G3); + __ st(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); + + __ bind(no_alternative_target); + } +#endif // 6243940 We might end up in handle_wrong_method if // the callee is deoptimized as we race thru here. If that @@ -1006,6 +1022,15 @@ __ delayed()->nop(); } +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { + AdapterGenerator agen(masm); + agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs); +} + // --------------------------------------------------------------- AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, int total_args_passed, @@ -1016,9 +1041,7 @@ AdapterFingerPrint* fingerprint) { address i2c_entry = __ pc(); - AdapterGenerator agen(masm); - - agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs); + gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); // ------------------------------------------------------------------------- @@ -1063,7 +1086,7 @@ } address c2i_entry = __ pc(); - + AdapterGenerator agen(masm); agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, L_skip_fixup); __ flush(); @@ -2916,6 +2939,11 @@ pad += StackShadowPages*16 + 32; } #endif +#if INCLUDE_JVMCI + if (EnableJVMCI) { + pad += 1000; // Increase the buffer size when compiling for JVMCI + } +#endif #ifdef _LP64 CodeBuffer buffer("deopt_blob", 2100+pad, 512); #else @@ -2982,6 +3010,45 @@ __ ba(cont); __ delayed()->mov(Deoptimization::Unpack_deopt, L0deopt_mode); + +#if INCLUDE_JVMCI + Label after_fetch_unroll_info_call; + int implicit_exception_uncommon_trap_offset = 0; + int uncommon_trap_offset = 0; + + if (EnableJVMCI) { + masm->block_comment("BEGIN implicit_exception_uncommon_trap"); + implicit_exception_uncommon_trap_offset = __ offset() - start; + + __ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()), O7); + __ st_ptr(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); + __ add(O7, -8, O7); + + uncommon_trap_offset = __ offset() - start; + + // Save everything in sight. + (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); + __ set_last_Java_frame(SP, NULL); + + __ ld(G2_thread, in_bytes(JavaThread::pending_deoptimization_offset()), O1); + __ sub(G0, 1, L1); + __ st(L1, G2_thread, in_bytes(JavaThread::pending_deoptimization_offset())); + + __ mov((int32_t)Deoptimization::Unpack_reexecute, L0deopt_mode); + __ mov(G2_thread, O0); + __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)); + __ delayed()->nop(); + oop_maps->add_gc_map( __ offset()-start, map->deep_copy()); + __ get_thread(); + __ add(O7, 8, O7); + __ reset_last_Java_frame(); + + __ ba(after_fetch_unroll_info_call); + __ delayed()->nop(); // Delay slot + masm->block_comment("END implicit_exception_uncommon_trap"); + } // EnableJVMCI +#endif // INCLUDE_JVMCI + int exception_offset = __ offset() - start; // restore G2, the trampoline destroyed it @@ -3004,6 +3071,7 @@ int exception_in_tls_offset = __ offset() - start; // No need to update oop_map as each call to save_live_registers will produce identical oopmap + // Opens a new stack frame (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); // Restore G2_thread @@ -3035,7 +3103,12 @@ // Reexecute entry, similar to c2 uncommon trap // int reexecute_offset = __ offset() - start; - +#if INCLUDE_JVMCI && !defined(COMPILER1) + if (EnableJVMCI && UseJVMCICompiler) { + // JVMCI does not use this kind of deoptimization + __ should_not_reach_here(); + } +#endif // No need to update oop_map as each call to save_live_registers will produce identical oopmap (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); @@ -3059,6 +3132,11 @@ __ reset_last_Java_frame(); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + __ bind(after_fetch_unroll_info_call); + } +#endif // NOTE: we know that only O0/O1 will be reloaded by restore_result_registers // so this move will survive @@ -3124,6 +3202,12 @@ masm->flush(); _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_words); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset); + _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); + } +#endif } #ifdef COMPILER2 --- old/src/cpu/sparc/vm/templateInterpreter_sparc.cpp 2015-09-16 15:17:34.000000000 -0700 +++ new/src/cpu/sparc/vm/templateInterpreter_sparc.cpp 2015-09-16 15:17:34.000000000 -0700 @@ -204,6 +204,20 @@ address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) { address entry = __ pc(); __ get_constant_pool_cache(LcpoolCache); // load LcpoolCache +#if INCLUDE_JVMCI + // Check if we need to take lock at entry of synchronized method. + if (UseJVMCICompiler) { + Label L; + Address pending_monitor_enter_addr(G2_thread, JavaThread::pending_monitorenter_offset()); + __ ldbool(pending_monitor_enter_addr, Gtemp); // Load if pending monitor enter + __ cmp_and_br_short(Gtemp, G0, Assembler::equal, Assembler::pn, L); + // Clear flag. + __ stbool(G0, pending_monitor_enter_addr); + // Take lock. + lock_method(); + __ bind(L); + } +#endif { Label L; Address exception_addr(G2_thread, Thread::pending_exception_offset()); __ ld_ptr(exception_addr, Gtemp); // Load pending exception. @@ -349,7 +363,7 @@ // Allocate monitor and lock method (asm interpreter) // ebx - Method* // -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { __ ld(Lmethod, in_bytes(Method::access_flags_offset()), O0); // Load access flags. #ifdef ASSERT --- old/src/cpu/sparc/vm/templateInterpreter_sparc.hpp 2015-09-16 15:17:35.000000000 -0700 +++ new/src/cpu/sparc/vm/templateInterpreter_sparc.hpp 2015-09-16 15:17:35.000000000 -0700 @@ -37,9 +37,9 @@ #ifdef _LP64 // The sethi() instruction generates lots more instructions when shell // stack limit is unlimited, so that's why this is much bigger. - const static int InterpreterCodeSize = 210 * K; + const static int InterpreterCodeSize = 260 * K; #else - const static int InterpreterCodeSize = 180 * K; + const static int InterpreterCodeSize = 230 * K; #endif #endif // CPU_SPARC_VM_TEMPLATEINTERPRETER_SPARC_HPP --- old/src/cpu/sparc/vm/templateTable_sparc.cpp 2015-09-16 15:17:36.000000000 -0700 +++ new/src/cpu/sparc/vm/templateTable_sparc.cpp 2015-09-16 15:17:35.000000000 -0700 @@ -2949,12 +2949,16 @@ void TemplateTable::generate_vtable_call(Register Rrecv, Register Rindex, Register Rret) { + Register Rtemp = G4_scratch; Register Rcall = Rindex; assert_different_registers(Rcall, G5_method, Gargs, Rret); // get target Method* & entry point __ lookup_virtual_method(Rrecv, Rindex, G5_method); __ profile_arguments_type(G5_method, Rcall, Gargs, true); +#if INCLUDE_JVMCI + __ profile_called_method(G5_method, Rtemp); +#endif __ call_from_interpreter(Rcall, Gargs, Rret); } @@ -3211,6 +3215,9 @@ assert_different_registers(Rcall, G5_method, Gargs, Rret); __ profile_arguments_type(G5_method, Rcall, Gargs, true); +#if INCLUDE_JVMCI + __ profile_called_method(G5_method, Rscratch); +#endif __ call_from_interpreter(Rcall, Gargs, Rret); } @@ -3486,7 +3493,8 @@ Register RspecifiedKlass = O4; // Check for casting a NULL - __ br_null_short(Otos_i, Assembler::pn, is_null); + __ br_null(Otos_i, false, Assembler::pn, is_null); + __ delayed()->nop(); // Get value klass in RobjKlass __ load_klass(Otos_i, RobjKlass); // get value klass @@ -3542,7 +3550,8 @@ Register RspecifiedKlass = O4; // Check for casting a NULL - __ br_null_short(Otos_i, Assembler::pt, is_null); + __ br_null(Otos_i, false, Assembler::pt, is_null); + __ delayed()->nop(); // Get value klass in RobjKlass __ load_klass(Otos_i, RobjKlass); // get value klass --- old/src/cpu/sparc/vm/vmStructs_sparc.hpp 2015-09-16 15:17:36.000000000 -0700 +++ new/src/cpu/sparc/vm/vmStructs_sparc.hpp 2015-09-16 15:17:36.000000000 -0700 @@ -37,10 +37,11 @@ /******************************/ \ /* JavaFrameAnchor */ \ /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _flags, int) - -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + volatile_nonstatic_field(JavaFrameAnchor, _flags, int) \ + static_field(VM_Version, _features, int) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + declare_toplevel_type(VM_Version) #define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ /******************************/ \ @@ -78,7 +79,11 @@ declare_c2_constant(R_G4_num) \ declare_c2_constant(R_G5_num) \ declare_c2_constant(R_G6_num) \ - declare_c2_constant(R_G7_num) + declare_c2_constant(R_G7_num) \ + declare_constant(VM_Version::vis1_instructions_m) \ + declare_constant(VM_Version::vis2_instructions_m) \ + declare_constant(VM_Version::vis3_instructions_m) \ + declare_constant(VM_Version::cbcond_instructions_m) #define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) --- old/src/cpu/sparc/vm/vm_version_sparc.hpp 2015-09-16 15:17:37.000000000 -0700 +++ new/src/cpu/sparc/vm/vm_version_sparc.hpp 2015-09-16 15:17:37.000000000 -0700 @@ -29,6 +29,7 @@ #include "runtime/vm_version.hpp" class VM_Version: public Abstract_VM_Version { + friend class VMStructs; protected: enum Feature_Flag { v8_instructions = 0, --- old/src/cpu/x86/vm/assembler_x86.cpp 2015-09-16 15:17:38.000000000 -0700 +++ new/src/cpu/x86/vm/assembler_x86.cpp 2015-09-16 15:17:37.000000000 -0700 @@ -877,21 +877,35 @@ // Check second byte NOT_LP64(assert((0xC0 & *ip) == 0xC0, "shouldn't have LDS and LES instructions")); + int vex_opcode; // First byte if ((0xFF & *inst) == VEX_3bytes) { + vex_opcode = VEX_OPCODE_MASK & *ip; ip++; // third byte is_64bit = ((VEX_W & *ip) == VEX_W); + } else { + vex_opcode = VEX_OPCODE_0F; } ip++; // opcode // To find the end of instruction (which == end_pc_operand). - switch (0xFF & *ip) { - case 0x61: // pcmpestri r, r/a, #8 - case 0x70: // pshufd r, r/a, #8 - case 0x73: // psrldq r, #8 - tail_size = 1; // the imm8 - break; - default: - break; + switch (vex_opcode) { + case VEX_OPCODE_0F: + switch (0xFF & *ip) { + case 0x70: // pshufd r, r/a, #8 + case 0x71: // ps[rl|ra|ll]w r, #8 + case 0x72: // ps[rl|ra|ll]d r, #8 + case 0x73: // ps[rl|ra|ll]q r, #8 + case 0xC2: // cmp[ps|pd|ss|sd] r, r, r/a, #8 + case 0xC4: // pinsrw r, r, r/a, #8 + case 0xC5: // pextrw r/a, r, #8 + case 0xC6: // shufp[s|d] r, r, r/a, #8 + tail_size = 1; // the imm8 + break; + } + break; + case VEX_OPCODE_0F_3A: + tail_size = 1; + break; } ip++; // skip opcode debug_only(has_disp32 = true); // has both kinds of operands! @@ -2347,7 +2361,7 @@ void Assembler::movsbl(Register dst, Register src) { // movsxb NOT_LP64(assert(src->has_byte_register(), "must have byte register")); - int encode = prefix_and_encode(dst->encoding(), src->encoding(), true); + int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true); emit_int8(0x0F); emit_int8((unsigned char)0xBE); emit_int8((unsigned char)(0xC0 | encode)); @@ -2464,7 +2478,7 @@ void Assembler::movzbl(Register dst, Register src) { // movzxb NOT_LP64(assert(src->has_byte_register(), "must have byte register")); - int encode = prefix_and_encode(dst->encoding(), src->encoding(), true); + int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true); emit_int8(0x0F); emit_int8((unsigned char)0xB6); emit_int8(0xC0 | encode); @@ -6150,12 +6164,12 @@ return reg_enc; } -int Assembler::prefix_and_encode(int dst_enc, int src_enc, bool byteinst) { +int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { if (dst_enc < 8) { if (src_enc >= 8) { prefix(REX_B); src_enc -= 8; - } else if (byteinst && src_enc >= 4) { + } else if ((src_is_byte && src_enc >= 4) || (dst_is_byte && dst_enc >= 4)) { prefix(REX); } } else { --- old/src/cpu/x86/vm/assembler_x86.hpp 2015-09-16 15:17:38.000000000 -0700 +++ new/src/cpu/x86/vm/assembler_x86.hpp 2015-09-16 15:17:38.000000000 -0700 @@ -533,7 +533,8 @@ VEX_OPCODE_NONE = 0x0, VEX_OPCODE_0F = 0x1, VEX_OPCODE_0F_38 = 0x2, - VEX_OPCODE_0F_3A = 0x3 + VEX_OPCODE_0F_3A = 0x3, + VEX_OPCODE_MASK = 0x1F }; enum AvxVectorLen { @@ -604,7 +605,10 @@ int prefix_and_encode(int reg_enc, bool byteinst = false); int prefixq_and_encode(int reg_enc); - int prefix_and_encode(int dst_enc, int src_enc, bool byteinst = false); + int prefix_and_encode(int dst_enc, int src_enc) { + return prefix_and_encode(dst_enc, false, src_enc, false); + } + int prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte); int prefixq_and_encode(int dst_enc, int src_enc); void prefix(Register reg); --- old/src/cpu/x86/vm/assembler_x86.inline.hpp 2015-09-16 15:17:39.000000000 -0700 +++ new/src/cpu/x86/vm/assembler_x86.inline.hpp 2015-09-16 15:17:39.000000000 -0700 @@ -33,7 +33,7 @@ inline int Assembler::prefix_and_encode(int reg_enc, bool byteinst) { return reg_enc; } inline int Assembler::prefixq_and_encode(int reg_enc) { return reg_enc; } -inline int Assembler::prefix_and_encode(int dst_enc, int src_enc, bool byteinst) { return dst_enc << 3 | src_enc; } +inline int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { return dst_enc << 3 | src_enc; } inline int Assembler::prefixq_and_encode(int dst_enc, int src_enc) { return dst_enc << 3 | src_enc; } inline void Assembler::prefix(Register reg) {} --- old/src/cpu/x86/vm/compiledIC_x86.cpp 2015-09-16 15:17:40.000000000 -0700 +++ new/src/cpu/x86/vm/compiledIC_x86.cpp 2015-09-16 15:17:40.000000000 -0700 @@ -50,13 +50,15 @@ // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from // calling compiled code to calling interpreted code. // movq rbx, 0 // jmp -5 # to self - address mark = cbuf.insts_mark(); // Get mark within main instrs section. + if (mark == NULL) { + mark = cbuf.insts_mark(); // Get mark within main instrs section. + } // Note that the code buffer's insts_mark is always relative to insts. // That's why we must use the macroassembler to generate a stub. @@ -73,6 +75,8 @@ // This is recognized as unresolved by relocs/nativeinst/ic code. __ jump(RuntimeAddress(__ pc())); + assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size"); + // Update current stubs pointer and restore insts_end. __ end_a_stub(); return base; @@ -104,10 +108,15 @@ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); - assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(), +#ifdef ASSERT + // read the value once + intptr_t data = method_holder->data(); + address destination = jump->jump_destination(); + assert(data == 0 || data == (intptr_t)callee(), "a) MT-unsafe modification of inline cache"); - assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry, + assert(destination == (address)-1 || destination == entry, "b) MT-unsafe modification of inline cache"); +#endif // Update stub. method_holder->set_data((intptr_t)callee()); @@ -124,11 +133,12 @@ assert(stub != NULL, "stub not found"); // Creation also verifies the object. NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); - NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); method_holder->set_data(0); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); jump->set_jump_destination((address)-1); } + //----------------------------------------------------------------------------- // Non-product mode code #ifndef PRODUCT @@ -150,5 +160,4 @@ // Verify state. assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); } - #endif // !PRODUCT --- old/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp 2015-09-16 15:17:40.000000000 -0700 +++ new/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp 2015-09-16 15:17:40.000000000 -0700 @@ -29,6 +29,7 @@ void generate_more_monitors(); void generate_deopt_handling(); + void lock_method(void); address generate_interpreter_frame_manager(bool synchronized); // C++ interpreter only void generate_compute_interpreter_state(const Register state, const Register prev_state, --- old/src/cpu/x86/vm/cppInterpreter_x86.cpp 2015-09-16 15:17:41.000000000 -0700 +++ new/src/cpu/x86/vm/cppInterpreter_x86.cpp 2015-09-16 15:17:41.000000000 -0700 @@ -741,7 +741,7 @@ // Find preallocated monitor and lock method (C++ interpreter) // rbx - Method* // -void InterpreterGenerator::lock_method(void) { +void InterpreterGenerator::lock_method() { // assumes state == rsi/r13 == pointer to current interpreterState // minimally destroys rax, rdx|c_rarg1, rdi // --- old/src/cpu/x86/vm/frame_x86.cpp 2015-09-16 15:17:42.000000000 -0700 +++ new/src/cpu/x86/vm/frame_x86.cpp 2015-09-16 15:17:42.000000000 -0700 @@ -458,11 +458,11 @@ // This is the sp before any possible extension (adapter/locals). intptr_t* unextended_sp = interpreter_frame_sender_sp(); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (map->update_map()) { update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset)); } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI return frame(sender_sp, unextended_sp, link(), sender_pc()); } @@ -683,10 +683,19 @@ DESCRIBE_FP_OFFSET(interpreter_frame_locals); DESCRIBE_FP_OFFSET(interpreter_frame_bcp); DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp); -#endif +#ifdef AMD64 + } else if (is_entry_frame()) { + // This could be more descriptive if we use the enum in + // stubGenerator to map to real names but it's most important to + // claim these frame slots so the error checking works. + for (int i = 0; i < entry_frame_after_call_words; i++) { + values.describe(frame_no, fp() - i, err_msg("call_stub word fp - %d", i)); + } +#endif // AMD64 } -} #endif +} +#endif // !PRODUCT intptr_t *frame::initial_deoptimization_info() { // used to reset the saved FP --- old/src/cpu/x86/vm/frame_x86.inline.hpp 2015-09-16 15:17:42.000000000 -0700 +++ new/src/cpu/x86/vm/frame_x86.inline.hpp 2015-09-16 15:17:42.000000000 -0700 @@ -78,7 +78,11 @@ assert(((nmethod*)_cb)->insts_contains(_pc), "original PC must be in nmethod"); _deopt_state = is_deoptimized; } else { - _deopt_state = not_deoptimized; + if (_cb->is_deoptimization_stub()) { + _deopt_state = is_deoptimized; + } else { + _deopt_state = not_deoptimized; + } } } --- old/src/cpu/x86/vm/globals_x86.hpp 2015-09-16 15:17:43.000000000 -0700 +++ new/src/cpu/x86/vm/globals_x86.hpp 2015-09-16 15:17:43.000000000 -0700 @@ -46,7 +46,7 @@ // the the vep is aligned at CodeEntryAlignment whereas c2 only aligns // the uep and the vep doesn't get real alignment but just slops on by // only assured that the entry instruction meets the 5 byte size requirement. -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI define_pd_global(intx, CodeEntryAlignment, 32); #else define_pd_global(intx, CodeEntryAlignment, 16); --- old/src/cpu/x86/vm/interp_masm_x86.cpp 2015-09-16 15:17:44.000000000 -0700 +++ new/src/cpu/x86/vm/interp_masm_x86.cpp 2015-09-16 15:17:44.000000000 -0700 @@ -1495,13 +1495,39 @@ bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. +#if INCLUDE_JVMCI + if (MethodProfileWidth == 0) { + update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); + } +#else update_mdp_by_constant(mdp, in_bytes(VirtualCallData:: virtual_call_data_size())); +#endif bind(profile_continue); } } +#if INCLUDE_JVMCI +void InterpreterMacroAssembler::profile_called_method(Register method, Register mdp, Register reg2) { + assert_different_registers(method, mdp, reg2); + if (ProfileInterpreter && MethodProfileWidth > 0) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + Label done; + record_item_in_profile_helper(method, mdp, reg2, 0, done, MethodProfileWidth, + &VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset())); + bind(done); + + update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); + bind(profile_continue); + } +} +#endif + // This routine creates a state machine for updating the multi-row // type profile at a virtual call site (or other type-sensitive bytecode). // The machine visits each row (of receiver/count) until the receiver type @@ -1521,14 +1547,36 @@ if (is_virtual_call) { increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); } - return; +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + increment_mdp_data_at(mdp, in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset())); + } +#endif + } else { + int non_profiled_offset = -1; + if (is_virtual_call) { + non_profiled_offset = in_bytes(CounterData::count_offset()); + } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()); + } +#endif + + record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth, + &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); } +} - int last_row = VirtualCallData::row_limit() - 1; +void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp, + Register reg2, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset) { + int last_row = total_rows - 1; assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the receiver and for null. + // Test this row for both the item and for null. // Take any of three different outcomes: - // 1. found receiver => increment count and goto done + // 1. found item => increment count and goto done // 2. found null => keep looking for case 1, maybe allocate this cell // 3. found something else => keep looking for cases 1 and 2 // Case 3 is handled by a recursive call. @@ -1536,30 +1584,30 @@ Label next_test; bool test_for_null_also = (row == start_row); - // See if the receiver is receiver[n]. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); - test_mdp_data_at(mdp, recvr_offset, receiver, + // See if the item is item[n]. + int item_offset = in_bytes(item_offset_fn(row)); + test_mdp_data_at(mdp, item_offset, item, (test_for_null_also ? reg2 : noreg), next_test); - // (Reg2 now contains the receiver from the CallData.) + // (Reg2 now contains the item from the CallData.) - // The receiver is receiver[n]. Increment count[n]. - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); + // The item is item[n]. Increment count[n]. + int count_offset = in_bytes(item_count_offset_fn(row)); increment_mdp_data_at(mdp, count_offset); jmp(done); bind(next_test); if (test_for_null_also) { Label found_null; - // Failed the equality check on receiver[n]... Test for null. + // Failed the equality check on item[n]... Test for null. testptr(reg2, reg2); if (start_row == last_row) { // The only thing left to do is handle the null case. - if (is_virtual_call) { + if (non_profiled_offset >= 0) { jccb(Assembler::zero, found_null); - // Receiver did not match any saved receiver and there is no empty row for it. + // Item did not match any saved item and there is no empty row for it. // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + increment_mdp_data_at(mdp, non_profiled_offset); jmp(done); bind(found_null); } else { @@ -1571,21 +1619,22 @@ jcc(Assembler::zero, found_null); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); + record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows, + item_offset_fn, item_count_offset_fn, non_profiled_offset); - // Found a null. Keep searching for a matching receiver, + // Found a null. Keep searching for a matching item, // but remember that this is an empty (unused) slot. bind(found_null); } } - // In the fall-through case, we found no matching receiver, but we - // observed the receiver[start_row] is NULL. + // In the fall-through case, we found no matching item, but we + // observed the item[start_row] is NULL. - // Fill in the receiver field and increment the count. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); - set_mdp_data_at(mdp, recvr_offset, receiver); - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); + // Fill in the item field and increment the count. + int item_offset = in_bytes(item_offset_fn(start_row)); + set_mdp_data_at(mdp, item_offset, item); + int count_offset = in_bytes(item_count_offset_fn(start_row)); movl(reg2, DataLayout::counter_increment); set_mdp_data_at(mdp, count_offset, reg2); if (start_row > 0) { --- old/src/cpu/x86/vm/interp_masm_x86.hpp 2015-09-16 15:17:45.000000000 -0700 +++ new/src/cpu/x86/vm/interp_masm_x86.hpp 2015-09-16 15:17:44.000000000 -0700 @@ -32,6 +32,7 @@ // This file specializes the assember with interpreter-specific macros +typedef ByteSize (*OffsetFunction)(uint); class InterpreterMacroAssembler: public MacroAssembler { @@ -249,6 +250,10 @@ void record_klass_in_profile_helper(Register receiver, Register mdp, Register reg2, int start_row, Label& done, bool is_virtual_call); + void record_item_in_profile_helper(Register item, Register mdp, + Register reg2, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset); void update_mdp_by_offset(Register mdp_in, int offset_of_offset); void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); @@ -262,6 +267,9 @@ void profile_virtual_call(Register receiver, Register mdp, Register scratch2, bool receiver_can_be_null = false); +#if INCLUDE_JVMCI + void profile_called_method(Register method, Register mdp, Register reg2); +#endif void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); void profile_typecheck(Register mdp, Register klass, Register scratch); --- old/src/cpu/x86/vm/interpreterGenerator_x86.hpp 2015-09-16 15:17:45.000000000 -0700 +++ new/src/cpu/x86/vm/interpreterGenerator_x86.hpp 2015-09-16 15:17:45.000000000 -0700 @@ -48,7 +48,6 @@ address generate_Double_longBitsToDouble_entry(); address generate_Double_doubleToRawLongBits_entry(); #endif - void lock_method(void); void generate_stack_overflow_check(void); void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); --- old/src/cpu/x86/vm/macroAssembler_x86.cpp 2015-09-16 15:17:46.000000000 -0700 +++ new/src/cpu/x86/vm/macroAssembler_x86.cpp 2015-09-16 15:17:46.000000000 -0700 @@ -2888,7 +2888,7 @@ } // !defined(COMPILER2) is because of stupid core builds -#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) +#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) || INCLUDE_JVMCI void MacroAssembler::empty_FPU_stack() { if (VM_Version::supports_mmx()) { emms(); @@ -2896,7 +2896,7 @@ for (int i = 8; i-- > 0; ) ffree(i); } } -#endif // !LP64 || C1 || !C2 +#endif // !LP64 || C1 || !C2 || JVMCI // Defines obj, preserves var_size_in_bytes --- old/src/cpu/x86/vm/nativeInst_x86.cpp 2015-09-16 15:17:47.000000000 -0700 +++ new/src/cpu/x86/vm/nativeInst_x86.cpp 2015-09-16 15:17:46.000000000 -0700 @@ -41,7 +41,6 @@ ICache::invalidate_word(addr_at(offset)); } - void NativeCall::verify() { // Make sure code pattern is actually a call imm32 instruction. int inst = ubyte_at(0); @@ -474,6 +473,7 @@ // // In C2 the 5+ byte sized instruction is enforced by code in MachPrologNode::emit. // In C1 the restriction is enforced by CodeEmitter::method_entry +// In JVMCI, the restriction is enforced by HotSpotFrameContext.enter(...) // void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { // complete jump instruction (to be inserted) is in code_buffer; --- old/src/cpu/x86/vm/nativeInst_x86.hpp 2015-09-16 15:17:48.000000000 -0700 +++ new/src/cpu/x86/vm/nativeInst_x86.hpp 2015-09-16 15:17:47.000000000 -0700 @@ -60,6 +60,7 @@ bool is_nop() { return ubyte_at(0) == nop_instruction_code; } inline bool is_call(); + inline bool is_call_reg(); inline bool is_illegal(); inline bool is_return(); inline bool is_jump(); @@ -180,6 +181,24 @@ return call; } +class NativeCallReg: public NativeInstruction { + public: + enum Intel_specific_constants { + instruction_code = 0xFF, + instruction_offset = 0, + return_address_offset_norex = 2, + return_address_offset_rex = 3 + }; + + int next_instruction_offset() const { + if (ubyte_at(0) == NativeCallReg::instruction_code) { + return return_address_offset_norex; + } else { + return return_address_offset_rex; + } + } +}; + // An interface for accessing/manipulating native mov reg, imm32 instructions. // (used to manipulate inlined 32bit data dll calls, etc.) class NativeMovConstReg: public NativeInstruction { @@ -519,6 +538,9 @@ inline bool NativeInstruction::is_illegal() { return (short)int_at(0) == (short)NativeIllegalInstruction::instruction_code; } inline bool NativeInstruction::is_call() { return ubyte_at(0) == NativeCall::instruction_code; } +inline bool NativeInstruction::is_call_reg() { return ubyte_at(0) == NativeCallReg::instruction_code || + (ubyte_at(1) == NativeCallReg::instruction_code && + (ubyte_at(0) == Assembler::REX || ubyte_at(0) == Assembler::REX_B)); } inline bool NativeInstruction::is_return() { return ubyte_at(0) == NativeReturn::instruction_code || ubyte_at(0) == NativeReturnX::instruction_code; } inline bool NativeInstruction::is_jump() { return ubyte_at(0) == NativeJump::instruction_code || @@ -527,26 +549,24 @@ (ubyte_at(0) & 0xF0) == 0x70; /* short jump */ } inline bool NativeInstruction::is_safepoint_poll() { #ifdef AMD64 - if (Assembler::is_polling_page_far()) { - // two cases, depending on the choice of the base register in the address. - if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix && - ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl && - (ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) || - ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && - (ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) { - return true; - } else { - return false; - } - } else { - if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && - ubyte_at(1) == 0x05) { // 00 rax 101 - address fault = addr_at(6) + int_at(2); - return os::is_poll_address(fault); - } else { - return false; - } + // Try decoding a near safepoint first: + if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && + ubyte_at(1) == 0x05) { // 00 rax 101 + address fault = addr_at(6) + int_at(2); + NOT_JVMCI(assert(!Assembler::is_polling_page_far(), "unexpected poll encoding");) + return os::is_poll_address(fault); } + // Now try decoding a far safepoint: + // two cases, depending on the choice of the base register in the address. + if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix && + ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl && + (ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) || + ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && + (ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) { + NOT_JVMCI(assert(Assembler::is_polling_page_far(), "unexpected poll encoding");) + return true; + } + return false; #else return ( ubyte_at(0) == NativeMovRegMem::instruction_code_mem2reg || ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl ) && --- old/src/cpu/x86/vm/registerMap_x86.hpp 2015-09-16 15:17:48.000000000 -0700 +++ new/src/cpu/x86/vm/registerMap_x86.hpp 2015-09-16 15:17:48.000000000 -0700 @@ -31,11 +31,7 @@ private: // This is the hook for finding a register in an "well-known" location, // such as a register block of a predetermined format. - // Since there is none, we just return NULL. - // See registerMap_sparc.hpp for an example of grabbing registers - // from register save areas of a standard layout. - address pd_location(VMReg reg) const {return NULL;} - + address pd_location(VMReg reg) const; // no PD state to clear or copy: void pd_clear() {} void pd_initialize() {} --- old/src/cpu/x86/vm/register_x86.cpp 2015-09-16 15:17:49.000000000 -0700 +++ new/src/cpu/x86/vm/register_x86.cpp 2015-09-16 15:17:49.000000000 -0700 @@ -69,6 +69,31 @@ return is_valid() ? names[encoding()] : "xnoreg"; } +const char* XMMRegisterImpl::sub_word_name(int i) const { + const char* names[number_of_registers * 8] = { + "xmm0:0", "xmm0:1", "xmm0:2", "xmm0:3", "xmm0:4", "xmm0:5", "xmm0:6", "xmm0:7", + "xmm1:0", "xmm1:1", "xmm1:2", "xmm1:3", "xmm1:4", "xmm1:5", "xmm1:6", "xmm1:7", + "xmm2:0", "xmm2:1", "xmm2:2", "xmm2:3", "xmm2:4", "xmm2:5", "xmm2:6", "xmm2:7", + "xmm3:0", "xmm3:1", "xmm3:2", "xmm3:3", "xmm3:4", "xmm3:5", "xmm3:6", "xmm3:7", + "xmm4:0", "xmm4:1", "xmm4:2", "xmm4:3", "xmm4:4", "xmm4:5", "xmm4:6", "xmm4:7", + "xmm5:0", "xmm5:1", "xmm5:2", "xmm5:3", "xmm5:4", "xmm5:5", "xmm5:6", "xmm5:7", + "xmm6:0", "xmm6:1", "xmm6:2", "xmm6:3", "xmm6:4", "xmm6:5", "xmm6:6", "xmm6:7", + "xmm7:0", "xmm7:1", "xmm7:2", "xmm7:3", "xmm7:4", "xmm7:5", "xmm7:6", "xmm7:7", +#ifdef AMD64 + "xmm8:0", "xmm8:1", "xmm8:2", "xmm8:3", "xmm8:4", "xmm8:5", "xmm8:6", "xmm8:7", + "xmm9:0", "xmm9:1", "xmm9:2", "xmm9:3", "xmm9:4", "xmm9:5", "xmm9:6", "xmm9:7", + "xmm10:0", "xmm10:1", "xmm10:2", "xmm10:3", "xmm10:4", "xmm10:5", "xmm10:6", "xmm10:7", + "xmm11:0", "xmm11:1", "xmm11:2", "xmm11:3", "xmm11:4", "xmm11:5", "xmm11:6", "xmm11:7", + "xmm12:0", "xmm12:1", "xmm12:2", "xmm12:3", "xmm12:4", "xmm12:5", "xmm12:6", "xmm12:7", + "xmm13:0", "xmm13:1", "xmm13:2", "xmm13:3", "xmm13:4", "xmm13:5", "xmm13:6", "xmm13:7", + "xmm14:0", "xmm14:1", "xmm14:2", "xmm14:3", "xmm14:4", "xmm14:5", "xmm14:6", "xmm14:7", + "xmm15:0", "xmm15:1", "xmm15:2", "xmm15:3", "xmm15:4", "xmm15:5", "xmm15:6", "xmm15:7", +#endif // AMD64 + }; + assert(i >= 0 && i < 8, "offset too large"); + return is_valid() ? names[encoding() * 8 + i] : "xnoreg"; +} + const char* KRegisterImpl::name() const { const char* names[number_of_registers] = { "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7" --- old/src/cpu/x86/vm/register_x86.hpp 2015-09-16 15:17:50.000000000 -0700 +++ new/src/cpu/x86/vm/register_x86.hpp 2015-09-16 15:17:49.000000000 -0700 @@ -165,6 +165,7 @@ int encoding() const { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this )); return (intptr_t)this; } bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } const char* name() const; + const char* sub_word_name(int offset) const; }; --- old/src/cpu/x86/vm/relocInfo_x86.cpp 2015-09-16 15:17:50.000000000 -0700 +++ new/src/cpu/x86/vm/relocInfo_x86.cpp 2015-09-16 15:17:50.000000000 -0700 @@ -180,39 +180,17 @@ void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { #ifdef _LP64 - if (!Assembler::is_polling_page_far()) { - typedef Assembler::WhichOperand WhichOperand; - WhichOperand which = (WhichOperand) format(); - // This format is imm but it is really disp32 - which = Assembler::disp32_operand; + typedef Assembler::WhichOperand WhichOperand; + WhichOperand which = (WhichOperand) format(); +#if !INCLUDE_JVMCI + assert((which == Assembler::disp32_operand) == !Assembler::is_polling_page_far(), "format not set correctly"); +#endif + if (which == Assembler::disp32_operand) { address orig_addr = old_addr_for(addr(), src, dest); NativeInstruction* oni = nativeInstruction_at(orig_addr); int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); // This poll_addr is incorrect by the size of the instruction it is irrelevant intptr_t poll_addr = (intptr_t)oni + *orig_disp; - - NativeInstruction* ni = nativeInstruction_at(addr()); - intptr_t new_disp = poll_addr - (intptr_t) ni; - - int32_t* disp = (int32_t*) Assembler::locate_operand(addr(), which); - * disp = (int32_t)new_disp; - } -#endif // _LP64 -} - -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { -#ifdef _LP64 - if (!Assembler::is_polling_page_far()) { - typedef Assembler::WhichOperand WhichOperand; - WhichOperand which = (WhichOperand) format(); - // This format is imm but it is really disp32 - which = Assembler::disp32_operand; - address orig_addr = old_addr_for(addr(), src, dest); - NativeInstruction* oni = nativeInstruction_at(orig_addr); - int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); - // This poll_addr is incorrect by the size of the instruction it is irrelevant - intptr_t poll_addr = (intptr_t)oni + *orig_disp; - NativeInstruction* ni = nativeInstruction_at(addr()); intptr_t new_disp = poll_addr - (intptr_t) ni; --- old/src/cpu/x86/vm/sharedRuntime_x86_32.cpp 2015-09-16 15:17:51.000000000 -0700 +++ new/src/cpu/x86/vm/sharedRuntime_x86_32.cpp 2015-09-16 15:17:51.000000000 -0700 @@ -734,12 +734,11 @@ __ bind(L_fail); } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { - +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Note: rsi contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled // code goes non-entrant while we get args ready. --- old/src/cpu/x86/vm/sharedRuntime_x86_64.cpp 2015-09-16 15:17:52.000000000 -0700 +++ new/src/cpu/x86/vm/sharedRuntime_x86_64.cpp 2015-09-16 15:17:51.000000000 -0700 @@ -43,6 +43,9 @@ #ifdef COMPILER2 #include "opto/runtime.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif #define __ masm-> @@ -105,7 +108,7 @@ DEF_XMM_OFFS(29), DEF_XMM_OFFS(30), DEF_XMM_OFFS(31), - fpu_state_end = fpu_state_off + ((FPUStateSizeInWords - 1)*wordSize / BytesPerInt), + fpu_state_end = fpu_state_off + ((FPUStateSizeInWords-1)*wordSize / BytesPerInt), fpu_stateH_end, r15_off, r15H_off, r14_off, r14H_off, @@ -155,16 +158,18 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) { int vect_words = 0; + int ymmhi_offset = -1; int num_xmm_regs = 16; if (UseAVX > 2) { num_xmm_regs = 32; } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (save_vectors) { assert(UseAVX > 0, "512bit vectors are supported only with EVEX"); assert(MaxVectorSize == 64, "only 512bit vectors are supported now"); // Save upper half of YMM registers vect_words = 16 * num_xmm_regs / wordSize; + ymmhi_offset = additional_frame_words; additional_frame_words += vect_words; if (UseAVX > 2) { // Save upper half of ZMM registers as well @@ -172,7 +177,7 @@ } } #else - assert(!save_vectors, "vectors are generated only by C2"); + assert(!save_vectors, "vectors are generated only by C2 and JVMCI"); #endif // Always make the frame size 16-byte aligned @@ -282,6 +287,7 @@ OopMap* map = new OopMap(frame_size_in_slots, 0); #define STACK_OFFSET(x) VMRegImpl::stack2reg((x) + additional_frame_slots) +#define YMMHI_STACK_OFFSET(x) VMRegImpl::stack2reg((x / VMRegImpl::stack_slot_size) + ymmhi_offset) map->set_callee_saved(STACK_OFFSET( rax_off ), rax->as_VMReg()); map->set_callee_saved(STACK_OFFSET( rcx_off ), rcx->as_VMReg()); @@ -334,6 +340,28 @@ map->set_callee_saved(STACK_OFFSET(xmm31_off), xmm31->as_VMReg()); } +#if defined(COMPILER2) || INCLUDE_JVMCI + if (save_vectors) { + assert(ymmhi_offset != -1, "save area must exist"); + map->set_callee_saved(YMMHI_STACK_OFFSET( 0), xmm0->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET( 16), xmm1->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET( 32), xmm2->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET( 48), xmm3->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET( 64), xmm4->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET( 80), xmm5->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET( 96), xmm6->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET(112), xmm7->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET(128), xmm8->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET(144), xmm9->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET(160), xmm10->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET(176), xmm11->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET(192), xmm12->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET(208), xmm13->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET(224), xmm14->as_VMReg()->next()->next()->next()->next()); + map->set_callee_saved(YMMHI_STACK_OFFSET(240), xmm15->as_VMReg()->next()->next()->next()->next()); + } +#endif + // %%% These should all be a waste but we'll keep things as they were for now if (true) { map->set_callee_saved(STACK_OFFSET( raxH_off ), rax->as_VMReg()->next()); @@ -395,7 +423,7 @@ // Pop arg register save area __ addptr(rsp, frame::arg_reg_save_area_bytes); } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (restore_vectors) { // Restore upper half of YMM registes (0..15) assert(UseAVX > 0, "512bit vectors are supported only with AVX"); @@ -473,7 +501,7 @@ } } #else - assert(!restore_vectors, "vectors are generated only by C2"); + assert(!restore_vectors, "vectors are generated only by C2 and JVMCI"); #endif // Recover CPU state __ pop_CPU_state(); @@ -808,11 +836,11 @@ __ bind(L_fail); } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Note: r13 contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled @@ -905,6 +933,18 @@ // Pre-load the register-jump target early, to schedule it better. __ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_offset()))); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // check if this call should be routed towards a specific entry point + __ cmpptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0); + Label no_alternative_target; + __ jcc(Assembler::equal, no_alternative_target); + __ movptr(r11, Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); + __ movptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0); + __ bind(no_alternative_target); + } +#endif + // Now generate the shuffle code. Pick up all register args and move the // rest through the floating point stack top. for (int i = 0; i < total_args_passed; i++) { @@ -2838,7 +2878,13 @@ // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("deopt_blob", 2048, 1024); + int pad = 0; +#if INCLUDE_JVMCI + if (EnableJVMCI) { + pad += 512; // Increase the buffer size when compiling for JVMCI + } +#endif + CodeBuffer buffer("deopt_blob", 2048+pad, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; OopMap* map = NULL; @@ -2887,6 +2933,12 @@ __ jmp(cont); int reexecute_offset = __ pc() - start; +#if INCLUDE_JVMCI && !defined(COMPILER1) + if (EnableJVMCI && UseJVMCICompiler) { + // JVMCI does not use this kind of deoptimization + __ should_not_reach_here(); + } +#endif // Reexecute case // return address is the pc describes what bci to do re-execute at @@ -2897,6 +2949,38 @@ __ movl(r14, Deoptimization::Unpack_reexecute); // callee-saved __ jmp(cont); +#if INCLUDE_JVMCI + Label after_fetch_unroll_info_call; + int implicit_exception_uncommon_trap_offset = 0; + int uncommon_trap_offset = 0; + + if (EnableJVMCI) { + implicit_exception_uncommon_trap_offset = __ pc() - start; + + __ pushptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); + __ movptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())), (int32_t)NULL_WORD); + + uncommon_trap_offset = __ pc() - start; + + // Save everything in sight. + RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); + // fetch_unroll_info needs to call last_java_frame() + __ set_last_Java_frame(noreg, noreg, NULL); + + __ movl(c_rarg1, Address(r15_thread, in_bytes(JavaThread::pending_deoptimization_offset()))); + __ movl(Address(r15_thread, in_bytes(JavaThread::pending_deoptimization_offset())), -1); + + __ movl(r14, (int32_t)Deoptimization::Unpack_reexecute); + __ mov(c_rarg0, r15_thread); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); + oop_maps->add_gc_map( __ pc()-start, map->deep_copy()); + + __ reset_last_Java_frame(false, false); + + __ jmp(after_fetch_unroll_info_call); + } // EnableJVMCI +#endif // INCLUDE_JVMCI + int exception_offset = __ pc() - start; // Prolog for exception case @@ -2982,6 +3066,12 @@ __ reset_last_Java_frame(false, false); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + __ bind(after_fetch_unroll_info_call); + } +#endif + // Load UnrollBlock* into rdi __ mov(rdi, rax); @@ -3156,6 +3246,12 @@ _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset); + _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); + } +#endif } #ifdef COMPILER2 --- old/src/cpu/x86/vm/templateInterpreter_x86_32.cpp 2015-09-16 15:17:52.000000000 -0700 +++ new/src/cpu/x86/vm/templateInterpreter_x86_32.cpp 2015-09-16 15:17:52.000000000 -0700 @@ -538,7 +538,7 @@ // Allocate monitor and lock method (asm interpreter) // rbx, - Method* // -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { // synchronize method const Address access_flags (rbx, Method::access_flags_offset()); const Address monitor_block_top (rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); --- old/src/cpu/x86/vm/templateInterpreter_x86_64.cpp 2015-09-16 15:17:53.000000000 -0700 +++ new/src/cpu/x86/vm/templateInterpreter_x86_64.cpp 2015-09-16 15:17:53.000000000 -0700 @@ -198,13 +198,27 @@ } -address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, - int step) { +address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) { address entry = __ pc(); // NULL last_sp until next java call __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); __ restore_bcp(); __ restore_locals(); +#if INCLUDE_JVMCI + // Check if we need to take lock at entry of synchronized method. + if (UseJVMCICompiler) { + Label L; + __ cmpb(Address(r15_thread, JavaThread::pending_monitorenter_offset()), 0); + __ jcc(Assembler::zero, L); + // Clear flag. + __ movb(Address(r15_thread, JavaThread::pending_monitorenter_offset()), 0); + // Satisfy calling convention for lock_method(). + __ get_method(rbx); + // Take lock. + lock_method(); + __ bind(L); + } +#endif // handle exceptions { Label L; @@ -500,7 +514,7 @@ // rax // c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs) // rscratch1, rscratch2 (scratch regs) -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { // synchronize method const Address access_flags(rbx, Method::access_flags_offset()); const Address monitor_block_top( --- old/src/cpu/x86/vm/templateTable_x86.cpp 2015-09-16 15:17:54.000000000 -0700 +++ new/src/cpu/x86/vm/templateTable_x86.cpp 2015-09-16 15:17:54.000000000 -0700 @@ -3595,6 +3595,10 @@ __ profile_virtual_call(rax, rlocals, rdx); // get target Method* & entry point __ lookup_virtual_method(rax, index, method); +#if INCLUDE_JVMCI + __ profile_called_method(method, rdx, rbcp); +#endif + __ profile_arguments_type(rdx, method, rbcp, true); __ jump_from_interpreted(method, rdx); } @@ -3694,6 +3698,9 @@ __ testptr(rbx, rbx); __ jcc(Assembler::zero, no_such_method); +#if INCLUDE_JVMCI + __ profile_called_method(rbx, rbcp, rdx); +#endif __ profile_arguments_type(rdx, rbx, rbcp, true); // do the call --- old/src/cpu/x86/vm/vmStructs_x86.hpp 2015-09-16 15:17:55.000000000 -0700 +++ new/src/cpu/x86/vm/vmStructs_x86.hpp 2015-09-16 15:17:54.000000000 -0700 @@ -37,13 +37,42 @@ /******************************/ \ /* JavaFrameAnchor */ \ /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \ + static_field(VM_Version, _cpuFeatures, uint64_t) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + declare_toplevel_type(VM_Version) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ + LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \ + declare_constant(frame::interpreter_frame_sender_sp_offset) \ + declare_constant(frame::interpreter_frame_last_sp_offset) \ + declare_constant(VM_Version::CPU_CX8) \ + declare_constant(VM_Version::CPU_CMOV) \ + declare_constant(VM_Version::CPU_FXSR) \ + declare_constant(VM_Version::CPU_HT) \ + declare_constant(VM_Version::CPU_MMX) \ + declare_constant(VM_Version::CPU_3DNOW_PREFETCH) \ + declare_constant(VM_Version::CPU_SSE) \ + declare_constant(VM_Version::CPU_SSE2) \ + declare_constant(VM_Version::CPU_SSE3) \ + declare_constant(VM_Version::CPU_SSSE3) \ + declare_constant(VM_Version::CPU_SSE4A) \ + declare_constant(VM_Version::CPU_SSE4_1) \ + declare_constant(VM_Version::CPU_SSE4_2) \ + declare_constant(VM_Version::CPU_POPCNT) \ + declare_constant(VM_Version::CPU_LZCNT) \ + declare_constant(VM_Version::CPU_TSC) \ + declare_constant(VM_Version::CPU_TSCINV) \ + declare_constant(VM_Version::CPU_AVX) \ + declare_constant(VM_Version::CPU_AVX2) \ + declare_constant(VM_Version::CPU_AES) \ + declare_constant(VM_Version::CPU_ERMS) \ + declare_constant(VM_Version::CPU_CLMUL) \ + declare_constant(VM_Version::CPU_BMI1) \ + declare_constant(VM_Version::CPU_BMI2) #define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) --- old/src/cpu/x86/vm/vm_version_x86.cpp 2015-09-16 15:17:55.000000000 -0700 +++ new/src/cpu/x86/vm/vm_version_x86.cpp 2015-09-16 15:17:55.000000000 -0700 @@ -780,6 +780,8 @@ FLAG_SET_DEFAULT(UseFPUForSpilling, false); } } +#endif +#if defined(COMPILER2) || INCLUDE_JVMCI if (MaxVectorSize > 0) { if (!is_power_of_2(MaxVectorSize)) { warning("MaxVectorSize must be a power of 2"); @@ -796,7 +798,7 @@ // Vectors (in XMM) are only supported with SSE2+ FLAG_SET_DEFAULT(MaxVectorSize, 0); } -#ifdef ASSERT +#if defined(COMPILER2) && defined(ASSERT) if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) { tty->print_cr("State of YMM registers after signal handle:"); int nreg = 2 LP64_ONLY(+2); @@ -811,7 +813,9 @@ } #endif } +#endif +#ifdef COMPILER2 #ifdef _LP64 if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { UseMultiplyToLenIntrinsic = true; --- old/src/cpu/x86/vm/vm_version_x86.hpp 2015-09-16 15:17:56.000000000 -0700 +++ new/src/cpu/x86/vm/vm_version_x86.hpp 2015-09-16 15:17:56.000000000 -0700 @@ -29,6 +29,7 @@ #include "runtime/vm_version.hpp" class VM_Version : public Abstract_VM_Version { + friend class VMStructs; public: // cpuid result register layouts. These are all unions of a uint32_t // (in case anyone wants access to the register as a whole) and a bitfield. --- old/src/cpu/x86/vm/x86_64.ad 2015-09-16 15:17:57.000000000 -0700 +++ new/src/cpu/x86/vm/x86_64.ad 2015-09-16 15:17:56.000000000 -0700 @@ -2136,12 +2136,13 @@ RELOC_DISP32); } if (_method) { - // Emit stub for static call. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); + // Emit stubs for static call. + address mark = cbuf.insts_mark(); + address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, mark); if (stub == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; - } + } } %} --- old/src/os/windows/vm/os_windows.cpp 2015-09-16 15:17:58.000000000 -0700 +++ new/src/os/windows/vm/os_windows.cpp 2015-09-16 15:17:57.000000000 -0700 @@ -2272,12 +2272,17 @@ #ifdef _M_AMD64 PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Rip; - assert(pc[0] == 0xF7, "not an idiv opcode"); - assert((pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); - assert(ctx->Rax == min_jint, "unexpected idiv exception"); - // set correct result values and continue after idiv instruction - ctx->Rip = (DWORD)pc + 2; // idiv reg, reg is 2 bytes - ctx->Rax = (DWORD)min_jint; // result + assert(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && pc[1] == 0xF7 || pc[0] == 0xF7, "not an idiv opcode"); + assert(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && (pc[2] & ~0x7) == 0xF8 || (pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); + if (pc[0] == 0xF7) { + // set correct result values and continue after idiv instruction + ctx->Rip = (DWORD64)pc + 2; // idiv reg, reg is 2 bytes + } else { + ctx->Rip = (DWORD64)pc + 3; // REX idiv reg, reg is 3 bytes + } + // Do not set ctx->Rax as it already contains the correct value (either 32 or 64 bit, depending on the operation) + // this is the case because the exception only happens for -MinValue/-1 and -MinValue is always in rax because of the + // idiv opcode (0xF7). ctx->Rdx = (DWORD)0; // remainder // Continue the execution #else --- old/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp 2015-09-16 15:17:58.000000000 -0700 +++ new/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp 2015-09-16 15:17:58.000000000 -0700 @@ -66,8 +66,8 @@ frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { -#ifdef COMPILER2 - // C2 uses ebp as a general register see if NULL fp helps +#if defined(COMPILER2) || INCLUDE_JVMCI + // C2 and JVMCI use ebp as a general register see if NULL fp helps frame ret_frame2(ret_sp, NULL, addr.pc()); if (!ret_frame2.safe_for_sender(jt)) { // nothing else to try if the frame isn't good @@ -77,7 +77,7 @@ #else // nothing else to try if the frame isn't good return false; -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ } *fr_addr = ret_frame; return true; --- old/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp 2015-09-16 15:17:59.000000000 -0700 +++ new/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp 2015-09-16 15:17:59.000000000 -0700 @@ -67,8 +67,8 @@ frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { -#ifdef COMPILER2 - // C2 uses ebp as a general register see if NULL fp helps +#if defined(COMPILER2) || INCLUDE_JVMCI + // C2 and JVMCI use ebp as a general register see if NULL fp helps frame ret_frame2(ret_sp, NULL, addr.pc()); if (!ret_frame2.safe_for_sender(jt)) { // nothing else to try if the frame isn't good @@ -78,7 +78,7 @@ #else // nothing else to try if the frame isn't good return false; -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ } *fr_addr = ret_frame; return true; --- old/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp 2015-09-16 15:18:00.000000000 -0700 +++ new/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp 2015-09-16 15:17:59.000000000 -0700 @@ -24,6 +24,7 @@ // no precompiled headers #include "asm/macroAssembler.hpp" +#include "macroAssembler_sparc.hpp" #include "classfile/classLoader.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" --- old/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp 2015-09-16 15:18:00.000000000 -0700 +++ new/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp 2015-09-16 15:18:00.000000000 -0700 @@ -30,29 +30,11 @@ // referenced by vmStructs.cpp. #define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Solaris Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) + nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ - \ - /************************/ \ - /* JavaThread constants */ \ - /************************/ \ - \ declare_constant(JavaFrameAnchor::flushed) #define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) --- old/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp 2015-09-16 15:18:01.000000000 -0700 +++ new/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp 2015-09-16 15:18:01.000000000 -0700 @@ -29,21 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Solaris Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) --- old/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp 2015-09-16 15:18:02.000000000 -0700 +++ new/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp 2015-09-16 15:18:02.000000000 -0700 @@ -74,8 +74,8 @@ frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { -#ifdef COMPILER2 - // C2 uses ebp as a general register see if NULL fp helps +#if defined(COMPILER2) || INCLUDE_JVMCI + // C2 and JVMCI use ebp as a general register see if NULL fp helps frame ret_frame2(ret_sp, NULL, addr.pc()); if (!ret_frame2.safe_for_sender(jt)) { // nothing else to try if the frame isn't good @@ -85,7 +85,7 @@ #else // nothing else to try if the frame isn't good return false; -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ } *fr_addr = ret_frame; return true; --- old/src/share/vm/asm/codeBuffer.cpp 2015-09-16 15:18:02.000000000 -0700 +++ new/src/share/vm/asm/codeBuffer.cpp 2015-09-16 15:18:02.000000000 -0700 @@ -602,21 +602,19 @@ return (csize_t) align_size_up(total, HeapWordSize); } -csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const { - address buf = NULL; +csize_t CodeBuffer::copy_relocations_to(address buf, csize_t buf_limit, bool only_inst) const { csize_t buf_offset = 0; - csize_t buf_limit = 0; - if (dest != NULL) { - buf = (address)dest->relocation_begin(); - buf_limit = (address)dest->relocation_end() - buf; - assert((uintptr_t)buf % HeapWordSize == 0, "buf must be fully aligned"); - assert(buf_limit % HeapWordSize == 0, "buf must be evenly sized"); - } - // if dest == NULL, this is just the sizing pass - csize_t code_end_so_far = 0; csize_t code_point_so_far = 0; + + assert((uintptr_t)buf % HeapWordSize == 0, "buf must be fully aligned"); + assert(buf_limit % HeapWordSize == 0, "buf must be evenly sized"); + for (int n = (int) SECT_FIRST; n < (int)SECT_LIMIT; n++) { + if (only_inst && (n != (int)SECT_INSTS)) { + // Need only relocation info for code. + continue; + } // pull relocs out of each section const CodeSection* cs = code_section(n); assert(!(cs->is_empty() && cs->locs_count() > 0), "sanity"); @@ -683,7 +681,23 @@ buf_offset += sizeof(relocInfo); } - assert(code_end_so_far == total_content_size(), "sanity"); + assert(only_inst || code_end_so_far == total_content_size(), "sanity"); + + return buf_offset; +} + +csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const { + address buf = NULL; + csize_t buf_offset = 0; + csize_t buf_limit = 0; + + if (dest != NULL) { + buf = (address)dest->relocation_begin(); + buf_limit = (address)dest->relocation_end() - buf; + } + // if dest == NULL, this is just the sizing pass + // + buf_offset = copy_relocations_to(buf, buf_limit, false); // Account for index: if (buf != NULL) { @@ -1126,7 +1140,8 @@ while (c && c->offset() == offset) { stream->bol(); stream->print("%s", _prefix); - stream->print_cr("%s", c->string()); + // Don't interpret as format strings since it could contain % + stream->print_raw_cr(c->string()); c = c->next_comment(); } } --- old/src/share/vm/asm/codeBuffer.hpp 2015-09-16 15:18:03.000000000 -0700 +++ new/src/share/vm/asm/codeBuffer.hpp 2015-09-16 15:18:03.000000000 -0700 @@ -452,7 +452,6 @@ initialize_misc(name); } - // (4) code buffer allocating codeBlob memory for code & relocation // info. The name must be something informative and code_size must // include both code and stubs sizes. @@ -553,6 +552,8 @@ // allocated size of all relocation data, including index, rounded up csize_t total_relocation_size() const; + csize_t copy_relocations_to(address buf, csize_t buf_limit, bool only_inst) const; + // allocated size of any and all recorded oops csize_t total_oop_size() const { OopRecorder* recorder = oop_recorder(); --- old/src/share/vm/c1/c1_Compilation.cpp 2015-09-16 15:18:04.000000000 -0700 +++ new/src/share/vm/c1/c1_Compilation.cpp 2015-09-16 15:18:04.000000000 -0700 @@ -325,7 +325,8 @@ locs_buffer_size / sizeof(relocInfo)); code->initialize_consts_size(Compilation::desired_max_constant_size()); // Call stubs + two deopt handlers (regular and MH) + exception handler - int stub_size = (call_stub_estimate * LIR_Assembler::call_stub_size) + + int call_stub_size = LIR_Assembler::call_stub_size; + int stub_size = (call_stub_estimate * call_stub_size) + LIR_Assembler::exception_handler_size + (2 * LIR_Assembler::deopt_handler_size); if (stub_size >= code->insts_capacity()) return false; --- old/src/share/vm/c1/c1_IR.hpp 2015-09-16 15:18:04.000000000 -0700 +++ new/src/share/vm/c1/c1_IR.hpp 2015-09-16 15:18:04.000000000 -0700 @@ -244,7 +244,8 @@ // reexecute allowed only for the topmost frame bool reexecute = topmost ? should_reexecute() : false; bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis. - recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, return_oop, locvals, expvals, monvals); + bool rethrow_exception = false; + recorder->describe_scope(pc_offset, methodHandle(), scope()->method(), bci(), reexecute, rethrow_exception, is_method_handle_invoke, return_oop, locvals, expvals, monvals); } }; --- old/src/share/vm/c1/c1_LIRAssembler.cpp 2015-09-16 15:18:05.000000000 -0700 +++ new/src/share/vm/c1/c1_LIRAssembler.cpp 2015-09-16 15:18:05.000000000 -0700 @@ -405,7 +405,8 @@ if (s == NULL) break; IRScope* scope = s->scope(); //Always pass false for reexecute since these ScopeDescs are never used for deopt - debug_info->describe_scope(pc_offset, scope->method(), s->bci(), false/*reexecute*/); + methodHandle null_mh; + debug_info->describe_scope(pc_offset, null_mh, scope->method(), s->bci(), false/*reexecute*/); } debug_info->end_non_safepoint(pc_offset); --- old/src/share/vm/classfile/classFileParser.cpp 2015-09-16 15:18:06.000000000 -0700 +++ new/src/share/vm/classfile/classFileParser.cpp 2015-09-16 15:18:06.000000000 -0700 @@ -1755,6 +1755,12 @@ if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_HotSpotIntrinsicCandidate; +#if INCLUDE_JVMCI + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_jvmci_hotspot_Stable_signature): + if (_location != _in_field) break; // only allow for fields + if (!privileged) break; // only allow in privileged code + return _field_Stable; +#endif case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature): if (_location != _in_field) break; // only allow for fields if (!privileged) break; // only allow in privileged code --- old/src/share/vm/classfile/javaClasses.cpp 2015-09-16 15:18:07.000000000 -0700 +++ new/src/share/vm/classfile/javaClasses.cpp 2015-09-16 15:18:06.000000000 -0700 @@ -54,6 +54,10 @@ #include "runtime/vframe.hpp" #include "utilities/preserveException.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif + PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC #define INJECTED_FIELD_COMPUTE_OFFSET(klass, name, signature, may_be_java) \ @@ -1580,7 +1584,7 @@ while (h_throwable.not_null()) { objArrayHandle result (THREAD, objArrayOop(backtrace(h_throwable()))); if (result.is_null()) { - st->print_cr("%s", no_stack_trace_message()); + st->print_raw_cr(no_stack_trace_message()); return; } @@ -1655,7 +1659,7 @@ } return; } - + // Instead of using vframe directly, this version of fill_in_stack_trace // basically handles everything by hand. This significantly improved the // speed of this method call up to 28.5% on Solaris sparc. 27.1% on Windows. @@ -3655,5 +3659,10 @@ void javaClasses_init() { JavaClasses::compute_offsets(); JavaClasses::check_offsets(); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + JVMCIJavaClasses::compute_offsets(); + } +#endif FilteredFieldsMap::initialize(); // must be done after computing offsets. } --- old/src/share/vm/classfile/javaClasses.hpp 2015-09-16 15:18:07.000000000 -0700 +++ new/src/share/vm/classfile/javaClasses.hpp 2015-09-16 15:18:07.000000000 -0700 @@ -157,7 +157,12 @@ if (count_offset > 0) { return java_string->int_field(count_offset); } else { - return ((typeArrayOop)java_string->obj_field(value_offset))->length(); + typeArrayOop value_array = ((typeArrayOop)java_string->obj_field(value_offset)); + if (value_array == NULL) { + return 0; + } else { + return value_array->length(); + } } } static int utf8_length(oop java_string); --- old/src/share/vm/classfile/metadataOnStackMark.cpp 2015-09-16 15:18:08.000000000 -0700 +++ new/src/share/vm/classfile/metadataOnStackMark.cpp 2015-09-16 15:18:08.000000000 -0700 @@ -32,6 +32,9 @@ #include "runtime/thread.hpp" #include "services/threadService.hpp" #include "utilities/chunkedList.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#endif MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL; @@ -57,6 +60,9 @@ CompileBroker::mark_on_stack(); JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack); ThreadService::metadata_do(Metadata::mark_on_stack); +#if INCLUDE_JVMCI + JVMCIRuntime::metadata_do(Metadata::mark_on_stack); +#endif } } --- old/src/share/vm/classfile/systemDictionary.cpp 2015-09-16 15:18:09.000000000 -0700 +++ new/src/share/vm/classfile/systemDictionary.cpp 2015-09-16 15:18:08.000000000 -0700 @@ -66,6 +66,9 @@ #include "classfile/sharedClassUtil.hpp" #include "classfile/systemDictionaryShared.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#endif #if INCLUDE_TRACE #include "trace/tracing.hpp" #endif @@ -228,7 +231,7 @@ // Forwards to resolve_instance_class_or_null Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) { - assert(!THREAD->is_Compiler_thread(), + assert(THREAD->can_call_java(), err_msg("can not load classes with compiler thread: class=%s, classloader=%s", class_name->as_C_string(), class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string())); @@ -1917,7 +1920,14 @@ WKID jsr292_group_end = WK_KLASS_ENUM_NAME(VolatileCallSite_klass); initialize_wk_klasses_until(jsr292_group_start, scan, CHECK); initialize_wk_klasses_through(jsr292_group_end, scan, CHECK); - initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK); + initialize_wk_klasses_until(NOT_JVMCI(WKID_LIMIT) JVMCI_ONLY(FIRST_JVMCI_WKID), scan, CHECK); + +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // JVMCI classes + initialize_wk_klasses_through(LAST_JVMCI_WKID, scan, CHECK); + } +#endif _box_klasses[T_BOOLEAN] = WK_KLASS(Boolean_klass); _box_klasses[T_CHAR] = WK_KLASS(Character_klass); @@ -2343,7 +2353,7 @@ Handle *method_type_result, TRAPS) { methodHandle empty; - assert(!THREAD->is_Compiler_thread(), ""); + assert(THREAD->can_call_java() ,""); Handle method_type = SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_(empty)); @@ -2411,7 +2421,7 @@ if (spe != NULL && spe->method_type() != NULL) { assert(java_lang_invoke_MethodType::is_instance(spe->method_type()), ""); return Handle(THREAD, spe->method_type()); - } else if (THREAD->is_Compiler_thread()) { + } else if (!THREAD->can_call_java()) { warning("SystemDictionary::find_method_handle_type called from compiler thread"); // FIXME return Handle(); // do not attempt from within compiler, unless it was cached } --- old/src/share/vm/classfile/systemDictionary.hpp 2015-09-16 15:18:10.000000000 -0700 +++ new/src/share/vm/classfile/systemDictionary.hpp 2015-09-16 15:18:09.000000000 -0700 @@ -33,6 +33,7 @@ #include "runtime/reflectionUtils.hpp" #include "utilities/hashtable.hpp" #include "utilities/hashtable.inline.hpp" +#include "jvmci/systemDictionary_jvmci.hpp" // The system dictionary stores all loaded classes and maps: @@ -192,6 +193,10 @@ do_klass(Short_klass, java_lang_Short, Pre ) \ do_klass(Integer_klass, java_lang_Integer, Pre ) \ do_klass(Long_klass, java_lang_Long, Pre ) \ + \ + /* JVMCI classes. These are loaded on-demand. */ \ + JVMCI_WK_KLASSES_DO(do_klass) \ + /*end*/ @@ -209,6 +214,11 @@ WKID_LIMIT, +#if INCLUDE_JVMCI + FIRST_JVMCI_WKID = WK_KLASS_ENUM_NAME(HotSpotCompiledCode_klass), + LAST_JVMCI_WKID = WK_KLASS_ENUM_NAME(Value_klass), +#endif + FIRST_WKID = NO_WKID + 1 }; @@ -219,6 +229,9 @@ // Options after this point will use resolve_or_null instead. Opt, // preload tried; NULL if not present +#if INCLUDE_JVMCI + Jvmci, // preload tried; error if not present, use only with JVMCI +#endif OPTION_LIMIT, CEIL_LG_OPTION_LIMIT = 2 // OPTION_LIMIT <= (1<") \ @@ -382,6 +385,7 @@ template(bitCount_name, "bitCount") \ template(profile_name, "profile") \ template(equals_name, "equals") \ + template(length_name, "length") \ template(target_name, "target") \ template(toString_name, "toString") \ template(values_name, "values") \ @@ -432,6 +436,7 @@ template(void_long_signature, "()J") \ template(void_float_signature, "()F") \ template(void_double_signature, "()D") \ + template(bool_void_signature, "(Z)V") \ template(int_void_signature, "(I)V") \ template(int_int_signature, "(I)I") \ template(char_char_signature, "(C)C") \ --- old/src/share/vm/code/codeBlob.hpp 2015-09-16 15:18:11.000000000 -0700 +++ new/src/share/vm/code/codeBlob.hpp 2015-09-16 15:18:11.000000000 -0700 @@ -120,6 +120,7 @@ virtual bool is_compiled_by_c2() const { return false; } virtual bool is_compiled_by_c1() const { return false; } + virtual bool is_compiled_by_jvmci() const { return false; } // Casting nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; } @@ -380,6 +381,12 @@ int _unpack_with_exception_in_tls; +#if INCLUDE_JVMCI + // Offsets when JVMCI calls uncommon_trap. + int _uncommon_trap_offset; + int _implicit_exception_uncommon_trap_offset; +#endif + // Creation support DeoptimizationBlob( CodeBuffer* cb, @@ -429,6 +436,21 @@ assert(code_contains(code_begin() + _unpack_with_exception_in_tls), "must be PC inside codeblob"); } address unpack_with_exception_in_tls() const { return code_begin() + _unpack_with_exception_in_tls; } + +#if INCLUDE_JVMCI + // Offsets when JVMCI calls uncommon_trap. + void set_uncommon_trap_offset(int offset) { + _uncommon_trap_offset = offset; + assert(contains(code_begin() + _uncommon_trap_offset), "must be PC inside codeblob"); + } + address uncommon_trap() const { return code_begin() + _uncommon_trap_offset; } + + void set_implicit_exception_uncommon_trap_offset(int offset) { + _implicit_exception_uncommon_trap_offset = offset; + assert(contains(code_begin() + _implicit_exception_uncommon_trap_offset), "must be PC inside codeblob"); + } + address implicit_exception_uncommon_trap() const { return code_begin() + _implicit_exception_uncommon_trap_offset; } +#endif }; --- old/src/share/vm/code/compiledIC.cpp 2015-09-16 15:18:12.000000000 -0700 +++ new/src/share/vm/code/compiledIC.cpp 2015-09-16 15:18:12.000000000 -0700 @@ -280,11 +280,13 @@ bool is_monomorphic = (cb != NULL && cb->is_nmethod()); // Check that the cached_value is a klass for non-optimized monomorphic calls // This assertion is invalid for compiler1: a call that does not look optimized (no static stub) can be used - // for calling directly to vep without using the inline cache (i.e., cached_value == NULL) + // for calling directly to vep without using the inline cache (i.e., cached_value == NULL). + // For JVMCI this occurs because CHA is only used to improve inlining so call sites which could be optimized + // virtuals because there are no currently loaded subclasses of a type are left as virtual call sites. #ifdef ASSERT CodeBlob* caller = CodeCache::find_blob_unsafe(instruction_address()); - bool is_c1_method = caller->is_compiled_by_c1(); - assert( is_c1_method || + bool is_c1_or_jvmci_method = caller->is_compiled_by_c1() || caller->is_compiled_by_jvmci(); + assert( is_c1_or_jvmci_method || !is_monomorphic || is_optimized() || (cached_metadata() != NULL && cached_metadata()->is_klass()), "sanity check"); --- old/src/share/vm/code/compiledIC.hpp 2015-09-16 15:18:13.000000000 -0700 +++ new/src/share/vm/code/compiledIC.hpp 2015-09-16 15:18:13.000000000 -0700 @@ -306,7 +306,7 @@ friend CompiledStaticCall* compiledStaticCall_at(Relocation* call_site); // Code - static address emit_to_interp_stub(CodeBuffer &cbuf); + static address emit_to_interp_stub(CodeBuffer &cbuf, address mark = NULL); static int to_interp_stub_size(); static int reloc_to_interp_stub(); --- old/src/share/vm/code/debugInfo.cpp 2015-09-16 15:18:14.000000000 -0700 +++ new/src/share/vm/code/debugInfo.cpp 2015-09-16 15:18:13.000000000 -0700 @@ -59,7 +59,7 @@ #ifdef ASSERT assert(_obj_pool != NULL, "object pool does not exist"); for (int i = _obj_pool->length() - 1; i >= 0; i--) { - assert(((ObjectValue*) _obj_pool->at(i))->id() != id, "should not be read twice"); + assert(_obj_pool->at(i)->as_ObjectValue()->id() != id, "should not be read twice"); } #endif ObjectValue* result = new ObjectValue(id); @@ -73,7 +73,7 @@ int id = read_int(); assert(_obj_pool != NULL, "object pool does not exist"); for (int i = _obj_pool->length() - 1; i >= 0; i--) { - ObjectValue* ov = (ObjectValue*) _obj_pool->at(i); + ObjectValue* ov = _obj_pool->at(i)->as_ObjectValue(); if (ov->id() == id) { return ov; } --- old/src/share/vm/code/debugInfo.hpp 2015-09-16 15:18:14.000000000 -0700 +++ new/src/share/vm/code/debugInfo.hpp 2015-09-16 15:18:14.000000000 -0700 @@ -41,6 +41,7 @@ // - ConstantValue describes a constant class ConstantOopReadValue; +class ObjectValue; class ScopeValue: public ResourceObj { public: @@ -58,6 +59,11 @@ return (ConstantOopReadValue*) this; } + ObjectValue* as_ObjectValue() { + assert(is_object(), "must be"); + return (ObjectValue*)this; + } + // Serialization of debugging information virtual void write_on(DebugInfoWriteStream* stream) = 0; static ScopeValue* read_from(DebugInfoReadStream* stream); --- old/src/share/vm/code/debugInfoRec.cpp 2015-09-16 15:18:15.000000000 -0700 +++ new/src/share/vm/code/debugInfoRec.cpp 2015-09-16 15:18:15.000000000 -0700 @@ -37,6 +37,9 @@ int _offset; // location in the stream of this scope int _length; // number of bytes in the stream int _hash; // hash of stream bytes (for quicker reuse) +#if INCLUDE_JVMCI + DebugInformationRecorder* _DIR; +#endif void* operator new(size_t ignore, DebugInformationRecorder* dir) throw() { assert(ignore == sizeof(DIR_Chunk), ""); @@ -51,6 +54,9 @@ DIR_Chunk(int offset, int length, DebugInformationRecorder* dir) { _offset = offset; _length = length; +#if INCLUDE_JVMCI + _DIR = dir; +#endif unsigned int hash = 0; address p = dir->stream()->buffer() + _offset; for (int i = 0; i < length; i++) { @@ -77,6 +83,25 @@ } return NULL; } + +#if INCLUDE_JVMCI + static int compare(DIR_Chunk*& a, DIR_Chunk*& b) { + if (b->_hash > a->_hash) { + return 1; + } + if (b->_hash < a->_hash) { + return -1; + } + if (b->_length > a->_length) { + return 1; + } + if (b->_length < a->_length) { + return -1; + } + address buf = a->_DIR->stream()->buffer(); + return memcmp(buf + b->_offset, buf + a->_offset, a->_length); + } +#endif }; static inline bool compute_recording_non_safepoints() { @@ -113,7 +138,9 @@ _oop_recorder = oop_recorder; _all_chunks = new GrowableArray(300); +#if !INCLUDE_JVMCI _shared_chunks = new GrowableArray(30); +#endif _next_chunk = _next_chunk_limit = NULL; add_new_pc_offset(PcDesc::lower_offset_limit); // sentinel record @@ -235,10 +262,13 @@ int DebugInformationRecorder::find_sharable_decode_offset(int stream_offset) { - // Only pull this trick if non-safepoint recording - // is enabled, for now. - if (!recording_non_safepoints()) + if (FLAG_IS_DEFAULT(ShareDebugInfo)) { + if (!ShareDebugInfo && !recording_non_safepoints()) { + return serialized_null; + } + } else if (!ShareDebugInfo) { return serialized_null; + } NOT_PRODUCT(++dir_stats.chunks_queried); int stream_length = stream()->position() - stream_offset; @@ -247,6 +277,19 @@ DIR_Chunk* ns = new(this) DIR_Chunk(stream_offset, stream_length, this); +#if INCLUDE_JVMCI + DIR_Chunk* match = _all_chunks->insert_sorted(ns); + if (match != ns) { + // Found an existing chunk + NOT_PRODUCT(++dir_stats.chunks_shared); + assert(ns+1 == _next_chunk, ""); + _next_chunk = ns; + return match->_offset; + } else { + // Inserted this chunk, so nothing to do + return serialized_null; + } +#else // Look in previously shared scopes first: DIR_Chunk* ms = ns->find_match(_shared_chunks, 0, this); if (ms != NULL) { @@ -274,15 +317,18 @@ // No match. Add this guy to the list, in hopes of future shares. _all_chunks->append(ns); return serialized_null; +#endif } // must call add_safepoint before: it sets PcDesc and this routine uses // the last PcDesc set void DebugInformationRecorder::describe_scope(int pc_offset, + methodHandle methodH, ciMethod* method, int bci, bool reexecute, + bool rethrow_exception, bool is_method_handle_invoke, bool return_oop, DebugToken* locals, @@ -298,6 +344,7 @@ // Record flags into pcDesc. last_pd->set_should_reexecute(reexecute); + last_pd->set_rethrow_exception(rethrow_exception); last_pd->set_is_method_handle_invoke(is_method_handle_invoke); last_pd->set_return_oop(return_oop); @@ -305,8 +352,16 @@ stream()->write_int(sender_stream_offset); // serialize scope - Metadata* method_enc = (method == NULL)? NULL: method->constant_encoding(); - stream()->write_int(oop_recorder()->find_index(method_enc)); + Metadata* method_enc; + if (method != NULL) { + method_enc = method->constant_encoding(); + } else if (methodH.not_null()) { + method_enc = methodH(); + } else { + method_enc = NULL; + } + int method_enc_index = oop_recorder()->find_index(method_enc); + stream()->write_int(method_enc_index); stream()->write_bci(bci); assert(method == NULL || (method->is_native() && bci == 0) || @@ -338,7 +393,7 @@ PcDesc* last_pd = &_pcs[_pcs_length-1]; if (objects != NULL) { for (int i = objects->length() - 1; i >= 0; i--) { - ((ObjectValue*) objects->at(i))->set_visited(false); + objects->at(i)->as_ObjectValue()->set_visited(false); } } int offset = serialize_scope_values(objects); --- old/src/share/vm/code/debugInfoRec.hpp 2015-09-16 15:18:16.000000000 -0700 +++ new/src/share/vm/code/debugInfoRec.hpp 2015-09-16 15:18:15.000000000 -0700 @@ -98,9 +98,11 @@ // by add_non_safepoint, and the locals, expressions, and monitors // must all be null. void describe_scope(int pc_offset, + methodHandle methodH, ciMethod* method, int bci, bool reexecute, + bool rethrow_exception = false, bool is_method_handle_invoke = false, bool return_oop = false, DebugToken* locals = NULL, @@ -143,6 +145,12 @@ bool recording_non_safepoints() { return _recording_non_safepoints; } + PcDesc* pcs() const { return _pcs; } + int pcs_length() const { return _pcs_length; } + + DebugInfoWriteStream* stream() const { return _stream; } + + private: friend class ScopeDesc; friend class vframeStreamCommon; @@ -155,13 +163,13 @@ DebugInfoWriteStream* _stream; - DebugInfoWriteStream* stream() const { return _stream; } - OopRecorder* _oop_recorder; // Scopes that have been described so far. GrowableArray* _all_chunks; +#if !INCLUDE_JVMCI GrowableArray* _shared_chunks; +#endif DIR_Chunk* _next_chunk; DIR_Chunk* _next_chunk_limit; --- old/src/share/vm/code/dependencies.cpp 2015-09-16 15:18:16.000000000 -0700 +++ new/src/share/vm/code/dependencies.cpp 2015-09-16 15:18:16.000000000 -0700 @@ -31,6 +31,7 @@ #include "code/dependencies.hpp" #include "compiler/compileLog.hpp" #include "oops/oop.inline.hpp" +#include "oops/objArrayKlass.hpp" #include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/thread.inline.hpp" @@ -52,6 +53,9 @@ _oop_recorder = env->oop_recorder(); _log = env->log(); _dep_seen = new(arena) GrowableArray(arena, 500, 0, 0); +#if INCLUDE_JVMCI + _using_dep_values = false; +#endif DEBUG_ONLY(_deps[end_marker] = NULL); for (int i = (int)FIRST_TYPE; i < (int)TYPE_LIMIT; i++) { _deps[i] = new(arena) GrowableArray(arena, 10, 0, 0); @@ -120,6 +124,65 @@ assert_common_2(call_site_target_value, call_site, method_handle); } +#if INCLUDE_JVMCI + +Dependencies::Dependencies(Arena* arena, OopRecorder* oop_recorder, CompileLog* log) { + _oop_recorder = oop_recorder; + _log = log; + _dep_seen = new(arena) GrowableArray(arena, 500, 0, 0); + _using_dep_values = true; + DEBUG_ONLY(_dep_values[end_marker] = NULL); + for (int i = (int)FIRST_TYPE; i < (int)TYPE_LIMIT; i++) { + _dep_values[i] = new(arena) GrowableArray(arena, 10, 0, DepValue()); + } + _content_bytes = NULL; + _size_in_bytes = (size_t)-1; + + assert(TYPE_LIMIT <= (1<oop_is_array()) { + // As a special case, support this assertion on an array type, + // which reduces to an assertion on its element type. + // Note that this cannot be done with assertions that + // relate to concreteness or abstractness. + BasicType elemt = ArrayKlass::cast(ctxk)->element_type(); + if (is_java_primitive(elemt)) return; // Ex: int[][] + ctxk = ObjArrayKlass::cast(ctxk)->bottom_klass(); + //if (ctxk->is_final()) return; // Ex: String[][] + } + check_ctxk(ctxk); + assert_common_1(leaf_type, DepValue(_oop_recorder, ctxk)); +} + +void Dependencies::assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Klass* conck) { + check_ctxk_abstract(ctxk); + DepValue ctxk_dv(_oop_recorder, ctxk); + DepValue conck_dv(_oop_recorder, conck, &ctxk_dv); + assert_common_2(abstract_with_unique_concrete_subtype, ctxk_dv, conck_dv); +} + +void Dependencies::assert_unique_concrete_method(Klass* ctxk, Method* uniqm) { + check_ctxk(ctxk); + assert_common_2(unique_concrete_method, DepValue(_oop_recorder, ctxk), DepValue(_oop_recorder, uniqm)); +} + +void Dependencies::assert_call_site_target_value(oop call_site, oop method_handle) { + assert_common_2(call_site_target_value, DepValue(_oop_recorder, JNIHandles::make_local(call_site)), DepValue(_oop_recorder, JNIHandles::make_local(method_handle))); +} +#endif // INCLUDE_JVMCI + + // Helper function. If we are adding a new dep. under ctxk2, // try to find an old dep. under a broader* ctxk1. If there is // @@ -230,6 +293,78 @@ deps->append(x2); } +#if INCLUDE_JVMCI +bool Dependencies::maybe_merge_ctxk(GrowableArray* deps, + int ctxk_i, DepValue ctxk2_dv) { + Klass* ctxk1 = deps->at(ctxk_i).as_klass(_oop_recorder); + Klass* ctxk2 = ctxk2_dv.as_klass(_oop_recorder); + if (ctxk2->is_subtype_of(ctxk1)) { + return true; // success, and no need to change + } else if (ctxk1->is_subtype_of(ctxk2)) { + // new context class fully subsumes previous one + deps->at_put(ctxk_i, ctxk2_dv); + return true; + } else { + return false; + } +} + +void Dependencies::assert_common_1(DepType dept, DepValue x) { + assert(dep_args(dept) == 1, "sanity"); + //log_dependency(dept, x); + GrowableArray* deps = _dep_values[dept]; + + // see if the same (or a similar) dep is already recorded + if (note_dep_seen(dept, x)) { + assert(deps->find(x) >= 0, "sanity"); + } else { + deps->append(x); + } +} + +void Dependencies::assert_common_2(DepType dept, + DepValue x0, DepValue x1) { + assert(dep_args(dept) == 2, "sanity"); + //log_dependency(dept, x0, x1); + GrowableArray* deps = _dep_values[dept]; + + // see if the same (or a similar) dep is already recorded + bool has_ctxk = has_explicit_context_arg(dept); + if (has_ctxk) { + assert(dep_context_arg(dept) == 0, "sanity"); + if (note_dep_seen(dept, x1)) { + // look in this bucket for redundant assertions + const int stride = 2; + for (int i = deps->length(); (i -= stride) >= 0; ) { + DepValue y1 = deps->at(i+1); + if (x1 == y1) { // same subject; check the context + if (maybe_merge_ctxk(deps, i+0, x0)) { + return; + } + } + } + } + } else { + assert(dep_implicit_context_arg(dept) == 0, "sanity"); + if (note_dep_seen(dept, x0) && note_dep_seen(dept, x1)) { + // look in this bucket for redundant assertions + const int stride = 2; + for (int i = deps->length(); (i -= stride) >= 0; ) { + DepValue y0 = deps->at(i+0); + DepValue y1 = deps->at(i+1); + if (x0 == y0 && x1 == y1) { + return; + } + } + } + } + + // append the assertion in the correct bucket: + deps->append(x0); + deps->append(x1); +} +#endif // INCLUDE_JVMCI + /// Support for encoding dependencies into an nmethod: void Dependencies::copy_to(nmethod* nm) { @@ -256,7 +391,40 @@ static int sort_dep_arg_3(ciBaseObject** p1, ciBaseObject** p2) { return sort_dep(p1, p2, 3); } +#if INCLUDE_JVMCI +// metadata deps are sorted before object deps +static int sort_dep_value(Dependencies::DepValue* p1, Dependencies::DepValue* p2, int narg) { + for (int i = 0; i < narg; i++) { + int diff = p1[i].sort_key() - p2[i].sort_key(); + if (diff != 0) return diff; + } + return 0; +} +static int sort_dep_value_arg_1(Dependencies::DepValue* p1, Dependencies::DepValue* p2) +{ return sort_dep_value(p1, p2, 1); } +static int sort_dep_value_arg_2(Dependencies::DepValue* p1, Dependencies::DepValue* p2) +{ return sort_dep_value(p1, p2, 2); } +static int sort_dep_value_arg_3(Dependencies::DepValue* p1, Dependencies::DepValue* p2) +{ return sort_dep_value(p1, p2, 3); } +#endif // INCLUDE_JVMCI + void Dependencies::sort_all_deps() { +#if INCLUDE_JVMCI + if (_using_dep_values) { + for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { + DepType dept = (DepType)deptv; + GrowableArray* deps = _dep_values[dept]; + if (deps->length() <= 1) continue; + switch (dep_args(dept)) { + case 1: deps->sort(sort_dep_value_arg_1, 1); break; + case 2: deps->sort(sort_dep_value_arg_2, 2); break; + case 3: deps->sort(sort_dep_value_arg_3, 3); break; + default: ShouldNotReachHere(); + } + } + return; + } +#endif for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { DepType dept = (DepType)deptv; GrowableArray* deps = _deps[dept]; @@ -272,6 +440,16 @@ size_t Dependencies::estimate_size_in_bytes() { size_t est_size = 100; +#if INCLUDE_JVMCI + if (_using_dep_values) { + for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { + DepType dept = (DepType)deptv; + GrowableArray* deps = _dep_values[dept]; + est_size += deps->length() * 2; // tags and argument(s) + } + return est_size; + } +#endif for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { DepType dept = (DepType)deptv; GrowableArray* deps = _deps[dept]; @@ -311,6 +489,37 @@ // cast is safe, no deps can overflow INT_MAX CompressedWriteStream bytes((int)estimate_size_in_bytes()); +#if INCLUDE_JVMCI + if (_using_dep_values) { + for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { + DepType dept = (DepType)deptv; + GrowableArray* deps = _dep_values[dept]; + if (deps->length() == 0) continue; + int stride = dep_args(dept); + int ctxkj = dep_context_arg(dept); // -1 if no context arg + assert(stride > 0, "sanity"); + for (int i = 0; i < deps->length(); i += stride) { + jbyte code_byte = (jbyte)dept; + int skipj = -1; + if (ctxkj >= 0 && ctxkj+1 < stride) { + Klass* ctxk = deps->at(i+ctxkj+0).as_klass(_oop_recorder); + DepValue x = deps->at(i+ctxkj+1); // following argument + if (ctxk == ctxk_encoded_as_null(dept, x.as_metadata(_oop_recorder))) { + skipj = ctxkj; // we win: maybe one less oop to keep track of + code_byte |= default_context_type_bit; + } + } + bytes.write_byte(code_byte); + for (int j = 0; j < stride; j++) { + if (j == skipj) continue; + DepValue v = deps->at(i+j); + int idx = v.index(); + bytes.write_int(idx); + } + } + } + } else { +#endif for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { DepType dept = (DepType)deptv; GrowableArray* deps = _deps[dept]; @@ -344,6 +553,9 @@ } } } +#if INCLUDE_JVMCI + } +#endif // write a sentinel byte to mark the end bytes.write_byte(end_marker); @@ -540,10 +752,10 @@ } void Dependencies::print_dependency(DepType dept, GrowableArray* args, - Klass* witness) { + Klass* witness, outputStream* st) { ResourceMark rm; ttyLocker ttyl; // keep the following output all in one block - tty->print_cr("%s of type %s", + st->print_cr("%s of type %s", (witness == NULL)? "Dependency": "Failed dependency", dep_name(dept)); // print arguments @@ -565,22 +777,22 @@ } else { what = "object "; } - tty->print(" %s = %s", what, (put_star? "*": "")); + st->print(" %s = %s", what, (put_star? "*": "")); if (arg.is_klass()) { - tty->print("%s", ((Klass*)arg.metadata_value())->external_name()); + st->print("%s", ((Klass*)arg.metadata_value())->external_name()); } else if (arg.is_method()) { - ((Method*)arg.metadata_value())->print_value(); + ((Method*)arg.metadata_value())->print_value_on(st); } else if (arg.is_oop()) { - arg.oop_value()->print_value_on(tty); + arg.oop_value()->print_value_on(st); } else { ShouldNotReachHere(); // Provide impl for this type. } - tty->cr(); + st->cr(); } if (witness != NULL) { bool put_star = !Dependencies::is_concrete_klass(witness); - tty->print_cr(" witness = %s%s", + st->print_cr(" witness = %s%s", (put_star? "*": ""), witness->external_name()); } @@ -600,14 +812,19 @@ } int argslen = args->length(); if (_deps != NULL && _deps->log() != NULL) { - Dependencies::write_dependency_to(_deps->log(), type(), args, witness); + if (ciEnv::current() != NULL) { + Dependencies::write_dependency_to(_deps->log(), type(), args, witness); + } else { + // Treat the CompileLog as an xmlstream instead + Dependencies::write_dependency_to((xmlStream*)_deps->log(), type(), args, witness); + } } else { Dependencies::write_dependency_to(xtty, type(), args, witness); } guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope"); } -void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose) { +void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose, outputStream* st) { ResourceMark rm; int nargs = argument_count(); GrowableArray* args = new GrowableArray(nargs); @@ -619,12 +836,12 @@ } } int argslen = args->length(); - Dependencies::print_dependency(type(), args, witness); + Dependencies::print_dependency(type(), args, witness, st); if (verbose) { if (_code != NULL) { - tty->print(" code: "); - _code->print_value_on(tty); - tty->cr(); + st->print(" code: "); + _code->print_value_on(st); + st->cr(); } } guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope"); --- old/src/share/vm/code/dependencies.hpp 2015-09-16 15:18:17.000000000 -0700 +++ new/src/share/vm/code/dependencies.hpp 2015-09-16 15:18:17.000000000 -0700 @@ -202,10 +202,59 @@ static void check_valid_dependency_type(DepType dept); +#if INCLUDE_JVMCI + // A Metadata* or object value recorded in an OopRecorder + class DepValue VALUE_OBJ_CLASS_SPEC { + private: + // Unique identifier of the value within the associated OopRecorder that + // encodes both the category of the value (0: invalid, positive: metadata, negative: object) + // and the index within a category specific array (metadata: index + 1, object: -(index + 1)) + int _id; + + public: + DepValue() : _id(0) {} + DepValue(OopRecorder* rec, Metadata* metadata, DepValue* candidate = NULL) { + assert(candidate == NULL || candidate->is_metadata(), "oops"); + if (candidate != NULL && candidate->as_metadata(rec) == metadata) { + _id = candidate->_id; + } else { + _id = rec->find_index(metadata) + 1; + } + } + DepValue(OopRecorder* rec, jobject obj, DepValue* candidate = NULL) { + assert(candidate == NULL || candidate->is_object(), "oops"); + if (candidate != NULL && candidate->as_object(rec) == obj) { + _id = candidate->_id; + } else { + _id = -(rec->find_index(obj) + 1); + } + } + + // Used to sort values in ascending order of index() with metadata values preceding object values + int sort_key() const { return -_id; } + + bool operator == (const DepValue& other) const { return other._id == _id; } + + bool is_valid() const { return _id != 0; } + int index() const { assert(is_valid(), "oops"); return _id < 0 ? -(_id + 1) : _id - 1; } + bool is_metadata() const { assert(is_valid(), "oops"); return _id > 0; } + bool is_object() const { assert(is_valid(), "oops"); return _id < 0; } + + Metadata* as_metadata(OopRecorder* rec) const { assert(is_metadata(), "oops"); return rec->metadata_at(index()); } + Klass* as_klass(OopRecorder* rec) const { assert(as_metadata(rec)->is_klass(), "oops"); return (Klass*) as_metadata(rec); } + Method* as_method(OopRecorder* rec) const { assert(as_metadata(rec)->is_method(), "oops"); return (Method*) as_metadata(rec); } + jobject as_object(OopRecorder* rec) const { assert(is_object(), "oops"); return rec->oop_at(index()); } + }; +#endif + private: // State for writing a new set of dependencies: GrowableArray* _dep_seen; // (seen[h->ident] & (1<* _deps[TYPE_LIMIT]; +#if INCLUDE_JVMCI + bool _using_dep_values; + GrowableArray* _dep_values[TYPE_LIMIT]; +#endif static const char* _dep_name[TYPE_LIMIT]; static int _dep_args[TYPE_LIMIT]; @@ -224,8 +273,25 @@ return (seen & (1<at_grow(x_id, 0); + _dep_seen->at_put(x_id, seen | (1<* deps, int ctxk_i, ciKlass* ctxk); +#if INCLUDE_JVMCI + bool maybe_merge_ctxk(GrowableArray* deps, + int ctxk_i, DepValue ctxk); +#endif void sort_all_deps(); size_t estimate_size_in_bytes(); @@ -247,6 +313,9 @@ Dependencies(ciEnv* env) { initialize(env); } +#if INCLUDE_JVMCI + Dependencies(Arena* arena, OopRecorder* oop_recorder, CompileLog* log); +#endif private: // Check for a valid context type. @@ -279,6 +348,27 @@ void assert_has_no_finalizable_subclasses(ciKlass* ctxk); void assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle); +#if INCLUDE_JVMCI + private: + static void check_ctxk(Klass* ctxk) { + assert(ctxk->oop_is_instance(), "java types only"); + } + static void check_ctxk_abstract(Klass* ctxk) { + check_ctxk(ctxk); + assert(ctxk->is_abstract(), "must be abstract"); + } + void assert_common_1(DepType dept, DepValue x); + void assert_common_2(DepType dept, DepValue x0, DepValue x1); + + public: + void assert_evol_method(Method* m); + void assert_has_no_finalizable_subclasses(Klass* ctxk); + void assert_leaf_type(Klass* ctxk); + void assert_unique_concrete_method(Klass* ctxk, Method* uniqm); + void assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Klass* conck); + void assert_call_site_target_value(oop callSite, oop methodHandle); +#endif // JVMCI + // Define whether a given method or type is concrete. // These methods define the term "concrete" as used in this module. // For this module, an "abstract" class is one which is non-concrete. @@ -422,7 +512,7 @@ static void print_dependency(DepType dept, GrowableArray* args, - Klass* witness = NULL); + Klass* witness = NULL, outputStream* st = tty); private: // helper for encoding common context types as zero: @@ -534,7 +624,7 @@ void log_dependency(Klass* witness = NULL); // Print the current dependency to tty. - void print_dependency(Klass* witness = NULL, bool verbose = false); + void print_dependency(Klass* witness = NULL, bool verbose = false, outputStream* st = tty); }; friend class Dependencies::DepStream; --- old/src/share/vm/code/exceptionHandlerTable.cpp 2015-09-16 15:18:18.000000000 -0700 +++ new/src/share/vm/code/exceptionHandlerTable.cpp 2015-09-16 15:18:17.000000000 -0700 @@ -102,9 +102,12 @@ void ExceptionHandlerTable::copy_to(nmethod* nm) { assert(size_in_bytes() == nm->handler_table_size(), "size of space allocated in nmethod incorrect"); - memmove(nm->handler_table_begin(), _table, size_in_bytes()); + copy_bytes_to(nm->handler_table_begin()); } +void ExceptionHandlerTable::copy_bytes_to(address addr) { + memmove(addr, _table, size_in_bytes()); +} HandlerTableEntry* ExceptionHandlerTable::entry_for(int catch_pco, int handler_bci, int scope_depth) const { HandlerTableEntry* t = subtable_for(catch_pco); --- old/src/share/vm/code/exceptionHandlerTable.hpp 2015-09-16 15:18:18.000000000 -0700 +++ new/src/share/vm/code/exceptionHandlerTable.hpp 2015-09-16 15:18:18.000000000 -0700 @@ -88,12 +88,12 @@ int _length; // the current length of the table int _size; // the number of allocated entries ReallocMark _nesting; // assertion check for reallocations - + + public: // add the entry & grow the table if needed void add_entry(HandlerTableEntry entry); HandlerTableEntry* subtable_for(int catch_pco) const; - public: // (compile-time) construction within compiler ExceptionHandlerTable(int initial_size = 8); @@ -116,6 +116,7 @@ // nmethod support int size_in_bytes() const { return round_to(_length * sizeof(HandlerTableEntry), oopSize); } void copy_to(nmethod* nm); + void copy_bytes_to(address addr); // lookup HandlerTableEntry* entry_for(int catch_pco, int handler_bci, int scope_depth) const; --- old/src/share/vm/code/nmethod.cpp 2015-09-16 15:18:19.000000000 -0700 +++ new/src/share/vm/code/nmethod.cpp 2015-09-16 15:18:19.000000000 -0700 @@ -26,6 +26,7 @@ #include "code/codeCache.hpp" #include "code/compiledIC.hpp" #include "code/dependencies.hpp" +#include "code/nativeInst.hpp" #include "code/nmethod.hpp" #include "code/scopeDesc.hpp" #include "compiler/abstractCompiler.hpp" @@ -46,9 +47,27 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" +#ifdef TARGET_ARCH_x86 +# include "nativeInst_x86.hpp" +#endif +#ifdef TARGET_ARCH_sparc +# include "nativeInst_sparc.hpp" +#endif +#ifdef TARGET_ARCH_zero +# include "nativeInst_zero.hpp" +#endif +#ifdef TARGET_ARCH_arm +# include "nativeInst_arm.hpp" +#endif +#ifdef TARGET_ARCH_ppc +# include "nativeInst_ppc.hpp" +#endif #ifdef SHARK #include "shark/sharkCompiler.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC @@ -84,6 +103,11 @@ } return compiler()->is_c1(); } +bool nmethod::is_compiled_by_jvmci() const { + if (compiler() == NULL || method() == NULL) return false; // can happen during debug printing + if (is_native_method()) return false; + return compiler()->is_jvmci(); +} bool nmethod::is_compiled_by_c2() const { if (compiler() == NULL) { return false; @@ -108,8 +132,7 @@ #ifndef PRODUCT // These variables are put into one block to reduce relocations // and make it simpler to print from the debugger. -static -struct nmethod_stats_struct { +struct java_nmethod_stats_struct { int nmethod_count; int total_size; int relocation_size; @@ -122,6 +145,7 @@ int handler_table_size; int nul_chk_table_size; int oops_size; + int metadata_size; void note_nmethod(nmethod* nm) { nmethod_count += 1; @@ -131,39 +155,46 @@ insts_size += nm->insts_size(); stub_size += nm->stub_size(); oops_size += nm->oops_size(); + metadata_size += nm->metadata_size(); scopes_data_size += nm->scopes_data_size(); scopes_pcs_size += nm->scopes_pcs_size(); dependencies_size += nm->dependencies_size(); handler_table_size += nm->handler_table_size(); nul_chk_table_size += nm->nul_chk_table_size(); } - void print_nmethod_stats() { + void print_nmethod_stats(const char* name) { if (nmethod_count == 0) return; - tty->print_cr("Statistics for %d bytecoded nmethods:", nmethod_count); + tty->print_cr("Statistics for %d bytecoded nmethods for %s:", nmethod_count, name); if (total_size != 0) tty->print_cr(" total in heap = %d", total_size); + if (nmethod_count != 0) tty->print_cr(" header = %d", nmethod_count * sizeof(nmethod)); if (relocation_size != 0) tty->print_cr(" relocation = %d", relocation_size); if (consts_size != 0) tty->print_cr(" constants = %d", consts_size); if (insts_size != 0) tty->print_cr(" main code = %d", insts_size); if (stub_size != 0) tty->print_cr(" stub code = %d", stub_size); if (oops_size != 0) tty->print_cr(" oops = %d", oops_size); + if (metadata_size != 0) tty->print_cr(" metadata = %d", metadata_size); if (scopes_data_size != 0) tty->print_cr(" scopes data = %d", scopes_data_size); if (scopes_pcs_size != 0) tty->print_cr(" scopes pcs = %d", scopes_pcs_size); if (dependencies_size != 0) tty->print_cr(" dependencies = %d", dependencies_size); if (handler_table_size != 0) tty->print_cr(" handler table = %d", handler_table_size); if (nul_chk_table_size != 0) tty->print_cr(" nul chk table = %d", nul_chk_table_size); } +}; +struct native_nmethod_stats_struct { int native_nmethod_count; int native_total_size; int native_relocation_size; int native_insts_size; int native_oops_size; + int native_metadata_size; void note_native_nmethod(nmethod* nm) { native_nmethod_count += 1; native_total_size += nm->size(); native_relocation_size += nm->relocation_size(); native_insts_size += nm->insts_size(); native_oops_size += nm->oops_size(); + native_metadata_size += nm->metadata_size(); } void print_native_nmethod_stats() { if (native_nmethod_count == 0) return; @@ -172,8 +203,11 @@ if (native_relocation_size != 0) tty->print_cr(" N. relocation = %d", native_relocation_size); if (native_insts_size != 0) tty->print_cr(" N. main code = %d", native_insts_size); if (native_oops_size != 0) tty->print_cr(" N. oops = %d", native_oops_size); + if (native_metadata_size != 0) tty->print_cr(" N. metadata = %d", native_metadata_size); } +}; +struct pc_nmethod_stats_struct { int pc_desc_resets; // number of resets (= number of caches) int pc_desc_queries; // queries to nmethod::find_pc_desc int pc_desc_approx; // number of those which have approximate true @@ -194,9 +228,51 @@ pc_desc_repeats, pc_desc_hits, pc_desc_tests, pc_desc_searches, pc_desc_adds); } -} nmethod_stats; -#endif //PRODUCT +}; +#ifdef COMPILER1 +static java_nmethod_stats_struct c1_java_nmethod_stats; +#endif +#ifdef COMPILER2 +static java_nmethod_stats_struct c2_java_nmethod_stats; +#endif +#if INCLUDE_JVMCI +static java_nmethod_stats_struct jvmci_java_nmethod_stats; +#endif +#ifdef SHARK +static java_nmethod_stats_struct shark_java_nmethod_stats; +#endif +static java_nmethod_stats_struct unknown_java_nmethod_stats; + +static native_nmethod_stats_struct native_nmethod_stats; +static pc_nmethod_stats_struct pc_nmethod_stats; + +static void note_java_nmethod(nmethod* nm) { +#ifdef COMPILER1 + if (nm->is_compiled_by_c1()) { + c1_java_nmethod_stats.note_nmethod(nm); + } else +#endif +#ifdef COMPILER2 + if (nm->is_compiled_by_c2()) { + c2_java_nmethod_stats.note_nmethod(nm); + } else +#endif +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci()) { + jvmci_java_nmethod_stats.note_nmethod(nm); + } else +#endif +#ifdef SHARK + if (nm->is_compiled_by_shark()) { + shark_java_nmethod_stats.note_nmethod(nm); + } else +#endif + { + unknown_java_nmethod_stats.note_nmethod(nm); + } +} +#endif // !PRODUCT //--------------------------------------------------------------------------------- @@ -276,7 +352,7 @@ // Helper used by both find_pc_desc methods. static inline bool match_desc(PcDesc* pc, int pc_offset, bool approximate) { - NOT_PRODUCT(++nmethod_stats.pc_desc_tests); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_tests); if (!approximate) return pc->pc_offset() == pc_offset; else @@ -288,7 +364,7 @@ _pc_descs[0] = NULL; // native method; no PcDescs at all return; } - NOT_PRODUCT(++nmethod_stats.pc_desc_resets); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_resets); // reset the cache by filling it with benign (non-null) values assert(initial_pc_desc->pc_offset() < 0, "must be sentinel"); for (int i = 0; i < cache_size; i++) @@ -296,8 +372,8 @@ } PcDesc* PcDescCache::find_pc_desc(int pc_offset, bool approximate) { - NOT_PRODUCT(++nmethod_stats.pc_desc_queries); - NOT_PRODUCT(if (approximate) ++nmethod_stats.pc_desc_approx); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_queries); + NOT_PRODUCT(if (approximate) ++pc_nmethod_stats.pc_desc_approx); // Note: one might think that caching the most recently // read value separately would be a win, but one would be @@ -313,7 +389,7 @@ res = _pc_descs[0]; if (res == NULL) return NULL; // native method; no PcDescs at all if (match_desc(res, pc_offset, approximate)) { - NOT_PRODUCT(++nmethod_stats.pc_desc_repeats); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_repeats); return res; } @@ -322,7 +398,7 @@ res = _pc_descs[i]; if (res->pc_offset() < 0) break; // optimization: skip empty cache if (match_desc(res, pc_offset, approximate)) { - NOT_PRODUCT(++nmethod_stats.pc_desc_hits); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_hits); return res; } } @@ -332,7 +408,7 @@ } void PcDescCache::add_pc_desc(PcDesc* pc_desc) { - NOT_PRODUCT(++nmethod_stats.pc_desc_adds); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_adds); // Update the LRU cache by shifting pc_desc forward. for (int i = 0; i < cache_size; i++) { PcDesc* next = _pc_descs[i]; @@ -459,7 +535,7 @@ _marked_for_deoptimization = 0; _lock_count = 0; _stack_traversal_mark = 0; - _unload_reported = false; // jvmti state + _unload_reported = false; // jvmti state #ifdef ASSERT _oops_are_stale = false; @@ -478,6 +554,10 @@ #if INCLUDE_RTM_OPT _rtm_state = NoRTM; #endif +#if INCLUDE_JVMCI + _jvmci_installed_code = NULL; + _speculation_log = NULL; +#endif } nmethod* nmethod::new_native_nmethod(methodHandle method, @@ -503,7 +583,7 @@ code_buffer, frame_size, basic_lock_owner_sp_offset, basic_lock_sp_offset, oop_maps); - NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_native_nmethod(nm)); + NOT_PRODUCT(if (nm != NULL) native_nmethod_stats.note_native_nmethod(nm)); if ((PrintAssembly || CompilerOracle::should_print(method)) && nm != NULL) { Disassembler::decode(nm); } @@ -531,6 +611,10 @@ ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, int comp_level +#if INCLUDE_JVMCI + , Handle installed_code, + Handle speculationLog +#endif ) { assert(debug_info->oop_recorder() == code_buffer->oop_recorder(), "shared OR"); @@ -553,7 +637,12 @@ handler_table, nul_chk_table, compiler, - comp_level); + comp_level +#if INCLUDE_JVMCI + , installed_code, + speculationLog +#endif + ); if (nm != NULL) { // To make dependency checking during class loading fast, record @@ -578,7 +667,7 @@ InstanceKlass::cast(klass)->add_dependent_nmethod(nm); } } - NOT_PRODUCT(nmethod_stats.note_nmethod(nm)); + NOT_PRODUCT(if (nm != NULL) note_java_nmethod(nm)); if (PrintAssembly || CompilerOracle::has_option_string(method, "PrintAssembly")) { Disassembler::decode(nm); } @@ -593,7 +682,10 @@ return nm; } - +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4355) // warning C4355: 'this' : used in base member initializer list +#endif // For native wrappers nmethod::nmethod( Method* method, @@ -683,6 +775,10 @@ } } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw () { return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level)); } @@ -703,6 +799,10 @@ ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, int comp_level +#if INCLUDE_JVMCI + , Handle installed_code, + Handle speculation_log +#endif ) : CodeBlob("nmethod", code_buffer, sizeof(nmethod), nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps), @@ -727,15 +827,42 @@ _consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts()); _stub_offset = content_offset() + code_buffer->total_offset_of(code_buffer->stubs()); +#if INCLUDE_JVMCI + _jvmci_installed_code = installed_code(); + _speculation_log = (instanceOop)speculation_log(); + + if (compiler->is_jvmci()) { + // JVMCI might not produce any stub sections + if (offsets->value(CodeOffsets::Exceptions) != -1) { + _exception_offset = code_offset() + offsets->value(CodeOffsets::Exceptions); + } else { + _exception_offset = -1; + } + if (offsets->value(CodeOffsets::Deopt) != -1) { + _deoptimize_offset = code_offset() + offsets->value(CodeOffsets::Deopt); + } else { + _deoptimize_offset = -1; + } + if (offsets->value(CodeOffsets::DeoptMH) != -1) { + _deoptimize_mh_offset = code_offset() + offsets->value(CodeOffsets::DeoptMH); + } else { + _deoptimize_mh_offset = -1; + } + } else { +#endif // Exception handler and deopt handler are in the stub section assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set"); assert(offsets->value(CodeOffsets::Deopt ) != -1, "must be set"); + _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); _deoptimize_offset = _stub_offset + offsets->value(CodeOffsets::Deopt); if (offsets->value(CodeOffsets::DeoptMH) != -1) { _deoptimize_mh_offset = _stub_offset + offsets->value(CodeOffsets::DeoptMH); } else { _deoptimize_mh_offset = -1; +#if INCLUDE_JVMCI + } +#endif } if (offsets->value(CodeOffsets::UnwindHandler) != -1) { _unwind_handler_offset = code_offset() + offsets->value(CodeOffsets::UnwindHandler); @@ -779,12 +906,12 @@ // we use the information of entry points to find out if a method is // static or non static - assert(compiler->is_c2() || + assert(compiler->is_c2() || compiler->is_jvmci() || _method->is_static() == (entry_point() == _verified_entry_point), " entry points must be same for static methods and vice versa"); } - bool printnmethods = PrintNMethods + bool printnmethods = PrintNMethods || PrintNMethodsAtLevel == _comp_level || CompilerOracle::should_print(_method) || CompilerOracle::has_option_string(_method, "PrintNMethods"); if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { @@ -792,7 +919,6 @@ } } - // Print a short set of xml attributes to identify this nmethod. The // output should be embedded in some other element. void nmethod::log_identity(xmlStream* log) const { @@ -833,6 +959,7 @@ LOG_OFFSET(xtty, handler_table); LOG_OFFSET(xtty, nul_chk_table); LOG_OFFSET(xtty, oops); + LOG_OFFSET(xtty, metadata); xtty->method(method()); xtty->stamp(); @@ -874,13 +1001,13 @@ oop_maps()->print(); } } - if (PrintDebugInfo) { + if (PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) { print_scopes(); } - if (PrintRelocations) { + if (PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) { print_relocations(); } - if (PrintDependencies) { + if (PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) { print_dependencies(); } if (PrintExceptionHandlers) { @@ -990,7 +1117,7 @@ PcDesc* pd = pc_desc_at(pc); guarantee(pd != NULL, "scope must be present"); return new ScopeDesc(this, pd->scope_decode_offset(), - pd->obj_decode_offset(), pd->should_reexecute(), + pd->obj_decode_offset(), pd->should_reexecute(), pd->rethrow_exception(), pd->return_oop()); } @@ -1161,7 +1288,7 @@ } void nmethod::inc_decompile_count() { - if (!is_compiled_by_c2()) return; + if (!is_compiled_by_c2() && !is_compiled_by_jvmci()) return; // Could be gated by ProfileTraps, but do not bother... Method* m = method(); if (m == NULL) return; @@ -1225,6 +1352,7 @@ } _method = NULL; // Clear the method of this dead nmethod } + // Make the class unloaded - i.e., change state and notify sweeper assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); if (is_in_use()) { @@ -1237,6 +1365,18 @@ // Unregister must be done before the state change Universe::heap()->unregister_nmethod(this); +#if INCLUDE_JVMCI + // The method can only be unloaded after the pointer to the installed code + // Java wrapper is no longer alive. Here we need to clear out this weak + // reference to the dead object. Nulling out the reference has to happen + // after the method is unregistered since the original value may be still + // tracked by the rset. + if (_jvmci_installed_code != NULL) { + InstalledCode::set_address(_jvmci_installed_code, 0); + _jvmci_installed_code = NULL; + } +#endif + _state = unloaded; // Log the unloading. @@ -1400,9 +1540,16 @@ } else { assert(state == not_entrant, "other cases may need to be handled differently"); } +#if INCLUDE_JVMCI + if (_jvmci_installed_code != NULL) { + // Break the link between nmethod and InstalledCode such that the nmethod can subsequently be flushed safely. + InstalledCode::set_address(_jvmci_installed_code, 0); + } +#endif if (TraceCreateZombies) { - tty->print_cr("nmethod <" INTPTR_FORMAT "> code made %s", this, (state == not_entrant) ? "not entrant" : "zombie"); + ResourceMark m; + tty->print_cr("nmethod <" INTPTR_FORMAT "> %s code made %s", this, this->method() ? this->method()->name_and_sig_as_C_string() : "null", (state == not_entrant) ? "not entrant" : "zombie"); } NMethodSweeper::report_state_change(this); @@ -1690,6 +1837,33 @@ } } +#if INCLUDE_JVMCI + // Follow JVMCI method + BarrierSet* bs = Universe::heap()->barrier_set(); + if (_jvmci_installed_code != NULL) { + if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { + if (!is_alive->do_object_b(_jvmci_installed_code)) { + bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); + _jvmci_installed_code = NULL; + bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + } + } else { + if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { + return; + } + } + } + + if (_speculation_log != NULL) { + if (!is_alive->do_object_b(_speculation_log)) { + bs->write_ref_nmethod_pre(&_speculation_log, this); + _speculation_log = NULL; + bs->write_ref_nmethod_post(&_speculation_log, this); + } + } +#endif + + // Ensure that all metadata is still alive verify_metadata_loaders(low_boundary, is_alive); } @@ -1772,6 +1946,27 @@ unloading_occurred = true; } +#if INCLUDE_JVMCI + // Follow JVMCI method + if (_jvmci_installed_code != NULL) { + if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { + if (!is_alive->do_object_b(_jvmci_installed_code)) { + _jvmci_installed_code = NULL; + } + } else { + if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { + return false; + } + } + } + + if (_speculation_log != NULL) { + if (!is_alive->do_object_b(_speculation_log)) { + _speculation_log = NULL; + } + } +#endif + // Exception cache clean_exception_cache(is_alive); @@ -1829,6 +2024,32 @@ return postponed; } +#if INCLUDE_JVMCI + // Follow JVMCI method + BarrierSet* bs = Universe::heap()->barrier_set(); + if (_jvmci_installed_code != NULL) { + if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { + if (!is_alive->do_object_b(_jvmci_installed_code)) { + bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); + _jvmci_installed_code = NULL; + bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + } + } else { + if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { + is_unloaded = true; + } + } + } + + if (_speculation_log != NULL) { + if (!is_alive->do_object_b(_speculation_log)) { + bs->write_ref_nmethod_pre(&_speculation_log, this); + _speculation_log = NULL; + bs->write_ref_nmethod_post(&_speculation_log, this); + } + } +#endif + // Ensure that all metadata is still alive verify_metadata_loaders(low_boundary, is_alive); @@ -2013,6 +2234,15 @@ // (See comment above.) } +#if INCLUDE_JVMCI + if (_jvmci_installed_code != NULL) { + f->do_oop((oop*) &_jvmci_installed_code); + } + if (_speculation_log != NULL) { + f->do_oop((oop*) &_speculation_log); + } +#endif + RelocIterator iter(this, low_boundary); while (iter.next()) { @@ -2137,7 +2367,7 @@ // called with a frame corresponding to a Java invoke void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { #ifndef SHARK - if (!method()->is_native()) { + if (method() != NULL && !method()->is_native()) { SimpleScopeDesc ssd(this, fr.pc()); Bytecode_invoke call(ssd.method(), ssd.bci()); bool has_receiver = call.has_receiver(); @@ -2203,6 +2433,14 @@ memcpy(scopes_data_begin(), buffer, size); } +// When using JVMCI the address might be off by the size of a call instruction. +bool nmethod::is_deopt_entry(address pc) { + return pc == deopt_handler_begin() +#if INCLUDE_JVMCI + || pc == (deopt_handler_begin() + NativeCall::instruction_size) +#endif + ; +} #ifdef ASSERT static PcDesc* linear_search(nmethod* nm, int pc_offset, bool approximate) { @@ -2211,7 +2449,7 @@ lower += 1; // exclude initial sentinel PcDesc* res = NULL; for (PcDesc* p = lower; p < upper; p++) { - NOT_PRODUCT(--nmethod_stats.pc_desc_tests); // don't count this call to match_desc + NOT_PRODUCT(--pc_nmethod_stats.pc_desc_tests); // don't count this call to match_desc if (match_desc(p, pc_offset, approximate)) { if (res == NULL) res = p; @@ -2258,7 +2496,7 @@ // Use the last successful return as a split point. PcDesc* mid = _pc_desc_cache.last_pc_desc(); - NOT_PRODUCT(++nmethod_stats.pc_desc_searches); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_searches); if (mid->pc_offset() < pc_offset) { lower = mid; } else { @@ -2271,7 +2509,7 @@ for (int step = (1 << (LOG2_RADIX*3)); step > 1; step >>= LOG2_RADIX) { while ((mid = lower + step) < upper) { assert_LU_OK; - NOT_PRODUCT(++nmethod_stats.pc_desc_searches); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_searches); if (mid->pc_offset() < pc_offset) { lower = mid; } else { @@ -2286,7 +2524,7 @@ while (true) { assert_LU_OK; mid = lower + 1; - NOT_PRODUCT(++nmethod_stats.pc_desc_searches); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_searches); if (mid->pc_offset() < pc_offset) { lower = mid; } else { @@ -2473,7 +2711,6 @@ assert(nm->_lock_count >= 0, "unmatched nmethod lock/unlock"); } - // ----------------------------------------------------------------------------- // nmethod::get_deopt_original_pc // @@ -2587,7 +2824,7 @@ PcDesc* pd = pc_desc_at(nativeCall_at(call_site)->return_address()); assert(pd != NULL, "PcDesc must exist"); for (ScopeDesc* sd = new ScopeDesc(this, pd->scope_decode_offset(), - pd->obj_decode_offset(), pd->should_reexecute(), + pd->obj_decode_offset(), pd->should_reexecute(), pd->rethrow_exception(), pd->return_oop()); !sd->is_top(); sd = sd->sender()) { sd->verify(); @@ -2680,6 +2917,8 @@ tty->print("(c2) "); } else if (is_compiled_by_shark()) { tty->print("(shark) "); + } else if (is_compiled_by_jvmci()) { + tty->print("(JVMCI) "); } else { tty->print("(nm) "); } @@ -2764,7 +3003,10 @@ continue; ScopeDesc* sd = scope_desc_at(p->real_pc(this)); - sd->print_on(tty, p); + while (sd != NULL) { + sd->print_on(tty, p); + sd = sd->sender(); + } } } @@ -2881,7 +3123,7 @@ PcDesc* p = pc_desc_near(begin+1); if (p != NULL && p->real_pc(this) <= end) { return new ScopeDesc(this, p->scope_decode_offset(), - p->obj_decode_offset(), p->should_reexecute(), + p->obj_decode_offset(), p->should_reexecute(), p->rethrow_exception(), p->return_oop()); } return NULL; @@ -2890,9 +3132,9 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin) const { if (block_begin == entry_point()) stream->print_cr("[Entry Point]"); if (block_begin == verified_entry_point()) stream->print_cr("[Verified Entry Point]"); - if (block_begin == exception_begin()) stream->print_cr("[Exception Handler]"); + if (JVMCI_ONLY(_exception_offset >= 0 &&) block_begin == exception_begin()) stream->print_cr("[Exception Handler]"); if (block_begin == stub_begin()) stream->print_cr("[Stub Code]"); - if (block_begin == deopt_handler_begin()) stream->print_cr("[Deopt Handler Code]"); + if (JVMCI_ONLY(_deoptimize_offset >= 0 &&) block_begin == deopt_handler_begin()) stream->print_cr("[Deopt Handler Code]"); if (has_method_handle_invokes()) if (block_begin == deopt_mh_handler_begin()) stream->print_cr("[Deopt MH Handler Code]"); @@ -3058,6 +3300,7 @@ } } } + st->print(" {reexecute=%d rethrow=%d return_oop=%d}", sd->should_reexecute(), sd->rethrow_exception(), sd->return_oop()); } // Print all scopes @@ -3130,12 +3373,49 @@ void nmethod::print_statistics() { ttyLocker ttyl; if (xtty != NULL) xtty->head("statistics type='nmethod'"); - nmethod_stats.print_native_nmethod_stats(); - nmethod_stats.print_nmethod_stats(); + native_nmethod_stats.print_native_nmethod_stats(); +#ifdef COMPILER1 + c1_java_nmethod_stats.print_nmethod_stats("C1"); +#endif +#ifdef COMPILER2 + c2_java_nmethod_stats.print_nmethod_stats("C2"); +#endif +#if INCLUDE_JVMCI + jvmci_java_nmethod_stats.print_nmethod_stats("JVMCI"); +#endif +#ifdef SHARK + shark_java_nmethod_stats.print_nmethod_stats("Shark"); +#endif + unknown_java_nmethod_stats.print_nmethod_stats("Unknown"); DebugInformationRecorder::print_statistics(); - nmethod_stats.print_pc_stats(); +#ifndef PRODUCT + pc_nmethod_stats.print_pc_stats(); +#endif Dependencies::print_statistics(); if (xtty != NULL) xtty->tail("statistics"); } -#endif // PRODUCT +#endif // !PRODUCT + +#if INCLUDE_JVMCI +char* nmethod::jvmci_installed_code_name(char* buf, size_t buflen) { + if (!this->is_compiled_by_jvmci()) { + return NULL; + } + oop installedCode = this->jvmci_installed_code(); + if (installedCode != NULL) { + oop installedCodeName = NULL; + if (installedCode->is_a(InstalledCode::klass())) { + installedCodeName = InstalledCode::name(installedCode); + } + if (installedCodeName != NULL) { + return java_lang_String::as_utf8_string(installedCodeName, buf, (int)buflen); + } else { + jio_snprintf(buf, buflen, "null"); + return buf; + } + } + jio_snprintf(buf, buflen, "noInstalledCode"); + return buf; +} +#endif --- old/src/share/vm/code/nmethod.hpp 2015-09-16 15:18:20.000000000 -0700 +++ new/src/share/vm/code/nmethod.hpp 2015-09-16 15:18:20.000000000 -0700 @@ -126,6 +126,12 @@ int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method jmethodID _jmethod_id; // Cache of method()->jmethod_id() +#if INCLUDE_JVMCI + // Needed to keep nmethods alive that are not the default nmethod for the associated Method. + oop _jvmci_installed_code; + oop _speculation_log; +#endif + // To support simple linked-list chaining of nmethods: nmethod* _osr_link; // from InstanceKlass::osr_nmethods_head @@ -273,7 +279,12 @@ ExceptionHandlerTable* handler_table, ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, - int comp_level); + int comp_level +#if INCLUDE_JVMCI + , Handle installed_code, + Handle speculation_log +#endif + ); // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); @@ -309,7 +320,12 @@ ExceptionHandlerTable* handler_table, ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, - int comp_level); + int comp_level +#if INCLUDE_JVMCI + , Handle installed_code = Handle(), + Handle speculation_log = Handle() +#endif + ); static nmethod* new_native_nmethod(methodHandle method, int compile_id, @@ -332,6 +348,7 @@ bool is_osr_method() const { return _entry_bci != InvocationEntryBci; } bool is_compiled_by_c1() const; + bool is_compiled_by_jvmci() const; bool is_compiled_by_c2() const; bool is_compiled_by_shark() const; @@ -582,6 +599,14 @@ // Evolution support. We make old (discarded) compiled methods point to new Method*s. void set_method(Method* method) { _method = method; } +#if INCLUDE_JVMCI + oop jvmci_installed_code() { return _jvmci_installed_code ; } + char* jvmci_installed_code_name(char* buf, size_t buflen); + void set_jvmci_installed_code(oop installed_code) { _jvmci_installed_code = installed_code; } + oop speculation_log() { return _speculation_log ; } + void set_speculation_log(oop speculation_log) { _speculation_log = speculation_log; } +#endif + // GC support void do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred); // The parallel versions are used by G1. @@ -639,7 +664,7 @@ // Deopt // Return true is the PC is one would expect if the frame is being deopted. bool is_deopt_pc (address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); } - bool is_deopt_entry (address pc) { return pc == deopt_handler_begin(); } + bool is_deopt_entry (address pc); bool is_deopt_mh_entry(address pc) { return pc == deopt_mh_handler_begin(); } // Accessor/mutator for the original pc of a frame before a frame was deopted. address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); } @@ -690,7 +715,7 @@ // Prints a comment for one native instruction (reloc info, pc desc) void print_code_comment_on(outputStream* st, int column, address begin, address end); - static void print_statistics() PRODUCT_RETURN; + static void print_statistics() PRODUCT_RETURN; // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, --- old/src/share/vm/code/oopRecorder.cpp 2015-09-16 15:18:20.000000000 -0700 +++ new/src/share/vm/code/oopRecorder.cpp 2015-09-16 15:18:20.000000000 -0700 @@ -157,3 +157,49 @@ // Explicitly instantiate these types template class ValueRecorder; template class ValueRecorder; + +oop ObjectLookup::ObjectEntry::oop_value() { return JNIHandles::resolve(_value); } + +ObjectLookup::ObjectLookup(): _gc_count(Universe::heap()->total_collections()), _values(4) {} + +void ObjectLookup::maybe_resort() { + // The values are kept sorted by address which may be invalidated + // after a GC, so resort if a GC has occurred since last time. + if (_gc_count != Universe::heap()->total_collections()) { + _gc_count = Universe::heap()->total_collections(); + _values.sort(sort_by_address); + } +} + +int ObjectLookup::sort_by_address(oop a, oop b) { + if (b > a) return 1; + if (a > b) return -1; + return 0; +} + +int ObjectLookup::sort_by_address(ObjectEntry* a, ObjectEntry* b) { + return sort_by_address(a->oop_value(), b->oop_value()); +} + +int ObjectLookup::sort_oop_by_address(oop& a, ObjectEntry& b) { + return sort_by_address(a, b.oop_value()); +} + +int ObjectLookup::find_index(jobject handle, OopRecorder* oop_recorder) { + if (handle == NULL) { + return 0; + } + oop object = JNIHandles::resolve(handle); + maybe_resort(); + bool found; + int location = _values.find_sorted(object, found); + if (!found) { + assert(location <= _values.length(), "out of range"); + jobject handle = JNIHandles::make_local(object); + ObjectEntry r(handle, oop_recorder->allocate_oop_index(handle)); + _values.insert_before(location, r); + return r.index(); + } + return _values.at(location).index(); +} + --- old/src/share/vm/code/oopRecorder.hpp 2015-09-16 15:18:21.000000000 -0700 +++ new/src/share/vm/code/oopRecorder.hpp 2015-09-16 15:18:21.000000000 -0700 @@ -146,18 +146,57 @@ #endif }; +class OopRecorder; + +class ObjectLookup : public ResourceObj { + private: + class ObjectEntry { + private: + jobject _value; + int _index; + + public: + ObjectEntry(jobject value, int index): _value(value), _index(index) {} + ObjectEntry() {} + oop oop_value(); // { return JNIHandles::resolve(_value); } + int index() { return _index; } + }; + + GrowableArray _values; + unsigned int _gc_count; + + // Utility sort functions + static int sort_by_address(oop a, oop b); + static int sort_by_address(ObjectEntry* a, ObjectEntry* b); + static int sort_oop_by_address(oop& a, ObjectEntry& b); + + public: + ObjectLookup(); + + // Resort list if a GC has occurred since the last sort + void maybe_resort(); + int find_index(jobject object, OopRecorder* oop_recorder); +}; + class OopRecorder : public ResourceObj { private: ValueRecorder _oops; ValueRecorder _metadata; + ObjectLookup* _object_lookup; public: - OopRecorder(Arena* arena = NULL): _oops(arena), _metadata(arena) {} + OopRecorder(Arena* arena = NULL, bool deduplicate = false): _oops(arena), _metadata(arena) { + if (deduplicate) { + _object_lookup = new ObjectLookup(); + } else { + _object_lookup = NULL; + } + } int allocate_oop_index(jobject h) { return _oops.allocate_index(h); } - int find_index(jobject h) { - return _oops.find_index(h); + virtual int find_index(jobject h) { + return _object_lookup != NULL ? _object_lookup->find_index(h, this) : _oops.find_index(h); } jobject oop_at(int index) { return _oops.at(index); @@ -175,7 +214,7 @@ int allocate_metadata_index(Metadata* oop) { return _metadata.allocate_index(oop); } - int find_index(Metadata* h) { + virtual int find_index(Metadata* h) { return _metadata.find_index(h); } Metadata* metadata_at(int index) { --- old/src/share/vm/code/pcDesc.hpp 2015-09-16 15:18:22.000000000 -0700 +++ new/src/share/vm/code/pcDesc.hpp 2015-09-16 15:18:22.000000000 -0700 @@ -42,7 +42,8 @@ enum { PCDESC_reexecute = 1 << 0, PCDESC_is_method_handle_invoke = 1 << 1, - PCDESC_return_oop = 1 << 2 + PCDESC_return_oop = 1 << 2, + PCDESC_rethrow_exception = 1 << 3 }; int _flags; @@ -71,6 +72,8 @@ }; // Flags + bool rethrow_exception() const { return (_flags & PCDESC_rethrow_exception) != 0; } + void set_rethrow_exception(bool z) { set_flag(PCDESC_rethrow_exception, z); } bool should_reexecute() const { return (_flags & PCDESC_reexecute) != 0; } void set_should_reexecute(bool z) { set_flag(PCDESC_reexecute, z); } --- old/src/share/vm/code/relocInfo.cpp 2015-09-16 15:18:22.000000000 -0700 +++ new/src/share/vm/code/relocInfo.cpp 2015-09-16 15:18:22.000000000 -0700 @@ -30,6 +30,7 @@ #include "memory/resourceArea.hpp" #include "runtime/stubCodeGenerator.hpp" #include "utilities/copy.hpp" +#include "oops/oop.inline.hpp" PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC @@ -424,6 +425,30 @@ ShouldNotReachHere(); } +void Relocation::const_set_data_value(address x) { +#ifdef _LP64 + if (format() == relocInfo::narrow_oop_in_const) { + *(narrowOop*)addr() = oopDesc::encode_heap_oop((oop) x); + } else { +#endif + *(address*)addr() = x; +#ifdef _LP64 + } +#endif +} + +void Relocation::const_verify_data_value(address x) { +#ifdef _LP64 + if (format() == relocInfo::narrow_oop_in_const) { + assert(*(narrowOop*)addr() == oopDesc::encode_heap_oop((oop) x), "must agree"); + } else { +#endif + assert(*(address*)addr() == x, "must agree"); +#ifdef _LP64 + } +#endif +} + RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { if (rtype == relocInfo::none) return RelocationHolder::none; @@ -580,7 +605,8 @@ void static_stub_Relocation::unpack_data() { address base = binding()->section_start(CodeBuffer::SECT_INSTS); - _static_call = address_from_scaled_offset(unpack_1_int(), base); + jint offset = unpack_1_int(); + _static_call = address_from_scaled_offset(offset, base); } void trampoline_stub_Relocation::pack_data_to(CodeSection* dest ) { @@ -794,7 +820,8 @@ RelocIterator iter(code()); while (iter.next()) { if (iter.type() == relocInfo::static_stub_type) { - if (iter.static_stub_reloc()->static_call() == static_call_addr) { + static_stub_Relocation* stub_reloc = iter.static_stub_reloc(); + if (stub_reloc->static_call() == static_call_addr) { return iter.addr(); } } @@ -816,7 +843,8 @@ RelocIterator iter(code()); while (iter.next()) { if (iter.type() == relocInfo::static_stub_type) { - if (iter.static_stub_reloc()->static_call() == static_call_addr) { + static_stub_Relocation* stub_reloc = iter.static_stub_reloc(); + if (stub_reloc->static_call() == static_call_addr) { return iter.addr(); } } --- old/src/share/vm/code/relocInfo.hpp 2015-09-16 15:18:23.000000000 -0700 +++ new/src/share/vm/code/relocInfo.hpp 2015-09-16 15:18:23.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -210,6 +210,11 @@ // See [About Offsets] below. // //%note reloc_2 // +// relocInfo::poll_[return_]type -- a safepoint poll +// Value: none +// Instruction types: memory load or test +// Data: none +// // For example: // // INSTRUCTIONS RELOC: TYPE PREFIX DATA @@ -443,6 +448,11 @@ }; public: enum { +#ifdef _LP64 + // for use in format + // format_width must be at least 1 on _LP64 + narrow_oop_in_const = 1, +#endif // Conservatively large estimate of maximum length (in shorts) // of any relocation record. // Extended format is length prefix, data words, and tag/offset suffix. @@ -525,19 +535,19 @@ typedef relocInfo::relocType relocType; private: - address _limit; // stop producing relocations after this _addr - relocInfo* _current; // the current relocation information - relocInfo* _end; // end marker; we're done iterating when _current == _end - nmethod* _code; // compiled method containing _addr - address _addr; // instruction to which the relocation applies - short _databuf; // spare buffer for compressed data - short* _data; // pointer to the relocation's data - short _datalen; // number of halfwords in _data - char _format; // position within the instruction + address _limit; // stop producing relocations after this _addr + relocInfo* _current; // the current relocation information + relocInfo* _end; // end marker; we're done iterating when _current == _end + nmethod* _code; // compiled method containing _addr + address _addr; // instruction to which the relocation applies + short _databuf; // spare buffer for compressed data + short* _data; // pointer to the relocation's data + short _datalen; // number of halfwords in _data + char _format; // position within the instruction // Base addresses needed to compute targets of section_word_type relocs. - address _section_start[SECT_LIMIT]; - address _section_end [SECT_LIMIT]; + address _section_start[SECT_LIMIT]; + address _section_end [SECT_LIMIT]; void set_has_current(bool b) { _datalen = !b ? -1 : 0; @@ -565,7 +575,7 @@ public: // constructor - RelocIterator(nmethod* nm, address begin = NULL, address limit = NULL); + RelocIterator(nmethod* nm, address begin = NULL, address limit = NULL); RelocIterator(CodeSection* cb, address begin = NULL, address limit = NULL); // get next reloc info, return !eos @@ -762,6 +772,9 @@ } protected: + // platform-independent utility for patching constant section + void const_set_data_value (address x); + void const_verify_data_value (address x); // platform-dependent utilities for decoding and patching instructions void pd_set_data_value (address x, intptr_t off, bool verify_only = false); // a set or mem-ref void pd_verify_data_value (address x, intptr_t off) { pd_set_data_value(x, off, true); } @@ -872,13 +885,13 @@ void set_value(address x) { set_value(x, offset()); } void set_value(address x, intptr_t o) { if (addr_in_const()) - *(address*)addr() = x; + const_set_data_value(x); else pd_set_data_value(x, o); } void verify_value(address x) { if (addr_in_const()) - assert(*(address*)addr() == x, "must agree"); + const_verify_data_value(x); else pd_verify_data_value(x, offset()); } @@ -1117,7 +1130,7 @@ } private: - address _static_call; // location of corresponding static_call + address _static_call; // location of corresponding static_call static_stub_Relocation(address static_call) { _static_call = static_call; @@ -1318,10 +1331,8 @@ void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); }; -class poll_return_Relocation : public Relocation { - bool is_data() { return true; } +class poll_return_Relocation : public poll_Relocation { relocInfo::relocType type() { return relocInfo::poll_return_type; } - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); }; // We know all the xxx_Relocation classes, so now we can define these: --- old/src/share/vm/code/scopeDesc.cpp 2015-09-16 15:18:24.000000000 -0700 +++ new/src/share/vm/code/scopeDesc.cpp 2015-09-16 15:18:24.000000000 -0700 @@ -32,20 +32,22 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC -ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool return_oop) { +ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) { _code = code; _decode_offset = decode_offset; _objects = decode_object_values(obj_decode_offset); _reexecute = reexecute; + _rethrow_exception = rethrow_exception; _return_oop = return_oop; decode_body(); } -ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool return_oop) { +ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) { _code = code; _decode_offset = decode_offset; _objects = decode_object_values(DebugInformationRecorder::serialized_null); _reexecute = reexecute; + _rethrow_exception = rethrow_exception; _return_oop = return_oop; decode_body(); } @@ -56,6 +58,7 @@ _decode_offset = parent->_sender_decode_offset; _objects = parent->_objects; _reexecute = false; //reexecute only applies to the first scope + _rethrow_exception = false; _return_oop = false; decode_body(); } @@ -227,17 +230,18 @@ } } -#ifdef COMPILER2 - if (DoEscapeAnalysis && is_top() && _objects != NULL) { +#if defined(COMPILER2) || INCLUDE_JVMCI + if (NOT_JVMCI(DoEscapeAnalysis &&) is_top() && _objects != NULL) { st->print_cr(" Objects"); for (int i = 0; i < _objects->length(); i++) { ObjectValue* sv = (ObjectValue*) _objects->at(i); st->print(" - %d: ", sv->id()); + st->print("%s ", java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())->external_name()); sv->print_fields_on(st); st->cr(); } } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI } #endif --- old/src/share/vm/code/scopeDesc.hpp 2015-09-16 15:18:24.000000000 -0700 +++ new/src/share/vm/code/scopeDesc.hpp 2015-09-16 15:18:24.000000000 -0700 @@ -41,7 +41,7 @@ int _bci; public: - SimpleScopeDesc(nmethod* code,address pc) { + SimpleScopeDesc(nmethod* code, address pc) { PcDesc* pc_desc = code->pc_desc_at(pc); assert(pc_desc != NULL, "Must be able to find matching PcDesc"); DebugInfoReadStream buffer(code, pc_desc->scope_decode_offset()); @@ -60,17 +60,18 @@ class ScopeDesc : public ResourceObj { public: // Constructor - ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool return_oop); + ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop); // Calls above, giving default value of "serialized_null" to the // "obj_decode_offset" argument. (We don't use a default argument to // avoid a .hpp-.hpp dependency.) - ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool return_oop); + ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop); // JVM state Method* method() const { return _method; } int bci() const { return _bci; } bool should_reexecute() const { return _reexecute; } + bool rethrow_exception() const { return _rethrow_exception; } bool return_oop() const { return _return_oop; } GrowableArray* locals(); @@ -95,6 +96,7 @@ Method* _method; int _bci; bool _reexecute; + bool _rethrow_exception; bool _return_oop; // Decoding offsets --- old/src/share/vm/compiler/abstractCompiler.cpp 2015-09-16 15:18:25.000000000 -0700 +++ new/src/share/vm/compiler/abstractCompiler.cpp 2015-09-16 15:18:25.000000000 -0700 @@ -58,7 +58,7 @@ } void AbstractCompiler::set_state(int state) { - // Ensure that ste is only set by one thread at a time + // Ensure that state is only set by one thread at a time MutexLocker only_one(CompileThread_lock); _compiler_state = state; CompileThread_lock->notify_all(); --- old/src/share/vm/compiler/abstractCompiler.hpp 2015-09-16 15:18:26.000000000 -0700 +++ new/src/share/vm/compiler/abstractCompiler.hpp 2015-09-16 15:18:26.000000000 -0700 @@ -27,6 +27,47 @@ #include "ci/compilerInterface.hpp" +typedef void (*initializer)(void); + +#if INCLUDE_JVMCI +// Per-compiler statistics +class CompilerStatistics VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + + class Data VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + public: + elapsedTimer _time; // time spent compiling + int _bytes; // number of bytecodes compiled, including inlined bytecodes + int _count; // number of compilations + Data() : _bytes(0), _count(0) {} + void update(elapsedTimer time, int bytes) { + _time.add(time); + _bytes += bytes; + _count++; + } + void reset() { + _time.reset(); + } + }; + + public: + Data _standard; // stats for non-OSR compilations + Data _osr; // stats for OSR compilations + int _nmethods_size; // + int _nmethods_code_size; + int bytes_per_second() { + int bytes = _standard._bytes + _osr._bytes; + if (bytes == 0) { + return 0; + } + double seconds = _standard._time.seconds() + _osr._time.seconds(); + return seconds == 0.0 ? 0 : (int) (bytes / seconds); + } + CompilerStatistics() : _nmethods_size(0), _nmethods_code_size(0) {} +}; +#endif + class AbstractCompiler : public CHeapObj { private: volatile int _num_compiler_threads; @@ -45,12 +86,17 @@ none, c1, c2, + jvmci, shark }; private: Type _type; +#if INCLUDE_JVMCI + CompilerStatistics _stats; +#endif + public: AbstractCompiler(Type type) : _type(type), _compiler_state(uninitialized), _num_compiler_threads(0) {} @@ -115,6 +161,7 @@ // Compiler type queries. bool is_c1() { return _type == c1; } bool is_c2() { return _type == c2; } + bool is_jvmci() { return _type == jvmci; } bool is_shark() { return _type == shark; } // Customization @@ -138,6 +185,10 @@ virtual void print_timers() { ShouldNotReachHere(); } + +#if INCLUDE_JVMCI + CompilerStatistics* stats() { return &_stats; } +#endif }; #endif // SHARE_VM_COMPILER_ABSTRACTCOMPILER_HPP --- old/src/share/vm/compiler/compileBroker.cpp 2015-09-16 15:18:26.000000000 -0700 +++ new/src/share/vm/compiler/compileBroker.cpp 2015-09-16 15:18:26.000000000 -0700 @@ -51,6 +51,11 @@ #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "runtime/vframe.hpp" +#endif #ifdef COMPILER2 #include "opto/c2compiler.hpp" #endif @@ -386,6 +391,8 @@ if (!short_form) { st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp } + // print compiler name if requested + if (CIPrintCompilerName) st->print("%s:", CompileBroker::compiler_name(comp_level)); st->print("%4d ", compile_id); // print compilation number // For unloaded methods the transition to zombie occurs after the @@ -518,7 +525,8 @@ if (_osr_bci != CompileBroker::standard_entry_bci) { log->print(" osr_bci='%d'", _osr_bci); } - if (_comp_level != CompLevel_highest_tier) { + // Always print the level in tiered. + if (_comp_level != CompLevel_highest_tier || TieredCompilation) { log->print(" level='%d'", _comp_level); } if (_is_blocking) { @@ -555,6 +563,24 @@ // ------------------------------------------------------------------ +// CompileTask::log_task_dequeued +void CompileTask::log_task_dequeued(const char* comment) { + if (LogCompilation && xtty != NULL) { + Thread* thread = Thread::current(); + ttyLocker ttyl; + ResourceMark rm(thread); + + xtty->begin_elem("task_dequeued"); + log_task(xtty); + if (comment != NULL) { + xtty->print(" comment='%s'", comment); + } + xtty->end_elem(); + } +} + + +// ------------------------------------------------------------------ // CompileTask::log_task_start void CompileTask::log_task_start(CompileLog* log) { log->begin_head("task"); @@ -871,6 +897,30 @@ // Set the interface to the current compiler(s). int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple); int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization); + +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // This is creating a JVMCICompiler singleton. + JVMCICompiler* jvmci = new JVMCICompiler(); + + if (UseJVMCICompiler) { + _compilers[1] = jvmci; + if (FLAG_IS_DEFAULT(JVMCIThreads)) { + if (BootstrapJVMCI) { + // JVMCI will bootstrap so give it more threads + c2_count = MIN2(32, os::active_processor_count()); + } + } else { + c2_count = JVMCIThreads; + } + if (FLAG_IS_DEFAULT(JVMCIHostThreads)) { + } else { + c1_count = JVMCIHostThreads; + } + } + } +#endif + #ifdef COMPILER1 if (c1_count > 0) { _compilers[0] = new Compiler(); @@ -878,8 +928,10 @@ #endif // COMPILER1 #ifdef COMPILER2 - if (c2_count > 0) { - _compilers[1] = new C2Compiler(); + if (true JVMCI_ONLY( && !UseJVMCICompiler)) { + if (c2_count > 0) { + _compilers[1] = new C2Compiler(); + } } #endif // COMPILER2 @@ -1099,7 +1151,7 @@ const bool compiler_thread = true; for (int i = 0; i < c2_compiler_count; i++) { // Create a name for our thread. - sprintf(name_buffer, "C2 CompilerThread%d", i); + sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i); CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); // Shark and C2 make_thread(name_buffer, _c2_compile_queue, counters, _compilers[1], compiler_thread, CHECK); @@ -1169,7 +1221,7 @@ if (osr_bci != InvocationEntryBci) { tty->print(" osr_bci: %d", osr_bci); } - tty->print(" comment: %s count: %d", comment, hot_count); + tty->print(" level: %d comment: %s count: %d", comp_level, comment, hot_count); if (!hot_method.is_null()) { tty->print(" hot: "); if (hot_method() != method()) { @@ -1261,6 +1313,41 @@ // Should this thread wait for completion of the compile? blocking = is_compile_blocking(); +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + if (blocking) { + // Don't allow blocking compiles for requests triggered by JVMCI. + if (thread->is_Compiler_thread()) { + blocking = false; + } + + // Don't allow blocking compiles if inside a class initializer or while performing class loading + vframeStream vfst((JavaThread*) thread); + for (; !vfst.at_end(); vfst.next()) { + if (vfst.method()->is_static_initializer() || + (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) && + vfst.method()->name() == vmSymbols::loadClass_name())) { + blocking = false; + break; + } + } + + // Don't allow blocking compilation requests to JVMCI + // if JVMCI itself is not yet initialized + if (!JVMCIRuntime::is_HotSpotJVMCIRuntime_initialized() && compiler(comp_level)->is_jvmci()) { + blocking = false; + } + + // Don't allow blocking compilation requests if we are in JVMCIRuntime::shutdown + // to avoid deadlock between compiler thread(s) and threads run at shutdown + // such as the DestroyJavaVM thread. + if (JVMCIRuntime::shutdown_called()) { + blocking = false; + } + } + } +#endif + // We will enter the compilation in the queue. // 14012000: Note that this sets the queued_for_compile bits in // the target method. We can now reason that a method cannot be @@ -1442,7 +1529,10 @@ // return requested nmethod // We accept a higher level osr method - return osr_bci == InvocationEntryBci ? method->code() : method->lookup_osr_nmethod_for(osr_bci, comp_level, false); + if (osr_bci == InvocationEntryBci) { + return method->code(); + } + return method->lookup_osr_nmethod_for(osr_bci, comp_level, false); } @@ -1565,6 +1655,15 @@ #endif } +// ------------------------------------------------------------------ +// CompileBroker::assign_compile_id_unlocked +// +// Public wrapper for assign_compile_id that acquires the needed locks +uint CompileBroker::assign_compile_id_unlocked(Thread* thread, methodHandle method, int osr_bci) { + MutexLocker locker(MethodCompileQueue_lock, thread); + return assign_compile_id(method, osr_bci); +} + /** * Should the current thread block until this compilation request * has been fulfilled? @@ -1924,6 +2023,35 @@ tty->print("%s", s.as_string()); } +void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env) { + + if (success) { + task->mark_success(); + if (ci_env != NULL) { + task->set_num_inlined_bytecodes(ci_env->num_inlined_bytecodes()); + } + if (_compilation_log != NULL) { + nmethod* code = task->code(); + if (code != NULL) { + _compilation_log->log_nmethod(thread, code); + } + } + } + + // simulate crash during compilation + assert(task->compile_id() != CICrashAt, "just as planned"); + if (event.should_commit()) { + event.set_method(task->method()); + event.set_compileID(task->compile_id()); + event.set_compileLevel(task->comp_level()); + event.set_succeded(task->is_success()); + event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci); + event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size()); + event.set_inlinedBytes(task->num_inlined_bytecodes()); + event.commit(); + } +} + // ------------------------------------------------------------------ // CompileBroker::invoke_compiler_on_method // @@ -1972,12 +2100,27 @@ push_jni_handle_block(); Method* target_handle = task->method(); int compilable = ciEnv::MethodCompilable; + AbstractCompiler *comp = compiler(task_level); + + int system_dictionary_modification_counter; + { + MutexLocker locker(Compile_lock, thread); + system_dictionary_modification_counter = SystemDictionary::number_of_modifications(); + } +#if INCLUDE_JVMCI + if (UseJVMCICompiler && comp != NULL && comp->is_jvmci()) { + JVMCICompiler* jvmci = (JVMCICompiler*) comp; + + TraceTime t1("compilation", &time); + EventCompilation event; + + JVMCIEnv env(task, system_dictionary_modification_counter); + jvmci->compile_method(target_handle, osr_bci, &env); + + post_compile(thread, task, event, task->code() != NULL, NULL); + } else +#endif { - int system_dictionary_modification_counter; - { - MutexLocker locker(Compile_lock, thread); - system_dictionary_modification_counter = SystemDictionary::number_of_modifications(); - } NoHandleMark nhm; ThreadToNativeFromVM ttn(thread); @@ -2003,7 +2146,6 @@ TraceTime t1("compilation", &time); EventCompilation event; - AbstractCompiler *comp = compiler(task_level); if (comp == NULL) { ci_env.record_method_not_compilable("no compiler", !TieredCompilation); } else { @@ -2039,28 +2181,9 @@ err_msg_res("COMPILE SKIPPED: %s", ci_env.failure_reason()); task->print_compilation(tty, msg); } - } else { - task->mark_success(); - task->set_num_inlined_bytecodes(ci_env.num_inlined_bytecodes()); - if (_compilation_log != NULL) { - nmethod* code = task->code(); - if (code != NULL) { - _compilation_log->log_nmethod(thread, code); - } - } - } - // simulate crash during compilation - assert(task->compile_id() != CICrashAt, "just as planned"); - if (event.should_commit()) { - event.set_method(target->get_Method()); - event.set_compileID(compile_id); - event.set_compileLevel(task->comp_level()); - event.set_succeded(task->is_success()); - event.set_isOsr(is_osr); - event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size()); - event.set_inlinedBytes(task->num_inlined_bytecodes()); - event.commit(); } + + post_compile(thread, task, event, !ci_env.failing(), &ci_env); } pop_jni_handle_block(); @@ -2311,13 +2434,19 @@ _peak_compilation_time = time.milliseconds() > _peak_compilation_time ? time.milliseconds() : _peak_compilation_time; if (CITime) { + int bytes_compiled = method->code_size() + task->num_inlined_bytecodes(); + JVMCI_ONLY(CompilerStatistics* stats = compiler(task->comp_level())->stats();) if (is_osr) { _t_osr_compilation.add(time); - _sum_osr_bytes_compiled += method->code_size() + task->num_inlined_bytecodes(); + _sum_osr_bytes_compiled += bytes_compiled; + JVMCI_ONLY(stats->_osr.update(time, bytes_compiled);) } else { _t_standard_compilation.add(time); _sum_standard_bytes_compiled += method->code_size() + task->num_inlined_bytecodes(); + JVMCI_ONLY(stats->_standard.update(time, bytes_compiled);) } + JVMCI_ONLY(stats->_nmethods_size += code->total_size();) + JVMCI_ONLY(stats->_nmethods_code_size += code->insts_size();) } if (UsePerfData) { @@ -2373,22 +2502,106 @@ } } -void CompileBroker::print_times() { +#if INCLUDE_JVMCI +void CompileBroker::print_times(AbstractCompiler* comp) { + CompilerStatistics* stats = comp->stats(); + tty->print_cr(" %s {speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}", + comp->name(), stats->bytes_per_second(), + stats->_standard._time.seconds(), stats->_standard._bytes, stats->_standard._count, + stats->_osr._time.seconds(), stats->_osr._bytes, stats->_osr._count, + stats->_nmethods_size, stats->_nmethods_code_size); + comp->print_timers(); +} +#endif + +void CompileBroker::print_times(bool per_compiler, bool aggregate) { +#if INCLUDE_JVMCI + elapsedTimer standard_compilation; + elapsedTimer total_compilation; + elapsedTimer osr_compilation; + + int standard_bytes_compiled = 0; + int osr_bytes_compiled = 0; + + int standard_compile_count = 0; + int osr_compile_count = 0; + int total_compile_count = 0; + + int nmethods_size = 0; + int nmethods_code_size = 0; + bool printedHeader = false; + + for (unsigned int i = 0; i < sizeof(_compilers) / sizeof(AbstractCompiler*); i++) { + AbstractCompiler* comp = _compilers[i]; + if (comp != NULL) { + if (per_compiler && aggregate && !printedHeader) { + printedHeader = true; + tty->cr(); + tty->print_cr("Individual compiler times (for compiled methods only)"); + tty->print_cr("------------------------------------------------"); + tty->cr(); + } + CompilerStatistics* stats = comp->stats(); + + standard_compilation.add(stats->_standard._time); + osr_compilation.add(stats->_osr._time); + + standard_bytes_compiled += stats->_standard._bytes; + osr_bytes_compiled += stats->_osr._bytes; + + standard_compile_count += stats->_standard._count; + osr_compile_count += stats->_osr._count; + + nmethods_size += stats->_nmethods_size; + nmethods_code_size += stats->_nmethods_code_size; + + if (per_compiler) { + print_times(comp); + } + } + } + total_compile_count = osr_compile_count + standard_compile_count; + total_compilation.add(osr_compilation); + total_compilation.add(standard_compilation); + + // In hosted mode, print the JVMCI compiler specific counters manually. + if (!UseJVMCICompiler) { + JVMCICompiler::print_compilation_timers(); + } +#else + elapsedTimer standard_compilation = CompileBroker::_t_standard_compilation; + elapsedTimer osr_compilation = CompileBroker::_t_osr_compilation; + elapsedTimer total_compilation = CompileBroker::_t_total_compilation; + + int standard_bytes_compiled = CompileBroker::_sum_standard_bytes_compiled; + int osr_bytes_compiled = CompileBroker::_sum_osr_bytes_compiled; + + int standard_compile_count = CompileBroker::_total_standard_compile_count; + int osr_compile_count = CompileBroker::_total_osr_compile_count; + int total_compile_count = CompileBroker::_total_compile_count; + + int nmethods_size = CompileBroker::_sum_nmethod_code_size; + int nmethods_code_size = CompileBroker::_sum_nmethod_size; +#endif + + if (!aggregate) { + return; + } tty->cr(); tty->print_cr("Accumulated compiler times"); tty->print_cr("----------------------------------------------------------"); //0000000000111111111122222222223333333333444444444455555555556666666666 //0123456789012345678901234567890123456789012345678901234567890123456789 - tty->print_cr(" Total compilation time : %7.3f s", CompileBroker::_t_total_compilation.seconds()); + tty->print_cr(" Total compilation time : %7.3f s", total_compilation.seconds()); tty->print_cr(" Standard compilation : %7.3f s, Average : %2.3f s", - CompileBroker::_t_standard_compilation.seconds(), - CompileBroker::_t_standard_compilation.seconds() / CompileBroker::_total_standard_compile_count); + standard_compilation.seconds(), + standard_compilation.seconds() / standard_compile_count); tty->print_cr(" Bailed out compilation : %7.3f s, Average : %2.3f s", CompileBroker::_t_bailedout_compilation.seconds(), CompileBroker::_t_bailedout_compilation.seconds() / CompileBroker::_total_bailout_count); tty->print_cr(" On stack replacement : %7.3f s, Average : %2.3f s", - CompileBroker::_t_osr_compilation.seconds(), - CompileBroker::_t_osr_compilation.seconds() / CompileBroker::_total_osr_compile_count); + osr_compilation.seconds(), + osr_compilation.seconds() / osr_compile_count); tty->print_cr(" Invalidated : %7.3f s, Average : %2.3f s", CompileBroker::_t_invalidated_compilation.seconds(), CompileBroker::_t_invalidated_compilation.seconds() / CompileBroker::_total_invalidated_count); @@ -2404,18 +2617,19 @@ comp->print_timers(); } tty->cr(); - tty->print_cr(" Total compiled methods : %8d methods", CompileBroker::_total_compile_count); - tty->print_cr(" Standard compilation : %8d methods", CompileBroker::_total_standard_compile_count); - tty->print_cr(" On stack replacement : %8d methods", CompileBroker::_total_osr_compile_count); - int tcb = CompileBroker::_sum_osr_bytes_compiled + CompileBroker::_sum_standard_bytes_compiled; + tty->print_cr(" Total compiled methods : %8d methods", total_compile_count); + tty->print_cr(" Standard compilation : %8d methods", standard_compile_count); + tty->print_cr(" On stack replacement : %8d methods", osr_compile_count); + int tcb = osr_bytes_compiled + standard_bytes_compiled; tty->print_cr(" Total compiled bytecodes : %8d bytes", tcb); - tty->print_cr(" Standard compilation : %8d bytes", CompileBroker::_sum_standard_bytes_compiled); - tty->print_cr(" On stack replacement : %8d bytes", CompileBroker::_sum_osr_bytes_compiled); - int bps = (int)(tcb / CompileBroker::_t_total_compilation.seconds()); + tty->print_cr(" Standard compilation : %8d bytes", standard_bytes_compiled); + tty->print_cr(" On stack replacement : %8d bytes", osr_bytes_compiled); + double tcs = total_compilation.seconds(); + int bps = tcs == 0.0 ? 0 : (int)(tcb / tcs); tty->print_cr(" Average compilation speed : %8d bytes/s", bps); tty->cr(); - tty->print_cr(" nmethod code size : %8d bytes", CompileBroker::_sum_nmethod_code_size); - tty->print_cr(" nmethod total size : %8d bytes", CompileBroker::_sum_nmethod_size); + tty->print_cr(" nmethod code size : %8d bytes", nmethods_code_size); + tty->print_cr(" nmethod total size : %8d bytes", nmethods_size); } // Debugging output for failure --- old/src/share/vm/compiler/compileBroker.hpp 2015-09-16 15:18:27.000000000 -0700 +++ new/src/share/vm/compiler/compileBroker.hpp 2015-09-16 15:18:27.000000000 -0700 @@ -28,6 +28,7 @@ #include "ci/compilerInterface.hpp" #include "compiler/abstractCompiler.hpp" #include "runtime/perfData.hpp" +#include "trace/tracing.hpp" class nmethod; class nmethodLocker; @@ -140,6 +141,7 @@ void log_task(xmlStream* log); void log_task_queued(); + void log_task_dequeued(const char* comment); void log_task_start(CompileLog* log); void log_task_done(CompileLog* log); @@ -358,6 +360,7 @@ static void wait_for_completion(CompileTask* task); static void invoke_compiler_on_method(CompileTask* task); + static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env); static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level); static void push_jni_handle_block(); static void pop_jni_handle_block(); @@ -403,6 +406,9 @@ int hot_count, const char* comment, Thread* thread); + // Acquire any needed locks and assign a compile id + static uint assign_compile_id_unlocked(Thread* thread, methodHandle method, int osr_bci); + static void compiler_thread_loop(); static uint get_compilation_id() { return _compilation_id; } @@ -451,8 +457,13 @@ // Redefine Classes support static void mark_on_stack(); +#if INCLUDE_JVMCI + // Print curent compilation time stats for a given compiler + static void print_times(AbstractCompiler* comp); +#endif + // Print a detailed accounting of compilation time - static void print_times(); + static void print_times(bool per_compiler = true, bool aggregate = true); // Debugging output for failure static void print_last_compile(); --- old/src/share/vm/compiler/disassembler.cpp 2015-09-16 15:18:28.000000000 -0700 +++ new/src/share/vm/compiler/disassembler.cpp 2015-09-16 15:18:28.000000000 -0700 @@ -487,8 +487,14 @@ void Disassembler::decode(CodeBlob* cb, outputStream* st) { if (!load_library()) return; + if (cb->is_nmethod()) { + decode((nmethod*)cb, st); + return; + } decode_env env(cb, st); - env.output()->print_cr("Decoding CodeBlob " PTR_FORMAT, cb); + env.output()->print_cr("----------------------------------------------------------------------"); + env.output()->print_cr("%s", cb->name()); + env.output()->print_cr(" at [" PTR_FORMAT ", " PTR_FORMAT "] %d bytes", cb->code_begin(), cb->code_end(), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*)); env.decode_instructions(cb->code_begin(), cb->code_end()); } @@ -501,8 +507,7 @@ void Disassembler::decode(nmethod* nm, outputStream* st) { if (!load_library()) return; decode_env env(nm, st); - env.output()->print_cr("Decoding compiled method " PTR_FORMAT ":", nm); - env.output()->print_cr("Code:"); + env.output()->print_cr("----------------------------------------------------------------------"); #ifdef SHARK SharkEntry* entry = (SharkEntry *) nm->code_begin(); @@ -513,6 +518,21 @@ unsigned char* end = nm->code_end(); #endif // SHARK + nm->method()->method_holder()->name()->print_symbol_on(env.output()); + env.output()->print("."); + nm->method()->name()->print_symbol_on(env.output()); + nm->method()->signature()->print_symbol_on(env.output()); +#if INCLUDE_JVMCI + { + char buffer[O_BUFLEN]; + char* jvmciName = nm->jvmci_installed_code_name(buffer, O_BUFLEN); + if (jvmciName != NULL) { + env.output()->print(" (%s)", jvmciName); + } + } +#endif + env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] %d bytes", p, end, ((jlong)(end - p))); + // If there has been profiling, print the buckets. if (FlatProfiler::bucket_start_for(p) != NULL) { unsigned char* p1 = p; --- old/src/share/vm/compiler/oopMap.cpp 2015-09-16 15:18:28.000000000 -0700 +++ new/src/share/vm/compiler/oopMap.cpp 2015-09-16 15:18:28.000000000 -0700 @@ -39,6 +39,9 @@ #ifdef COMPILER2 #include "opto/optoreg.hpp" #endif +#ifdef SPARC +#include "vmreg_sparc.inline.hpp" +#endif // OopMapStream @@ -48,7 +51,7 @@ _size = oop_map->omv_count(); _position = 0; _valid_omv = false; -} +} OopMapStream::OopMapStream(const ImmutableOopMap* oop_map, int oop_types_mask) { _stream = new CompressedReadStream(oop_map->data_addr()); @@ -276,10 +279,15 @@ static void add_derived_oop(oop* base, oop* derived) { #ifndef TIERED COMPILER1_PRESENT(ShouldNotReachHere();) +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + ShouldNotReachHere(); + } +#endif #endif // TIERED -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI DerivedPointerTable::add(derived, base); -#endif // COMPILER2 +#endif // COMPILER2 || JVMCI } @@ -288,7 +296,7 @@ // Print oopmap and regmap tty->print_cr("------ "); CodeBlob* cb = fr->cb(); - ImmutableOopMapSet* maps = cb->oop_maps(); + const ImmutableOopMapSet* maps = cb->oop_maps(); const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc()); map->print(); if( cb->is_nmethod() ) { @@ -325,7 +333,7 @@ NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);) - ImmutableOopMapSet* maps = cb->oop_maps(); + const ImmutableOopMapSet* maps = cb->oop_maps(); const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc()); assert(map != NULL, "no ptr map found"); @@ -337,6 +345,11 @@ if (!oms.is_done()) { #ifndef TIERED COMPILER1_PRESENT(ShouldNotReachHere();) +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + ShouldNotReachHere(); + } +#endif #endif // !TIERED // Protect the operation on the derived pointers. This // protects the addition of derived pointers to the shared @@ -382,7 +395,7 @@ } #ifdef ASSERT if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) || - !Universe::heap()->is_in_or_null(*loc)) { + !Universe::heap()->is_in_or_null(*loc)) { tty->print_cr("# Found non oop pointer. Dumping state at failure"); // try to dump out some helpful debugging information trace_codeblob_maps(fr, reg_map); @@ -402,7 +415,9 @@ } else if ( omv.type() == OopMapValue::narrowoop_value ) { narrowOop *nl = (narrowOop*)loc; #ifndef VM_LITTLE_ENDIAN - if (!omv.reg()->is_stack()) { + VMReg vmReg = omv.reg(); + // Don't do this on SPARC float registers as they can be individually addressed + if (!vmReg->is_stack() SPARC_ONLY(&& !vmReg->is_FloatRegister())) { // compressed oops in registers only take up 4 bytes of an // 8 byte register but they are in the wrong part of the // word so adjust loc to point at the right place. @@ -451,7 +466,7 @@ // Check that runtime stubs save all callee-saved registers #ifdef COMPILER2 - assert(cb->is_compiled_by_c1() || !cb->is_runtime_stub() || + assert(cb->is_compiled_by_c1() || cb->is_compiled_by_jvmci() || !cb->is_runtime_stub() || (nof_callee >= SAVED_ON_ENTRY_REG_COUNT || nof_callee >= C_SAVED_ON_ENTRY_REG_COUNT), "must save all"); #endif // COMPILER2 @@ -465,13 +480,18 @@ bool ImmutableOopMap::has_derived_pointer() const { #ifndef TIERED COMPILER1_PRESENT(return false); +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + return false; + } +#endif #endif // !TIERED -#ifdef COMPILER2 - OopMapStream oms((OopMap*)this,OopMapValue::derived_oop_value); +#if defined(COMPILER2) || INCLUDE_JVMCI + OopMapStream oms(this,OopMapValue::derived_oop_value); return oms.is_done(); #else return false; -#endif // COMPILER2 +#endif // COMPILER2 || JVMCI } #endif //PRODUCT @@ -607,74 +627,9 @@ } #endif -class ImmutableOopMapBuilder { -private: - class Mapping; - -private: - const OopMapSet* _set; - const OopMap* _empty; - const OopMap* _last; - int _empty_offset; - int _last_offset; - int _offset; - Mapping* _mapping; - ImmutableOopMapSet* _new_set; - - /* Used for bookkeeping when building ImmutableOopMaps */ - class Mapping : public ResourceObj { - public: - enum kind_t { OOPMAP_UNKNOWN = 0, OOPMAP_NEW = 1, OOPMAP_EMPTY = 2, OOPMAP_DUPLICATE = 3 }; - - kind_t _kind; - int _offset; - int _size; - const OopMap* _map; - const OopMap* _other; - - Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(NULL) {} - - void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) { - _kind = kind; - _offset = offset; - _size = size; - _map = map; - _other = other; - } - }; - -public: - ImmutableOopMapBuilder(const OopMapSet* set) : _set(set), _new_set(NULL), _empty(NULL), _last(NULL), _empty_offset(-1), _last_offset(-1), _offset(0) { - _mapping = NEW_RESOURCE_ARRAY(Mapping, _set->size()); - } - - int heap_size(); - ImmutableOopMapSet* build(); -private: - bool is_empty(const OopMap* map) const { - return map->count() == 0; - } - - bool is_last_duplicate(const OopMap* map) { - if (_last != NULL && _last->count() > 0 && _last->equals(map)) { - return true; - } - return false; - } - -#ifdef ASSERT - void verify(address buffer, int size, const ImmutableOopMapSet* set); -#endif - - bool has_empty() const { - return _empty_offset != -1; - } - - int size_for(const OopMap* map) const; - void fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); - int fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); - void fill(ImmutableOopMapSet* set, int size); -}; +ImmutableOopMapBuilder::ImmutableOopMapBuilder(const OopMapSet* set) : _set(set), _new_set(NULL), _empty(NULL), _last(NULL), _empty_offset(-1), _last_offset(-1), _offset(0), _required(-1) { + _mapping = NEW_RESOURCE_ARRAY(Mapping, _set->size()); +} int ImmutableOopMapBuilder::size_for(const OopMap* map) const { return align_size_up(sizeof(ImmutableOopMap) + map->data_size(), 8); @@ -719,6 +674,7 @@ int total = base + pairs + _offset; DEBUG_ONLY(total += 8); + _required = total; return total; } @@ -770,31 +726,35 @@ } #endif -ImmutableOopMapSet* ImmutableOopMapBuilder::build() { - int required = heap_size(); - - // We need to allocate a chunk big enough to hold the ImmutableOopMapSet and all of its ImmutableOopMaps - address buffer = (address) NEW_C_HEAP_ARRAY(unsigned char, required, mtCode); - DEBUG_ONLY(memset(&buffer[required-8], 0xff, 8)); +ImmutableOopMapSet* ImmutableOopMapBuilder::generate_into(address buffer) { + DEBUG_ONLY(memset(&buffer[_required-8], 0xff, 8)); - _new_set = new (buffer) ImmutableOopMapSet(_set, required); - fill(_new_set, required); + _new_set = new (buffer) ImmutableOopMapSet(_set, _required); + fill(_new_set, _required); - DEBUG_ONLY(verify(buffer, required, _new_set)); + DEBUG_ONLY(verify(buffer, _required, _new_set)); return _new_set; } +ImmutableOopMapSet* ImmutableOopMapBuilder::build() { + _required = heap_size(); + + // We need to allocate a chunk big enough to hold the ImmutableOopMapSet and all of its ImmutableOopMaps + address buffer = (address) NEW_C_HEAP_ARRAY(unsigned char, _required, mtCode); + return generate_into(buffer); +} + ImmutableOopMapSet* ImmutableOopMapSet::build_from(const OopMapSet* oopmap_set) { ResourceMark mark; ImmutableOopMapBuilder builder(oopmap_set); return builder.build(); } - + //------------------------------DerivedPointerTable--------------------------- -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI class DerivedPointerEntry : public CHeapObj { private: @@ -887,4 +847,4 @@ _active = false; } -#endif // COMPILER2 +#endif // COMPILER2 || JVMCI --- old/src/share/vm/compiler/oopMap.hpp 2015-09-16 15:18:29.000000000 -0700 +++ new/src/share/vm/compiler/oopMap.hpp 2015-09-16 15:18:29.000000000 -0700 @@ -188,6 +188,8 @@ void copy_data_to(address addr) const; OopMap* deep_copy(); + bool has_derived_pointer() const PRODUCT_RETURN0; + bool legal_vm_reg_name(VMReg local) { return OopMapValue::legal_vm_reg_name(local); } @@ -354,13 +356,82 @@ #endif }; +class ImmutableOopMapBuilder { +private: + class Mapping; + +private: + const OopMapSet* _set; + const OopMap* _empty; + const OopMap* _last; + int _empty_offset; + int _last_offset; + int _offset; + int _required; + Mapping* _mapping; + ImmutableOopMapSet* _new_set; + + /* Used for bookkeeping when building ImmutableOopMaps */ + class Mapping : public ResourceObj { + public: + enum kind_t { OOPMAP_UNKNOWN = 0, OOPMAP_NEW = 1, OOPMAP_EMPTY = 2, OOPMAP_DUPLICATE = 3 }; + + kind_t _kind; + int _offset; + int _size; + const OopMap* _map; + const OopMap* _other; + + Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(NULL) {} + + void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) { + _kind = kind; + _offset = offset; + _size = size; + _map = map; + _other = other; + } + }; + +public: + ImmutableOopMapBuilder(const OopMapSet* set); + + int heap_size(); + ImmutableOopMapSet* build(); + ImmutableOopMapSet* generate_into(address buffer); +private: + bool is_empty(const OopMap* map) const { + return map->count() == 0; + } + + bool is_last_duplicate(const OopMap* map) { + if (_last != NULL && _last->count() > 0 && _last->equals(map)) { + return true; + } + return false; + } + +#ifdef ASSERT + void verify(address buffer, int size, const ImmutableOopMapSet* set); +#endif + + bool has_empty() const { + return _empty_offset != -1; + } + + int size_for(const OopMap* map) const; + void fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); + int fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); + void fill(ImmutableOopMapSet* set, int size); +}; + // Derived pointer support. This table keeps track of all derived points on a // stack. It is cleared before each scavenge/GC. During the traversal of all // oops, it is filled in with references to all locations that contains a // derived oop (assumed to be very few). When the GC is complete, the derived // pointers are updated based on their base pointers new value and an offset. -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI class DerivedPointerTable : public AllStatic { friend class VMStructs; private: @@ -396,6 +467,6 @@ } } }; -#endif // COMPILER2 +#endif // COMPILER2 || JVMCI #endif // SHARE_VM_COMPILER_OOPMAP_HPP --- old/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp 2015-09-16 15:18:30.000000000 -0700 +++ new/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp 2015-09-16 15:18:30.000000000 -0700 @@ -2377,7 +2377,9 @@ // way with the marking information used by GC. NoRefDiscovery no_discovery(ref_processor()); - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;) +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif // Clear any marks from a previous round verification_mark_bm()->clear_all(); @@ -3002,7 +3004,9 @@ } { - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;) +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif if (CMSParallelInitialMarkEnabled) { // The parallel version. WorkGang* workers = gch->workers(); @@ -4331,7 +4335,9 @@ } { - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;) +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif // Note on the role of the mod union table: // Since the marker in "markFromRoots" marks concurrently with --- old/src/share/vm/gc/g1/g1CollectedHeap.cpp 2015-09-16 15:18:31.000000000 -0700 +++ new/src/share/vm/gc/g1/g1CollectedHeap.cpp 2015-09-16 15:18:30.000000000 -0700 @@ -1436,7 +1436,9 @@ check_bitmaps("Full GC Start"); pre_full_gc_dump(gc_timer); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif // Disable discovery and empty the discovered lists // for the CM ref processor. @@ -1496,7 +1498,9 @@ // not been removed from the discovered lists. ref_processor_stw()->enqueue_discovered_references(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif MemoryService::track_memory_usage(); @@ -3552,8 +3556,9 @@ // FIXME: what is this about? // I'm ignoring the "fill_newgen()" call if "alloc_event_enabled" // is set. - COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(), - "derived pointer present")); +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_empty(), "derived pointer present"); +#endif // always_do_update_barrier = true; resize_all_tlabs(); @@ -3993,7 +3998,9 @@ check_bitmaps("GC Start"); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif // Please see comment in g1CollectedHeap.hpp and // G1CollectedHeap::ref_processing_init() to see how @@ -5652,7 +5659,9 @@ enqueue_discovered_references(per_thread_states); redirty_logged_cards(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif } void G1CollectedHeap::record_obj_copy_mem_stats() { --- old/src/share/vm/gc/g1/g1MarkSweep.cpp 2015-09-16 15:18:31.000000000 -0700 +++ new/src/share/vm/gc/g1/g1MarkSweep.cpp 2015-09-16 15:18:31.000000000 -0700 @@ -93,8 +93,10 @@ mark_sweep_phase2(); +#if defined(COMPILER2) || INCLUDE_JVMCI // Don't add any more derived pointers during phase3 - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); + DerivedPointerTable::set_active(false); +#endif mark_sweep_phase3(); @@ -168,7 +170,9 @@ if (VerifyDuringGC) { HandleMark hm; // handle scope - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif g1h->prepare_for_verify(); // Note: we can verify only the heap here. When an object is // marked, the previous value of the mark word (including --- old/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp 2015-09-16 15:18:32.000000000 -0700 +++ new/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp 2015-09-16 15:18:32.000000000 -0700 @@ -254,3 +254,52 @@ } } } + +void G1SATBCardTableModRefBS::write_ref_nmethod_post(oop* dst, nmethod* nm) { + oop obj = oopDesc::load_heap_oop(dst); + if (obj != NULL) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + HeapRegion* hr = g1h->heap_region_containing(obj); + hr->add_strong_code_root(nm); + } +} + +class G1EnsureLastRefToRegion : public OopClosure { + G1CollectedHeap* _g1h; + HeapRegion* _hr; + oop* _dst; + + bool _value; +public: + G1EnsureLastRefToRegion(G1CollectedHeap* g1h, HeapRegion* hr, oop* dst) : + _g1h(g1h), _hr(hr), _dst(dst), _value(true) {} + + void do_oop(oop* p) { + if (_value && p != _dst) { + oop obj = oopDesc::load_heap_oop(p); + if (obj != NULL) { + HeapRegion* hr = _g1h->heap_region_containing(obj); + if (hr == _hr) { + // Another reference to the same region. + _value = false; + } + } + } + } + void do_oop(narrowOop* p) { ShouldNotReachHere(); } + bool value() const { return _value; } +}; + +void G1SATBCardTableModRefBS::write_ref_nmethod_pre(oop* dst, nmethod* nm) { + oop obj = oopDesc::load_heap_oop(dst); + if (obj != NULL) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + HeapRegion* hr = g1h->heap_region_containing(obj); + G1EnsureLastRefToRegion ensure_last_ref(g1h, hr, dst); + nm->oops_do(&ensure_last_ref); + if (ensure_last_ref.value()) { + // Last reference to this region, remove the nmethod from the rset. + hr->remove_strong_code_root(nm); + } + } +} --- old/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp 2015-09-16 15:18:33.000000000 -0700 +++ new/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp 2015-09-16 15:18:33.000000000 -0700 @@ -38,6 +38,7 @@ // snapshot-at-the-beginning marking. class G1SATBCardTableModRefBS: public CardTableModRefBS { + friend class VMStructs; protected: enum G1CardValues { g1_young_gen = CT_MR_BS_last_reserved << 1 @@ -122,6 +123,9 @@ jbyte val = _byte_map[card_index]; return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); } + virtual void write_ref_nmethod_pre(oop* dst, nmethod* nm); + virtual void write_ref_nmethod_post(oop* dst, nmethod* nm); + }; template<> --- old/src/share/vm/gc/parallel/psMarkSweep.cpp 2015-09-16 15:18:33.000000000 -0700 +++ new/src/share/vm/gc/parallel/psMarkSweep.cpp 2015-09-16 15:18:33.000000000 -0700 @@ -189,7 +189,9 @@ allocate_stacks(); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif ref_processor()->enable_discovery(); ref_processor()->setup_policy(clear_all_softrefs); @@ -198,9 +200,11 @@ mark_sweep_phase2(); +#if defined(COMPILER2) || INCLUDE_JVMCI // Don't add any more derived pointers during phase3 - COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity")); - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); + assert(DerivedPointerTable::is_active(), "Sanity"); + DerivedPointerTable::set_active(false); +#endif mark_sweep_phase3(); @@ -245,7 +249,9 @@ CodeCache::gc_epilogue(); JvmtiExport::gc_epilogue(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif ref_processor()->enqueue_discovered_references(NULL); --- old/src/share/vm/gc/parallel/psParallelCompact.cpp 2015-09-16 15:18:34.000000000 -0700 +++ new/src/share/vm/gc/parallel/psParallelCompact.cpp 2015-09-16 15:18:34.000000000 -0700 @@ -1045,7 +1045,9 @@ CodeCache::gc_epilogue(); JvmtiExport::gc_epilogue(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif ref_processor()->enqueue_discovered_references(NULL); @@ -2042,7 +2044,9 @@ CodeCache::gc_prologue(); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif ref_processor()->enable_discovery(); ref_processor()->setup_policy(maximum_heap_compaction); @@ -2056,8 +2060,10 @@ && GCCause::is_user_requested_gc(gc_cause); summary_phase(vmthread_cm, maximum_heap_compaction || max_on_system_gc); - COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity")); - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_active(), "Sanity"); + DerivedPointerTable::set_active(false); +#endif // adjust_roots() updates Universe::_intArrayKlassObj which is // needed by the compaction for filling holes in the dense prefix. --- old/src/share/vm/gc/parallel/psScavenge.cpp 2015-09-16 15:18:35.000000000 -0700 +++ new/src/share/vm/gc/parallel/psScavenge.cpp 2015-09-16 15:18:35.000000000 -0700 @@ -351,7 +351,9 @@ } save_to_space_top_before_gc(); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif reference_processor()->enable_discovery(); reference_processor()->setup_policy(false); @@ -623,7 +625,9 @@ assert(young_gen->to_space()->is_empty(), "to space should be empty now"); } - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif NOT_PRODUCT(reference_processor()->verify_no_references_recorded()); --- old/src/share/vm/gc/serial/genMarkSweep.cpp 2015-09-16 15:18:36.000000000 -0700 +++ new/src/share/vm/gc/serial/genMarkSweep.cpp 2015-09-16 15:18:35.000000000 -0700 @@ -96,8 +96,10 @@ mark_sweep_phase2(); // Don't add any more derived pointers during phase3 - COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity")); - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_active(), "Sanity"); + DerivedPointerTable::set_active(false); +#endif mark_sweep_phase3(); --- old/src/share/vm/gc/shared/barrierSet.hpp 2015-09-16 15:18:36.000000000 -0700 +++ new/src/share/vm/gc/shared/barrierSet.hpp 2015-09-16 15:18:36.000000000 -0700 @@ -185,6 +185,9 @@ static void static_write_ref_array_pre(HeapWord* start, size_t count); static void static_write_ref_array_post(HeapWord* start, size_t count); + virtual void write_ref_nmethod_pre(oop* dst, nmethod* nm) {} + virtual void write_ref_nmethod_post(oop* dst, nmethod* nm) {} + protected: virtual void write_ref_array_work(MemRegion mr) = 0; public: --- old/src/share/vm/gc/shared/cardTableRS.cpp 2015-09-16 15:18:37.000000000 -0700 +++ new/src/share/vm/gc/shared/cardTableRS.cpp 2015-09-16 15:18:37.000000000 -0700 @@ -344,15 +344,22 @@ "[_begin, _end) = [" PTR_FORMAT "," PTR_FORMAT ")", p2i(jp), p2i(_begin), p2i(_end))); oop obj = oopDesc::load_decode_heap_oop(p); - guarantee(obj == NULL || (HeapWord*)obj >= _boundary, - err_msg("pointer " PTR_FORMAT " at " PTR_FORMAT " on " - "clean card crosses boundary" PTR_FORMAT, - p2i((HeapWord*)obj), p2i(jp), p2i(_boundary))); + if (!(obj == NULL || (HeapWord*)obj >= _boundary)) { + tty->print_cr("pointer " PTR_FORMAT " at " PTR_FORMAT " on " + "clean card crosses boundary" PTR_FORMAT, + p2i((HeapWord*)obj), p2i(jp), p2i(_boundary)); +#ifndef PRODUCT + obj->print(); +#endif + had_error = true; + } } public: + bool had_error; + VerifyCleanCardClosure(HeapWord* b, HeapWord* begin, HeapWord* end) : - _boundary(b), _begin(begin), _end(end) { + _boundary(b), _begin(begin), _end(end), had_error(false) { assert(b <= begin, err_msg("Error: boundary " PTR_FORMAT " should be at or below begin " PTR_FORMAT, p2i(b), p2i(begin))); @@ -394,6 +401,7 @@ // We don't need to do young-gen spaces. if (s->end() <= gen_boundary) return; MemRegion used = s->used_region(); + bool had_error = false; jbyte* cur_entry = byte_for(used.start()); jbyte* limit = byte_after(used.last()); @@ -432,6 +440,13 @@ for (HeapWord* cur = start_block; cur < end; cur += s->block_size(cur)) { if (s->block_is_obj(cur) && s->obj_is_alive(cur)) { oop(cur)->oop_iterate_no_header(&verify_blk, mr); + had_error |= verify_blk.had_error; + if (verify_blk.had_error) { + verify_blk.had_error = false; +#ifndef PRODUCT + oop(cur)->print(); +#endif + } } } } @@ -592,6 +607,7 @@ cur_entry++; } } + guarantee(!had_error, "Card table errors found"); } void CardTableRS::verify() { --- old/src/share/vm/gc/shared/collectedHeap.cpp 2015-09-16 15:18:38.000000000 -0700 +++ new/src/share/vm/gc/shared/collectedHeap.cpp 2015-09-16 15:18:37.000000000 -0700 @@ -227,7 +227,7 @@ void CollectedHeap::pre_initialize() { // Used for ReduceInitialCardMarks (when COMPILER2 is used); // otherwise remains unused. -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI _defer_initial_card_mark = ReduceInitialCardMarks && can_elide_tlab_store_barriers() && (DeferInitialCardMark || card_mark_must_follow_store()); #else @@ -535,7 +535,7 @@ " to threads list is doomed to failure!"); for (JavaThread *thread = Threads::first(); thread; thread = thread->next()) { if (use_tlab) thread->tlab().make_parsable(retire_tlabs); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // The deferred store barriers must all have been flushed to the // card-table (or other remembered set structure) before GC starts // processing the card-table (or other remembered set). --- old/src/share/vm/gc/shared/collectedHeap.hpp 2015-09-16 15:18:38.000000000 -0700 +++ new/src/share/vm/gc/shared/collectedHeap.hpp 2015-09-16 15:18:38.000000000 -0700 @@ -90,7 +90,8 @@ GCHeapLog* _gc_heap_log; - // Used in support of ReduceInitialCardMarks; only consulted if COMPILER2 is being used + // Used in support of ReduceInitialCardMarks; only consulted if COMPILER2 + // or INCLUDE_JVMCI is being used bool _defer_initial_card_mark; MemRegion _reserved; --- old/src/share/vm/gc/shared/genCollectedHeap.cpp 2015-09-16 15:18:39.000000000 -0700 +++ new/src/share/vm/gc/shared/genCollectedHeap.cpp 2015-09-16 15:18:39.000000000 -0700 @@ -1225,7 +1225,7 @@ }; void GenCollectedHeap::gc_epilogue(bool full) { -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI assert(DerivedPointerTable::is_empty(), "derived pointer present"); size_t actual_gap = pointer_delta((HeapWord*) (max_uintx-3), *(end_addr())); guarantee(actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps"); --- old/src/share/vm/gc/shared/referenceProcessor.cpp 2015-09-16 15:18:40.000000000 -0700 +++ new/src/share/vm/gc/shared/referenceProcessor.cpp 2015-09-16 15:18:39.000000000 -0700 @@ -54,8 +54,11 @@ java_lang_ref_SoftReference::set_clock(_soft_ref_timestamp_clock); _always_clear_soft_ref_policy = new AlwaysClearPolicy(); - _default_soft_ref_policy = new COMPILER2_PRESENT(LRUMaxHeapPolicy()) - NOT_COMPILER2(LRUCurrentHeapPolicy()); +#if defined(COMPILER2) || INCLUDE_JVMCI + _default_soft_ref_policy = new LRUMaxHeapPolicy(); +#else + _default_soft_ref_policy = new LRUCurrentHeapPolicy(); +#endif if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) { vm_exit_during_initialization("Could not allocate reference policy object"); } --- old/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp 2015-09-16 15:18:40.000000000 -0700 +++ new/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp 2015-09-16 15:18:40.000000000 -0700 @@ -40,6 +40,9 @@ void ThreadLocalAllocBuffer::clear_before_allocation() { _slow_refill_waste += (unsigned)remaining(); + // In debug mode we expect the storage above top to be uninitialized + // or filled with a padding object. + assert(!ZapUnusedHeapArea || VM_Version::reserve_for_allocation_prefetch() > 0 || top() == NULL || *(intptr_t*)top() != 0, "overzeroing detected"); make_parsable(true); // also retire the TLAB } --- old/src/share/vm/interpreter/interpreter.cpp 2015-09-16 15:18:41.000000000 -0700 +++ new/src/share/vm/interpreter/interpreter.cpp 2015-09-16 15:18:41.000000000 -0700 @@ -447,7 +447,7 @@ address AbstractInterpreter::deopt_reexecute_entry(Method* method, address bcp) { assert(method->contains(bcp), "just checkin'"); Bytecodes::Code code = Bytecodes::java_code_at(method, bcp); -#ifdef COMPILER1 +#if defined(COMPILER1) || INCLUDE_JVMCI if(code == Bytecodes::_athrow ) { return Interpreter::rethrow_exception_entry(); } --- old/src/share/vm/interpreter/interpreterRuntime.cpp 2015-09-16 15:18:42.000000000 -0700 +++ new/src/share/vm/interpreter/interpreterRuntime.cpp 2015-09-16 15:18:41.000000000 -0700 @@ -481,6 +481,17 @@ } } while (should_repeat == true); +#if INCLUDE_JVMCI + if (UseJVMCICompiler && h_method->method_data() != NULL) { + ResourceMark rm(thread); + ProfileData* pdata = h_method->method_data()->allocate_bci_to_data(current_bci, NULL); + if (pdata != NULL && pdata->is_BitData()) { + BitData* bit_data = (BitData*) pdata; + bit_data->set_exception_seen(); + } + } +#endif + // notify JVMTI of an exception throw; JVMTI will detect if this is a first // time throw or a stack unwinding throw and accordingly notify the debugger if (JvmtiExport::can_post_on_exceptions()) { --- old/src/share/vm/interpreter/linkResolver.cpp 2015-09-16 15:18:42.000000000 -0700 +++ new/src/share/vm/interpreter/linkResolver.cpp 2015-09-16 15:18:42.000000000 -0700 @@ -124,7 +124,7 @@ // Note: with several active threads, the must_be_compiled may be true // while can_be_compiled is false; remove assert // assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile"); - if (THREAD->is_Compiler_thread()) { + if (!THREAD->can_call_java()) { // don't force compilation, resolve was on behalf of compiler return; } @@ -450,7 +450,7 @@ } return result; } else if (iid == vmIntrinsics::_invokeGeneric - && !THREAD->is_Compiler_thread() + && THREAD->can_call_java() && appendix_result_or_null != NULL) { // This is a method with type-checking semantics. // We will ask Java code to spin an adapter method for it. --- old/src/share/vm/interpreter/linkResolver.hpp 2015-09-16 15:18:43.000000000 -0700 +++ new/src/share/vm/interpreter/linkResolver.hpp 2015-09-16 15:18:43.000000000 -0700 @@ -174,9 +174,11 @@ static methodHandle lookup_polymorphic_method(const LinkInfo& link_info, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS); + JVMCI_ONLY(public:) // Needed for CompilerToVM.resolveMethod() // Not Linktime so doesn't take LinkInfo static methodHandle lookup_instance_method_in_klasses ( KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); + JVMCI_ONLY(private:) // Similar loader constraint checking functions that throw // LinkageError with descriptive message. --- old/src/share/vm/interpreter/templateInterpreterGenerator.hpp 2015-09-16 15:18:44.000000000 -0700 +++ new/src/share/vm/interpreter/templateInterpreterGenerator.hpp 2015-09-16 15:18:44.000000000 -0700 @@ -59,6 +59,8 @@ address generate_safept_entry_for(TosState state, address runtime_entry); void generate_throw_exception(); + void lock_method(); + // Instruction generation void generate_and_dispatch (Template* t, TosState tos_out = ilgl); void set_vtos_entry_points (Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep); --- old/src/share/vm/memory/universe.cpp 2015-09-16 15:18:44.000000000 -0700 +++ new/src/share/vm/memory/universe.cpp 2015-09-16 15:18:44.000000000 -0700 @@ -143,6 +143,10 @@ // Heap int Universe::_verify_count = 0; +// Oop verification (see MacroAssembler::verify_oop) +uintptr_t Universe::_verify_oop_mask = 0; +uintptr_t Universe::_verify_oop_bits = (uintptr_t) -1; + int Universe::_base_vtable_size = 0; bool Universe::_bootstrapping = false; bool Universe::_fully_initialized = false; @@ -1171,17 +1175,9 @@ _verify_in_progress = false; } -// Oop verification (see MacroAssembler::verify_oop) - -static uintptr_t _verify_oop_data[2] = {0, (uintptr_t)-1}; -static uintptr_t _verify_klass_data[2] = {0, (uintptr_t)-1}; - #ifndef PRODUCT - -static void calculate_verify_data(uintptr_t verify_data[2], - HeapWord* low_boundary, - HeapWord* high_boundary) { +void Universe::calculate_verify_data(HeapWord* low_boundary, HeapWord* high_boundary) { assert(low_boundary < high_boundary, "bad interval"); // decide which low-order bits we require to be clear: @@ -1206,28 +1202,25 @@ // require address alignment, too: mask |= (alignSize - 1); - if (!(verify_data[0] == 0 && verify_data[1] == (uintptr_t)-1)) { - assert(verify_data[0] == mask && verify_data[1] == bits, "mask stability"); + if (!(_verify_oop_mask == 0 && _verify_oop_bits == (uintptr_t)-1)) { + assert(_verify_oop_mask == mask && _verify_oop_bits == bits, "mask stability"); } - verify_data[0] = mask; - verify_data[1] = bits; + _verify_oop_mask = mask; + _verify_oop_bits = bits; } // Oop verification (see MacroAssembler::verify_oop) uintptr_t Universe::verify_oop_mask() { MemRegion m = heap()->reserved_region(); - calculate_verify_data(_verify_oop_data, - m.start(), - m.end()); - return _verify_oop_data[0]; + calculate_verify_data(m.start(), m.end()); + return _verify_oop_mask; } - - uintptr_t Universe::verify_oop_bits() { - verify_oop_mask(); - return _verify_oop_data[1]; + MemRegion m = heap()->reserved_region(); + calculate_verify_data(m.start(), m.end()); + return _verify_oop_bits; } uintptr_t Universe::verify_mark_mask() { --- old/src/share/vm/memory/universe.hpp 2015-09-16 15:18:45.000000000 -0700 +++ new/src/share/vm/memory/universe.hpp 2015-09-16 15:18:45.000000000 -0700 @@ -248,9 +248,14 @@ // Debugging static int _verify_count; // number of verifies done + // True during call to verify(). Should only be set/cleared in verify(). static bool _verify_in_progress; + static uintptr_t _verify_oop_mask; + static uintptr_t _verify_oop_bits; + + static void calculate_verify_data(HeapWord* low_boundary, HeapWord* high_boundary) PRODUCT_RETURN; static void compute_verify_oop_data(); public: --- old/src/share/vm/oops/constantPool.hpp 2015-09-16 15:18:46.000000000 -0700 +++ new/src/share/vm/oops/constantPool.hpp 2015-09-16 15:18:46.000000000 -0700 @@ -662,6 +662,8 @@ int klass_ref_index_at(int which) { return impl_klass_ref_index_at(which, false); } int name_and_type_ref_index_at(int which) { return impl_name_and_type_ref_index_at(which, false); } + int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG + // Lookup for entries consisting of (name_index, signature_index) int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt) int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt) @@ -783,8 +785,6 @@ int impl_klass_ref_index_at(int which, bool uncached); int impl_name_and_type_ref_index_at(int which, bool uncached); - int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG - // Used while constructing constant pool (only by ClassFileParser) jint klass_index_at(int which) { assert(tag_at(which).is_klass_index(), "Corrupted constant pool"); --- old/src/share/vm/oops/method.cpp 2015-09-16 15:18:46.000000000 -0700 +++ new/src/share/vm/oops/method.cpp 2015-09-16 15:18:46.000000000 -0700 @@ -220,7 +220,7 @@ Thread* myThread = Thread::current(); methodHandle h_this(myThread, this); -#ifdef ASSERT +#if defined(ASSERT) && !INCLUDE_JVMCI bool has_capability = myThread->is_VM_thread() || myThread->is_ConcurrentGC_thread() || myThread->is_GC_task_thread(); @@ -1373,7 +1373,7 @@ // These two methods are static since a GC may move the Method bool Method::load_signature_classes(methodHandle m, TRAPS) { - if (THREAD->is_Compiler_thread()) { + if (!THREAD->can_call_java()) { // There is nothing useful this routine can do from within the Compile thread. // Hopefully, the signature contains only well-known classes. // We could scan for this and return true/false, but the caller won't care. @@ -1491,14 +1491,20 @@ void Method::print_name(outputStream* st) { Thread *thread = Thread::current(); ResourceMark rm(thread); - SignatureTypePrinter sig(signature(), st); st->print("%s ", is_static() ? "static" : "virtual"); - sig.print_returntype(); - st->print(" %s.", method_holder()->internal_name()); - name()->print_symbol_on(st); - st->print("("); - sig.print_parameters(); - st->print(")"); + if (WizardMode) { + st->print("%s.", method_holder()->internal_name()); + name()->print_symbol_on(st); + signature()->print_symbol_on(st); + } else { + SignatureTypePrinter sig(signature(), st); + sig.print_returntype(); + st->print(" %s.", method_holder()->internal_name()); + name()->print_symbol_on(st); + st->print("("); + sig.print_parameters(); + st->print(")"); + } } #endif // !PRODUCT || INCLUDE_JVMTI --- old/src/share/vm/oops/method.hpp 2015-09-16 15:18:47.000000000 -0700 +++ new/src/share/vm/oops/method.hpp 2015-09-16 15:18:47.000000000 -0700 @@ -685,8 +685,10 @@ TRAPS); static Klass* check_non_bcp_klass(Klass* klass); - // How many extra stack entries for invokedynamic when it's enabled - static const int extra_stack_entries_for_jsr292 = 1; + enum { + // How many extra stack entries for invokedynamic + extra_stack_entries_for_jsr292 = 1 + }; // this operates only on invoke methods: // presize interpreter frames for extra interpreter stack entries, if needed --- old/src/share/vm/oops/methodData.cpp 2015-09-16 15:18:48.000000000 -0700 +++ new/src/share/vm/oops/methodData.cpp 2015-09-16 15:18:48.000000000 -0700 @@ -413,13 +413,39 @@ } } +#if INCLUDE_JVMCI +void VirtualCallData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { + ReceiverTypeData::clean_weak_klass_links(is_alive_cl); + for (uint row = 0; row < method_row_limit(); row++) { + Method* p = method(row); + if (p != NULL && !p->method_holder()->is_loader_alive(is_alive_cl)) { + clear_method_row(row); + } + } +} + +void VirtualCallData::clean_weak_method_links() { + ReceiverTypeData::clean_weak_method_links(); + for (uint row = 0; row < method_row_limit(); row++) { + Method* p = method(row); + if (p != NULL && !p->on_stack()) { + clear_method_row(row); + } + } +} +#endif // INCLUDE_JVMCI + void ReceiverTypeData::print_receiver_data_on(outputStream* st) const { uint row; int entries = 0; for (row = 0; row < row_limit(); row++) { if (receiver(row) != NULL) entries++; } +#if INCLUDE_JVMCI + st->print_cr("count(%u) nonprofiled_count(%u) entries(%u)", count(), nonprofiled_count(), entries); +#else st->print_cr("count(%u) entries(%u)", count(), entries); +#endif int total = count(); for (row = 0; row < row_limit(); row++) { if (receiver(row) != NULL) { @@ -438,9 +464,38 @@ print_shared(st, "ReceiverTypeData", extra); print_receiver_data_on(st); } + +#if INCLUDE_JVMCI +void VirtualCallData::print_method_data_on(outputStream* st) const { + uint row; + int entries = 0; + for (row = 0; row < method_row_limit(); row++) { + if (method(row) != NULL) entries++; + } + tab(st); + st->print_cr("method_entries(%u)", entries); + int total = count(); + for (row = 0; row < method_row_limit(); row++) { + if (method(row) != NULL) { + total += method_count(row); + } + } + for (row = 0; row < method_row_limit(); row++) { + if (method(row) != NULL) { + tab(st); + method(row)->print_value_on(st); + st->print_cr("(%u %4.2f)", method_count(row), (float) method_count(row) / (float) total); + } + } +} +#endif + void VirtualCallData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "VirtualCallData", extra); print_receiver_data_on(st); +#if INCLUDE_JVMCI + print_method_data_on(st); +#endif } // ================================================================== @@ -665,7 +720,7 @@ } int MethodData::bytecode_cell_count(Bytecodes::Code code) { -#if defined(COMPILER1) && !defined(COMPILER2) +#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) return no_profile_data; #else switch (code) { @@ -796,6 +851,26 @@ return false; } +#if INCLUDE_JVMCI +int MethodData::compute_extra_data_count(int data_size, int empty_bc_count, bool needs_speculative_traps) { + if (!ProfileTraps) return 0; + + // Assume that up to 30% of the possibly trapping BCIs with no MDP will need to allocate one. + int extra_data_count = MIN2(empty_bc_count, MAX2(4, (empty_bc_count * 30) / 100)); + + // Make sure we have a minimum number of extra data slots to + // allocate SpeculativeTrapData entries. We would want to have one + // entry per compilation that inlines this method and for which + // some type speculation assumption fails. So the room we need for + // the SpeculativeTrapData entries doesn't directly depend on the + // size of the method. Because it's hard to estimate, we reserve + // space for an arbitrary number of entries. + int spec_data_count = (needs_speculative_traps ? SpecTrapLimitExtraEntries : 0) * + (SpeculativeTrapData::static_cell_count() + DataLayout::header_size_in_cells()); + + return MAX2(extra_data_count, spec_data_count); +} +#else int MethodData::compute_extra_data_count(int data_size, int empty_bc_count, bool needs_speculative_traps) { if (ProfileTraps) { // Assume that up to 3% of BCIs with no MDP will need to allocate one. @@ -823,6 +898,7 @@ return 0; } } +#endif // Compute the size of the MethodData* necessary to store // profiling information about a given method. Size is in bytes. @@ -835,7 +911,7 @@ while ((c = stream.next()) >= 0) { int size_in_bytes = compute_data_size(&stream); data_size += size_in_bytes; - if (size_in_bytes == 0) empty_bc_count += 1; + if (size_in_bytes == 0 JVMCI_ONLY(&& Bytecodes::can_trap(c))) empty_bc_count += 1; needs_speculative_traps = needs_speculative_traps || is_speculative_trap_bytecode(c); } int object_size = in_bytes(data_offset()) + data_size; @@ -869,7 +945,7 @@ // the segment in bytes. int MethodData::initialize_data(BytecodeStream* stream, int data_index) { -#if defined(COMPILER1) && !defined(COMPILER2) +#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) return 0; #else int cell_count = -1; @@ -1060,10 +1136,14 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) : _extra_data_lock(Monitor::leaf, "MDO extra data lock"), _parameters_type_data_di(parameters_uninitialized) { - No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC - ResourceMark rm; // Set the method back-pointer. _method = method(); + initialize(); +} + +void MethodData::initialize() { + No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC + ResourceMark rm; init(); set_creation_mileage(mileage_of(method())); @@ -1073,13 +1153,13 @@ int data_size = 0; int empty_bc_count = 0; // number of bytecodes lacking data _data[0] = 0; // apparently not set below. - BytecodeStream stream(method); + BytecodeStream stream(method()); Bytecodes::Code c; bool needs_speculative_traps = false; while ((c = stream.next()) >= 0) { int size_in_bytes = initialize_data(&stream, data_size); data_size += size_in_bytes; - if (size_in_bytes == 0) empty_bc_count += 1; + if (size_in_bytes == 0 JVMCI_ONLY(&& Bytecodes::can_trap(c))) empty_bc_count += 1; needs_speculative_traps = needs_speculative_traps || is_speculative_trap_bytecode(c); } _data_size = data_size; @@ -1097,7 +1177,7 @@ // the code for traps cells works. DataLayout *dp = data_layout_at(data_size + extra_size); - int arg_size = method->size_of_parameters(); + int arg_size = method()->size_of_parameters(); dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1); int arg_data_size = DataLayout::compute_size_in_bytes(arg_size+1); @@ -1126,6 +1206,7 @@ post_initialize(&stream); + assert(object_size == compute_allocation_size_in_bytes(methodHandle(_method)), "MethodData: computed size != initialized size"); set_size(object_size); } @@ -1146,6 +1227,10 @@ _num_blocks = 0; _would_profile = unknown; +#if INCLUDE_JVMCI + _jvmci_ir_size = 0; +#endif + #if INCLUDE_RTM_OPT _rtm_state = NoRTM; // No RTM lock eliding by default if (UseRTMLocking && --- old/src/share/vm/oops/methodData.hpp 2015-09-16 15:18:49.000000000 -0700 +++ new/src/share/vm/oops/methodData.hpp 2015-09-16 15:18:48.000000000 -0700 @@ -539,7 +539,11 @@ enum { // null_seen: // saw a null operand (cast/aastore/instanceof) - null_seen_flag = DataLayout::first_flag + 0 + null_seen_flag = DataLayout::first_flag + 0 +#if INCLUDE_JVMCI + // bytecode threw any exception + , exception_seen_flag = null_seen_flag + 1 +#endif }; enum { bit_cell_count = 0 }; // no additional data fields needed. public: @@ -563,6 +567,11 @@ bool null_seen() { return flag_at(null_seen_flag); } void set_null_seen() { set_flag_at(null_seen_flag); } +#if INCLUDE_JVMCI + // true if an exception was thrown at the specific BCI + bool exception_seen() { return flag_at(exception_seen_flag); } + void set_exception_seen() { set_flag_at(exception_seen_flag); } +#endif // Code generation support static int null_seen_byte_constant() { @@ -1166,7 +1175,22 @@ class ReceiverTypeData : public CounterData { protected: enum { +#if INCLUDE_JVMCI + // Description of the different counters + // ReceiverTypeData for instanceof/checkcast/aastore: + // C1/C2: count is incremented on type overflow and decremented for failed type checks + // JVMCI: count decremented for failed type checks and nonprofiled_count is incremented on type overflow + // TODO (chaeubl): in fact, JVMCI should also increment the count for failed type checks to mimic the C1/C2 behavior + // VirtualCallData for invokevirtual/invokeinterface: + // C1/C2: count is incremented on type overflow + // JVMCI: count is incremented on type overflow, nonprofiled_count is incremented on method overflow + + // JVMCI is interested in knowing the percentage of type checks involving a type not explicitly in the profile + nonprofiled_count_off_set = counter_cell_count, + receiver0_offset, +#else receiver0_offset = counter_cell_count, +#endif count0_offset, receiver_type_row_cell_count = (count0_offset + 1) - receiver0_offset }; @@ -1181,7 +1205,7 @@ virtual bool is_ReceiverTypeData() const { return true; } static int static_cell_count() { - return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count; + return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count JVMCI_ONLY(+ 1); } virtual int cell_count() const { @@ -1243,6 +1267,13 @@ set_count(0); set_receiver(row, NULL); set_receiver_count(row, 0); +#if INCLUDE_JVMCI + if (!this->is_VirtualCallData()) { + // if this is a ReceiverTypeData for JVMCI, the nonprofiled_count + // must also be reset (see "Description of the different counters" above) + set_nonprofiled_count(0); + } +#endif } // Code generation support @@ -1252,6 +1283,17 @@ static ByteSize receiver_count_offset(uint row) { return cell_offset(receiver_count_cell_index(row)); } +#if INCLUDE_JVMCI + static ByteSize nonprofiled_receiver_count_offset() { + return cell_offset(nonprofiled_count_off_set); + } + uint nonprofiled_count() const { + return uint_at(nonprofiled_count_off_set); + } + void set_nonprofiled_count(uint count) { + set_uint_at(nonprofiled_count_off_set, count); + } +#endif static ByteSize receiver_type_data_size() { return cell_offset(static_cell_count()); } @@ -1316,7 +1358,7 @@ static int static_cell_count() { // At this point we could add more profile state, e.g., for arguments. // But for now it's the same size as the base record type. - return ReceiverTypeData::static_cell_count(); + return ReceiverTypeData::static_cell_count() JVMCI_ONLY(+ (uint) MethodProfileWidth * receiver_type_row_cell_count); } virtual int cell_count() const { @@ -1338,6 +1380,64 @@ } #endif // CC_INTERP +#if INCLUDE_JVMCI + static ByteSize method_offset(uint row) { + return cell_offset(method_cell_index(row)); + } + static ByteSize method_count_offset(uint row) { + return cell_offset(method_count_cell_index(row)); + } + static int method_cell_index(uint row) { + return receiver0_offset + (row + TypeProfileWidth) * receiver_type_row_cell_count; + } + static int method_count_cell_index(uint row) { + return count0_offset + (row + TypeProfileWidth) * receiver_type_row_cell_count; + } + static uint method_row_limit() { + return MethodProfileWidth; + } + + Method* method(uint row) const { + assert(row < method_row_limit(), "oob"); + + Method* method = (Method*)intptr_at(method_cell_index(row)); + assert(method == NULL || method->is_method(), "must be"); + return method; + } + + uint method_count(uint row) const { + assert(row < method_row_limit(), "oob"); + return uint_at(method_count_cell_index(row)); + } + + void set_method(uint row, Method* m) { + assert((uint)row < method_row_limit(), "oob"); + set_intptr_at(method_cell_index(row), (uintptr_t)m); + } + + void set_method_count(uint row, uint count) { + assert(row < method_row_limit(), "oob"); + set_uint_at(method_count_cell_index(row), count); + } + + void clear_method_row(uint row) { + assert(row < method_row_limit(), "oob"); + // Clear total count - indicator of polymorphic call site (see comment for clear_row() in ReceiverTypeData). + set_nonprofiled_count(0); + set_method(row, NULL); + set_method_count(row, 0); + } + + // GC support + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); + + // Redefinition support + virtual void clean_weak_method_links(); +#endif + +#if INCLUDE_JVMCI + void print_method_data_on(outputStream* st) const; +#endif void print_data_on(outputStream* st, const char* extra = NULL) const; }; @@ -2053,10 +2153,11 @@ MethodData() : _extra_data_lock(Monitor::leaf, "MDO extra data lock") {}; // For ciMethodData bool is_methodData() const volatile { return true; } + void initialize(); // Whole-method sticky bits and flags enum { - _trap_hist_limit = 22, // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 22 JVMCI_ONLY(+5), // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values @@ -2104,6 +2205,11 @@ enum WouldProfile {unknown, no_profile, profile}; WouldProfile _would_profile; +#if INCLUDE_JVMCI + // Support for HotSpotMethodData.setCompiledIRSize(int) + int _jvmci_ir_size; +#endif + // Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size; @@ -2382,7 +2488,7 @@ // Return (uint)-1 for overflow. uint trap_count(int reason) const { - assert((uint)reason < _trap_hist_limit, "oob"); + assert((uint)reason < JVMCI_ONLY(2*) _trap_hist_limit, "oob"); return (int)((_trap_hist._array[reason]+1) & _trap_hist_mask) - 1; } // For loops: @@ -2391,17 +2497,13 @@ uint inc_trap_count(int reason) { // Count another trap, anywhere in this method. assert(reason >= 0, "must be single trap"); - if ((uint)reason < _trap_hist_limit) { - uint cnt1 = 1 + _trap_hist._array[reason]; - if ((cnt1 & _trap_hist_mask) != 0) { // if no counter overflow... - _trap_hist._array[reason] = cnt1; - return cnt1; - } else { - return _trap_hist_mask + (++_nof_overflow_traps); - } + assert((uint)reason < JVMCI_ONLY(2*) _trap_hist_limit, "oob"); + uint cnt1 = 1 + _trap_hist._array[reason]; + if ((cnt1 & _trap_hist_mask) != 0) { // if no counter overflow... + _trap_hist._array[reason] = cnt1; + return cnt1; } else { - // Could not represent the count in the histogram. - return (++_nof_overflow_traps); + return _trap_hist_mask + (++_nof_overflow_traps); } } @@ -2446,6 +2548,10 @@ return byte_offset_of(MethodData, _data[0]); } + static ByteSize trap_history_offset() { + return byte_offset_of(MethodData, _trap_hist._array); + } + static ByteSize invocation_counter_offset() { return byte_offset_of(MethodData, _invocation_counter); } --- old/src/share/vm/opto/compile.cpp 2015-09-16 15:18:49.000000000 -0700 +++ new/src/share/vm/opto/compile.cpp 2015-09-16 15:18:49.000000000 -0700 @@ -2254,6 +2254,8 @@ if (failing()) return; } } + // Ensure that major progress is now clear + C->clear_major_progress(); { // Verify that all previous optimizations produced a valid graph --- old/src/share/vm/opto/node.cpp 2015-09-16 15:18:50.000000000 -0700 +++ new/src/share/vm/opto/node.cpp 2015-09-16 15:18:50.000000000 -0700 @@ -47,6 +47,10 @@ #ifndef PRODUCT extern int nodes_created; #endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif #ifdef ASSERT @@ -456,6 +460,10 @@ _in[6] = n6; if (n6 != NULL) n6->add_out((Node *)this); } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + //------------------------------clone------------------------------------------ // Clone a Node. --- old/src/share/vm/opto/output.cpp 2015-09-16 15:18:51.000000000 -0700 +++ new/src/share/vm/opto/output.cpp 2015-09-16 15:18:51.000000000 -0700 @@ -973,7 +973,9 @@ assert(jvms->bci() >= InvocationEntryBci && jvms->bci() <= 0x10000, "must be a valid or entry BCI"); assert(!jvms->should_reexecute() || depth == max_depth, "reexecute allowed only for the youngest"); // Now we can describe the scope. - debug_info()->describe_scope(safepoint_pc_offset, scope_method, jvms->bci(), jvms->should_reexecute(), is_method_handle_invoke, return_oop, locvals, expvals, monvals); + methodHandle null_mh; + bool rethrow_exception = false; + debug_info()->describe_scope(safepoint_pc_offset, null_mh, scope_method, jvms->bci(), jvms->should_reexecute(), rethrow_exception, is_method_handle_invoke, return_oop, locvals, expvals, monvals); } // End jvms loop // Mark the end of the scope set. @@ -1056,7 +1058,8 @@ JVMState* jvms = youngest_jvms->of_depth(depth); ciMethod* method = jvms->has_method() ? jvms->method() : NULL; assert(!jvms->should_reexecute() || depth==max_depth, "reexecute allowed only for the youngest"); - debug_info->describe_scope(pc_offset, method, jvms->bci(), jvms->should_reexecute()); + methodHandle null_mh; + debug_info->describe_scope(pc_offset, null_mh, method, jvms->bci(), jvms->should_reexecute()); } // Mark the end of the scope set. --- old/src/share/vm/opto/superword.hpp 2015-09-16 15:18:51.000000000 -0700 +++ new/src/share/vm/opto/superword.hpp 2015-09-16 15:18:51.000000000 -0700 @@ -200,6 +200,31 @@ static const SWNodeInfo initial; }; +// JVMCI: OrderedPair is moved up to deal with compilation issues on Windows +//------------------------------OrderedPair--------------------------- +// Ordered pair of Node*. +class OrderedPair VALUE_OBJ_CLASS_SPEC { + protected: + Node* _p1; + Node* _p2; + public: + OrderedPair() : _p1(NULL), _p2(NULL) {} + OrderedPair(Node* p1, Node* p2) { + if (p1->_idx < p2->_idx) { + _p1 = p1; _p2 = p2; + } else { + _p1 = p2; _p2 = p1; + } + } + + bool operator==(const OrderedPair &rhs) { + return _p1 == rhs._p1 && _p2 == rhs._p2; + } + void print() { tty->print(" (%d, %d)", _p1->_idx, _p2->_idx); } + + static const OrderedPair initial; +}; + // -----------------------------SuperWord--------------------------------- // Transforms scalar operations into packed (superword) operations. class SuperWord : public ResourceObj { @@ -634,29 +659,4 @@ #endif }; - -//------------------------------OrderedPair--------------------------- -// Ordered pair of Node*. -class OrderedPair VALUE_OBJ_CLASS_SPEC { - protected: - Node* _p1; - Node* _p2; - public: - OrderedPair() : _p1(NULL), _p2(NULL) {} - OrderedPair(Node* p1, Node* p2) { - if (p1->_idx < p2->_idx) { - _p1 = p1; _p2 = p2; - } else { - _p1 = p2; _p2 = p1; - } - } - - bool operator==(const OrderedPair &rhs) { - return _p1 == rhs._p1 && _p2 == rhs._p2; - } - void print() { tty->print(" (%d, %d)", _p1->_idx, _p2->_idx); } - - static const OrderedPair initial; -}; - #endif // SHARE_VM_OPTO_SUPERWORD_HPP --- old/src/share/vm/precompiled/precompiled.hpp 2015-09-16 15:18:52.000000000 -0700 +++ new/src/share/vm/precompiled/precompiled.hpp 2015-09-16 15:18:52.000000000 -0700 @@ -293,6 +293,9 @@ # include "c1/c1_ValueType.hpp" # include "c1/c1_globals.hpp" #endif // COMPILER1 +#if INCLUDE_JVMCI +# include "jvmci/jvmci_globals.hpp" +#endif // INCLUDE_JVMCI #if INCLUDE_ALL_GCS # include "gc/cms/compactibleFreeListSpace.hpp" # include "gc/cms/concurrentMarkSweepGeneration.hpp" --- old/src/share/vm/prims/jni.cpp 2015-09-16 15:18:53.000000000 -0700 +++ new/src/share/vm/prims/jni.cpp 2015-09-16 15:18:53.000000000 -0700 @@ -81,6 +81,10 @@ #if INCLUDE_ALL_GCS #include "gc/g1/g1SATBCardTableModRefBS.hpp" #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif static jint CurrentVersion = JNI_VERSION_1_8; @@ -3984,6 +3988,19 @@ *vm = (JavaVM *)(&main_vm); *(JNIEnv**)penv = thread->jni_environment(); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + if (UseJVMCICompiler) { + // JVMCI is initialized on a CompilerThread + if (BootstrapJVMCI) { + JavaThread* THREAD = thread; + JVMCICompiler* compiler = JVMCICompiler::instance(CATCH); + compiler->bootstrap(); + } + } + } +#endif + // Tracks the time application was running before GC RuntimeService::record_application_start(); --- old/src/share/vm/prims/jvm.cpp 2015-09-16 15:18:53.000000000 -0700 +++ new/src/share/vm/prims/jvm.cpp 2015-09-16 15:18:53.000000000 -0700 @@ -427,6 +427,8 @@ const char* compiler_name = "HotSpot " CSIZE "Client Compiler"; #elif defined(COMPILER2) const char* compiler_name = "HotSpot " CSIZE "Server Compiler"; +#elif INCLUDE_JVMCI + #error "INCLUDE_JVMCI should imply TIERED" #else const char* compiler_name = ""; #endif // compilers --- old/src/share/vm/prims/jvmtiCodeBlobEvents.cpp 2015-09-16 15:18:54.000000000 -0700 +++ new/src/share/vm/prims/jvmtiCodeBlobEvents.cpp 2015-09-16 15:18:54.000000000 -0700 @@ -266,7 +266,7 @@ address scopes_data = nm->scopes_data_begin(); for( pcd = nm->scopes_pcs_begin(); pcd < nm->scopes_pcs_end(); ++pcd ) { - ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute(), pcd->return_oop()); + ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute(), pcd->rethrow_exception(), pcd->return_oop()); ScopeDesc *sd = &sc0; while( !sd->is_top() ) { sd = sd->sender(); } int bci = sd->bci(); --- old/src/share/vm/prims/methodHandles.cpp 2015-09-16 15:18:55.000000000 -0700 +++ new/src/share/vm/prims/methodHandles.cpp 2015-09-16 15:18:55.000000000 -0700 @@ -345,7 +345,7 @@ Symbol* MethodHandles::signature_polymorphic_intrinsic_name(vmIntrinsics::ID iid) { - assert(is_signature_polymorphic_intrinsic(iid), err_msg("iid=%d", iid)); + assert(is_signature_polymorphic_intrinsic(iid), err_msg("%d %s", iid, vmIntrinsics::name_at(iid))); switch (iid) { case vmIntrinsics::_invokeBasic: return vmSymbols::invokeBasic_name(); case vmIntrinsics::_linkToVirtual: return vmSymbols::linkToVirtual_name(); @@ -353,7 +353,7 @@ case vmIntrinsics::_linkToSpecial: return vmSymbols::linkToSpecial_name(); case vmIntrinsics::_linkToInterface: return vmSymbols::linkToInterface_name(); } - assert(false, ""); + fatal(err_msg("unexpected intrinsic id: %d %s", iid, vmIntrinsics::name_at(iid))); return 0; } @@ -365,7 +365,7 @@ case vmIntrinsics::_linkToSpecial: return JVM_REF_invokeSpecial; case vmIntrinsics::_linkToInterface: return JVM_REF_invokeInterface; } - assert(false, err_msg("iid=%d", iid)); + fatal(err_msg("unexpected intrinsic id: %d %s", iid, vmIntrinsics::name_at(iid))); return 0; } --- old/src/share/vm/prims/nativeLookup.cpp 2015-09-16 15:18:56.000000000 -0700 +++ new/src/share/vm/prims/nativeLookup.cpp 2015-09-16 15:18:56.000000000 -0700 @@ -111,6 +111,10 @@ void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls); void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass); void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass); +#if INCLUDE_JVMCI + void JNICALL JVM_InitializeJVMCINatives(JNIEnv *env, jclass compilerToVMClass); + jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); +#endif } #define CC (char*) /* cast a literal from (const char*) */ @@ -121,6 +125,10 @@ { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, { CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) }, { CC"Java_sun_hotspot_WhiteBox_registerNatives", NULL, FN_PTR(JVM_RegisterWhiteBoxMethods) }, +#if INCLUDE_JVMCI + { CC"Java_jdk_internal_jvmci_runtime_JVMCI_initializeRuntime", NULL, FN_PTR(JVM_GetJVMCIRuntime) }, + { CC"Java_jdk_internal_jvmci_hotspot_CompilerToVM_init", NULL, FN_PTR(JVM_InitializeJVMCINatives) }, +#endif }; static address lookup_special_native(char* jni_name) { --- old/src/share/vm/runtime/advancedThresholdPolicy.cpp 2015-09-16 15:18:56.000000000 -0700 +++ new/src/share/vm/runtime/advancedThresholdPolicy.cpp 2015-09-16 15:18:56.000000000 -0700 @@ -162,6 +162,9 @@ // Called with the queue locked and with at least one element CompileTask* AdvancedThresholdPolicy::select_task(CompileQueue* compile_queue) { +#if INCLUDE_JVMCI + CompileTask *max_non_jvmci_task = NULL; +#endif CompileTask *max_task = NULL; Method* max_method = NULL; jlong t = os::javaTimeMillis(); @@ -179,6 +182,7 @@ if (PrintTieredEvents) { print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel)task->comp_level()); } + task->log_task_dequeued("stale"); compile_queue->remove_and_mark_stale(task); method->clear_queued_for_compilation(); task = next_task; @@ -194,6 +198,15 @@ task = next_task; } +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + if (max_non_jvmci_task != NULL) { + max_task = max_non_jvmci_task; + max_method = max_task->method(); + } + } +#endif + if (max_task->comp_level() == CompLevel_full_profile && TieredStopAtLevel > CompLevel_full_profile && is_method_profiled(max_method)) { max_task->set_comp_level(CompLevel_limited_profile); @@ -354,6 +367,14 @@ if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { next_level = CompLevel_full_optimization; } else if ((this->*p)(i, b, cur_level, method)) { +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + // Since JVMCI takes a while to warm up, its queue inevitably backs up during + // early VM execution. + next_level = CompLevel_full_profile; + break; + } +#endif // C1-generated fully profiled code is about 30% slower than the limited profile // code that has only invocation and backedge counters. The observation is that // if C2 queue is large enough we can spend too much time in the fully profiled code @@ -362,7 +383,7 @@ // we choose to compile a limited profiled version and then recompile with full profiling // when the load on C2 goes down. if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) > - Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { + Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { next_level = CompLevel_limited_profile; } else { next_level = CompLevel_full_profile; --- old/src/share/vm/runtime/arguments.cpp 2015-09-16 15:18:57.000000000 -0700 +++ new/src/share/vm/runtime/arguments.cpp 2015-09-16 15:18:57.000000000 -0700 @@ -51,6 +51,9 @@ #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" #include "utilities/stringUtils.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#endif #if INCLUDE_ALL_GCS #include "gc/cms/compactibleFreeListSpace.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" @@ -214,6 +217,8 @@ // Set OS specific system properties values os::init_system_properties_values(); + + JVMCI_ONLY(JVMCIRuntime::parse_properties(&_system_properties);) } // Update/Initialize System properties after JDK version number is known @@ -1096,7 +1101,7 @@ } } -#if defined(COMPILER2) || defined(_LP64) || !INCLUDE_CDS +#if defined(COMPILER2) || INCLUDE_JVMCI || defined(_LP64) || !INCLUDE_CDS // Conflict: required to use shared spaces (-Xshare:on), but // incompatible command line options were chosen. @@ -1556,7 +1561,7 @@ void Arguments::set_ergonomics_flags() { select_gc(); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // Shared spaces work fine with other GCs but causes bytecode rewriting // to be disabled, which hurts interpreter performance and decreases // server performance. When -server is specified, keep the default off @@ -1643,7 +1648,7 @@ void Arguments::set_g1_gc_flags() { assert(UseG1GC, "Error"); -#ifdef COMPILER1 +#if defined(COMPILER1) || INCLUDE_JVMCI FastTLABRefill = false; #endif FLAG_SET_DEFAULT(ParallelGCThreads, Abstract_VM_Version::parallel_worker_threads()); @@ -2130,6 +2135,22 @@ } #endif } +#if INCLUDE_JVMCI + if (EnableJVMCI) { + if (!ScavengeRootsInCode) { + warning("forcing ScavengeRootsInCode non-zero because JVMCI is enabled"); + ScavengeRootsInCode = 1; + } + if (FLAG_IS_DEFAULT(TypeProfileLevel)) { + TypeProfileLevel = 0; + } + if (UseJVMCICompiler) { + if (FLAG_IS_DEFAULT(TypeProfileWidth)) { + TypeProfileWidth = 8; + } + } + } +#endif // Check lower bounds of the code cache // Template Interpreter code is approximately 3X larger in debug builds. @@ -3265,6 +3286,32 @@ const char* fileSep = os::file_separator(); sprintf(path, "%s%slib%sendorsed", Arguments::get_java_home(), fileSep, fileSep); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // Append lib/jvmci/*.jar to boot class path + char jvmciDir[JVM_MAXPATHLEN]; + const char* fileSep = os::file_separator(); + jio_snprintf(jvmciDir, sizeof(jvmciDir), "%s%slib%sjvmci", Arguments::get_java_home(), fileSep, fileSep); + DIR* dir = os::opendir(jvmciDir); + if (dir != NULL) { + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(jvmciDir), mtInternal); + while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { + const char* name = entry->d_name; + const char* ext = name + strlen(name) - 4; + if (ext > name && strcmp(ext, ".jar") == 0) { + char fileName[JVM_MAXPATHLEN]; + jio_snprintf(fileName, sizeof(fileName), "%s%s%s", jvmciDir, fileSep, name); + scp_p->add_suffix(fileName); + scp_assembly_required = true; + } + } + FREE_C_HEAP_ARRAY(char, dbuf); + os::closedir(dir); + } + } +#endif // INCLUDE_JVMCI + if (CheckEndorsedAndExtDirs) { int nonEmptyDirs = 0; // check endorsed directory @@ -3323,7 +3370,7 @@ FLAG_SET_ERGO(uintx, InitialTenuringThreshold, MaxTenuringThreshold); } -#ifndef COMPILER2 +#if !defined(COMPILER2) && !INCLUDE_JVMCI // Don't degrade server performance for footprint if (FLAG_IS_DEFAULT(UseLargePages) && MaxHeapSize < LargePageHeapSizeThreshold) { @@ -3333,7 +3380,7 @@ FLAG_SET_DEFAULT(UseLargePages, false); } -#else +#elif defined(COMPILER2) if (!FLAG_IS_DEFAULT(OptoLoopAlignment) && FLAG_IS_DEFAULT(MaxLoopPad)) { FLAG_SET_DEFAULT(MaxLoopPad, OptoLoopAlignment-1); } @@ -3879,6 +3926,9 @@ #ifdef COMPILER1 || !UseFastLocking #endif // COMPILER1 +#if INCLUDE_JVMCI + || !JVMCIUseFastLocking +#endif ) { if (!FLAG_IS_DEFAULT(UseBiasedLocking) && UseBiasedLocking) { // flag set to true on command line; warn the user that they --- old/src/share/vm/runtime/commandLineFlagConstraintList.cpp 2015-09-16 15:18:58.000000000 -0700 +++ new/src/share/vm/runtime/commandLineFlagConstraintList.cpp 2015-09-16 15:18:58.000000000 -0700 @@ -33,6 +33,9 @@ #include "runtime/commandLineFlagConstraintsRuntime.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" +#if INCLUDE_JVMCI +#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" +#endif class CommandLineFlagConstraint_bool : public CommandLineFlagConstraint { CommandLineFlagConstraintFunc_bool _constraint; @@ -251,6 +254,18 @@ IGNORE_RANGE, EMIT_CONSTRAINT_CHECK)); +#if INCLUDE_JVMCI + emit_constraint_no(NULL JVMCI_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, + EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, + EMIT_CONSTRAINT_PRODUCT_FLAG, + EMIT_CONSTRAINT_PD_PRODUCT_FLAG, + EMIT_CONSTRAINT_DIAGNOSTIC_FLAG, + EMIT_CONSTRAINT_EXPERIMENTAL_FLAG, + EMIT_CONSTRAINT_NOTPRODUCT_FLAG, + IGNORE_RANGE, + EMIT_CONSTRAINT_CHECK)); +#endif // INCLUDE_JVMCI + #ifdef COMPILER1 emit_constraint_no(NULL C1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, --- old/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp 2015-09-16 15:18:59.000000000 -0700 +++ new/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp 2015-09-16 15:18:58.000000000 -0700 @@ -58,7 +58,7 @@ */ Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { int min_number_of_compiler_threads = 0; -#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) +#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) && !INCLUDE_JVMCI // case 1 #else if (!TieredCompilation || (TieredStopAtLevel < CompLevel_full_optimization)) { --- old/src/share/vm/runtime/deoptimization.cpp 2015-09-16 15:18:59.000000000 -0700 +++ new/src/share/vm/runtime/deoptimization.cpp 2015-09-16 15:18:59.000000000 -0700 @@ -37,6 +37,7 @@ #include "memory/resourceArea.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" +#include "oops/fieldStreams.hpp" #include "oops/verifyOopClosure.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/biasedLocking.hpp" @@ -55,6 +56,12 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#endif + + bool DeoptimizationMarker::_is_active = false; Deoptimization::UnrollBlock::UnrollBlock(int size_of_deoptimized_frame, @@ -132,6 +139,9 @@ // handler. Note this fact before we start generating temporary frames // that can confuse an asynchronous stack walker. This counter is // decremented at the end of unpack_frames(). + if (TraceDeoptimization) { + tty->print_cr("Deoptimizing thread " INTPTR_FORMAT, thread); + } thread->inc_in_deopt_handler(); return fetch_unroll_info_helper(thread); @@ -179,11 +189,13 @@ bool realloc_failures = false; -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // Reallocate the non-escaping objects and restore their fields. Then // relock objects if synchronization on them was eliminated. +#ifndef INCLUDE_JVMCI if (DoEscapeAnalysis || EliminateNestedLocks) { if (EliminateAllocations) { +#endif // INCLUDE_JVMCI assert (chunk->at(0)->scope() != NULL,"expect only compiled java frames"); GrowableArray* objects = chunk->at(0)->scope()->objects(); @@ -226,8 +238,10 @@ // Restore result. deoptee.set_saved_oop_result(&map, return_value()); } +#ifndef INCLUDE_JVMCI } if (EliminateLocks) { +#endif // INCLUDE_JVMCI #ifndef PRODUCT bool first = true; #endif @@ -238,7 +252,7 @@ if (monitors->is_nonempty()) { relock_objects(monitors, thread, realloc_failures); #ifndef PRODUCT - if (TraceDeoptimization) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; for (int j = 0; j < monitors->length(); j++) { MonitorInfo* mi = monitors->at(j); @@ -256,19 +270,22 @@ } } } -#endif +#endif // !PRODUCT } } +#ifndef INCLUDE_JVMCI } } -#endif // COMPILER2 +#endif // INCLUDE_JVMCI +#endif // COMPILER2 || INCLUDE_JVMCI + // Ensure that no safepoint is taken after pointers have been stored // in fields of rematerialized objects. If a safepoint occurs from here on // out the java state residing in the vframeArray will be missed. No_Safepoint_Verifier no_safepoint; vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk, realloc_failures); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (realloc_failures) { pop_frames_failed_reallocs(thread, array); } @@ -318,7 +335,11 @@ unpack_sp = deoptee.unextended_sp(); #ifdef ASSERT - assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub(), "just checking"); + assert(cb->is_deoptimization_stub() || + cb->is_uncommon_trap_stub() || + strcmp("Stub", cb->name()) == 0 || + strcmp("Stub", cb->name()) == 0, + err_msg("unexpected code blob: %s", cb->name())); #endif #else intptr_t* unpack_sp = stub_frame.sender(&dummy_map).unextended_sp(); @@ -721,7 +742,7 @@ Deoptimization::DeoptAction Deoptimization::_unloaded_action = Deoptimization::Action_reinterpret; -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArray* objects, TRAPS) { Handle pending_exception(thread->pending_exception()); const char* exception_file = thread->exception_file(); @@ -769,77 +790,6 @@ return failures; } -// This assumes that the fields are stored in ObjectValue in the same order -// they are yielded by do_nonstatic_fields. -class FieldReassigner: public FieldClosure { - frame* _fr; - RegisterMap* _reg_map; - ObjectValue* _sv; - InstanceKlass* _ik; - oop _obj; - - int _i; -public: - FieldReassigner(frame* fr, RegisterMap* reg_map, ObjectValue* sv, oop obj) : - _fr(fr), _reg_map(reg_map), _sv(sv), _obj(obj), _i(0) {} - - int i() const { return _i; } - - - void do_field(fieldDescriptor* fd) { - intptr_t val; - StackValue* value = - StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(i())); - int offset = fd->offset(); - switch (fd->field_type()) { - case T_OBJECT: case T_ARRAY: - assert(value->type() == T_OBJECT, "Agreement."); - _obj->obj_field_put(offset, value->get_obj()()); - break; - - case T_LONG: case T_DOUBLE: { - assert(value->type() == T_INT, "Agreement."); - StackValue* low = - StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(++_i)); -#ifdef _LP64 - jlong res = (jlong)low->get_int(); -#else -#ifdef SPARC - // For SPARC we have to swap high and low words. - jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); -#else - jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); -#endif //SPARC -#endif - _obj->long_field_put(offset, res); - break; - } - // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. - case T_INT: case T_FLOAT: // 4 bytes. - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->int_field_put(offset, (jint)*((jint*)&val)); - break; - - case T_SHORT: case T_CHAR: // 2 bytes - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->short_field_put(offset, (jshort)*((jint*)&val)); - break; - - case T_BOOLEAN: case T_BYTE: // 1 byte - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->bool_field_put(offset, (jboolean)*((jint*)&val)); - break; - - default: - ShouldNotReachHere(); - } - _i++; - } -}; - // restore elements of an eliminated type array void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) { int index = 0; @@ -867,11 +817,43 @@ } // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. - case T_INT: case T_FLOAT: // 4 bytes. + case T_INT: case T_FLOAT: { // 4 bytes. assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - obj->int_at_put(index, (jint)*((jint*)&val)); + bool big_value = false; + if (i + 1 < sv->field_size() && type == T_INT) { + if (sv->field_at(i)->is_location()) { + Location::Type type = ((LocationValue*) sv->field_at(i))->location().type(); + if (type == Location::dbl || type == Location::lng) { + big_value = true; + } + } else if (sv->field_at(i)->is_constant_int()) { + ScopeValue* next_scope_field = sv->field_at(i + 1); + if (next_scope_field->is_constant_long() || next_scope_field->is_constant_double()) { + big_value = true; + } + } + } + + if (big_value) { + StackValue* low = StackValue::create_stack_value(fr, reg_map, sv->field_at(++i)); + #ifdef _LP64 + jlong res = (jlong)low->get_int(); + #else + #ifdef SPARC + // For SPARC we have to swap high and low words. + jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); + #else + jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); + #endif //SPARC + #endif + obj->int_at_put(index, (jint)*((jint*)&res)); + obj->int_at_put(++index, (jint)*(((jint*)&res) + 1)); + } else { + val = value->get_int(); + obj->int_at_put(index, (jint)*((jint*)&val)); + } break; + } case T_SHORT: case T_CHAR: // 2 bytes assert(value->type() == T_INT, "Agreement."); @@ -902,6 +884,117 @@ } } +class ReassignedField { +public: + int _offset; + BasicType _type; +public: + ReassignedField() { + _offset = 0; + _type = T_ILLEGAL; + } +}; + +int compare(ReassignedField* left, ReassignedField* right) { + return left->_offset - right->_offset; +} + +// Restore fields of an eliminated instance object using the same field order +// returned by HotSpotResolvedObjectTypeImpl.getInstanceFields(true) +static int reassign_fields_by_klass(InstanceKlass* klass, frame* fr, RegisterMap* reg_map, ObjectValue* sv, int svIndex, oop obj) { + if (klass->superklass() != NULL) { + svIndex = reassign_fields_by_klass(klass->superklass(), fr, reg_map, sv, svIndex, obj); + } + + GrowableArray* fields = new GrowableArray(); + for (AllFieldStream fs(klass); !fs.done(); fs.next()) { + if (!fs.access_flags().is_static()) { + ReassignedField field; + field._offset = fs.offset(); + field._type = FieldType::basic_type(fs.signature()); + fields->append(field); + } + } + fields->sort(compare); + for (int i = 0; i < fields->length(); i++) { + intptr_t val; + ScopeValue* scope_field = sv->field_at(svIndex); + StackValue* value = StackValue::create_stack_value(fr, reg_map, scope_field); + int offset = fields->at(i)._offset; + BasicType type = fields->at(i)._type; + switch (type) { + case T_OBJECT: case T_ARRAY: + assert(value->type() == T_OBJECT, "Agreement."); + obj->obj_field_put(offset, value->get_obj()()); + break; + + // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. + case T_INT: case T_FLOAT: { // 4 bytes. + assert(value->type() == T_INT, "Agreement."); + bool big_value = false; + if (i+1 < fields->length() && fields->at(i+1)._type == T_INT) { + if (scope_field->is_location()) { + Location::Type type = ((LocationValue*) scope_field)->location().type(); + if (type == Location::dbl || type == Location::lng) { + big_value = true; + } + } + if (scope_field->is_constant_int()) { + ScopeValue* next_scope_field = sv->field_at(svIndex + 1); + if (next_scope_field->is_constant_long() || next_scope_field->is_constant_double()) { + big_value = true; + } + } + } + + if (big_value) { + i++; + assert(i < fields->length(), "second T_INT field needed"); + assert(fields->at(i)._type == T_INT, "T_INT field needed"); + } else { + val = value->get_int(); + obj->int_field_put(offset, (jint)*((jint*)&val)); + break; + } + } + /* no break */ + + case T_LONG: case T_DOUBLE: { + assert(value->type() == T_INT, "Agreement."); + StackValue* low = StackValue::create_stack_value(fr, reg_map, sv->field_at(++svIndex)); +#ifdef _LP64 + jlong res = (jlong)low->get_int(); +#else +#ifdef SPARC + // For SPARC we have to swap high and low words. + jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); +#else + jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); +#endif //SPARC +#endif + obj->long_field_put(offset, res); + break; + } + + case T_SHORT: case T_CHAR: // 2 bytes + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->short_field_put(offset, (jshort)*((jint*)&val)); + break; + + case T_BOOLEAN: case T_BYTE: // 1 byte + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->bool_field_put(offset, (jboolean)*((jint*)&val)); + break; + + default: + ShouldNotReachHere(); + } + svIndex++; + } + return svIndex; +} // restore fields of all eliminated objects and arrays void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects, bool realloc_failures) { @@ -910,14 +1003,16 @@ KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())); Handle obj = sv->value(); assert(obj.not_null() || realloc_failures, "reallocation was missed"); + if (PrintDeoptimizationDetails) { + tty->print_cr("reassign fields for object of type %s!", k->name()->as_C_string()); + } if (obj.is_null()) { continue; } if (k->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(k()); - FieldReassigner reassign(fr, reg_map, sv, obj()); - ik->do_nonstatic_fields(&reassign); + reassign_fields_by_klass(ik, fr, reg_map, sv, 0, obj()); } else if (k->oop_is_typeArray()) { TypeArrayKlass* ak = TypeArrayKlass::cast(k()); reassign_type_array_elements(fr, reg_map, sv, (typeArrayOop) obj(), ak->element_type()); @@ -982,13 +1077,13 @@ } } #endif -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray* chunk, bool realloc_failures) { Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, fr.pc(), fr.sp()); #ifndef PRODUCT - if (TraceDeoptimization) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; tty->print("DEOPT PACKING thread " INTPTR_FORMAT " ", thread); fr.print_on(tty); @@ -1033,7 +1128,7 @@ assert(array->structural_compare(thread, chunk), "just checking"); #ifndef PRODUCT - if (TraceDeoptimization) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; tty->print_cr(" Created vframeArray " INTPTR_FORMAT, array); } @@ -1042,7 +1137,7 @@ return array; } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array) { // Reallocation of some scalar replaced objects failed. Record // that we need to pop all the interpreter frames for the @@ -1150,17 +1245,38 @@ } -void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr) { +void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) { assert(fr.can_be_deoptimized(), "checking frame type"); - gather_statistics(Reason_constraint, Action_none, Bytecodes::_illegal); + gather_statistics(reason, Action_none, Bytecodes::_illegal); + + if (LogCompilation && xtty != NULL) { + nmethod* nm = fr.cb()->as_nmethod_or_null(); + assert(nm != NULL, "only compiled methods can deopt"); - // Patch the nmethod so that when execution returns to it we will + ttyLocker ttyl; + xtty->begin_head("deoptimized thread='" UINTX_FORMAT "'", thread->osthread()->thread_id()); + nm->log_identity(xtty); + xtty->end_head(); + for (ScopeDesc* sd = nm->scope_desc_at(fr.pc()); ; sd = sd->sender()) { + xtty->begin_elem("jvms bci='%d'", sd->bci()); + xtty->method(sd->method()); + xtty->end_elem(); + if (sd->is_top()) break; + } + xtty->tail("deoptimized"); + } + + // Patch the compiled method so that when execution returns to it we will // deopt the execution state and return to the interpreter. fr.deoptimize(thread); } void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map) { + deoptimize(thread, fr, map, Reason_constraint); +} + +void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map, DeoptReason reason) { // Deoptimize only if the frame comes from compile code. // Do not deoptimize the frame which is already patched // during the execution of the loops below. @@ -1172,12 +1288,12 @@ if (UseBiasedLocking) { revoke_biases_of_monitors(thread, fr, map); } - deoptimize_single_frame(thread, fr); + deoptimize_single_frame(thread, fr, reason); } -void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id) { +void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason) { assert(thread == Thread::current() || SafepointSynchronize::is_at_safepoint(), "can only deoptimize other thread at a safepoint"); // Compute frame and register map based on thread and sp. @@ -1186,19 +1302,22 @@ while (fr.id() != id) { fr = fr.sender(®_map); } - deoptimize(thread, fr, ®_map); + deoptimize(thread, fr, ®_map, reason); } -void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) { +void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason) { if (thread == Thread::current()) { - Deoptimization::deoptimize_frame_internal(thread, id); + Deoptimization::deoptimize_frame_internal(thread, id, reason); } else { - VM_DeoptimizeFrame deopt(thread, id); + VM_DeoptimizeFrame deopt(thread, id, reason); VMThread::execute(&deopt); } } +void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) { + deoptimize_frame(thread, id, Reason_constraint); +} // JVMTI PopFrame support JRT_LEAF(void, Deoptimization::popframe_preserve_args(JavaThread* thread, int bytes_to_save, void* start_address)) @@ -1225,7 +1344,7 @@ return mdo; } -#if defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI void Deoptimization::load_class_by_index(constantPoolHandle constant_pool, int index, TRAPS) { // in case of an unresolved klass entry, load the class. if (constant_pool->tag_at(index).is_unresolved_klass()) { @@ -1288,7 +1407,12 @@ thread->inc_in_deopt_handler(); // We need to update the map if we have biased locking. +#if INCLUDE_JVMCI + // JVMCI might need to get an exception from the stack, which in turn requires the register map to be valid + RegisterMap reg_map(thread, true); +#else RegisterMap reg_map(thread, UseBiasedLocking); +#endif frame stub_frame = thread->last_frame(); frame fr = stub_frame.sender(®_map); // Make sure the calling nmethod is not getting deoptimized and removed @@ -1296,8 +1420,8 @@ nmethodLocker nl(fr.pc()); // Log a message - Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT, - trap_request, fr.pc()); + Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT " relative=" INTPTR_FORMAT, + trap_request, fr.pc(), fr.pc() - fr.cb()->code_begin()); { ResourceMark rm; @@ -1307,6 +1431,9 @@ DeoptReason reason = trap_request_reason(trap_request); DeoptAction action = trap_request_action(trap_request); +#if INCLUDE_JVMCI + int debug_id = trap_request_debug_id(trap_request); +#endif jint unloaded_class_index = trap_request_index(trap_request); // CP idx or -1 vframe* vf = vframe::new_vframe(&fr, ®_map, thread); @@ -1315,10 +1442,71 @@ nmethod* nm = cvf->code(); ScopeDesc* trap_scope = cvf->scope(); + + if (TraceDeoptimization) { + ttyLocker ttyl; + tty->print_cr(" bci=%d pc=" INTPTR_FORMAT ", relative_pc=%d, method=%s" JVMCI_ONLY(", debug_id=%d"), trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name_and_sig_as_C_string() +#if INCLUDE_JVMCI + , debug_id +#endif + ); + } + methodHandle trap_method = trap_scope->method(); int trap_bci = trap_scope->bci(); +#if INCLUDE_JVMCI + oop speculation = thread->pending_failed_speculation(); + if (nm->is_compiled_by_jvmci()) { + if (speculation != NULL) { + oop speculation_log = nm->speculation_log(); + if (speculation_log != NULL) { + if (TraceDeoptimization || TraceUncollectedSpeculations) { + if (SpeculationLog::lastFailed(speculation_log) != NULL) { + tty->print_cr("A speculation that was not collected by the compiler is being overwritten"); + } + } + if (TraceDeoptimization) { + tty->print_cr("Saving speculation to speculation log"); + } + SpeculationLog::set_lastFailed(speculation_log, speculation); + } else { + if (TraceDeoptimization) { + tty->print_cr("Speculation present but no speculation log"); + } + } + thread->set_pending_failed_speculation(NULL); + } else { + if (TraceDeoptimization) { + tty->print_cr("No speculation"); + } + } + } else { + assert(speculation == NULL, "There should not be a speculation for method compiled by non-JVMCI compilers"); + } + + if (trap_bci == SynchronizationEntryBCI) { + trap_bci = 0; + thread->set_pending_monitorenter(true); + } + + if (reason == Deoptimization::Reason_transfer_to_interpreter) { + thread->set_pending_transfer_to_interpreter(true); + } +#endif + Bytecodes::Code trap_bc = trap_method->java_code_at(trap_bci); + if (trap_scope->rethrow_exception()) { + if (PrintDeoptimizationDetails) { + tty->print_cr("Exception to be rethrown in the interpreter for method %s::%s at bci %d", trap_method->method_holder()->name()->as_C_string(), trap_method->name()->as_C_string(), trap_bci); + } + GrowableArray* expressions = trap_scope->expressions(); + guarantee(expressions != NULL, "must have exception to throw"); + ScopeValue* topOfStack = expressions->top(); + Handle topOfStackObj = StackValue::create_stack_value(&fr, ®_map, topOfStack)->get_obj(); + THREAD->set_pending_exception(topOfStackObj(), NULL, 0); + } + // Record this event in the histogram. gather_statistics(reason, action, trap_bc); @@ -1326,8 +1514,19 @@ // Need MDO to record RTM code generation state. bool create_if_missing = ProfileTraps || UseCodeAging RTM_OPT_ONLY( || UseRTMLocking ); + methodHandle profiled_method; +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci()) { + profiled_method = nm->method(); + } else { + profiled_method = trap_method; + } +#else + profiled_method = trap_method; +#endif + MethodData* trap_mdo = - get_method_data(thread, trap_method, create_if_missing); + get_method_data(thread, profiled_method, create_if_missing); // Log a message Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d", @@ -1385,12 +1584,33 @@ if (TraceDeoptimization) { // make noise on the tty tty->print("Uncommon trap occurred in"); nm->method()->print_short_name(tty); - tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d", + tty->print(" compiler=%s compile_id=%d", nm->compiler() == NULL ? "" : nm->compiler()->name(), nm->compile_id()); +#if INCLUDE_JVMCI + oop installedCode = nm->jvmci_installed_code(); + if (installedCode != NULL) { + oop installedCodeName = NULL; + if (installedCode->is_a(InstalledCode::klass())) { + installedCodeName = InstalledCode::name(installedCode); + } + if (installedCodeName != NULL) { + tty->print(" (JVMCI: installedCodeName=%s) ", java_lang_String::as_utf8_string(installedCodeName)); + } else { + tty->print(" (JVMCI: installed code has no name) "); + } + } else if (nm->is_compiled_by_jvmci()) { + tty->print(" (JVMCI: no installed code) "); + } +#endif + tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d" JVMCI_ONLY(" debug_id=%d"), fr.pc(), os::current_thread_id(), trap_reason_name(reason), trap_action_name(action), - unloaded_class_index); + unloaded_class_index +#if INCLUDE_JVMCI + , debug_id +#endif + ); if (class_name != NULL) { tty->print(unresolved ? " unresolved class: " : " symbol: "); class_name->print_symbol_on(tty); @@ -1524,11 +1744,14 @@ bool inc_recompile_count = false; ProfileData* pdata = NULL; if (ProfileTraps && update_trap_state && trap_mdo != NULL) { - assert(trap_mdo == get_method_data(thread, trap_method, false), "sanity"); + assert(trap_mdo == get_method_data(thread, profiled_method, false), "sanity"); uint this_trap_count = 0; bool maybe_prior_trap = false; bool maybe_prior_recompile = false; - pdata = query_update_method_data(trap_mdo, trap_bci, reason, + pdata = query_update_method_data(trap_mdo, trap_bci, reason, true, +#if INCLUDE_JVMCI + nm->is_compiled_by_jvmci() && nm->is_osr_method(), +#endif nm->method(), //outputs: this_trap_count, @@ -1660,26 +1883,42 @@ Deoptimization::query_update_method_data(MethodData* trap_mdo, int trap_bci, Deoptimization::DeoptReason reason, + bool update_total_trap_count, +#if INCLUDE_JVMCI + bool is_osr, +#endif Method* compiled_method, //outputs: uint& ret_this_trap_count, bool& ret_maybe_prior_trap, bool& ret_maybe_prior_recompile) { - uint prior_trap_count = trap_mdo->trap_count(reason); - uint this_trap_count = trap_mdo->inc_trap_count(reason); + bool maybe_prior_trap = false; + bool maybe_prior_recompile = false; + uint this_trap_count = 0; + if (update_total_trap_count) { + uint idx = reason; +#if INCLUDE_JVMCI + if (is_osr) { + idx += Reason_LIMIT; + } +#endif + uint prior_trap_count = trap_mdo->trap_count(idx); + this_trap_count = trap_mdo->inc_trap_count(idx); - // If the runtime cannot find a place to store trap history, - // it is estimated based on the general condition of the method. - // If the method has ever been recompiled, or has ever incurred - // a trap with the present reason , then this BCI is assumed - // (pessimistically) to be the culprit. - bool maybe_prior_trap = (prior_trap_count != 0); - bool maybe_prior_recompile = (trap_mdo->decompile_count() != 0); + // If the runtime cannot find a place to store trap history, + // it is estimated based on the general condition of the method. + // If the method has ever been recompiled, or has ever incurred + // a trap with the present reason , then this BCI is assumed + // (pessimistically) to be the culprit. + maybe_prior_trap = (prior_trap_count != 0); + maybe_prior_recompile = (trap_mdo->decompile_count() != 0); + } ProfileData* pdata = NULL; // For reasons which are recorded per bytecode, we check per-BCI data. DeoptReason per_bc_reason = reason_recorded_per_bytecode_if_any(reason); + assert(per_bc_reason != Reason_none || update_total_trap_count, "must be"); if (per_bc_reason != Reason_none) { // Find the profile data for this BCI. If there isn't one, // try to allocate one from the MDO's set of spares. @@ -1732,8 +1971,14 @@ bool ignore_maybe_prior_trap; bool ignore_maybe_prior_recompile; assert(!reason_is_speculate(reason), "reason speculate only used by compiler"); + // JVMCI uses the total counts to determine if deoptimizations are happening too frequently -> do not adjust total counts + bool update_total_counts = JVMCI_ONLY(false) NOT_JVMCI(true); query_update_method_data(trap_mdo, trap_bci, (DeoptReason)reason, + update_total_counts, +#if INCLUDE_JVMCI + false, +#endif NULL, ignore_this_trap_count, ignore_maybe_prior_trap, @@ -1741,7 +1986,9 @@ } Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, jint trap_request) { - + if (TraceDeoptimization) { + tty->print("Uncommon trap "); + } // Still in Java no safepoints { // This enters VM and may safepoint @@ -1846,12 +2093,12 @@ // Note: Keep this in sync. with enum DeoptReason. "none", "null_check", - "null_assert", + "null_assert" JVMCI_ONLY("_or_unreached0"), "range_check", "class_check", "array_check", - "intrinsic", - "bimorphic", + "intrinsic" JVMCI_ONLY("_or_type_checked_inlining"), + "bimorphic" JVMCI_ONLY("_or_optimized_type_check"), "unloaded", "uninitialized", "unreached", @@ -1866,6 +2113,13 @@ "rtm_state_change", "unstable_if", "unstable_fused_if", +#if INCLUDE_JVMCI + "aliasing", + "transfer_to_interpreter", + "not_compiled_exception_handler", + "unresolved", + "jsr_mismatch", +#endif "tenured" }; const char* Deoptimization::_trap_action_name[] = { @@ -1905,13 +2159,24 @@ jint unloaded_class_index = trap_request_index(trap_request); const char* reason = trap_reason_name(trap_request_reason(trap_request)); const char* action = trap_action_name(trap_request_action(trap_request)); +#if INCLUDE_JVMCI + int debug_id = trap_request_debug_id(trap_request); +#endif size_t len; if (unloaded_class_index < 0) { - len = jio_snprintf(buf, buflen, "reason='%s' action='%s'", - reason, action); + len = jio_snprintf(buf, buflen, "reason='%s' action='%s'" JVMCI_ONLY(" debug_id='%d'"), + reason, action +#if INCLUDE_JVMCI + ,debug_id +#endif + ); } else { - len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'", - reason, action, unloaded_class_index); + len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'" JVMCI_ONLY(" debug_id='%d'"), + reason, action, unloaded_class_index +#if INCLUDE_JVMCI + ,debug_id +#endif + ); } if (len >= buflen) buf[buflen-1] = '\0'; @@ -2008,7 +2273,7 @@ if (xtty != NULL) xtty->tail("statistics"); } } -#else // COMPILER2 || SHARK +#else // COMPILER2 || SHARK || INCLUDE_JVMCI // Stubs for C1 only system. @@ -2044,4 +2309,4 @@ return buf; } -#endif // COMPILER2 || SHARK +#endif // COMPILER2 || SHARK || INCLUDE_JVMCI --- old/src/share/vm/runtime/deoptimization.hpp 2015-09-16 15:19:00.000000000 -0700 +++ new/src/share/vm/runtime/deoptimization.hpp 2015-09-16 15:19:00.000000000 -0700 @@ -41,7 +41,13 @@ enum DeoptReason { Reason_many = -1, // indicates presence of several reasons Reason_none = 0, // indicates absence of a relevant deopt. - // Next 7 reasons are recorded per bytecode in DataLayout::trap_bits + // Next 7 reasons are recorded per bytecode in DataLayout::trap_bits. + // This is more complicated for JVMCI as JVMCI may deoptimize to *some* bytecode before the + // bytecode that actually caused the deopt (with inlining, JVMCI may even deoptimize to a + // bytecode in another method): + // - bytecode y in method b() causes deopt + // - JVMCI deoptimizes to bytecode x in method a() + // -> the deopt reason will be recorded for method a() at bytecode x Reason_null_check, // saw unexpected null or zero divisor (@bci) Reason_null_assert, // saw unexpected non-null or non-zero (@bci) Reason_range_check, // saw unexpected array index (@bci) @@ -50,6 +56,13 @@ Reason_intrinsic, // saw unexpected operand to intrinsic (@bci) Reason_bimorphic, // saw unexpected object class in bimorphic inlining (@bci) +#if INCLUDE_JVMCI + Reason_unreached0 = Reason_null_assert, + Reason_type_checked_inlining = Reason_intrinsic, + Reason_optimized_type_check = Reason_bimorphic, +#endif + + // recorded per method Reason_unloaded, // unloaded class or constant pool entry Reason_uninitialized, // bad class state (uninitialized) Reason_unreached, // code is not reached, compiler @@ -64,11 +77,19 @@ Reason_rtm_state_change, // rtm state change detected Reason_unstable_if, // a branch predicted always false was taken Reason_unstable_fused_if, // fused two ifs that had each one untaken branch. One is now taken. +#if INCLUDE_JVMCI + Reason_aliasing, // optimistic assumption about aliasing failed + Reason_transfer_to_interpreter, // explicit transferToInterpreter() + Reason_not_compiled_exception_handler, + Reason_unresolved, + Reason_jsr_mismatch, +#endif // Reason_tenured is counted separately, add normal counted Reasons above. // Related to MethodData::_trap_hist_limit where Reason_tenured isn't included Reason_tenured, // age of the code has reached the limit Reason_LIMIT, + // Note: Keep this enum in sync. with _trap_reason_name. Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc // Note: Reason_RECORDED_LIMIT should be < 8 to fit into 3 bits of @@ -91,8 +112,10 @@ enum { _action_bits = 3, _reason_bits = 5, + _debug_id_bits = 23, _action_shift = 0, _reason_shift = _action_shift+_action_bits, + _debug_id_shift = _reason_shift+_reason_bits, BC_CASE_LIMIT = PRODUCT_ONLY(1) NOT_PRODUCT(4) // for _deoptimization_hist }; @@ -109,10 +132,11 @@ // Deoptimizes a frame lazily. nmethod gets patched deopt happens on return to the frame static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map); + static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map, DeoptReason reason); private: // Does the actual work for deoptimizing a single frame - static void deoptimize_single_frame(JavaThread* thread, frame fr); + static void deoptimize_single_frame(JavaThread* thread, frame fr, DeoptReason reason); // Helper function to revoke biases of all monitors in frame if UseBiasedLocking // is enabled @@ -121,7 +145,9 @@ // executing in a particular CodeBlob if UseBiasedLocking is enabled static void revoke_biases_of_monitors(CodeBlob* cb); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI +JVMCI_ONLY(public:) + // Support for restoring non-escaping objects static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray* objects, TRAPS); static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type); @@ -130,7 +156,7 @@ static void relock_objects(GrowableArray* monitors, JavaThread* thread, bool realloc_failures); static void pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array); NOT_PRODUCT(static void print_objects(GrowableArray* objects, bool realloc_failures);) -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI public: static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray* chunk, bool realloc_failures); @@ -140,6 +166,7 @@ // UnrollBlock is returned by fetch_unroll_info() to the deoptimization handler (blob). // This is only a CheapObj to ease debugging after a deopt failure class UnrollBlock : public CHeapObj { + friend class VMStructs; private: int _size_of_deoptimized_frame; // Size, in bytes, of current deoptimized frame int _caller_adjustment; // Adjustment, in bytes, to caller's SP by initial interpreted frame @@ -243,10 +270,11 @@ // Only called from VMDeoptimizeFrame // @argument thread. Thread where stub_frame resides. // @argument id. id of frame that should be deoptimized. - static void deoptimize_frame_internal(JavaThread* thread, intptr_t* id); + static void deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason); - // If thread is not the current thread then execute + // if thread is not the current thread then execute // VM_DeoptimizeFrame otherwise deoptimize directly. + static void deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason); static void deoptimize_frame(JavaThread* thread, intptr_t* id); // Statistics @@ -276,6 +304,14 @@ // standard action for unloaded CP entry return _unloaded_action; } + static int trap_request_debug_id(int trap_request) { + if (trap_request < 0) { + return ((~(trap_request) >> _debug_id_shift) & right_n_bits(_debug_id_bits)); + } else { + // standard action for unloaded CP entry + return 0; + } + } static int trap_request_index(int trap_request) { if (trap_request < 0) return -1; @@ -374,6 +410,10 @@ static ProfileData* query_update_method_data(MethodData* trap_mdo, int trap_bci, DeoptReason reason, + bool update_total_trap_count, +#if INCLUDE_JVMCI + bool is_osr, +#endif Method* compiled_method, //outputs: uint& ret_this_trap_count, --- old/src/share/vm/runtime/frame.cpp 2015-09-16 15:19:01.000000000 -0700 +++ new/src/share/vm/runtime/frame.cpp 2015-09-16 15:19:01.000000000 -0700 @@ -661,9 +661,16 @@ Method* m = nm->method(); if (m != NULL) { m->name_and_sig_as_C_string(buf, buflen); - st->print("J %d%s %s %s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+0x%x]", + st->print("J %d%s %s ", nm->compile_id(), (nm->is_osr_method() ? "%" : ""), - ((nm->compiler() != NULL) ? nm->compiler()->name() : ""), + ((nm->compiler() != NULL) ? nm->compiler()->name() : "")); +#if INCLUDE_JVMCI + char* jvmciName = nm->jvmci_installed_code_name(buf, buflen); + if (jvmciName != NULL) { + st->print(" (%s)", jvmciName); + } +#endif + st->print("%s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+0x%x]", buf, m->code_size(), _pc, _cb->code_begin(), _pc - _cb->code_begin()); } else { st->print("J " PTR_FORMAT, pc()); @@ -1220,7 +1227,9 @@ // make sure we have the right receiver type } } - COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(), "must be empty before verify");) +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_empty(), "must be empty before verify"); +#endif oops_do_internal(&VerifyOopClosure::verify_oop, NULL, NULL, (RegisterMap*)map, false); } --- old/src/share/vm/runtime/globals.cpp 2015-09-16 15:19:01.000000000 -0700 +++ new/src/share/vm/runtime/globals.cpp 2015-09-16 15:19:01.000000000 -0700 @@ -42,6 +42,9 @@ #ifdef COMPILER1 #include "c1/c1_globals.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmci_globals.hpp" +#endif #ifdef COMPILER2 #include "opto/c2_globals.hpp" #endif @@ -442,6 +445,7 @@ Data data[] = { { KIND_C1, "C1" }, + { KIND_JVMCI, "JVMCI" }, { KIND_C2, "C2" }, { KIND_ARCH, "ARCH" }, { KIND_SHARK, "SHARK" }, @@ -548,6 +552,14 @@ #define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, #define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_NOT_PRODUCT) }, +#define JVMCI_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT) }, +#define JVMCI_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP) }, +#define JVMCI_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DIAGNOSTIC) }, +#define JVMCI_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_EXPERIMENTAL) }, +#define JVMCI_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_NOT_PRODUCT) }, + #ifdef _LP64 #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_LP64_PRODUCT) }, #else @@ -616,6 +628,17 @@ IGNORE_RANGE, \ IGNORE_CONSTRAINT) #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_STRUCT, \ + JVMCI_PD_DEVELOP_FLAG_STRUCT, \ + JVMCI_PRODUCT_FLAG_STRUCT, \ + JVMCI_PD_PRODUCT_FLAG_STRUCT, \ + JVMCI_DIAGNOSTIC_FLAG_STRUCT, \ + JVMCI_EXPERIMENTAL_FLAG_STRUCT, \ + JVMCI_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) +#endif // INCLUDE_JVMCI #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, \ C1_PD_DEVELOP_FLAG_STRUCT, \ --- old/src/share/vm/runtime/globals.hpp 2015-09-16 15:19:02.000000000 -0700 +++ new/src/share/vm/runtime/globals.hpp 2015-09-16 15:19:02.000000000 -0700 @@ -176,7 +176,7 @@ #endif #endif -#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) +#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) && !INCLUDE_JVMCI define_pd_global(bool, BackgroundCompilation, false); define_pd_global(bool, UseTLAB, false); define_pd_global(bool, CICompileOSR, false); @@ -211,11 +211,11 @@ #define CI_COMPILER_COUNT 0 #else -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI #define CI_COMPILER_COUNT 2 #else #define CI_COMPILER_COUNT 1 -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI #endif // no compilers @@ -254,6 +254,7 @@ KIND_SHARK = 1 << 15, KIND_LP64_PRODUCT = 1 << 16, KIND_COMMERCIAL = 1 << 17, + KIND_JVMCI = 1 << 18, KIND_MASK = ~VALUE_ORIGIN_MASK }; @@ -1112,9 +1113,18 @@ diagnostic(ccstr, PrintAssemblyOptions, NULL, \ "Print options string passed to disassembler.so") \ \ + notproduct(bool, PrintNMethodStatistics, false, \ + "Print a summary statistic for the generated nmethods") \ + \ + product(bool, ShareDebugInfo, IS_JVMCI_DEFINED, \ + "Always tries to share similar debug info inside a nmethod") \ + \ diagnostic(bool, PrintNMethods, false, \ "Print assembly code for nmethods when generated") \ \ + diagnostic(intx, PrintNMethodsAtLevel, -1, \ + "Only print code for nmethods at the given compilation level") \ + \ diagnostic(bool, PrintNativeNMethods, false, \ "Print assembly code for native nmethods when generated") \ \ @@ -2847,7 +2857,7 @@ \ develop(bool, CompileTheWorld, false, \ "Compile all methods in all classes in bootstrap class path " \ - "(stress test)") \ + "(stress test)") \ \ develop(bool, CompileTheWorldPreloadClasses, true, \ "Preload all classes used by a class before start loading") \ @@ -3085,6 +3095,9 @@ develop(bool, TraceDeoptimization, false, \ "Trace deoptimization") \ \ + develop(bool, PrintDeoptimizationDetails, false, \ + "Print more information about deoptimization") \ + \ develop(bool, DebugDeoptimization, false, \ "Tracing various information while debugging deoptimization") \ \ @@ -3231,9 +3244,12 @@ "If non-zero, maximum number of words that malloc/realloc can " \ "allocate (for testing only)") \ \ - product(intx, TypeProfileWidth, 2, \ + product(intx, TypeProfileWidth, 2, \ "Number of receiver types to record in call/cast profile") \ \ + product(intx, MethodProfileWidth, 0, \ + "Number of methods to record in call profile") \ + \ develop(intx, BciProfileWidth, 2, \ "Number of return bci's to record in ret profile") \ \ @@ -3769,7 +3785,7 @@ \ product(intx, Tier3CompileThreshold, 2000, \ "Threshold at which tier 3 compilation is invoked (invocation " \ - "minimum must be satisfied") \ + "minimum must be satisfied)") \ \ product(intx, Tier3BackEdgeThreshold, 60000, \ "Back edge threshold at which tier 3 OSR compilation is invoked") \ --- old/src/share/vm/runtime/globals_extension.hpp 2015-09-16 15:19:03.000000000 -0700 +++ new/src/share/vm/runtime/globals_extension.hpp 2015-09-16 15:19:03.000000000 -0700 @@ -44,6 +44,14 @@ #define RUNTIME_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), #define RUNTIME_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define JVMCI_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define JVMCI_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), + #ifdef _LP64 #define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #else @@ -105,6 +113,17 @@ IGNORE_RANGE, \ IGNORE_CONSTRAINT) #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_MEMBER, \ + JVMCI_PD_DEVELOP_FLAG_MEMBER, \ + JVMCI_PRODUCT_FLAG_MEMBER, \ + JVMCI_PD_PRODUCT_FLAG_MEMBER, \ + JVMCI_DIAGNOSTIC_FLAG_MEMBER, \ + JVMCI_EXPERIMENTAL_FLAG_MEMBER, \ + JVMCI_NOTPRODUCT_FLAG_MEMBER, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) +#endif // INCLUDE_JVMCI #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, \ C1_PD_DEVELOP_FLAG_MEMBER, \ @@ -151,6 +170,14 @@ #define RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), + #define C1_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), @@ -212,6 +239,17 @@ IGNORE_RANGE, IGNORE_CONSTRAINT) #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_MEMBER_WITH_TYPE, + JVMCI_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE, + JVMCI_PRODUCT_FLAG_MEMBER_WITH_TYPE, + JVMCI_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE, + JVMCI_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE, + JVMCI_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE, + JVMCI_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE, + IGNORE_RANGE, + IGNORE_CONSTRAINT) +#endif // INCLUDE_JVMCI #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER_WITH_TYPE, C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE, --- old/src/share/vm/runtime/java.cpp 2015-09-16 15:19:04.000000000 -0700 +++ new/src/share/vm/runtime/java.cpp 2015-09-16 15:19:03.000000000 -0700 @@ -31,6 +31,10 @@ #include "compiler/compilerOracle.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "interpreter/bytecodeHistogram.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif #include "memory/oopFactory.hpp" #include "memory/universe.hpp" #include "oops/constantPool.hpp" @@ -236,7 +240,6 @@ Runtime1::print_statistics(); Deoptimization::print_statistics(); SharedRuntime::print_statistics(); - nmethod::print_statistics(); } #endif /* COMPILER1 */ @@ -246,7 +249,6 @@ Compile::print_statistics(); #ifndef COMPILER1 Deoptimization::print_statistics(); - nmethod::print_statistics(); SharedRuntime::print_statistics(); #endif //COMPILER1 os::print_statistics(); @@ -264,7 +266,21 @@ IndexSet::print_statistics(); } #endif // ASSERT -#endif // COMPILER2 +#else +#ifdef INCLUDE_JVMCI +#ifndef COMPILER1 + if ((TraceDeoptimization || LogVMOutput || LogCompilation) && UseCompiler) { + FlagSetting fs(DisplayVMOutput, DisplayVMOutput && TraceDeoptimization); + Deoptimization::print_statistics(); + SharedRuntime::print_statistics(); + } +#endif +#endif +#endif + + if (PrintNMethodStatistics) { + nmethod::print_statistics(); + } if (CountCompiledCalls) { print_method_invocation_histogram(); } @@ -417,6 +433,10 @@ } } +#if INCLUDE_JVMCI + JVMCIRuntime::shutdown(); +#endif + // Hang forever on exit if we're reporting an error. if (ShowMessageBoxOnError && is_error_reported()) { os::infinite_sleep(); --- old/src/share/vm/runtime/javaCalls.cpp 2015-09-16 15:19:04.000000000 -0700 +++ new/src/share/vm/runtime/javaCalls.cpp 2015-09-16 15:19:04.000000000 -0700 @@ -41,6 +41,10 @@ #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif // ----------------------------------------------------- // Implementation of JavaCallWrapper @@ -51,7 +55,7 @@ guarantee(thread->is_Java_thread(), "crucial check - the VM thread cannot and must not escape to Java code"); assert(!thread->owns_locks(), "must release all locks when leaving VM"); - guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler"); + guarantee(thread->can_call_java(), "cannot make java calls from the native compiler"); _result = result; // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub, @@ -309,19 +313,27 @@ CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();) - // Verify the arguments +#if INCLUDE_JVMCI + // Gets the nmethod (if any) that should be called instead of normal target + nmethod* alternative_target = args->alternative_target(); + if (alternative_target == NULL) { +#endif +// Verify the arguments if (CheckJNICalls) { args->verify(method, result->get_type(), thread); } else debug_only(args->verify(method, result->get_type(), thread)); +#if INCLUDE_JVMCI + } +#else // Ignore call if method is empty if (method->is_empty_method()) { assert(result->get_type() == T_VOID, "an empty method must return a void value"); return; } - +#endif #ifdef ASSERT { InstanceKlass* holder = method->method_holder(); @@ -333,7 +345,7 @@ #endif - assert(!thread->is_Compiler_thread(), "cannot compile from the compiler"); + assert(thread->can_call_java(), "cannot compile from the native compiler"); if (CompilationPolicy::must_be_compiled(method)) { CompileBroker::compile_method(method, InvocationEntryBci, CompilationPolicy::policy()->initial_compile_level(), @@ -377,6 +389,17 @@ os::bang_stack_shadow_pages(); } +#if INCLUDE_JVMCI + if (alternative_target != NULL) { + if (alternative_target->is_alive()) { + thread->set_jvmci_alternate_call_target(alternative_target->verified_entry_point()); + entry_point = method->adapter()->get_i2c_entry(); + } else { + THROW(vmSymbols::jdk_internal_jvmci_code_InvalidInstalledCodeException()); + } + } +#endif + // do call { JavaCallWrapper link(method, receiver, result, CHECK); { HandleMark hm(thread); // HandleMark used by HandleMarkCleaner --- old/src/share/vm/runtime/javaCalls.hpp 2015-09-16 15:19:05.000000000 -0700 +++ new/src/share/vm/runtime/javaCalls.hpp 2015-09-16 15:19:05.000000000 -0700 @@ -103,6 +103,7 @@ int _size; int _max_size; bool _start_at_zero; // Support late setting of receiver + JVMCI_ONLY(nmethod* _alternative_target;) // Nmethod that should be called instead of normal target void initialize() { // Starts at first element to support set_receiver. @@ -112,6 +113,7 @@ _max_size = _default_size; _size = 0; _start_at_zero = false; + JVMCI_ONLY(_alternative_target = NULL;) } public: @@ -133,11 +135,22 @@ _max_size = max_size; _size = 0; _start_at_zero = false; + JVMCI_ONLY(_alternative_target = NULL;) } else { initialize(); } } +#if INCLUDE_JVMCI + void set_alternative_target(nmethod* target) { + _alternative_target = target; + } + + nmethod* alternative_target() { + return _alternative_target; + } +#endif + inline void push_oop(Handle h) { _is_oop[_size] = true; JNITypes::put_obj((oop)h.raw_value(), _value, _size); } --- old/src/share/vm/runtime/rframe.cpp 2015-09-16 15:19:06.000000000 -0700 +++ new/src/share/vm/runtime/rframe.cpp 2015-09-16 15:19:05.000000000 -0700 @@ -155,7 +155,7 @@ void RFrame::print(const char* kind) { #ifndef PRODUCT -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI int cnt = top_method()->interpreter_invocation_count(); #else int cnt = top_method()->invocation_count(); --- old/src/share/vm/runtime/sharedRuntime.cpp 2015-09-16 15:19:06.000000000 -0700 +++ new/src/share/vm/runtime/sharedRuntime.cpp 2015-09-16 15:19:06.000000000 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" @@ -47,6 +48,7 @@ #include "runtime/arguments.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/compilationPolicy.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" @@ -94,9 +96,10 @@ _resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C), "resolve_virtual_call"); _resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C), "resolve_static_call"); -#ifdef COMPILER2 - // Vectors are generated only by C2. - if (is_wide_vector(MaxVectorSize)) { +#if defined(COMPILER2) || INCLUDE_JVMCI + // Vectors are generated only by C2 and JVMCI. + bool support_wide = is_wide_vector(MaxVectorSize); + if (support_wide) { _polling_page_vectors_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_VECTOR_LOOP); } #endif // COMPILER2 @@ -462,6 +465,12 @@ // Reset method handle flag. thread->set_is_method_handle_return(false); +#if INCLUDE_JVMCI + // JVMCI's ExceptionHandlerStub expects the thread local exception PC to be clear + // and other exception handler continuations do not read it + thread->set_exception_pc(NULL); +#endif + // The fastest case first CodeBlob* blob = CodeCache::find_blob(return_address); nmethod* nm = (blob != NULL) ? blob->as_nmethod_or_null() : NULL; @@ -527,8 +536,11 @@ assert(((nmethod*)cb)->is_at_poll_or_poll_return(pc), "safepoint polling: type must be poll"); - assert(((NativeInstruction*)pc)->is_safepoint_poll(), - "Only polling locations are used for safepoint"); + if (!((NativeInstruction*)pc)->is_safepoint_poll()) { + tty->print_cr("bad pc: %p", pc); + Disassembler::decode(cb); + assert(false, "Only polling locations are used for safepoint"); + } bool at_poll_return = ((nmethod*)cb)->is_at_poll_return(pc); bool has_wide_vectors = ((nmethod*)cb)->has_wide_vectors(); @@ -618,6 +630,33 @@ assert(nm != NULL, "must exist"); ResourceMark rm; +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci()) { + // lookup exception handler for this pc + int catch_pco = ret_pc - nm->code_begin(); + ExceptionHandlerTable table(nm); + HandlerTableEntry *t = table.entry_for(catch_pco, -1, 0); + if (t != NULL) { + return nm->code_begin() + t->pco(); + } else { + // there is no exception handler for this pc => deoptimize + nm->make_not_entrant(); + + // Use Deoptimization::deoptimize for all of its side-effects: + // revoking biases of monitors, gathering traps statistics, logging... + // it also patches the return pc but we do not care about that + // since we return a continuation to the deopt_blob below. + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, UseBiasedLocking); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + Deoptimization::deoptimize(thread, caller_frame, ®_map, Deoptimization::Reason_not_compiled_exception_handler); + + return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + } +#endif + ScopeDesc* sd = nm->scope_desc_at(ret_pc); // determine handler bci, if any EXCEPTION_MARK; @@ -738,6 +777,15 @@ throw_and_post_jvmti_exception(thread, exception); JRT_END +#if INCLUDE_JVMCI +address SharedRuntime::deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason) { + assert(deopt_reason > Deoptimization::Reason_none && deopt_reason < Deoptimization::Reason_LIMIT, "invalid deopt reason"); + thread->set_jvmci_implicit_exception_pc(pc); + thread->set_pending_deoptimization(Deoptimization::make_trap_request((Deoptimization::DeoptReason)deopt_reason, Deoptimization::Action_reinterpret)); + return (SharedRuntime::deopt_blob()->implicit_exception_uncommon_trap()); +} +#endif + address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, address pc, SharedRuntime::ImplicitExceptionKind exception_kind) @@ -807,8 +855,8 @@ if (!cb->is_nmethod()) { bool is_in_blob = cb->is_adapter_blob() || cb->is_method_handles_adapter_blob(); if (!is_in_blob) { - cb->print(); - fatal(err_msg("exception happened outside interpreter, nmethods and vtable stubs at pc " INTPTR_FORMAT, pc)); + // Allow normal crash reporting to handle this + return NULL; } Events::log_exception(thread, "NullPointerException in code blob at " INTPTR_FORMAT, pc); // There is no handler here, so we will simply unwind. @@ -835,7 +883,19 @@ #ifndef PRODUCT _implicit_null_throws++; #endif +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci() && nm->pc_desc_at(pc) != NULL) { + // If there's no PcDesc then we'll die way down inside of + // deopt instead of just getting normal error reporting, + // so only go there if it will succeed. + return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check); + } else { +#endif + assert (nm->is_nmethod(), "Expect nmethod"); target_pc = nm->continuation_for_implicit_exception(pc); +#if INCLUDE_JVMCI + } +#endif // If there's an unexpected fault, target_pc might be NULL, // in which case we want to fall through into the normal // error handling code. @@ -847,11 +907,19 @@ case IMPLICIT_DIVIDE_BY_ZERO: { nmethod* nm = CodeCache::find_nmethod(pc); - guarantee(nm != NULL, "must have containing nmethod for implicit division-by-zero exceptions"); + guarantee(nm != NULL, "must have containing compiled method for implicit division-by-zero exceptions"); #ifndef PRODUCT _implicit_div0_throws++; #endif +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci() && nm->pc_desc_at(pc) != NULL) { + return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_div0_check); + } else { +#endif target_pc = nm->continuation_for_implicit_exception(pc); +#if INCLUDE_JVMCI + } +#endif // If there's an unexpected fault, target_pc might be NULL, // in which case we want to fall through into the normal // error handling code. @@ -863,11 +931,17 @@ assert(exception_kind == IMPLICIT_NULL || exception_kind == IMPLICIT_DIVIDE_BY_ZERO, "wrong implicit exception kind"); - // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort("java.lang.NullPointerException")); if (exception_kind == IMPLICIT_NULL) { +#ifndef PRODUCT + // for AbortVMOnException flag + Exceptions::debug_check_abort("java.lang.NullPointerException"); +#endif //PRODUCT Events::log_exception(thread, "Implicit null exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc); } else { +#ifndef PRODUCT + // for AbortVMOnException flag + Exceptions::debug_check_abort("java.lang.ArithmeticException"); +#endif //PRODUCT Events::log_exception(thread, "Implicit division by zero exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc); } return target_pc; @@ -917,6 +991,16 @@ JRT_ENTRY_NO_ASYNC(void, SharedRuntime::register_finalizer(JavaThread* thread, oopDesc* obj)) assert(obj->is_oop(), "must be a valid oop"); +#if INCLUDE_JVMCI + // This removes the requirement for JVMCI compilers to emit code + // performing a dynamic check that obj has a finalizer before + // calling this routine. There should be no performance impact + // for C1 since it emits a dynamic check. C2 and the interpreter + // uses other runtime routines for registering finalizers. + if (!obj->klass()->has_finalizer()) { + return; + } +#endif assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise"); InstanceKlass::register_finalizer(instanceOop(obj), CHECK); JRT_END @@ -1158,6 +1242,7 @@ methodHandle callee_method = call_info.selected_method(); assert((!is_virtual && invoke_code == Bytecodes::_invokestatic ) || + (!is_virtual && invoke_code == Bytecodes::_invokespecial) || (!is_virtual && invoke_code == Bytecodes::_invokehandle ) || (!is_virtual && invoke_code == Bytecodes::_invokedynamic) || ( is_virtual && invoke_code != Bytecodes::_invokestatic ), "inconsistent bytecode"); @@ -1368,9 +1453,6 @@ JRT_END - - - methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) { ResourceMark rm(thread); CallInfo call_info; @@ -1494,6 +1576,8 @@ } else { // Either clean or megamorphic } + } else { + fatal("Unimplemented"); } } // Release CompiledIC_lock @@ -1521,6 +1605,10 @@ address pc = caller.pc(); + // Check for static or virtual call + bool is_static_call = false; + nmethod* caller_nm = CodeCache::find_nmethod(pc); + // Default call_addr is the location of the "basic" call. // Determine the address of the call we a reresolving. With // Inline Caches we will always find a recognizable call. @@ -1550,10 +1638,6 @@ call_addr = ncall->instruction_address(); } } - - // Check for static or virtual call - bool is_static_call = false; - nmethod* caller_nm = CodeCache::find_nmethod(pc); // Make sure nmethod doesn't get deoptimized and removed until // this is done with it. // CLEANUP - with lazy deopt shouldn't need this lock @@ -2568,8 +2652,7 @@ // Perform the work while holding the lock, but perform any printing outside the lock MutexLocker mu(AdapterHandlerLibrary_lock); // See if somebody beat us to it - nm = method->code(); - if (nm != NULL) { + if (method->code() != NULL) { return; } @@ -2811,7 +2894,7 @@ FREE_C_HEAP_ARRAY(intptr_t, buf); JRT_END -bool AdapterHandlerLibrary::contains(CodeBlob* b) { +bool AdapterHandlerLibrary::contains(const CodeBlob* b) { AdapterHandlerTableIterator iter(_adapters); while (iter.has_next()) { AdapterHandlerEntry* a = iter.next(); @@ -2820,7 +2903,7 @@ return false; } -void AdapterHandlerLibrary::print_handler_on(outputStream* st, CodeBlob* b) { +void AdapterHandlerLibrary::print_handler_on(outputStream* st, const CodeBlob* b) { AdapterHandlerTableIterator iter(_adapters); while (iter.has_next()) { AdapterHandlerEntry* a = iter.next(); --- old/src/share/vm/runtime/sharedRuntime.hpp 2015-09-16 15:19:07.000000000 -0700 +++ new/src/share/vm/runtime/sharedRuntime.hpp 2015-09-16 15:19:07.000000000 -0700 @@ -199,6 +199,9 @@ static address continuation_for_implicit_exception(JavaThread* thread, address faulting_pc, ImplicitExceptionKind exception_kind); +#if INCLUDE_JVMCI + static address deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason); +#endif // Shared stub locations static address get_poll_stub(address pc); @@ -417,6 +420,12 @@ const VMRegPair *regs, AdapterFingerPrint* fingerprint); + static void gen_i2c_adapter(MacroAssembler *_masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs); + // OSR support // OSR_migration_begin will extract the jvm state from an interpreter @@ -475,6 +484,7 @@ // A compiled caller has just called the interpreter, but compiled code // exists. Patch the caller so he no longer calls into the interpreter. static void fixup_callers_callsite(Method* moop, address ret_pc); + static bool should_fixup_call_destination(address destination, address entry_point, address caller_pc, Method* moop, CodeBlob* cb); // Slow-path Locking and Unlocking static void complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread); @@ -673,9 +683,9 @@ static void create_native_wrapper(methodHandle method); static AdapterHandlerEntry* get_adapter(methodHandle method); - static void print_handler(CodeBlob* b) { print_handler_on(tty, b); } - static void print_handler_on(outputStream* st, CodeBlob* b); - static bool contains(CodeBlob* b); + static void print_handler(const CodeBlob* b) { print_handler_on(tty, b); } + static void print_handler_on(outputStream* st, const CodeBlob* b); + static bool contains(const CodeBlob* b); #ifndef PRODUCT static void print_statistics(); #endif // PRODUCT --- old/src/share/vm/runtime/sweeper.hpp 2015-09-16 15:19:08.000000000 -0700 +++ new/src/share/vm/runtime/sweeper.hpp 2015-09-16 15:19:07.000000000 -0700 @@ -27,7 +27,9 @@ class WhiteBox; +#include "code/codeCache.hpp" #include "utilities/ticks.hpp" + // An NmethodSweeper is an incremental cleaner for: // - cleanup inline caches // - reclamation of nmethods --- old/src/share/vm/runtime/thread.cpp 2015-09-16 15:19:09.000000000 -0700 +++ new/src/share/vm/runtime/thread.cpp 2015-09-16 15:19:08.000000000 -0700 @@ -99,6 +99,10 @@ #include "gc/g1/concurrentMarkThread.inline.hpp" #include "gc/parallel/pcTasks.hpp" #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif @@ -1386,6 +1390,33 @@ // ======= JavaThread ======== +#if INCLUDE_JVMCI + +jlong* JavaThread::_jvmci_old_thread_counters; + +bool jvmci_counters_include(JavaThread* thread) { + oop threadObj = thread->threadObj(); + return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread(); +} + +void JavaThread::collect_counters(typeArrayOop array) { + if (JVMCICounterSize > 0) { + MutexLocker tl(Threads_lock); + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, _jvmci_old_thread_counters[i]); + } + for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { + if (jvmci_counters_include(tp)) { + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, array->long_at(i) + tp->_jvmci_counters[i]); + } + } + } + } +} + +#endif + // A JavaThread is a normal Java thread void JavaThread::initialize() { @@ -1418,6 +1449,20 @@ _in_deopt_handler = 0; _doing_unsafe_access = false; _stack_guard_state = stack_guard_unused; +#if INCLUDE_JVMCI + _pending_monitorenter = false; + _pending_deoptimization = -1; + _pending_failed_speculation = NULL; + _pending_transfer_to_interpreter = false; + _jvmci._alternate_call_target = NULL; + assert(_jvmci._implicit_exception_pc == NULL, "must be"); + if (JVMCICounterSize > 0) { + _jvmci_counters = NEW_C_HEAP_ARRAY(jlong, JVMCICounterSize, mtInternal); + memset(_jvmci_counters, 0, sizeof(jlong) * JVMCICounterSize); + } else { + _jvmci_counters = NULL; + } +#endif (void)const_cast(_exception_oop = oop(NULL)); _exception_pc = 0; _exception_handler_pc = 0; @@ -1592,6 +1637,17 @@ ThreadSafepointState::destroy(this); if (_thread_profiler != NULL) delete _thread_profiler; if (_thread_stat != NULL) delete _thread_stat; + +#if INCLUDE_JVMCI + if (JVMCICounterSize > 0) { + if (jvmci_counters_include(this)) { + for (int i = 0; i < JVMCICounterSize; i++) { + _jvmci_old_thread_counters[i] += _jvmci_counters[i]; + } + } + FREE_C_HEAP_ARRAY(jlong, _jvmci_counters); + } +#endif } @@ -2135,7 +2191,7 @@ // Do not throw asynchronous exceptions against the compiler thread // (the compiler thread should not be a Java thread -- fix in 1.4.2) - if (is_Compiler_thread()) return; + if (!can_call_java()) return; { // Actually throw the Throwable against the target Thread - however @@ -2614,12 +2670,6 @@ StackFrameStream fst(this, UseBiasedLocking); for (; !fst.is_done(); fst.next()) { if (fst.current()->should_be_deoptimized()) { - if (LogCompilation && xtty != NULL) { - nmethod* nm = fst.current()->cb()->as_nmethod_or_null(); - xtty->elem("deoptimized thread='" UINTX_FORMAT "' compile_id='%d'", - this->name(), nm != NULL ? nm->compile_id() : -1); - } - Deoptimization::deoptimize(this, *fst.current(), fst.register_map()); } } @@ -2658,6 +2708,8 @@ // Traverse the GCHandles Thread::oops_do(f, cld_f, cf); + JVMCI_ONLY(f->do_oop((oop*)&_pending_failed_speculation);) + assert((!has_last_Java_frame() && java_call_counter() == 0) || (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!"); @@ -3175,6 +3227,10 @@ #endif } +bool CompilerThread::can_call_java() const { + return _compiler != NULL && _compiler->is_jvmci(); +} + // Create sweeper thread CodeCacheSweeperThread::CodeCacheSweeperThread() : JavaThread(&sweeper_thread_entry) { @@ -3380,6 +3436,15 @@ // Initialize global data structures and create system classes in heap vm_init_globals(); +#if INCLUDE_JVMCI + if (JVMCICounterSize > 0) { + JavaThread::_jvmci_old_thread_counters = NEW_C_HEAP_ARRAY(jlong, JVMCICounterSize, mtInternal); + memset(JavaThread::_jvmci_old_thread_counters, 0, sizeof(jlong) * JVMCICounterSize); + } else { + JavaThread::_jvmci_old_thread_counters = NULL; + } +#endif + // Attach the main thread to this os thread JavaThread* main_thread = new JavaThread(); main_thread->set_thread_state(_thread_in_vm); @@ -3506,7 +3571,7 @@ // Note that we do not use CHECK_0 here since we are inside an EXCEPTION_MARK and // set_init_completed has just been called, causing exceptions not to be shortcut // anymore. We call vm_exit_during_initialization directly instead. - SystemDictionary::compute_java_system_loader(CHECK_JNI_ERR); + SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR)); #if INCLUDE_ALL_GCS // Support for ConcurrentMarkSweep. This should be cleaned up @@ -3554,8 +3619,21 @@ Chunk::start_chunk_pool_cleaner_task(); } +#if INCLUDE_JVMCI + if (EnableJVMCI) { + const char* jvmciCompiler = Arguments::PropertyList_get_value(Arguments::system_properties(), "jvmci.compiler"); + if (jvmciCompiler != NULL) { + JVMCIRuntime::save_compiler(jvmciCompiler); + } + const char* jvmciOptions = Arguments::PropertyList_get_value(Arguments::system_properties(), "jvmci.options"); + if (jvmciOptions != NULL) { + JVMCIRuntime::save_options(jvmciOptions); + } + } +#endif + // initialize compiler(s) -#if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI CompileBroker::compilation_init(); #endif @@ -3963,6 +4041,12 @@ delete thread; +#if INCLUDE_JVMCI + if (JVMCICounterSize > 0) { + FREE_C_HEAP_ARRAY(jlong, JavaThread::_jvmci_old_thread_counters); + } +#endif + // exit_globals() will delete tty exit_globals(); @@ -4179,7 +4263,7 @@ { MutexLockerEx ml(doLock ? Threads_lock : NULL); ALL_JAVA_THREADS(p) { - if (p->is_Compiler_thread()) continue; + if (!p->can_call_java()) continue; address pending = (address)p->current_pending_monitor(); if (pending == monitor) { // found a match @@ -4236,7 +4320,7 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format, bool print_concurrent_locks) { char buf[32]; - st->print_cr("%s", os::local_time_string(buf, sizeof(buf))); + st->print_raw_cr(os::local_time_string(buf, sizeof(buf))); st->print_cr("Full thread dump %s (%s %s):", Abstract_VM_Version::vm_name(), --- old/src/share/vm/runtime/thread.hpp 2015-09-16 15:19:10.000000000 -0700 +++ new/src/share/vm/runtime/thread.hpp 2015-09-16 15:19:09.000000000 -0700 @@ -329,6 +329,9 @@ virtual bool is_Named_thread() const { return false; } virtual bool is_Worker_thread() const { return false; } + // Can this thread make Java upcalls + virtual bool can_call_java() const { return false; } + // Casts virtual WorkerThread* as_Worker_thread() const { return NULL; } @@ -892,6 +895,43 @@ private: +#if INCLUDE_JVMCI + // The _pending_* fields below are used to communicate extra information + // from an uncommon trap in JVMCI compiled code to the uncommon trap handler. + + // Communicates the DeoptReason and DeoptAction of the uncommon trap + int _pending_deoptimization; + + // An object that JVMCI compiled code can use to further describe and + // uniquely identify the speculative optimization guarded by the uncommon trap + oop _pending_failed_speculation; + + // Specifies whether the uncommon trap is to bci 0 of a synchronized method + // before the monitor has been acquired. + bool _pending_monitorenter; + + // Specifies if the DeoptReason for the last uncommon trap was Reason_transfer_to_interpreter + bool _pending_transfer_to_interpreter; + + // These fields are mutually exclusive in terms of live ranges. + union { + // Communicates the pc at which the most recent implicit exception occurred + // from the signal handler to a deoptimization stub. + address _implicit_exception_pc; + + // Communicates an alternative call target to an i2c stub from a JavaCall . + address _alternate_call_target; + } _jvmci; + + // Support for high precision, thread sensitive counters in JVMCI compiled code. + jlong* _jvmci_counters; + + public: + static jlong* _jvmci_old_thread_counters; + static void collect_counters(typeArrayOop array); + private: +#endif + StackGuardState _stack_guard_state; // Precompute the limit of the stack as used in stack overflow checks. @@ -906,6 +946,7 @@ volatile address _exception_handler_pc; // PC for handler of exception volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site. + private: // support for JNI critical regions jint _jni_active_critical; // count of entries into JNI critical region @@ -993,6 +1034,7 @@ // Testers virtual bool is_Java_thread() const { return true; } + virtual bool can_call_java() const { return true; } // Thread chain operations JavaThread* next() const { return _next; } @@ -1251,6 +1293,18 @@ MemRegion deferred_card_mark() const { return _deferred_card_mark; } void set_deferred_card_mark(MemRegion mr) { _deferred_card_mark = mr; } +#if INCLUDE_JVMCI + int pending_deoptimization() const { return _pending_deoptimization; } + oop pending_failed_speculation() const { return _pending_failed_speculation; } + bool has_pending_monitorenter() const { return _pending_monitorenter; } + void set_pending_monitorenter(bool b) { _pending_monitorenter = b; } + void set_pending_deoptimization(int reason) { _pending_deoptimization = reason; } + void set_pending_failed_speculation(oop failed_speculation) { _pending_failed_speculation = failed_speculation; } + void set_pending_transfer_to_interpreter(bool b) { _pending_transfer_to_interpreter = b; } + void set_jvmci_alternate_call_target(address a) { assert(_jvmci._alternate_call_target == NULL, "must be"); _jvmci._alternate_call_target = a; } + void set_jvmci_implicit_exception_pc(address a) { assert(_jvmci._implicit_exception_pc == NULL, "must be"); _jvmci._implicit_exception_pc = a; } +#endif + // Exception handling for compiled methods oop exception_oop() const { return _exception_oop; } address exception_pc() const { return _exception_pc; } @@ -1351,6 +1405,14 @@ static ByteSize thread_state_offset() { return byte_offset_of(JavaThread, _thread_state); } static ByteSize saved_exception_pc_offset() { return byte_offset_of(JavaThread, _saved_exception_pc); } static ByteSize osthread_offset() { return byte_offset_of(JavaThread, _osthread); } +#if INCLUDE_JVMCI + static ByteSize pending_deoptimization_offset() { return byte_offset_of(JavaThread, _pending_deoptimization); } + static ByteSize pending_monitorenter_offset() { return byte_offset_of(JavaThread, _pending_monitorenter); } + static ByteSize pending_failed_speculation_offset() { return byte_offset_of(JavaThread, _pending_failed_speculation); } + static ByteSize jvmci_alternate_call_target_offset() { return byte_offset_of(JavaThread, _jvmci._alternate_call_target); } + static ByteSize jvmci_implicit_exception_pc_offset() { return byte_offset_of(JavaThread, _jvmci._implicit_exception_pc); } + static ByteSize jvmci_counters_offset() { return byte_offset_of(JavaThread, _jvmci_counters); } +#endif static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } @@ -1820,8 +1882,11 @@ CompilerThread(CompileQueue* queue, CompilerCounters* counters); bool is_Compiler_thread() const { return true; } - // Hide this compiler thread from external view. - bool is_hidden_from_external_view() const { return true; } + + virtual bool can_call_java() const; + + // Hide native compiler threads from external view. + bool is_hidden_from_external_view() const { return !can_call_java(); } void set_compiler(AbstractCompiler* c) { _compiler = c; } AbstractCompiler* compiler() const { return _compiler; } --- old/src/share/vm/runtime/timer.cpp 2015-09-16 15:19:10.000000000 -0700 +++ new/src/share/vm/runtime/timer.cpp 2015-09-16 15:19:10.000000000 -0700 @@ -36,6 +36,22 @@ return counter_to_seconds(counter) * 1000.0; } +elapsedTimer::elapsedTimer(jlong time, jlong timeUnitsPerSecond) { + _active = false; + jlong osTimeUnitsPerSecond = os::elapsed_frequency(); + assert(osTimeUnitsPerSecond % 1000 == 0, "must be"); + assert(timeUnitsPerSecond % 1000 == 0, "must be"); + while (osTimeUnitsPerSecond < timeUnitsPerSecond) { + timeUnitsPerSecond /= 1000; + time *= 1000; + } + while (osTimeUnitsPerSecond > timeUnitsPerSecond) { + timeUnitsPerSecond *= 1000; + time /= 1000; + } + _counter = time; +} + void elapsedTimer::add(elapsedTimer t) { _counter += t._counter; } --- old/src/share/vm/runtime/timer.hpp 2015-09-16 15:19:11.000000000 -0700 +++ new/src/share/vm/runtime/timer.hpp 2015-09-16 15:19:11.000000000 -0700 @@ -37,6 +37,7 @@ bool _active; public: elapsedTimer() { _active = false; reset(); } + elapsedTimer(jlong time, jlong timeUnitsPerSecond); void add(elapsedTimer t); void start(); void stop(); --- old/src/share/vm/runtime/vframe.cpp 2015-09-16 15:19:12.000000000 -0700 +++ new/src/share/vm/runtime/vframe.cpp 2015-09-16 15:19:11.000000000 -0700 @@ -400,7 +400,7 @@ InterpreterOopMap oop_mask; // oopmap for current bci - if (TraceDeoptimization && Verbose) { + if ((TraceDeoptimization && Verbose) JVMCI_ONLY( || PrintDeoptimizationDetails)) { methodHandle m_h(Thread::current(), method()); OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask); } else { --- old/src/share/vm/runtime/vframeArray.cpp 2015-09-16 15:19:12.000000000 -0700 +++ new/src/share/vm/runtime/vframeArray.cpp 2015-09-16 15:19:12.000000000 -0700 @@ -294,7 +294,7 @@ _frame.patch_pc(thread, pc); - assert (!method()->is_synchronized() || locks > 0 || _removed_monitors, "synchronized methods must have monitors"); + assert (!method()->is_synchronized() || locks > 0 || _removed_monitors || raw_bci() == SynchronizationEntryBCI, "synchronized methods must have monitors"); BasicObjectLock* top = iframe()->interpreter_frame_monitor_begin(); for (int index = 0; index < locks; index++) { @@ -317,6 +317,10 @@ } } + if (PrintDeoptimizationDetails) { + tty->print_cr("Expressions size: %d", expressions()->size()); + } + // Unpack expression stack // If this is an intermediate frame (i.e. not top frame) then this // only unpacks the part of the expression stack not used by callee @@ -329,9 +333,26 @@ switch(value->type()) { case T_INT: *addr = value->get_int(); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print_cr("Reconstructed expression %d (INT): %d", i, (int)(*addr)); + } +#endif break; case T_OBJECT: *addr = value->get_int(T_OBJECT); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print("Reconstructed expression %d (OBJECT): ", i); + oop o = (oop)(address)(*addr); + if (o == NULL) { + tty->print_cr("NULL"); + } else { + ResourceMark rm; + tty->print_raw_cr(o->klass()->name()->as_C_string()); + } + } +#endif break; case T_CONFLICT: // A dead stack slot. Initialize to null in case it is an oop. @@ -350,9 +371,26 @@ switch(value->type()) { case T_INT: *addr = value->get_int(); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print_cr("Reconstructed local %d (INT): %d", i, (int)(*addr)); + } +#endif break; case T_OBJECT: *addr = value->get_int(T_OBJECT); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print("Reconstructed local %d (OBJECT): ", i); + oop o = (oop)(address)(*addr); + if (o == NULL) { + tty->print_cr("NULL"); + } else { + ResourceMark rm; + tty->print_raw_cr(o->klass()->name()->as_C_string()); + } + } +#endif break; case T_CONFLICT: // A dead location. If it is an oop then we need a NULL to prevent GC from following it @@ -394,7 +432,7 @@ } #ifndef PRODUCT - if (TraceDeoptimization && Verbose) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; tty->print_cr("[%d Interpreted Frame]", ++unpack_counter); iframe()->print_on(tty); --- old/src/share/vm/runtime/vmStructs.cpp 2015-09-16 15:19:13.000000000 -0700 +++ new/src/share/vm/runtime/vmStructs.cpp 2015-09-16 15:19:13.000000000 -0700 @@ -107,6 +107,22 @@ #include "utilities/hashtable.hpp" #include "utilities/macros.hpp" +#ifdef TARGET_OS_FAMILY_linux +# include "vmStructs_linux.hpp" +#endif +#ifdef TARGET_OS_FAMILY_solaris +# include "vmStructs_solaris.hpp" +#endif +#ifdef TARGET_OS_FAMILY_windows +# include "vmStructs_windows.hpp" +#endif +#ifdef TARGET_OS_FAMILY_aix +# include "vmStructs_aix.hpp" +#endif +#ifdef TARGET_OS_FAMILY_bsd +# include "vmStructs_bsd.hpp" +#endif + #ifdef TARGET_ARCH_x86 # include "vmStructs_x86.hpp" #endif @@ -125,6 +141,7 @@ #ifdef TARGET_ARCH_aarch64 # include "vmStructs_aarch64.hpp" #endif + #ifdef TARGET_OS_ARCH_linux_x86 # include "vmStructs_linux_x86.hpp" #endif @@ -161,6 +178,7 @@ #ifdef TARGET_OS_ARCH_bsd_zero # include "vmStructs_bsd_zero.hpp" #endif + #if INCLUDE_ALL_GCS #include "gc/cms/compactibleFreeListSpace.hpp" #include "gc/cms/concurrentMarkSweepGeneration.hpp" @@ -178,6 +196,10 @@ #include "gc/parallel/vmStructs_parallelgc.hpp" #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI +# include "jvmci/vmStructs_jvmci.hpp" +#endif + #if INCLUDE_TRACE #include "runtime/vmStructs_trace.hpp" #endif @@ -311,6 +333,7 @@ nonstatic_field(InstanceKlass, _static_oop_field_count, u2) \ nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \ nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \ + nonstatic_field(InstanceKlass, _misc_flags, u2) \ nonstatic_field(InstanceKlass, _minor_version, u2) \ nonstatic_field(InstanceKlass, _major_version, u2) \ nonstatic_field(InstanceKlass, _init_state, u1) \ @@ -384,6 +407,7 @@ nonstatic_field(Method, _vtable_index, int) \ nonstatic_field(Method, _method_size, u2) \ nonstatic_field(Method, _intrinsic_id, u1) \ + nonstatic_field(Method, _flags, u1) \ nonproduct_nonstatic_field(Method, _compiled_invocation_count, int) \ volatile_nonstatic_field(Method, _code, nmethod*) \ nonstatic_field(Method, _i2i_entry, address) \ @@ -408,6 +432,7 @@ nonstatic_field(Symbol, _identity_hash, short) \ nonstatic_field(Symbol, _length, unsigned short) \ unchecked_nonstatic_field(Symbol, _body, sizeof(jbyte)) /* NOTE: no type */ \ + nonstatic_field(Symbol, _body[0], jbyte) \ nonstatic_field(TypeArrayKlass, _max_length, int) \ \ /***********************/ \ @@ -470,6 +495,8 @@ static_field(Universe, _bootstrapping, bool) \ static_field(Universe, _fully_initialized, bool) \ static_field(Universe, _verify_count, int) \ + static_field(Universe, _verify_oop_mask, uintptr_t) \ + static_field(Universe, _verify_oop_bits, uintptr_t) \ static_field(Universe, _non_oop_bits, intptr_t) \ static_field(Universe, _narrow_oop._base, address) \ static_field(Universe, _narrow_oop._shift, int) \ @@ -489,6 +516,10 @@ \ unchecked_nonstatic_field(ageTable, sizes, sizeof(ageTable::sizes)) \ \ + nonstatic_field(BarrierSet, _fake_rtti, BarrierSet::FakeRtti) \ + \ + nonstatic_field(BarrierSet::FakeRtti, _concrete_tag, BarrierSet::Name) \ + \ nonstatic_field(BlockOffsetTable, _bottom, HeapWord*) \ nonstatic_field(BlockOffsetTable, _end, HeapWord*) \ \ @@ -578,6 +609,7 @@ nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _pf_top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \ static_field(ThreadLocalAllocBuffer, _target_refills, unsigned) \ @@ -787,6 +819,8 @@ /********************************/ \ \ static_field(CodeCache, _heaps, GrowableArray*) \ + static_field(CodeCache, _low_bound, address) \ + static_field(CodeCache, _high_bound, address) \ static_field(CodeCache, _scavenge_root_nmethods, nmethod*) \ \ /*******************************/ \ @@ -836,12 +870,42 @@ static_field(StubRoutines, _multiplyToLen, address) \ static_field(StubRoutines, _squareToLen, address) \ static_field(StubRoutines, _mulAdd, address) \ + static_field(StubRoutines, _jbyte_arraycopy, address) \ + static_field(StubRoutines, _jshort_arraycopy, address) \ + static_field(StubRoutines, _jint_arraycopy, address) \ + static_field(StubRoutines, _jlong_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _checkcast_arraycopy, address) \ + static_field(StubRoutines, _checkcast_arraycopy_uninit, address) \ + static_field(StubRoutines, _unsafe_arraycopy, address) \ + static_field(StubRoutines, _generic_arraycopy, address) \ \ /*****************/ \ /* SharedRuntime */ \ /*****************/ \ \ + static_field(SharedRuntime, _wrong_method_blob, RuntimeStub*) \ static_field(SharedRuntime, _ic_miss_blob, RuntimeStub*) \ + static_field(SharedRuntime, _deopt_blob, DeoptimizationBlob*) \ \ /***************************************/ \ /* PcDesc and other compiled code info */ \ @@ -856,16 +920,18 @@ /* CodeBlobs (NOTE: incomplete, but only a little) */ \ /***************************************************/ \ \ - nonstatic_field(CodeBlob, _name, const char*) \ - nonstatic_field(CodeBlob, _size, int) \ - nonstatic_field(CodeBlob, _header_size, int) \ - nonstatic_field(CodeBlob, _relocation_size, int) \ - nonstatic_field(CodeBlob, _content_offset, int) \ - nonstatic_field(CodeBlob, _code_offset, int) \ - nonstatic_field(CodeBlob, _frame_complete_offset, int) \ - nonstatic_field(CodeBlob, _data_offset, int) \ - nonstatic_field(CodeBlob, _frame_size, int) \ - nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \ + nonstatic_field(CodeBlob, _name, const char*) \ + nonstatic_field(CodeBlob, _size, int) \ + nonstatic_field(CodeBlob, _header_size, int) \ + nonstatic_field(CodeBlob, _relocation_size, int) \ + nonstatic_field(CodeBlob, _content_offset, int) \ + nonstatic_field(CodeBlob, _code_offset, int) \ + nonstatic_field(CodeBlob, _frame_complete_offset, int) \ + nonstatic_field(CodeBlob, _data_offset, int) \ + nonstatic_field(CodeBlob, _frame_size, int) \ + nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \ + \ + nonstatic_field(DeoptimizationBlob, _unpack_offset, int) \ \ nonstatic_field(RuntimeStub, _caller_must_gc_arguments, bool) \ \ @@ -873,7 +939,7 @@ /* NMethods (NOTE: incomplete, but only a little) */ \ /**************************************************/ \ \ - nonstatic_field(nmethod, _method, Method*) \ + nonstatic_field(nmethod, _method, Method*) \ nonstatic_field(nmethod, _entry_bci, int) \ nonstatic_field(nmethod, _osr_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \ @@ -903,7 +969,18 @@ nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \ nonstatic_field(nmethod, _marked_for_deoptimization, bool) \ \ - unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \ + unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \ + \ + nonstatic_field(Deoptimization::UnrollBlock, _size_of_deoptimized_frame, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _caller_adjustment, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _number_of_frames, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _total_frame_sizes, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _frame_sizes, intptr_t*) \ + nonstatic_field(Deoptimization::UnrollBlock, _frame_pcs, address*) \ + nonstatic_field(Deoptimization::UnrollBlock, _register_block, intptr_t*) \ + nonstatic_field(Deoptimization::UnrollBlock, _return_type, BasicType) \ + nonstatic_field(Deoptimization::UnrollBlock, _initial_info, intptr_t) \ + nonstatic_field(Deoptimization::UnrollBlock, _caller_actual_parameters, int) \ \ /********************************/ \ /* JavaCalls (NOTE: incomplete) */ \ @@ -1294,6 +1371,7 @@ nonstatic_field(CompileTask, _osr_bci, int) \ nonstatic_field(CompileTask, _comp_level, int) \ nonstatic_field(CompileTask, _compile_id, uint) \ + nonstatic_field(CompileTask, _num_inlined_bytecodes, int) \ nonstatic_field(CompileTask, _next, CompileTask*) \ nonstatic_field(CompileTask, _prev, CompileTask*) \ \ @@ -1473,6 +1551,8 @@ declare_type(MethodCounters, MetaspaceObj) \ declare_type(ConstMethod, MetaspaceObj) \ \ + declare_toplevel_type(narrowKlass) \ + \ declare_toplevel_type(vtableEntry) \ \ declare_toplevel_type(Symbol) \ @@ -1572,6 +1652,8 @@ declare_toplevel_type(TenuredGeneration*) \ declare_toplevel_type(ThreadLocalAllocBuffer*) \ \ + declare_toplevel_type(BarrierSet::FakeRtti) \ + \ /************************/ \ /* PerfMemory - jvmstat */ \ /************************/ \ @@ -1694,6 +1776,7 @@ declare_toplevel_type(Dependencies) \ declare_toplevel_type(CompileTask) \ declare_toplevel_type(Deoptimization) \ + declare_toplevel_type(Deoptimization::UnrollBlock) \ \ /************************/ \ /* OopMap and OopMapSet */ \ @@ -2253,6 +2336,7 @@ \ declare_constant(BarrierSet::ModRef) \ declare_constant(BarrierSet::CardTableModRef) \ + declare_constant(BarrierSet::CardTableForRS) \ declare_constant(BarrierSet::CardTableExtension) \ declare_constant(BarrierSet::G1SATBCT) \ declare_constant(BarrierSet::G1SATBCTLogging) \ @@ -2275,6 +2359,8 @@ \ declare_constant(CardTableRS::youngergen_card) \ \ + declare_constant(G1SATBCardTableModRefBS::g1_young_gen) \ + \ declare_constant(CollectedHeap::GenCollectedHeap) \ declare_constant(CollectedHeap::ParallelScavengeHeap) \ declare_constant(CollectedHeap::G1CollectedHeap) \ @@ -2333,6 +2419,36 @@ declare_constant(JVM_ACC_PROMOTED_FLAGS) \ declare_constant(JVM_ACC_FIELD_ACCESS_WATCHED) \ declare_constant(JVM_ACC_FIELD_MODIFICATION_WATCHED) \ + declare_constant(JVM_ACC_FIELD_INTERNAL) \ + declare_constant(JVM_ACC_FIELD_STABLE) \ + declare_constant(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) \ + \ + declare_constant(JVM_CONSTANT_Utf8) \ + declare_constant(JVM_CONSTANT_Unicode) \ + declare_constant(JVM_CONSTANT_Integer) \ + declare_constant(JVM_CONSTANT_Float) \ + declare_constant(JVM_CONSTANT_Long) \ + declare_constant(JVM_CONSTANT_Double) \ + declare_constant(JVM_CONSTANT_Class) \ + declare_constant(JVM_CONSTANT_String) \ + declare_constant(JVM_CONSTANT_Fieldref) \ + declare_constant(JVM_CONSTANT_Methodref) \ + declare_constant(JVM_CONSTANT_InterfaceMethodref) \ + declare_constant(JVM_CONSTANT_NameAndType) \ + declare_constant(JVM_CONSTANT_MethodHandle) \ + declare_constant(JVM_CONSTANT_MethodType) \ + declare_constant(JVM_CONSTANT_InvokeDynamic) \ + declare_constant(JVM_CONSTANT_ExternalMax) \ + \ + declare_constant(JVM_CONSTANT_Invalid) \ + declare_constant(JVM_CONSTANT_InternalMin) \ + declare_constant(JVM_CONSTANT_UnresolvedClass) \ + declare_constant(JVM_CONSTANT_ClassIndex) \ + declare_constant(JVM_CONSTANT_StringIndex) \ + declare_constant(JVM_CONSTANT_UnresolvedClassInError) \ + declare_constant(JVM_CONSTANT_MethodHandleInError) \ + declare_constant(JVM_CONSTANT_MethodTypeInError) \ + declare_constant(JVM_CONSTANT_InternalMax) \ \ /*****************************/ \ /* Thread::SuspendFlags enum */ \ @@ -2363,6 +2479,7 @@ /******************************/ \ \ declare_constant(Klass::_primary_super_limit) \ + declare_constant(Klass::_lh_neutral_value) \ declare_constant(Klass::_lh_instance_slow_path_bit) \ declare_constant(Klass::_lh_log2_element_size_shift) \ declare_constant(Klass::_lh_log2_element_size_mask) \ @@ -2384,6 +2501,15 @@ declare_constant(Method::_dont_inline) \ declare_constant(Method::_hidden) \ \ + declare_constant(Method::_jfr_towrite) \ + declare_constant(Method::_caller_sensitive) \ + declare_constant(Method::_force_inline) \ + declare_constant(Method::_dont_inline) \ + declare_constant(Method::_hidden) \ + declare_constant(Method::nonvirtual_vtable_index) \ + \ + declare_constant(Method::extra_stack_entries_for_jsr292) \ + \ declare_constant(ConstMethod::_has_linenumber_table) \ declare_constant(ConstMethod::_has_checked_exceptions) \ declare_constant(ConstMethod::_has_localvariable_table) \ @@ -2400,6 +2526,20 @@ /**************/ \ \ declare_constant(DataLayout::cell_size) \ + declare_constant(DataLayout::no_tag) \ + declare_constant(DataLayout::bit_data_tag) \ + declare_constant(DataLayout::counter_data_tag) \ + declare_constant(DataLayout::jump_data_tag) \ + declare_constant(DataLayout::receiver_type_data_tag) \ + declare_constant(DataLayout::virtual_call_data_tag) \ + declare_constant(DataLayout::ret_data_tag) \ + declare_constant(DataLayout::branch_data_tag) \ + declare_constant(DataLayout::multi_branch_data_tag) \ + declare_constant(DataLayout::arg_info_data_tag) \ + declare_constant(DataLayout::call_type_data_tag) \ + declare_constant(DataLayout::virtual_call_type_data_tag) \ + declare_constant(DataLayout::parameters_type_data_tag) \ + declare_constant(DataLayout::speculative_trap_data_tag) \ \ /*************************************/ \ /* InstanceKlass enum */ \ @@ -2453,13 +2593,14 @@ \ declare_constant(Symbol::max_symbol_length) \ \ - /*************************************************/ \ - /* ConstantPool* layout enum for InvokeDynamic */ \ - /*************************************************/ \ - \ - declare_constant(ConstantPool::_indy_bsm_offset) \ - declare_constant(ConstantPool::_indy_argc_offset) \ - declare_constant(ConstantPool::_indy_argv_offset) \ + /***********************************************/ \ + /* ConstantPool* layout enum for InvokeDynamic */ \ + /***********************************************/ \ + \ + declare_constant(ConstantPool::_indy_bsm_offset) \ + declare_constant(ConstantPool::_indy_argc_offset) \ + declare_constant(ConstantPool::_indy_argv_offset) \ + declare_constant(ConstantPool::CPCACHE_INDEX_TAG) \ \ /********************************/ \ /* ConstantPoolCacheEntry enums */ \ @@ -2554,6 +2695,18 @@ \ declare_constant(DEFAULT_CACHE_LINE_SIZE) \ \ + declare_constant(Deoptimization::Unpack_deopt) \ + declare_constant(Deoptimization::Unpack_exception) \ + declare_constant(Deoptimization::Unpack_uncommon_trap) \ + declare_constant(Deoptimization::Unpack_reexecute) \ + \ + declare_constant(Deoptimization::_action_bits) \ + declare_constant(Deoptimization::_reason_bits) \ + declare_constant(Deoptimization::_debug_id_bits) \ + declare_constant(Deoptimization::_action_shift) \ + declare_constant(Deoptimization::_reason_shift) \ + declare_constant(Deoptimization::_debug_id_shift) \ + \ /*********************/ \ /* Matcher (C2 only) */ \ /*********************/ \ @@ -2566,6 +2719,18 @@ \ declare_constant(InvocationEntryBci) \ \ + /*************/ \ + /* CompLevel */ \ + /*************/ \ + \ + declare_constant(CompLevel_any) \ + declare_constant(CompLevel_all) \ + declare_constant(CompLevel_none) \ + declare_constant(CompLevel_simple) \ + declare_constant(CompLevel_limited_profile) \ + declare_constant(CompLevel_full_profile) \ + declare_constant(CompLevel_full_optimization) \ + \ /***************/ \ /* OopMapValue */ \ /***************/ \ @@ -2697,10 +2862,40 @@ /* Constants in markOop used by CMS. */ \ declare_constant(markOopDesc::cms_shift) \ declare_constant(markOopDesc::cms_mask) \ - declare_constant(markOopDesc::size_shift) + declare_constant(markOopDesc::size_shift) \ + \ + /* InvocationCounter constants */ \ + declare_constant(InvocationCounter::count_increment) \ + declare_constant(InvocationCounter::count_shift) //-------------------------------------------------------------------------------- +// VM_ADDRESSES +// + +#define VM_ADDRESSES(declare_address, declare_preprocessor_address, declare_function) \ + \ + declare_function(SharedRuntime::register_finalizer) \ + declare_function(SharedRuntime::exception_handler_for_return_address) \ + declare_function(SharedRuntime::OSR_migration_end) \ + declare_function(SharedRuntime::dsin) \ + declare_function(SharedRuntime::dcos) \ + declare_function(SharedRuntime::dtan) \ + declare_function(SharedRuntime::dexp) \ + declare_function(SharedRuntime::dlog) \ + declare_function(SharedRuntime::dlog10) \ + declare_function(SharedRuntime::dpow) \ + \ + declare_function(os::dll_load) \ + declare_function(os::dll_lookup) \ + declare_function(os::javaTimeMillis) \ + declare_function(os::javaTimeNanos) \ + \ + declare_function(Deoptimization::fetch_unroll_info) \ + COMPILER2_PRESENT(declare_function(Deoptimization::uncommon_trap)) \ + declare_function(Deoptimization::unpack_frames) + +//-------------------------------------------------------------------------------- // Macros operating on the above lists //-------------------------------------------------------------------------------- @@ -2931,6 +3126,23 @@ # define GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) #endif /* COMPILER1 */ +//-------------------------------------------------------------------------------- +// VMAddressEntry macros +// + +#define GENERATE_VM_ADDRESS_ENTRY(name) \ + { QUOTE(name), (void*) (name) }, + +#define GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY(name, value) \ + { name, (void*) (value) }, + +#define GENERATE_VM_FUNCTION_ENTRY(name) \ + { QUOTE(name), CAST_FROM_FN_PTR(void*, &(name)) }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_ADDRESS_LAST_ENTRY() \ + { NULL, NULL } + // // Instantiation of VMStructEntries, VMTypeEntries and VMIntConstantEntries // @@ -2949,6 +3161,11 @@ GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) +#if INCLUDE_JVMCI + VM_STRUCTS_JVMCI(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY) +#endif + #if INCLUDE_ALL_GCS VM_STRUCTS_PARALLELGC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) @@ -2969,6 +3186,15 @@ VM_STRUCTS_EXT(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) + VM_STRUCTS_OS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, + GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, @@ -3001,6 +3227,11 @@ GENERATE_C2_VM_TYPE_ENTRY, GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) +#if INCLUDE_JVMCI + VM_TYPES_JVMCI(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY) +#endif + #if INCLUDE_ALL_GCS VM_TYPES_PARALLELGC(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) @@ -3022,6 +3253,15 @@ VM_TYPES_EXT(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) + VM_TYPES_OS(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_OOP_VM_TYPE_ENTRY, + GENERATE_INTEGER_VM_TYPE_ENTRY, + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, + GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_C2_VM_TYPE_ENTRY, + GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + VM_TYPES_CPU(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_OOP_VM_TYPE_ENTRY, @@ -3051,6 +3291,12 @@ GENERATE_C2_VM_INT_CONSTANT_ENTRY, GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) +#if INCLUDE_JVMCI + VM_INT_CONSTANTS_JVMCI(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + +#endif + #if INCLUDE_ALL_GCS VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY) @@ -3061,6 +3307,12 @@ VM_INT_CONSTANTS_TRACE(GENERATE_VM_INT_CONSTANT_ENTRY) #endif + VM_INT_CONSTANTS_OS(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, + GENERATE_C1_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, GENERATE_C1_VM_INT_CONSTANT_ENTRY, @@ -3084,6 +3336,12 @@ GENERATE_C2_VM_LONG_CONSTANT_ENTRY, GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + VM_LONG_CONSTANTS_OS(GENERATE_VM_LONG_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, + GENERATE_C1_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + VM_LONG_CONSTANTS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, GENERATE_C1_VM_LONG_CONSTANT_ENTRY, @@ -3099,6 +3357,25 @@ GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() }; +VMAddressEntry VMStructs::localHotSpotVMAddresses[] = { + + VM_ADDRESSES(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) + + VM_ADDRESSES_OS(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) + +#if INCLUDE_JVMCI + VM_ADDRESSES_JVMCI(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) +#endif + + GENERATE_VM_ADDRESS_LAST_ENTRY() +}; + // This is used both to check the types of referenced fields and, in // debug builds, to ensure that all of the field types are present. void @@ -3307,6 +3584,11 @@ ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMLongConstantEntryNameOffset, VMLongConstantEntry, name); ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMLongConstantEntryValueOffset, VMLongConstantEntry, value); ASSIGN_STRIDE_TO_64BIT_VAR(gHotSpotVMLongConstantEntryArrayStride, gHotSpotVMLongConstants); + +JNIEXPORT VMAddressEntry* gHotSpotVMAddresses = VMStructs::localHotSpotVMAddresses; +ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMAddressEntryNameOffset, VMAddressEntry, name); +ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMAddressEntryValueOffset, VMAddressEntry, value); +ASSIGN_STRIDE_TO_64BIT_VAR(gHotSpotVMAddressEntryArrayStride, gHotSpotVMAddresses); } #ifdef ASSERT @@ -3414,6 +3696,11 @@ &long_last_entry, sizeof(VMLongConstantEntry)) == 0, "Incorrect last entry in localHotSpotVMLongConstants"); + static VMAddressEntry address_last_entry = GENERATE_VM_ADDRESS_LAST_ENTRY(); + assert(memcmp(&localHotSpotVMAddresses[sizeof(localHotSpotVMAddresses) / sizeof(VMAddressEntry) - 1], + &address_last_entry, + sizeof(VMAddressEntry)) == 0, "Incorrect last entry in localHotSpotVMAddresses"); + // Check for duplicate entries in type array for (int i = 0; localHotSpotVMTypes[i].typeName != NULL; i++) { --- old/src/share/vm/runtime/vmStructs.hpp 2015-09-16 15:19:14.000000000 -0700 +++ new/src/share/vm/runtime/vmStructs.hpp 2015-09-16 15:19:14.000000000 -0700 @@ -95,6 +95,11 @@ uint64_t value; // Value of constant } VMLongConstantEntry; +typedef struct { + const char* name; // Name of address (example: "SharedRuntime::register_finalizer") + void* value; // Value of address +} VMAddressEntry; + // This class is a friend of most classes, to be able to access // private fields class VMStructs { @@ -117,6 +122,11 @@ // the fact that it has a NULL typeName static VMLongConstantEntry localHotSpotVMLongConstants[]; + /** + * Table of addresses. + */ + static VMAddressEntry localHotSpotVMAddresses[]; + // This is used to run any checking code necessary for validation of // the data structure (debug build only) static void init(); --- old/src/share/vm/runtime/vm_operations.cpp 2015-09-16 15:19:14.000000000 -0700 +++ new/src/share/vm/runtime/vm_operations.cpp 2015-09-16 15:19:14.000000000 -0700 @@ -117,14 +117,16 @@ NMethodSweeper::mark_active_nmethods(); } -VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id) { +VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason) { _thread = thread; _id = id; + _reason = reason; } void VM_DeoptimizeFrame::doit() { - Deoptimization::deoptimize_frame_internal(_thread, _id); + assert(_reason > Deoptimization::Reason_none && _reason < Deoptimization::Reason_LIMIT, "invalid deopt reason"); + Deoptimization::deoptimize_frame_internal(_thread, _id, (Deoptimization::DeoptReason)_reason); } --- old/src/share/vm/runtime/vm_operations.hpp 2015-09-16 15:19:15.000000000 -0700 +++ new/src/share/vm/runtime/vm_operations.hpp 2015-09-16 15:19:15.000000000 -0700 @@ -272,7 +272,8 @@ private: JavaThread* _thread; intptr_t* _id; - VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id); + int _reason; + VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason); public: VMOp_Type type() const { return VMOp_DeoptimizeFrame; } --- old/src/share/vm/shark/sharkCacheDecache.cpp 2015-09-16 15:19:16.000000000 -0700 +++ new/src/share/vm/shark/sharkCacheDecache.cpp 2015-09-16 15:19:16.000000000 -0700 @@ -150,8 +150,10 @@ void SharkDecacher::end_frame() { // Record the scope + methodHandle null_mh; debug_info()->describe_scope( pc_offset(), + null_mh, target(), bci(), true, --- old/src/share/vm/utilities/exceptions.cpp 2015-09-16 15:19:17.000000000 -0700 +++ new/src/share/vm/utilities/exceptions.cpp 2015-09-16 15:19:16.000000000 -0700 @@ -85,7 +85,7 @@ #endif // ASSERT if (thread->is_VM_thread() - || thread->is_Compiler_thread() + || !thread->can_call_java() || DumpSharedSpaces ) { // We do not care what kind of exception we get for the vm-thread or a thread which // is compiling. We just install a dummy exception object @@ -112,7 +112,7 @@ } if (thread->is_VM_thread() - || thread->is_Compiler_thread() + || !thread->can_call_java() || DumpSharedSpaces ) { // We do not care what kind of exception we get for the vm-thread or a thread which // is compiling. We just install a dummy exception object --- old/src/share/vm/utilities/fakeRttiSupport.hpp 2015-09-16 15:19:17.000000000 -0700 +++ new/src/share/vm/utilities/fakeRttiSupport.hpp 2015-09-16 15:19:17.000000000 -0700 @@ -50,6 +50,7 @@ // with. template class FakeRttiSupport VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; public: // Construct with the indicated concrete tag, and include the // concrete tag in the associated tag set. --- old/src/share/vm/utilities/globalDefinitions.hpp 2015-09-16 15:19:18.000000000 -0700 +++ new/src/share/vm/utilities/globalDefinitions.hpp 2015-09-16 15:19:18.000000000 -0700 @@ -903,20 +903,20 @@ CompLevel_simple = 1, // C1 CompLevel_limited_profile = 2, // C1, invocation & backedge counters CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo - CompLevel_full_optimization = 4, // C2 or Shark + CompLevel_full_optimization = 4, // C2, Shark or JVMCI -#if defined(COMPILER2) || defined(SHARK) - CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered +#if defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI + CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered or JVMCI and tiered #elif defined(COMPILER1) - CompLevel_highest_tier = CompLevel_simple, // pure C1 + CompLevel_highest_tier = CompLevel_simple, // pure C1 or JVMCI #else CompLevel_highest_tier = CompLevel_none, #endif #if defined(TIERED) CompLevel_initial_compile = CompLevel_full_profile // tiered -#elif defined(COMPILER1) - CompLevel_initial_compile = CompLevel_simple // pure C1 +#elif defined(COMPILER1) || INCLUDE_JVMCI + CompLevel_initial_compile = CompLevel_simple // pure C1 or JVMCI #elif defined(COMPILER2) || defined(SHARK) CompLevel_initial_compile = CompLevel_full_optimization // pure C2 #else --- old/src/share/vm/utilities/growableArray.hpp 2015-09-16 15:19:19.000000000 -0700 +++ new/src/share/vm/utilities/growableArray.hpp 2015-09-16 15:19:18.000000000 -0700 @@ -374,6 +374,41 @@ void sort(int f(E*,E*), int stride) { qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f); } + + // Binary search and insertion utility. Search array for element + // matching key according to the static compare function. Insert + // that element is not already in the list. Assumes the list is + // already sorted according to compare function. + template E insert_sorted(E& key) { + bool found; + int location = find_sorted(key, found); + if (!found) { + assert(location <= length(), "out of range"); + insert_before(location, key); + } + return at(location); + } + + template int find_sorted(K& key, bool& found) { + found = false; + int min = 0; + int max = length() - 1; + + while (max >= min) { + int mid = (max + min) / 2; + E value = at(mid); + int diff = compare(key, value); + if (diff > 0) { + min = mid + 1; + } else if (diff < 0) { + max = mid - 1; + } else { + found = true; + return mid; + } + } + return min; + } }; // Global GrowableArray methods (one instance in the library per each 'E' type). --- old/src/share/vm/utilities/macros.hpp 2015-09-16 15:19:19.000000000 -0700 +++ new/src/share/vm/utilities/macros.hpp 2015-09-16 15:19:19.000000000 -0700 @@ -173,6 +173,20 @@ #define INCLUDE_TRACE 1 #endif // INCLUDE_TRACE +#ifndef INCLUDE_JVMCI +#define INCLUDE_JVMCI 1 +#endif + +#if INCLUDE_JVMCI +#define JVMCI_ONLY(code) code +#define NOT_JVMCI(code) +#define IS_JVMCI_DEFINED true +#else +#define JVMCI_ONLY(code) +#define NOT_JVMCI(code) code +#define IS_JVMCI_DEFINED false +#endif // INCLUDE_JVMCI + // COMPILER1 variant #ifdef COMPILER1 #ifdef COMPILER2 @@ -195,7 +209,7 @@ #ifdef TIERED #define TIERED_ONLY(code) code #define NOT_TIERED(code) -#else +#else // TIERED #define TIERED_ONLY(code) #define NOT_TIERED(code) code #endif // TIERED --- old/src/share/vm/utilities/top.hpp 2015-09-16 15:19:20.000000000 -0700 +++ new/src/share/vm/utilities/top.hpp 2015-09-16 15:19:20.000000000 -0700 @@ -42,6 +42,9 @@ #ifdef COMPILER2 #include "opto/c2_globals.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmci_globals.hpp" +#endif // THIS FILE IS INTESIONALLY LEFT EMPTY // IT IS USED TO MINIMIZE THE NUMBER OF DEPENDENCIES IN includeDB --- old/src/share/vm/utilities/vmError.cpp 2015-09-16 15:19:21.000000000 -0700 +++ new/src/share/vm/utilities/vmError.cpp 2015-09-16 15:19:20.000000000 -0700 @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" #include "compiler/compileBroker.hpp" +#include "compiler/disassembler.hpp" #include "gc/shared/collectedHeap.hpp" #include "prims/whitebox.hpp" #include "runtime/arguments.hpp" @@ -704,6 +705,31 @@ st->cr(); } + STEP(265, "(printing code blob if possible)") + + if (_verbose && _context) { + CodeBlob* cb = CodeCache::find_blob(_pc); + if (cb != NULL) { + if (Interpreter::contains(_pc)) { + // The interpreter CodeBlob is very large so try to print the codelet instead. + InterpreterCodelet* codelet = Interpreter::codelet_containing(_pc); + if (codelet != NULL) { + codelet->print_on(st); + Disassembler::decode(codelet->code_begin(), codelet->code_end(), st); + } + } else { + StubCodeDesc* desc = StubCodeDesc::desc_for(_pc); + if (desc != NULL) { + desc->print_on(st); + Disassembler::decode(desc->begin(), desc->end(), st); + } else { + Disassembler::decode(cb, st); + st->cr(); + } + } + } + } + STEP(270, "(printing VM operation)" ) if (_verbose && _thread && _thread->is_VM_thread()) { --- /dev/null 2015-09-16 15:19:21.000000000 -0700 +++ new/make/copy/Copy-java.base.gmk 2015-09-16 15:19:21.000000000 -0700 @@ -0,0 +1,34 @@ +# +# Copyright (c) 2015, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# Copies the services files into the lib directory. + +$(eval $(call SetupCopyFiles, COPY_SERVICES_FILES, \ + SRC := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/META-INF/jvmci.services, \ + DEST := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jvmci/services, \ + FILES := $(wildcard $(SUPPORT_OUTPUTDIR)/gensrc/java.base/META-INF/jvmci.services/*), \ +)) + +TARGETS += $(COPY_SERVICES_FILES) --- /dev/null 2015-09-16 15:19:22.000000000 -0700 +++ new/make/gensrc/Gensrc-java.base.gmk 2015-09-16 15:19:22.000000000 -0700 @@ -0,0 +1,120 @@ +# +# Copyright (c) 2015, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +default: all + +include $(SPEC) +include MakeBase.gmk +include JavaCompilation.gmk +include SetupJavaCompilers.gmk + +GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base +SRC_DIR := $(HOTSPOT_TOPDIR)/src/java.base/share/classes + +################################################################################ +# Compile the annotation processor + +$(eval $(call SetupJavaCompilation, BUILD_JVMCI_OPTIONS, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := $(SRC_DIR)/jdk.internal.jvmci.options/src \ + $(SRC_DIR)/jdk.internal.jvmci.options.processor/src \ + $(SRC_DIR)/jdk.internal.jvmci.inittimer/src, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jvmci_options, \ + JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.internal.jvmci.options.jar, \ +)) + +$(eval $(call SetupJavaCompilation, BUILD_JVMCI_SERVICE, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := $(SRC_DIR)/jdk.internal.jvmci.service/src \ + $(SRC_DIR)/jdk.internal.jvmci.service.processor/src, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jvmci_service, \ + JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.internal.jvmci.service.jar, \ +)) + +################################################################################ + +PROC_SRC_SUBDIRS := \ + jdk.internal.jvmci.compiler \ + jdk.internal.jvmci.hotspot \ + jdk.internal.jvmci.hotspot.amd64 \ + jdk.internal.jvmci.hotspot.sparc \ + # + +PROC_SRC_DIRS := $(patsubst %, $(SRC_DIR)/%/src, $(PROC_SRC_SUBDIRS)) + +PROC_SRCS := $(filter %.java, $(call CacheFind, $(PROC_SRC_DIRS))) + +ALL_SRC_DIRS := $(wildcard $(SRC_DIR)/*/src) +SOURCEPATH := $(call PathList, $(ALL_SRC_DIRS)) +PROCESSOR_PATH := $(call PathList, \ + $(BUILDTOOLS_OUTPUTDIR)/jdk.internal.jvmci.options.jar \ + $(BUILDTOOLS_OUTPUTDIR)/jdk.internal.jvmci.service.jar) + +$(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) \ + $(BUILD_JVMCI_OPTIONS) $(BUILD_JVMCI_SERVICE) + $(MKDIR) -p $(@D) + $(call ListPathsSafely,PROC_SRCS,\n, >> $(@D)/_gensrc_proc_files) + $(JAVA_SMALL) $(NEW_JAVAC) \ + -sourcepath $(SOURCEPATH) \ + -implicit:none \ + -proc:only \ + -processorpath $(PROCESSOR_PATH) \ + -d $(GENSRC_DIR) \ + -s $(GENSRC_DIR) \ + @$(@D)/_gensrc_proc_files + $(TOUCH) $@ + +TARGETS += $(GENSRC_DIR)/_gensrc_proc_done + +################################################################################ + +$(GENSRC_DIR)/META-INF/services/jdk.internal.jvmci.options.OptionDescriptors: \ + $(GENSRC_DIR)/_gensrc_proc_done + $(MKDIR) -p $(@D) + ($(CD) $(GENSRC_DIR)/META-INF/jvmci.options && \ + for i in $$(ls); do \ + echo $${i}_OptionDescriptors >> $@; \ + done) + +TARGETS += $(GENSRC_DIR)/META-INF/services/jdk.internal.jvmci.options.OptionDescriptors + +################################################################################ + +$(GENSRC_DIR)/_providers_converted: $(GENSRC_DIR)/_gensrc_proc_done + $(MKDIR) -p $(GENSRC_DIR)/META-INF/services + ($(CD) $(GENSRC_DIR)/META-INF/jvmci.providers && \ + for i in $$($(LS)); do \ + c=$$($(CAT) $$i | $(TR) -d '\n\r'); \ + $(ECHO) $$i >> $(GENSRC_DIR)/META-INF/services/$$c; \ + done) + $(TOUCH) $@ + +TARGETS += $(GENSRC_DIR)/_providers_converted + +################################################################################ + +all: $(TARGETS) + +.PHONY: default all --- /dev/null 2015-09-16 15:19:23.000000000 -0700 +++ new/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp 2015-09-16 15:19:22.000000000 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_aarch64.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + Unimplemented(); + return 0; +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + Unimplemented(); +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + Unimplemented(); +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + return NULL; +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return false; +} --- /dev/null 2015-09-16 15:19:23.000000000 -0700 +++ new/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp 2015-09-16 15:19:23.000000000 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_ppc.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + Unimplemented(); + return 0; +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + Unimplemented(); +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + Unimplemented(); +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + return NULL; +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return false; +} --- /dev/null 2015-09-16 15:19:24.000000000 -0700 +++ new/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp 2015-09-16 15:19:24.000000000 -0700 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2013, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_sparc.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + if (inst->is_call() || inst->is_jump()) { + return pc_offset + NativeCall::instruction_size; + } else if (inst->is_call_reg()) { + return pc_offset + NativeCallReg::instruction_size; + } else if (inst->is_sethi()) { + return pc_offset + NativeFarCall::instruction_size; + } else { + fatal("unsupported type of instruction for call site"); + return 0; + } +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + address pc = _instructions->start() + pc_offset; + Handle obj = HotSpotObjectConstantImpl::object(constant); + jobject value = JNIHandles::make_local(obj()); + if (HotSpotObjectConstantImpl::compressed(constant)) { +#ifdef _LP64 + int oop_index = _oop_recorder->find_index(value); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + _instructions->relocate(pc, rspec, 1); +#else + fatal("compressed oop on 32bit"); +#endif + } else { + NativeMovConstReg* move = nativeMovConstReg_at(pc); + move->set_data((intptr_t) value); + + // We need two relocations: one on the sethi and one on the add. + int oop_index = _oop_recorder->find_index(value); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + _instructions->relocate(pc + NativeMovConstReg::sethi_offset, rspec); + _instructions->relocate(pc + NativeMovConstReg::add_offset, rspec); + } +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + address pc = _instructions->start() + pc_offset; + NativeInstruction* inst = nativeInstruction_at(pc); + NativeInstruction* inst1 = nativeInstruction_at(pc + 4); + if(inst->is_sethi() && inst1->is_nop()) { + address const_start = _constants->start(); + address dest = _constants->start() + data_offset; + if(_constants_size > 0) { + _instructions->relocate(pc + NativeMovConstReg::sethi_offset, internal_word_Relocation::spec((address) dest)); + _instructions->relocate(pc + NativeMovConstReg::add_offset, internal_word_Relocation::spec((address) dest)); + } + TRACE_jvmci_3("relocating at %p (+%d) with destination at %d", pc, pc_offset, data_offset); + }else { + int const_size = align_size_up(_constants->end()-_constants->start(), CodeEntryAlignment); + NativeMovRegMem* load = nativeMovRegMem_at(pc); + // This offset must match with SPARCLoadConstantTableBaseOp.emitCode + load->set_offset(- (const_size - data_offset + Assembler::min_simm13())); + TRACE_jvmci_3("relocating ld at %p (+%d) with destination at %d", pc, pc_offset, data_offset); + } +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + fatal("CodeInstaller::pd_relocate_CodeBlob - sparc unimp"); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + address pc = (address) inst; + if (inst->is_call()) { + NativeCall* call = nativeCall_at(pc); + call->set_destination((address) foreign_call_destination); + _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec()); + } else if (inst->is_sethi()) { + NativeJump* jump = nativeJump_at(pc); + jump->set_jump_destination((address) foreign_call_destination); + _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec()); + } else { + fatal(err_msg("unknown call or jump instruction at %p", pc)); + } + TRACE_jvmci_3("relocating (foreign call) at %p", inst); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { +#ifdef ASSERT + Method* method = NULL; + // we need to check, this might also be an unresolved method + if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { + method = getMethodFromHotSpotMethod(hotspot_method); + } +#endif + switch (_next_call_type) { + case INLINE_INVOKE: + break; + case INVOKEVIRTUAL: + case INVOKEINTERFACE: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc)); + break; + } + case INVOKESTATIC: { + assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_static_call_stub()); + _instructions->relocate(call->instruction_address(), relocInfo::static_call_type); + break; + } + case INVOKESPECIAL: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type); + break; + } + default: + fatal("invalid _next_call_type value"); + break; + } +} + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + switch (mark) { + case POLL_NEAR: + fatal("unimplemented"); + break; + case POLL_FAR: + _instructions->relocate(pc, relocInfo::poll_type); + break; + case POLL_RETURN_NEAR: + fatal("unimplemented"); + break; + case POLL_RETURN_FAR: + _instructions->relocate(pc, relocInfo::poll_return_type); + break; + default: + fatal("invalid mark value"); + break; + } +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + if (jvmci_reg < RegisterImpl::number_of_registers) { + return as_Register(jvmci_reg)->as_VMReg(); + } else { + jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers; + floatRegisterNumber += MAX2(0, floatRegisterNumber-32); // Beginning with f32, only every second register is going to be addressed + if (floatRegisterNumber < FloatRegisterImpl::number_of_registers) { + return as_FloatRegister(floatRegisterNumber)->as_VMReg(); + } + ShouldNotReachHere(); + return NULL; + } +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return !hotspotRegister->is_FloatRegister(); +} --- /dev/null 2015-09-16 15:19:24.000000000 -0700 +++ new/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp 2015-09-16 15:19:24.000000000 -0700 @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2013, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "compiler/disassembler.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/sharedRuntime.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "asm/register.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/vmreg.hpp" +#include "vmreg_x86.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + if (inst->is_call() || inst->is_jump()) { + assert(NativeCall::instruction_size == (int)NativeJump::instruction_size, "unexpected size"); + return (pc_offset + NativeCall::instruction_size); + } else if (inst->is_mov_literal64()) { + // mov+call instruction pair + jint offset = pc_offset + NativeMovConstReg::instruction_size; + u_char* call = (u_char*) (_instructions->start() + offset); + if (call[0] == Assembler::REX_B) { + offset += 1; /* prefix byte for extended register R8-R15 */ + call++; + } + assert(call[0] == 0xFF, "expected call"); + offset += 2; /* opcode byte + modrm byte */ + return (offset); + } else if (inst->is_call_reg()) { + // the inlined vtable stub contains a "call register" instruction + assert(method != NULL, "only valid for virtual calls"); + return (pc_offset + ((NativeCallReg *) inst)->next_instruction_offset()); + } else if (inst->is_cond_jump()) { + address pc = (address) (inst); + return pc_offset + (jint) (Assembler::locate_next_instruction(pc) - pc); + } else { + fatal("unsupported type of instruction for call site"); + return 0; + } +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + address pc = _instructions->start() + pc_offset; + Handle obj = HotSpotObjectConstantImpl::object(constant); + jobject value = JNIHandles::make_local(obj()); + if (HotSpotObjectConstantImpl::compressed(constant)) { +#ifdef _LP64 + address operand = Assembler::locate_operand(pc, Assembler::narrow_oop_operand); + int oop_index = _oop_recorder->find_index(value); + _instructions->relocate(pc, oop_Relocation::spec(oop_index), Assembler::narrow_oop_operand); + TRACE_jvmci_3("relocating (narrow oop constant) at %p/%p", pc, operand); +#else + fatal("compressed oop on 32bit"); +#endif + } else { + address operand = Assembler::locate_operand(pc, Assembler::imm_operand); + *((jobject*) operand) = value; + _instructions->relocate(pc, oop_Relocation::spec_for_immediate(), Assembler::imm_operand); + TRACE_jvmci_3("relocating (oop constant) at %p/%p", pc, operand); + } +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + address pc = _instructions->start() + pc_offset; + + address operand = Assembler::locate_operand(pc, Assembler::disp32_operand); + address next_instruction = Assembler::locate_next_instruction(pc); + address dest = _constants->start() + data_offset; + + long disp = dest - next_instruction; + assert(disp == (jint) disp, "disp doesn't fit in 32 bits"); + *((jint*) operand) = (jint) disp; + + _instructions->relocate(pc, section_word_Relocation::spec((address) dest, CodeBuffer::SECT_CONSTS), Assembler::disp32_operand); + TRACE_jvmci_3("relocating at %p/%p with destination at %p (%d)", pc, operand, dest, data_offset); +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point()); + } else { + nativeJump_at((address)inst)->set_jump_destination(cb->code_begin()); + } + _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + address pc = (address) inst; + if (inst->is_call()) { + // NOTE: for call without a mov, the offset must fit a 32-bit immediate + // see also CompilerToVM.getMaxCallTargetOffset() + NativeCall* call = nativeCall_at(pc); + call->set_destination((address) foreign_call_destination); + _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + } else if (inst->is_mov_literal64()) { + NativeMovConstReg* mov = nativeMovConstReg_at(pc); + mov->set_data((intptr_t) foreign_call_destination); + _instructions->relocate(mov->instruction_address(), runtime_call_Relocation::spec(), Assembler::imm_operand); + } else if (inst->is_jump()) { + NativeJump* jump = nativeJump_at(pc); + jump->set_jump_destination((address) foreign_call_destination); + _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + } else if (inst->is_cond_jump()) { + address old_dest = nativeGeneralJump_at(pc)->jump_destination(); + address disp = Assembler::locate_operand(pc, Assembler::call32_operand); + *(jint*) disp += ((address) foreign_call_destination) - old_dest; + _instructions->relocate(pc, runtime_call_Relocation::spec(), Assembler::call32_operand); + } else { + fatal("unsupported relocation for foreign call"); + } + + TRACE_jvmci_3("relocating (foreign call) at %p", inst); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { +#ifdef ASSERT + Method* method = NULL; + // we need to check, this might also be an unresolved method + if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { + method = getMethodFromHotSpotMethod(hotspot_method); + } +#endif + switch (_next_call_type) { + case INLINE_INVOKE: + break; + case INVOKEVIRTUAL: + case INVOKEINTERFACE: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface"); + + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), + virtual_call_Relocation::spec(_invoke_mark_pc), + Assembler::call32_operand); + break; + } + case INVOKESTATIC: { + assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic"); + + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_static_call_stub()); + _instructions->relocate(call->instruction_address(), + relocInfo::static_call_type, Assembler::call32_operand); + break; + } + case INVOKESPECIAL: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), + relocInfo::opt_virtual_call_type, Assembler::call32_operand); + break; + } + default: + break; + } +} + +static void relocate_poll_near(address pc) { + NativeInstruction* ni = nativeInstruction_at(pc); + int32_t* disp = (int32_t*) Assembler::locate_operand(pc, Assembler::disp32_operand); + int32_t offset = *disp; // The Java code installed the polling page offset into the disp32 operand + intptr_t new_disp = (intptr_t) (os::get_polling_page() + offset) - (intptr_t) ni; + *disp = (int32_t)new_disp; +} + + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + switch (mark) { + case POLL_NEAR: { + relocate_poll_near(pc); + _instructions->relocate(pc, relocInfo::poll_type, Assembler::disp32_operand); + break; + } + case POLL_FAR: + // This is a load from a register so there is no relocatable operand. + // We just have to ensure that the format is not disp32_operand + // so that poll_Relocation::fix_relocation_after_move does the right + // thing (i.e. ignores this relocation record) + _instructions->relocate(pc, relocInfo::poll_type, Assembler::imm_operand); + break; + case POLL_RETURN_NEAR: { + relocate_poll_near(pc); + _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::disp32_operand); + break; + } + case POLL_RETURN_FAR: + // see comment above for POLL_FAR + _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::imm_operand); + break; + default: + fatal("invalid mark value"); + break; + } +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + if (jvmci_reg < RegisterImpl::number_of_registers) { + return as_Register(jvmci_reg)->as_VMReg(); + } else { + jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers; + if (floatRegisterNumber < XMMRegisterImpl::number_of_registers) { + return as_XMMRegister(floatRegisterNumber)->as_VMReg(); + } + ShouldNotReachHere(); + return NULL; + } +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return !(hotspotRegister->is_FloatRegister() || hotspotRegister->is_XMMRegister()); +} --- /dev/null 2015-09-16 15:19:25.000000000 -0700 +++ new/src/cpu/x86/vm/registerMap_x86.cpp 2015-09-16 15:19:25.000000000 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "runtime/registerMap.hpp" +#include "vmreg_x86.inline.hpp" + +address RegisterMap::pd_location(VMReg reg) const { + if (reg->is_XMMRegister()) { + int regBase = reg->value() - ConcreteRegisterImpl::max_fpr; + if (regBase % 4 == 0) { + // Reads of the low and high 16 byte parts should be handled by location itself + // because they have separate callee saved entries. + // See RegisterSaver::save_live_registers(). + return NULL; + } + VMReg baseReg = as_XMMRegister(regBase / XMMRegisterImpl::max_slots_per_register)->as_VMReg(); + intptr_t offset = (reg->value() - baseReg->value()) * VMRegImpl::stack_slot_size; // offset in bytes + if (offset >= 16) { + // The high part of YMM registers are saved in a their own area in the frame + baseReg = baseReg->next()->next()->next()->next(); + offset -= 16; + } + address baseLocation = location(baseReg); + if (baseLocation != NULL) { + return baseLocation + offset; + } + } + return NULL; +} --- /dev/null 2015-09-16 15:19:26.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.amd64/src/jdk/internal/jvmci/amd64/AMD64.java 2015-09-16 15:19:25.000000000 -0700 @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.amd64; + +import static jdk.internal.jvmci.code.MemoryBarriers.*; +import static jdk.internal.jvmci.code.Register.*; + +import java.nio.*; +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.code.Register.RegisterCategory; +import jdk.internal.jvmci.meta.*; + +/** + * Represents the AMD64 architecture. + */ +public class AMD64 extends Architecture { + + public static final RegisterCategory CPU = new RegisterCategory("CPU"); + + // @formatter:off + + // General purpose CPU registers + public static final Register rax = new Register(0, 0, "rax", CPU); + public static final Register rcx = new Register(1, 1, "rcx", CPU); + public static final Register rdx = new Register(2, 2, "rdx", CPU); + public static final Register rbx = new Register(3, 3, "rbx", CPU); + public static final Register rsp = new Register(4, 4, "rsp", CPU); + public static final Register rbp = new Register(5, 5, "rbp", CPU); + public static final Register rsi = new Register(6, 6, "rsi", CPU); + public static final Register rdi = new Register(7, 7, "rdi", CPU); + + public static final Register r8 = new Register(8, 8, "r8", CPU); + public static final Register r9 = new Register(9, 9, "r9", CPU); + public static final Register r10 = new Register(10, 10, "r10", CPU); + public static final Register r11 = new Register(11, 11, "r11", CPU); + public static final Register r12 = new Register(12, 12, "r12", CPU); + public static final Register r13 = new Register(13, 13, "r13", CPU); + public static final Register r14 = new Register(14, 14, "r14", CPU); + public static final Register r15 = new Register(15, 15, "r15", CPU); + + public static final Register[] cpuRegisters = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15 + }; + + private static final int XMM_REFERENCE_MAP_SHIFT = 2; + + public static final RegisterCategory XMM = new RegisterCategory("XMM", cpuRegisters.length, XMM_REFERENCE_MAP_SHIFT); + + // XMM registers + public static final Register xmm0 = new Register(16, 0, "xmm0", XMM); + public static final Register xmm1 = new Register(17, 1, "xmm1", XMM); + public static final Register xmm2 = new Register(18, 2, "xmm2", XMM); + public static final Register xmm3 = new Register(19, 3, "xmm3", XMM); + public static final Register xmm4 = new Register(20, 4, "xmm4", XMM); + public static final Register xmm5 = new Register(21, 5, "xmm5", XMM); + public static final Register xmm6 = new Register(22, 6, "xmm6", XMM); + public static final Register xmm7 = new Register(23, 7, "xmm7", XMM); + + public static final Register xmm8 = new Register(24, 8, "xmm8", XMM); + public static final Register xmm9 = new Register(25, 9, "xmm9", XMM); + public static final Register xmm10 = new Register(26, 10, "xmm10", XMM); + public static final Register xmm11 = new Register(27, 11, "xmm11", XMM); + public static final Register xmm12 = new Register(28, 12, "xmm12", XMM); + public static final Register xmm13 = new Register(29, 13, "xmm13", XMM); + public static final Register xmm14 = new Register(30, 14, "xmm14", XMM); + public static final Register xmm15 = new Register(31, 15, "xmm15", XMM); + + public static final Register[] xmmRegisters = { + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + + public static final Register[] cpuxmmRegisters = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + + /** + * Register used to construct an instruction-relative address. + */ + public static final Register rip = new Register(32, -1, "rip", SPECIAL); + + public static final Register[] allRegisters = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, + rip + }; + + // @formatter:on + + /** + * Basic set of CPU features mirroring what is returned from the cpuid instruction. + */ + public static enum CPUFeature { + SSE, + SSE2, + SSE3, + SSE4a, + SSE4_1, + SSE4_2, + SSSE3, + POPCNT, + LZCNT, + AVX, + AVX2, + ERMS, + AMD_3DNOW_PREFETCH, + AES, + BMI1 + } + + private final EnumSet features; + + /** + * Set of flags to control code emission. + */ + public static enum Flag { + UseCountLeadingZerosInstruction, + UseCountTrailingZerosInstruction + } + + private final EnumSet flags; + + public AMD64(EnumSet features, EnumSet flags) { + super("AMD64", JavaKind.Long, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, cpuRegisters.length + (xmmRegisters.length << XMM_REFERENCE_MAP_SHIFT), 8); + this.features = features; + this.flags = flags; + assert features.contains(CPUFeature.SSE2) : "minimum config for x64"; + } + + public EnumSet getFeatures() { + return features; + } + + public EnumSet getFlags() { + return flags; + } + + @Override + public PlatformKind getPlatformKind(JavaKind javaKind) { + if (javaKind.isObject()) { + return getWordKind(); + } else { + return javaKind; + } + } + + @Override + public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) { + if (!(platformKind instanceof JavaKind)) { + return false; + } + + JavaKind kind = (JavaKind) platformKind; + if (category.equals(CPU)) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + return true; + } + } else if (category.equals(XMM)) { + switch (kind) { + case Float: + case Double: + return true; + } + } + + return false; + } + + @Override + public PlatformKind getLargestStorableKind(RegisterCategory category) { + if (category.equals(CPU)) { + return JavaKind.Long; + } else if (category.equals(XMM)) { + return JavaKind.Double; + } else { + return JavaKind.Illegal; + } + } +} --- /dev/null 2015-09-16 15:19:26.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/overview.html 2015-09-16 15:19:26.000000000 -0700 @@ -0,0 +1,37 @@ + + + + + + + + +The jdk.internal.jvmci.code project provides an API to the runtime's native code cache. +It allows installation and execution of native code. + + + --- /dev/null 2015-09-16 15:19:27.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/AbstractAddress.java 2015-09-16 15:19:27.000000000 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +/** + * Abstract base class that represents a platform specific address. + */ +public abstract class AbstractAddress { +} --- /dev/null 2015-09-16 15:19:27.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/Architecture.java 2015-09-16 15:19:27.000000000 -0700 @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.nio.*; +import java.util.*; + +import jdk.internal.jvmci.code.Register.RegisterCategory; +import jdk.internal.jvmci.meta.*; + +/** + * Represents a CPU architecture, including information such as its endianness, CPU registers, word + * width, etc. + */ +public abstract class Architecture { + + /** + * The number of entries required in a {@link ReferenceMap} covering all the registers that may + * store references. The index of a register in the reference map is given by + * {@link Register#getReferenceMapIndex()}. + */ + private final int registerReferenceMapSize; + + /** + * The architecture specific type of a native word. + */ + private final PlatformKind wordKind; + + /** + * The name of this architecture (e.g. "AMD64", "SPARCv9"). + */ + private final String name; + + /** + * Array of all available registers on this architecture. The index of each register in this + * array is equal to its {@linkplain Register#number number}. + */ + private final Register[] registers; + + /** + * The byte ordering can be either little or big endian. + */ + private final ByteOrder byteOrder; + + /** + * Whether the architecture supports unaligned memory accesses. + */ + private final boolean unalignedMemoryAccess; + + /** + * Mask of the barrier constants denoting the barriers that are not required to be explicitly + * inserted under this architecture. + */ + private final int implicitMemoryBarriers; + + /** + * Offset in bytes from the beginning of a call instruction to the displacement. + */ + private final int machineCodeCallDisplacementOffset; + + /** + * The size of the return address pushed to the stack by a call instruction. A value of 0 + * denotes that call linkage uses registers instead (e.g. SPARC). + */ + private final int returnAddressSize; + + protected Architecture(String name, PlatformKind wordKind, ByteOrder byteOrder, boolean unalignedMemoryAccess, Register[] registers, int implicitMemoryBarriers, int nativeCallDisplacementOffset, + int registerReferenceMapSize, int returnAddressSize) { + this.name = name; + this.registers = registers; + this.wordKind = wordKind; + this.byteOrder = byteOrder; + this.unalignedMemoryAccess = unalignedMemoryAccess; + this.implicitMemoryBarriers = implicitMemoryBarriers; + this.machineCodeCallDisplacementOffset = nativeCallDisplacementOffset; + this.registerReferenceMapSize = registerReferenceMapSize; + this.returnAddressSize = returnAddressSize; + } + + /** + * Converts this architecture to a string. + * + * @return the string representation of this architecture + */ + @Override + public final String toString() { + return getName().toLowerCase(); + } + + public int getRegisterReferenceMapSize() { + return registerReferenceMapSize; + } + + /** + * Gets the natural size of words (typically registers and pointers) of this architecture, in + * bytes. + */ + public int getWordSize() { + return wordKind.getSizeInBytes(); + } + + public PlatformKind getWordKind() { + return wordKind; + } + + /** + * Gets the name of this architecture. + */ + public String getName() { + return name; + } + + /** + * Gets an array of all available registers on this architecture. The index of each register in + * this array is equal to its {@linkplain Register#number number}. + */ + public Register[] getRegisters() { + return registers.clone(); + } + + public ByteOrder getByteOrder() { + return byteOrder; + } + + /** + * @return true if the architecture supports unaligned memory accesses. + */ + public boolean supportsUnalignedMemoryAccess() { + return unalignedMemoryAccess; + } + + /** + * Gets the size of the return address pushed to the stack by a call instruction. A value of 0 + * denotes that call linkage uses registers instead. + */ + public int getReturnAddressSize() { + return returnAddressSize; + } + + /** + * Gets the offset in bytes from the beginning of a call instruction to the displacement. + */ + public int getMachineCodeCallDisplacementOffset() { + return machineCodeCallDisplacementOffset; + } + + /** + * Determines the barriers in a given barrier mask that are explicitly required on this + * architecture. + * + * @param barriers a mask of the barrier constants + * @return the value of {@code barriers} minus the barriers unnecessary on this architecture + */ + public final int requiredBarriers(int barriers) { + return barriers & ~implicitMemoryBarriers; + } + + /** + * Determine whether a kind can be stored in a register of a given category. + * + * @param category the category of the register + * @param kind the kind that should be stored in the register + */ + public abstract boolean canStoreValue(RegisterCategory category, PlatformKind kind); + + /** + * Return the largest kind that can be stored in a register of a given category. + * + * @param category the category of the register + * @return the largest kind that can be stored in a register {@code category} + */ + public abstract PlatformKind getLargestStorableKind(RegisterCategory category); + + /** + * Return the {@link PlatformKind} that is used to store values of a given {@link JavaKind}. + */ + public abstract PlatformKind getPlatformKind(JavaKind javaKind); + + @Override + public final boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Architecture) { + Architecture that = (Architecture) obj; + if (this.name.equals(that.name)) { + assert this.byteOrder.equals(that.byteOrder); + assert this.implicitMemoryBarriers == that.implicitMemoryBarriers; + assert this.machineCodeCallDisplacementOffset == that.machineCodeCallDisplacementOffset; + assert this.registerReferenceMapSize == that.registerReferenceMapSize; + assert Arrays.equals(this.registers, that.registers); + assert this.returnAddressSize == that.returnAddressSize; + assert this.unalignedMemoryAccess == that.unalignedMemoryAccess; + assert this.wordKind == that.wordKind; + return true; + } + } + return false; + } + + @Override + public final int hashCode() { + return name.hashCode(); + } +} --- /dev/null 2015-09-16 15:19:28.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/BailoutException.java 2015-09-16 15:19:28.000000000 -0700 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.util.*; + +/** + * Exception thrown when the compiler refuses to compile a method because of problems with the + * method. e.g. bytecode wouldn't verify, too big, JSR/ret too complicated, etc. This exception is + * not meant to indicate problems with the compiler itself. + */ +public class BailoutException extends RuntimeException { + + public static final long serialVersionUID = 8974598793458772L; + private final boolean permanent; + + /** + * Creates a new {@link BailoutException}. + * + * + * @param args parameters to the formatter + */ + public BailoutException(String format, Object... args) { + super(String.format(Locale.ENGLISH, format, args)); + this.permanent = true; + } + + /** + * Creates a new {@link BailoutException}. + * + * + * @param args parameters to the formatter + */ + public BailoutException(Throwable cause, String format, Object... args) { + super(String.format(Locale.ENGLISH, format, args), cause); + this.permanent = true; + } + + /** + * Creates a new {@link BailoutException}. + * + * @param permanent specifies whether this exception will occur again if compilation is retried + * @param args parameters to the formatter + */ + public BailoutException(boolean permanent, String format, Object... args) { + super(String.format(Locale.ENGLISH, format, args)); + this.permanent = permanent; + } + + /** + * @return whether this exception will occur again if compilation is retried + */ + public boolean isPermanent() { + return permanent; + } +} --- /dev/null 2015-09-16 15:19:29.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/BytecodeFrame.java 2015-09-16 15:19:28.000000000 -0700 @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +/** + * Represents the Java bytecode frame state(s) at a given position including {@link Value locations} + * where to find the local variables, operand stack values and locked objects of the bytecode + * frame(s). + */ +public class BytecodeFrame extends BytecodePosition { + + /** + * An array of values representing how to reconstruct the state of the Java frame. This is array + * is partitioned as follows: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Start index (inclusive)End index (exclusive)Description
0numLocalsLocal variables
numLocalsnumLocals + numStackOperand stack
numLocals + numStackvalues.lengthLocked objects
+ *

+ * Note that the number of locals and the number of stack slots may be smaller than the maximum + * number of locals and stack slots as specified in the compiled method. + */ + public final JavaValue[] values; + + /** + * An array describing the Java kind of the {@link #values}. It records a kind for the locals + * and the operand stack. + */ + public final JavaKind[] slotKinds; + + /** + * The number of locals in the values array. + */ + public final int numLocals; + + /** + * The number of stack slots in the values array. + */ + public final int numStack; + + /** + * The number of locks in the values array. + */ + public final int numLocks; + + /** + * True if this is a position inside an exception handler before the exception object has been + * consumed. In this case, {@link #numStack} {@code == 1} and {@link #getStackValue(int) + * getStackValue(0)} is the location of the exception object. If deoptimization happens at this + * position, the interpreter will rethrow the exception instead of executing the bytecode + * instruction at this position. + */ + public final boolean rethrowException; + + public final boolean duringCall; + + /** + * This BCI should be used for frame states that are built for code with no meaningful BCI. + */ + public static final int UNKNOWN_BCI = -5; + + /** + * The BCI for exception unwind. This is synthetic code and has no representation in bytecode. + * In contrast with {@link #AFTER_EXCEPTION_BCI}, at this point, if the method is synchronized, + * the monitor is still held. + */ + public static final int UNWIND_BCI = -1; + + /** + * The BCI for the state before starting to execute a method. Note that if the method is + * synchronized, the monitor is not yet held. + */ + public static final int BEFORE_BCI = -2; + + /** + * The BCI for the state after finishing the execution of a method and returning normally. Note + * that if the method was synchronized the monitor is already released. + */ + public static final int AFTER_BCI = -3; + + /** + * The BCI for exception unwind. This is synthetic code and has no representation in bytecode. + * In contrast with {@link #UNWIND_BCI}, at this point, if the method is synchronized, the + * monitor is already released. + */ + public static final int AFTER_EXCEPTION_BCI = -4; + + /** + * This BCI should be used for states that cannot be the target of a deoptimization, like + * snippet frame states. + */ + public static final int INVALID_FRAMESTATE_BCI = -6; + + /** + * Determines if a given BCI matches one of the placeholder BCI constants defined in this class. + */ + public static boolean isPlaceholderBci(int bci) { + return bci < 0; + } + + /** + * Gets the name of a given placeholder BCI. + */ + public static String getPlaceholderBciName(int bci) { + assert isPlaceholderBci(bci); + if (bci == BytecodeFrame.AFTER_BCI) { + return "AFTER_BCI"; + } else if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { + return "AFTER_EXCEPTION_BCI"; + } else if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { + return "INVALID_FRAMESTATE_BCI"; + } else if (bci == BytecodeFrame.BEFORE_BCI) { + return "BEFORE_BCI"; + } else if (bci == BytecodeFrame.UNKNOWN_BCI) { + return "UNKNOWN_BCI"; + } else { + assert bci == BytecodeFrame.UNWIND_BCI; + return "UNWIND_BCI"; + } + } + + /** + * Creates a new frame object. + * + * @param caller the caller frame (which may be {@code null}) + * @param method the method + * @param bci a BCI within the method + * @param rethrowException specifies if the VM should re-throw the pending exception when + * deopt'ing using this frame + * @param values the frame state {@link #values} + * @param numLocals the number of local variables + * @param numStack the depth of the stack + * @param numLocks the number of locked objects + */ + public BytecodeFrame(BytecodeFrame caller, ResolvedJavaMethod method, int bci, boolean rethrowException, boolean duringCall, JavaValue[] values, JavaKind[] slotKinds, int numLocals, int numStack, + int numLocks) { + super(caller, method, bci); + assert values != null; + this.rethrowException = rethrowException; + this.duringCall = duringCall; + this.values = values; + this.slotKinds = slotKinds; + this.numLocals = numLocals; + this.numStack = numStack; + this.numLocks = numLocks; + assert !rethrowException || numStack == 1 : "must have exception on top of the stack"; + } + + /** + * Ensure that the frame state is formatted as expected by the JVM, with null or Illegal in the + * slot following a double word item. This should really be checked in FrameState itself but + * because of Word type rewriting and alternative backends that can't be done. + */ + public boolean validateFormat() { + if (caller() != null) { + caller().validateFormat(); + } + for (int i = 0; i < numLocals + numStack; i++) { + if (values[i] != null) { + JavaKind kind = slotKinds[i]; + if (kind.needsTwoSlots()) { + assert slotKinds.length > i + 1 : String.format("missing second word %s", this); + assert slotKinds[i + 1] == JavaKind.Illegal : this; + } + } + } + return true; + } + + /** + * Gets the value representing the specified local variable. + * + * @param i the local variable index + * @return the value that can be used to reconstruct the local's current value + */ + public JavaValue getLocalValue(int i) { + return values[i]; + } + + /** + * Gets the value representing the specified stack slot. + * + * @param i the stack index + * @return the value that can be used to reconstruct the stack slot's current value + */ + public JavaValue getStackValue(int i) { + return values[i + numLocals]; + } + + /** + * Gets the value representing the specified lock. + * + * @param i the lock index + * @return the value that can be used to reconstruct the lock's current value + */ + public JavaValue getLockValue(int i) { + return values[i + numLocals + numStack]; + } + + /** + * Gets the caller of this frame. + * + * @return {@code null} if this frame has no caller + */ + public BytecodeFrame caller() { + return (BytecodeFrame) getCaller(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof BytecodeFrame && super.equals(obj)) { + BytecodeFrame that = (BytecodeFrame) obj; + // @formatter:off + if (this.duringCall == that.duringCall && + this.rethrowException == that.rethrowException && + this.numLocals == that.numLocals && + this.numLocks == that.numLocks && + this.numStack == that.numStack && + Arrays.equals(this.values, that.values)) { + return true; + } + // @formatter:off + return true; + } + return false; + } + + @Override + public String toString() { + return CodeUtil.append(new StringBuilder(100), this).toString(); + } +} --- /dev/null 2015-09-16 15:19:29.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/BytecodePosition.java 2015-09-16 15:19:29.000000000 -0700 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009, 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +/** + * Represents a code position, that is, a chain of inlined methods with bytecode locations, that is + * communicated from the compiler to the runtime system. A code position can be used by the runtime + * system to reconstruct a source-level stack trace for exceptions and to create + * {@linkplain BytecodeFrame frames} for deoptimization. + */ +public class BytecodePosition { + + private final BytecodePosition caller; + private final ResolvedJavaMethod method; + private final int bci; + + /** + * Constructs a new object representing a given parent/caller, a given method, and a given BCI. + * + * @param caller the parent position + * @param method the method + * @param bci a BCI within the method + */ + public BytecodePosition(BytecodePosition caller, ResolvedJavaMethod method, int bci) { + assert method != null; + this.caller = caller; + this.method = method; + this.bci = bci; + } + + /** + * Converts this code position to a string representation. + * + * @return a string representation of this code position + */ + @Override + public String toString() { + return CodeUtil.append(new StringBuilder(100), this).toString(); + } + + /** + * Deep equality test. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && getClass() == obj.getClass()) { + BytecodePosition that = (BytecodePosition) obj; + if (this.bci == that.bci && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.caller, that.caller)) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return getBCI(); + } + + /** + * @return The location within the method, as a bytecode index. The constant {@code -1} may be + * used to indicate the location is unknown, for example within code synthesized by the + * compiler. + */ + public int getBCI() { + return bci; + } + + /** + * @return The runtime interface method for this position. + */ + public ResolvedJavaMethod getMethod() { + return method; + } + + /** + * The position where this position has been called, {@code null} if none. + */ + public BytecodePosition getCaller() { + return caller; + } + + /** + * Adds a caller to the current position returning the new position. + */ + public BytecodePosition addCaller(BytecodePosition link) { + if (getCaller() == null) { + return new BytecodePosition(link, getMethod(), getBCI()); + } else { + return new BytecodePosition(getCaller().addCaller(link), getMethod(), getBCI()); + } + } +} --- /dev/null 2015-09-16 15:19:30.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/CallingConvention.java 2015-09-16 15:19:30.000000000 -0700 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2009, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import jdk.internal.jvmci.meta.*; +import static jdk.internal.jvmci.code.ValueUtil.*; + +/** + * A calling convention describes the locations in which the arguments for a call are placed and the + * location in which the return value is placed if the call is not void. + */ +public class CallingConvention { + + /** + * Constants denoting the type of a call for which a calling convention is requested. + */ + public enum Type { + /** + * A request for the outgoing argument locations at a call site to Java code. + */ + JavaCall(true), + + /** + * A request for the incoming argument locations. + */ + JavaCallee(false), + + /** + * A request for the outgoing argument locations at a call site to external native code that + * complies with the platform ABI. + */ + NativeCall(true); + + /** + * Determines if this is a request for the outgoing argument locations at a call site. + */ + public final boolean out; + + public static final Type[] VALUES = values(); + + private Type(boolean out) { + this.out = out; + } + } + + /** + * The amount of stack space (in bytes) required for the stack-based arguments of the call. + */ + private final int stackSize; + + private final AllocatableValue returnLocation; + + /** + * The ordered locations in which the arguments are placed. + */ + private final AllocatableValue[] argumentLocations; + + /** + * Creates a description of the registers and stack locations used by a call. + * + * @param stackSize amount of stack space (in bytes) required for the stack-based arguments of + * the call + * @param returnLocation the location for the return value or {@link Value#ILLEGAL} if a void + * call + * @param argumentLocations the ordered locations in which the arguments are placed + */ + public CallingConvention(int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) { + assert argumentLocations != null; + assert returnLocation != null; + this.argumentLocations = argumentLocations; + this.stackSize = stackSize; + this.returnLocation = returnLocation; + assert verify(); + } + + /** + * Gets the location for the return value or {@link Value#ILLEGAL} if a void call. + */ + public AllocatableValue getReturn() { + return returnLocation; + } + + /** + * Gets the location for the {@code index}'th argument. + */ + public AllocatableValue getArgument(int index) { + return argumentLocations[index]; + } + + /** + * Gets the amount of stack space (in bytes) required for the stack-based arguments of the call. + */ + public int getStackSize() { + return stackSize; + } + + /** + * Gets the number of locations required for the arguments. + */ + public int getArgumentCount() { + return argumentLocations.length; + } + + /** + * Gets the locations required for the arguments. + */ + public AllocatableValue[] getArguments() { + if (argumentLocations.length == 0) { + return argumentLocations; + } + return argumentLocations.clone(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("CallingConvention["); + String sep = ""; + for (Value op : argumentLocations) { + sb.append(sep).append(op); + sep = ", "; + } + if (!returnLocation.equals(Value.ILLEGAL)) { + sb.append(" -> ").append(returnLocation); + } + sb.append("]"); + return sb.toString(); + } + + private boolean verify() { + for (int i = 0; i < argumentLocations.length; i++) { + Value location = argumentLocations[i]; + assert isStackSlot(location) || isAllocatableValue(location); + } + return true; + } +} --- /dev/null 2015-09-16 15:19:30.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/CodeCacheProvider.java 2015-09-16 15:19:30.000000000 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import jdk.internal.jvmci.code.CompilationResult.*; +import jdk.internal.jvmci.code.DataSection.*; +import jdk.internal.jvmci.meta.*; + +/** + * Access to code cache related details and requirements. + */ +public interface CodeCacheProvider { + + /** + * Adds the given compilation result as an implementation of the given method without making it + * the default implementation. + * + * @param method a method to which the executable code is begin added + * @param compResult the compilation result to be added + * @param speculationLog the speculation log to be used + * @return a reference to the compiled and ready-to-run code or throws a + * {@link BailoutException} if the code installation failed + */ + InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode); + + /** + * Sets the given compilation result as the default implementation of the given method. + * + * @param method a method to which the executable code is begin added + * @param compResult the compilation result to be added + * @return a reference to the compiled and ready-to-run code or null if the code installation + * failed + */ + InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult); + + /** + * Gets a name for a {@link Mark} mark. + */ + default String getMarkName(Mark mark) { + return String.valueOf(mark.id); + } + + /** + * Gets a name for the {@linkplain Call#target target} of a {@link Call}. + */ + default String getTargetName(Call call) { + return String.valueOf(call.target); + } + + /** + * Gets the register configuration to use when compiling a given method. + */ + RegisterConfig getRegisterConfig(); + + /** + * Minimum size of the stack area reserved for outgoing parameters. This area is reserved in all + * cases, even when the compiled method has no regular call instructions. + * + * @return the minimum size of the outgoing parameter area in bytes + */ + int getMinimumOutgoingSize(); + + /** + * Determines if a {@link DataPatch} should be created for a given primitive constant that is + * part of a {@link CompilationResult}. A data patch is always created for an object constant. + */ + boolean needsDataPatch(JavaConstant constant); + + /** + * Create a {@link Data} item for one or more {@link Constant Constants}, that can be used in a + * {@link DataPatch}. If more than one {@link Constant} is given, then they are tightly packed + * into a single {@link Data} item. + */ + Data createDataItem(Constant... constants); + + /** + * Gets a description of the target architecture. + */ + TargetDescription getTarget(); + + /** + * Create a new speculation log for the target runtime. + */ + SpeculationLog createSpeculationLog(); +} --- /dev/null 2015-09-16 15:19:31.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/CodeUtil.java 2015-09-16 15:19:31.000000000 -0700 @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2010, 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +/** + * Miscellaneous collection of utility methods used by {@code jdk.internal.jvmci.code} and its + * clients. + */ +public class CodeUtil { + + public static final String NEW_LINE = String.format("%n"); + + public static final int K = 1024; + public static final int M = 1024 * 1024; + + public static boolean isOdd(int n) { + return (n & 1) == 1; + } + + public static boolean isEven(int n) { + return (n & 1) == 0; + } + + /** + * Checks whether the specified integer is a power of two. + * + * @param val the value to check + * @return {@code true} if the value is a power of two; {@code false} otherwise + */ + public static boolean isPowerOf2(int val) { + return val > 0 && (val & val - 1) == 0; + } + + /** + * Checks whether the specified long is a power of two. + * + * @param val the value to check + * @return {@code true} if the value is a power of two; {@code false} otherwise + */ + public static boolean isPowerOf2(long val) { + return val > 0 && (val & val - 1) == 0; + } + + /** + * Computes the log (base 2) of the specified integer, rounding down. (E.g {@code log2(8) = 3}, + * {@code log2(21) = 4} ) + * + * @param val the value + * @return the log base 2 of the value + */ + public static int log2(int val) { + assert val > 0; + return (Integer.SIZE - 1) - Integer.numberOfLeadingZeros(val); + } + + /** + * Computes the log (base 2) of the specified long, rounding down. (E.g {@code log2(8) = 3}, + * {@code log2(21) = 4}) + * + * @param val the value + * @return the log base 2 of the value + */ + public static int log2(long val) { + assert val > 0; + return (Long.SIZE - 1) - Long.numberOfLeadingZeros(val); + } + + /** + * Narrow an integer value to a given bit width, and return the result as a signed long. + * + * @param value the value + * @param resultBits the result bit width + * @return {@code value} interpreted as {@code resultBits} bit number, encoded as signed long + */ + public static long narrow(long value, int resultBits) { + long ret = value & mask(resultBits); + return signExtend(ret, resultBits); + } + + /** + * Sign extend an integer. + * + * @param value the input value + * @param inputBits the bit width of the input value + * @return a signed long with the same value as the signed {@code inputBits}-bit number + * {@code value} + */ + public static long signExtend(long value, int inputBits) { + if (inputBits < 64) { + if ((value >>> (inputBits - 1) & 1) == 1) { + return value | (-1L << inputBits); + } else { + return value & ~(-1L << inputBits); + } + } else { + return value; + } + } + + /** + * Zero extend an integer. + * + * @param value the input value + * @param inputBits the bit width of the input value + * @return an unsigned long with the same value as the unsigned {@code inputBits}-bit number + * {@code value} + */ + public static long zeroExtend(long value, int inputBits) { + if (inputBits < 64) { + return value & ~(-1L << inputBits); + } else { + return value; + } + } + + /** + * Convert an integer to long. + * + * @param value the input value + * @param inputBits the bit width of the input value + * @param unsigned whether the values should be interpreted as signed or unsigned + * @return a long with the same value as the {@code inputBits}-bit number {@code value} + */ + public static long convert(long value, int inputBits, boolean unsigned) { + if (unsigned) { + return zeroExtend(value, inputBits); + } else { + return signExtend(value, inputBits); + } + } + + /** + * Get a bitmask with the low {@code bits} bit set and the high {@code 64 - bits} bit clear. + */ + public static long mask(int bits) { + assert 0 <= bits && bits <= 64; + if (bits == 64) { + return 0xffffffffffffffffL; + } else { + return (1L << bits) - 1; + } + } + + /** + * Get the minimum value representable in a {@code bits} bit signed integer. + */ + public static long minValue(int bits) { + assert 0 < bits && bits <= 64; + return -1L << (bits - 1); + } + + /** + * Get the maximum value representable in a {@code bits} bit signed integer. + */ + public static long maxValue(int bits) { + assert 0 < bits && bits <= 64; + return mask(bits - 1); + } + + /** + * Formats the values in a frame as a tabulated string. + * + * @param frame + * @return the values in {@code frame} as a tabulated string + */ + public static String tabulateValues(BytecodeFrame frame) { + int cols = Math.max(frame.numLocals, Math.max(frame.numStack, frame.numLocks)); + assert cols > 0; + ArrayList cells = new ArrayList<>(); + cells.add(""); + for (int i = 0; i < cols; i++) { + cells.add(i); + } + cols++; + if (frame.numLocals != 0) { + cells.add("locals:"); + cells.addAll(Arrays.asList(frame.values).subList(0, frame.numLocals)); + cells.addAll(Collections.nCopies(cols - frame.numLocals - 1, "")); + } + if (frame.numStack != 0) { + cells.add("stack:"); + cells.addAll(Arrays.asList(frame.values).subList(frame.numLocals, frame.numLocals + frame.numStack)); + cells.addAll(Collections.nCopies(cols - frame.numStack - 1, "")); + } + if (frame.numLocks != 0) { + cells.add("locks:"); + cells.addAll(Arrays.asList(frame.values).subList(frame.numLocals + frame.numStack, frame.values.length)); + cells.addAll(Collections.nCopies(cols - frame.numLocks - 1, "")); + } + Object[] cellArray = cells.toArray(); + for (int i = 0; i < cellArray.length; i++) { + if ((i % cols) != 0) { + cellArray[i] = "|" + cellArray[i]; + } + } + return CodeUtil.tabulate(cellArray, cols, 1, 1); + } + + /** + * Formats a given table as a string. The value of each cell is produced by + * {@link String#valueOf(Object)}. + * + * @param cells the cells of the table in row-major order + * @param cols the number of columns per row + * @param lpad the number of space padding inserted before each formatted cell value + * @param rpad the number of space padding inserted after each formatted cell value + * @return a string with one line per row and each column left-aligned + */ + public static String tabulate(Object[] cells, int cols, int lpad, int rpad) { + int rows = (cells.length + (cols - 1)) / cols; + int[] colWidths = new int[cols]; + for (int col = 0; col < cols; col++) { + for (int row = 0; row < rows; row++) { + int index = col + (row * cols); + if (index < cells.length) { + Object cell = cells[index]; + colWidths[col] = Math.max(colWidths[col], String.valueOf(cell).length()); + } + } + } + StringBuilder sb = new StringBuilder(); + String nl = NEW_LINE; + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + int index = col + (row * cols); + if (index < cells.length) { + for (int i = 0; i < lpad; i++) { + sb.append(' '); + } + Object cell = cells[index]; + String s = String.valueOf(cell); + int w = s.length(); + sb.append(s); + while (w < colWidths[col]) { + sb.append(' '); + w++; + } + for (int i = 0; i < rpad; i++) { + sb.append(' '); + } + } + } + sb.append(nl); + } + return sb.toString(); + } + + /** + * Appends a formatted code position to a {@link StringBuilder}. + * + * @param sb the {@link StringBuilder} to append to + * @param pos the code position to format and append to {@code sb} + * @return the value of {@code sb} + */ + public static StringBuilder append(StringBuilder sb, BytecodePosition pos) { + MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI()); + if (pos.getCaller() != null) { + sb.append(NEW_LINE); + append(sb, pos.getCaller()); + } + return sb; + } + + /** + * Appends a formatted frame to a {@link StringBuilder}. + * + * @param sb the {@link StringBuilder} to append to + * @param frame the frame to format and append to {@code sb} + * @return the value of {@code sb} + */ + public static StringBuilder append(StringBuilder sb, BytecodeFrame frame) { + MetaUtil.appendLocation(sb.append("at "), frame.getMethod(), frame.getBCI()); + assert sb.charAt(sb.length() - 1) == ']'; + sb.deleteCharAt(sb.length() - 1); + sb.append(", duringCall: ").append(frame.duringCall).append(", rethrow: ").append(frame.rethrowException).append(']'); + if (frame.values != null && frame.values.length > 0) { + sb.append(NEW_LINE); + String table = tabulateValues(frame); + String[] rows = table.split(NEW_LINE); + for (int i = 0; i < rows.length; i++) { + String row = rows[i]; + if (!row.trim().isEmpty()) { + sb.append(" ").append(row); + if (i != rows.length - 1) { + sb.append(NEW_LINE); + } + } + } + } + if (frame.caller() != null) { + sb.append(NEW_LINE); + append(sb, frame.caller()); + } else if (frame.getCaller() != null) { + sb.append(NEW_LINE); + append(sb, frame.getCaller()); + } + return sb; + } + + public interface RefMapFormatter { + + String formatStackSlot(int frameRefMapIndex); + + String formatRegister(int regRefMapIndex); + } + + /** + * Formats a location in a register reference map. + */ + public static class DefaultRegFormatter implements RefMapFormatter { + + private final Register[] registers; + + public DefaultRegFormatter(Architecture arch) { + registers = new Register[arch.getRegisterReferenceMapSize()]; + for (Register r : arch.getRegisters()) { + if (r.getReferenceMapIndex() >= 0) { + registers[r.getReferenceMapIndex()] = r; + } + } + } + + public String formatStackSlot(int frameRefMapIndex) { + return null; + } + + public String formatRegister(int regRefMapIndex) { + int i = regRefMapIndex; + int idx = 0; + while (registers[i] == null) { + i--; + idx++; + } + if (idx == 0) { + return registers[i].toString(); + } else { + return String.format("%s+%d", registers[i].toString(), idx); + } + } + } + + /** + * Formats a location present in a register or frame reference map. + */ + public static class DefaultRefMapFormatter extends DefaultRegFormatter { + + /** + * The size of a stack slot. + */ + public final int slotSize; + + /** + * The register used as the frame pointer. + */ + public final Register fp; + + /** + * The offset (in bytes) from the slot pointed to by {@link #fp} to the slot corresponding + * to bit 0 in the frame reference map. + */ + public final int refMapToFPOffset; + + public DefaultRefMapFormatter(Architecture arch, int slotSize, Register fp, int refMapToFPOffset) { + super(arch); + this.slotSize = slotSize; + this.fp = fp; + this.refMapToFPOffset = refMapToFPOffset; + } + + @Override + public String formatStackSlot(int frameRefMapIndex) { + int refMapOffset = frameRefMapIndex * slotSize; + int fpOffset = refMapOffset + refMapToFPOffset; + if (fpOffset >= 0) { + return fp + "+" + fpOffset; + } + return fp.name + fpOffset; + } + } + + public static class NumberedRefMapFormatter implements RefMapFormatter { + + public String formatStackSlot(int frameRefMapIndex) { + return "s" + frameRefMapIndex; + } + + public String formatRegister(int regRefMapIndex) { + return "r" + regRefMapIndex; + } + } + + /** + * Appends a formatted debug info to a {@link StringBuilder}. + * + * @param sb the {@link StringBuilder} to append to + * @param info the debug info to format and append to {@code sb} + * @return the value of {@code sb} + */ + public static StringBuilder append(StringBuilder sb, DebugInfo info, RefMapFormatter formatterArg) { + RefMapFormatter formatter = formatterArg; + if (formatter == null) { + formatter = new NumberedRefMapFormatter(); + } + String nl = NEW_LINE; + ReferenceMap refMap = info.getReferenceMap(); + if (refMap != null) { + sb.append(refMap.toString()); + } + RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); + if (calleeSaveInfo != null) { + sb.append("callee-save-info:").append(nl); + Map map = calleeSaveInfo.slotsToRegisters(true); + for (Map.Entry e : map.entrySet()) { + sb.append(" ").append(e.getValue()).append(" -> ").append(formatter.formatStackSlot(e.getKey())).append(nl); + } + } + BytecodeFrame frame = info.frame(); + if (frame != null) { + append(sb, frame); + } else if (info.getBytecodePosition() != null) { + append(sb, info.getBytecodePosition()); + } + return sb; + } + + /** + * Create a calling convention from a {@link ResolvedJavaMethod}. + */ + public static CallingConvention getCallingConvention(CodeCacheProvider codeCache, CallingConvention.Type type, ResolvedJavaMethod method, boolean stackOnly) { + Signature sig = method.getSignature(); + JavaType retType = sig.getReturnType(null); + int sigCount = sig.getParameterCount(false); + JavaType[] argTypes; + int argIndex = 0; + if (!method.isStatic()) { + argTypes = new JavaType[sigCount + 1]; + argTypes[argIndex++] = method.getDeclaringClass(); + } else { + argTypes = new JavaType[sigCount]; + } + for (int i = 0; i < sigCount; i++) { + argTypes[argIndex++] = sig.getParameterType(i, null); + } + + RegisterConfig registerConfig = codeCache.getRegisterConfig(); + return registerConfig.getCallingConvention(type, retType, argTypes, codeCache.getTarget(), stackOnly); + } +} --- /dev/null 2015-09-16 15:19:32.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/CompilationResult.java 2015-09-16 15:19:31.000000000 -0700 @@ -0,0 +1,1054 @@ +/* + * Copyright (c) 2009, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import static java.util.Collections.*; +import static jdk.internal.jvmci.meta.MetaUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.meta.Assumptions.*; + +/** + * Represents the output from compiling a method, including the compiled machine code, associated + * data and references, relocation information, deoptimization information, etc. + */ +public class CompilationResult { + + /** + * Represents a code position with associated additional information. + */ + public abstract static class Site { + + /** + * The position (or offset) of this site with respect to the start of the target method. + */ + public final int pcOffset; + + public Site(int pos) { + this.pcOffset = pos; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public abstract boolean equals(Object obj); + } + + /** + * Represents an infopoint with associated debug info. Note that safepoints are also infopoints. + */ + public static class Infopoint extends Site implements Comparable { + + public final DebugInfo debugInfo; + + public final InfopointReason reason; + + public Infopoint(int pcOffset, DebugInfo debugInfo, InfopointReason reason) { + super(pcOffset); + this.debugInfo = debugInfo; + this.reason = reason; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(pcOffset); + sb.append("[]"); + appendDebugInfo(sb, debugInfo); + return sb.toString(); + } + + @Override + public int compareTo(Infopoint o) { + if (pcOffset < o.pcOffset) { + return -1; + } else if (pcOffset > o.pcOffset) { + return 1; + } + return this.reason.compareTo(o.reason); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj != null && obj.getClass() == getClass()) { + Infopoint that = (Infopoint) obj; + if (this.pcOffset == that.pcOffset && Objects.equals(this.debugInfo, that.debugInfo) && Objects.equals(this.reason, that.reason)) { + return true; + } + } + return false; + } + } + + public enum MetaSpaceAccessType { + Move, + Store, // store only works for compressed oops (memory <- 32bit value). Compressed oops is + // not supported using AOT. TODO: Look at HotSpotStoreConstantOp + Compare; // HotSpotCompareMemoryConstantOp, HotSpotCompareConstantOp + + private MetaSpaceAccessType() { + } + } + + /** + * Represents a meta space pointer access in the code. + */ + public static final class MetaSpaceAccess extends Infopoint { + + private static final long serialVersionUID = 1701958512608684706L; + + /** + * Metaspace reference. + */ + public final Object reference; // Object here is a HotSpotResolvedObjectType or a + // HotSpotMetaSpaceConstant + + public final MetaSpaceAccessType type; + + /** + * Instruction size. + */ + public final int instructionSize; + + public MetaSpaceAccess(Object reference, int instructionSize, MetaSpaceAccessType type, int pcOffset, DebugInfo debugInfo) { + super(pcOffset, debugInfo, InfopointReason.METASPACE_ACCESS); + this.type = type; + this.reference = reference; + this.instructionSize = instructionSize; + } + } + + /** + * Represents a call in the code. + */ + public static final class Call extends Infopoint { + + /** + * The target of the call. + */ + public final InvokeTarget target; + + /** + * The size of the call instruction. + */ + public final int size; + + /** + * Specifies if this call is direct or indirect. A direct call has an immediate operand + * encoding the absolute or relative (to the call itself) address of the target. An indirect + * call has a register or memory operand specifying the target address of the call. + */ + public final boolean direct; + + public Call(InvokeTarget target, int pcOffset, int size, boolean direct, DebugInfo debugInfo) { + super(pcOffset, debugInfo, InfopointReason.CALL); + this.size = size; + this.target = target; + this.direct = direct; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Call && super.equals(obj)) { + Call that = (Call) obj; + if (this.size == that.size && this.direct == that.direct && Objects.equals(this.target, that.target)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(pcOffset); + sb.append('['); + sb.append(target); + sb.append(']'); + + if (debugInfo != null) { + appendDebugInfo(sb, debugInfo); + } + + return sb.toString(); + } + } + + /** + * Represents some external data that is referenced by the code. + */ + public abstract static class Reference { + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(Object obj); + } + + public static final class ConstantReference extends Reference { + + private final VMConstant constant; + + public ConstantReference(VMConstant constant) { + this.constant = constant; + } + + public VMConstant getConstant() { + return constant; + } + + @Override + public String toString() { + return constant.toString(); + } + + @Override + public int hashCode() { + return constant.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ConstantReference) { + ConstantReference that = (ConstantReference) obj; + return Objects.equals(this.constant, that.constant); + } + return false; + } + } + + public static final class DataSectionReference extends Reference { + + private boolean initialized; + private int offset; + + public DataSectionReference() { + // will be set after the data section layout is fixed + offset = 0xDEADDEAD; + } + + public int getOffset() { + assert initialized; + + return offset; + } + + public void setOffset(int offset) { + assert !initialized; + initialized = true; + + this.offset = offset; + } + + @Override + public int hashCode() { + return offset; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DataSectionReference) { + DataSectionReference that = (DataSectionReference) obj; + return this.offset == that.offset; + } + return false; + } + } + + /** + * Represents a code site that references some data. The associated data can be either a + * {@link DataSectionReference reference} to the data section, or it may be an inlined + * {@link JavaConstant} that needs to be patched. + */ + public static final class DataPatch extends Site { + + public Reference reference; + public Object note; + + public DataPatch(int pcOffset, Reference reference) { + super(pcOffset); + this.reference = reference; + this.note = null; + } + + public DataPatch(int pcOffset, Reference reference, Object note) { + super(pcOffset); + this.reference = reference; + this.note = note; + } + + @Override + public String toString() { + if (note != null) { + return String.format("%d[, note: %s]", pcOffset, reference.toString(), note.toString()); + } else { + return String.format("%d[]", pcOffset, reference.toString()); + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DataPatch) { + DataPatch that = (DataPatch) obj; + if (this.pcOffset == that.pcOffset && Objects.equals(this.reference, that.reference) && Objects.equals(this.note, that.note)) { + return true; + } + } + return false; + } + } + + /** + * Provides extra information about instructions or data at specific positions in + * {@link CompilationResult#getTargetCode()}. This is optional information that can be used to + * enhance a disassembly of the code. + */ + public abstract static class CodeAnnotation { + + public final int position; + + public CodeAnnotation(int position) { + this.position = position; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public abstract boolean equals(Object obj); + } + + /** + * A string comment about one or more instructions at a specific position in the code. + */ + public static final class CodeComment extends CodeAnnotation { + + public final String value; + + public CodeComment(int position, String comment) { + super(position); + this.value = comment; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof CodeComment) { + CodeComment that = (CodeComment) obj; + if (this.position == that.position && this.value.equals(that.value)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "@" + position + ": " + value; + } + } + + /** + * Describes a table of signed offsets embedded in the code. The offsets are relative to the + * starting address of the table. This type of table maybe generated when translating a + * multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch} + * JVM instruction). + * + * The table is indexed by the contiguous range of integers from {@link #low} to {@link #high} + * inclusive. + */ + public static final class JumpTable extends CodeAnnotation { + + /** + * The low value in the key range (inclusive). + */ + public final int low; + + /** + * The high value in the key range (inclusive). + */ + public final int high; + + /** + * The size (in bytes) of each table entry. + */ + public final int entrySize; + + public JumpTable(int position, int low, int high, int entrySize) { + super(position); + this.low = low; + this.high = high; + this.entrySize = entrySize; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof JumpTable) { + JumpTable that = (JumpTable) obj; + if (this.position == that.position && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "@" + position + ": [" + low + " .. " + high + "]"; + } + } + + /** + * Represents exception handler information for a specific code position. It includes the catch + * code position as well as the caught exception type. + */ + public static final class ExceptionHandler extends Site { + + public final int handlerPos; + + ExceptionHandler(int pcOffset, int handlerPos) { + super(pcOffset); + this.handlerPos = handlerPos; + } + + @Override + public String toString() { + return String.format("%d[]", pcOffset, handlerPos); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ExceptionHandler) { + ExceptionHandler that = (ExceptionHandler) obj; + if (this.pcOffset == that.pcOffset && this.handlerPos == that.handlerPos) { + return true; + } + } + return false; + } + } + + /** + * Represents a mark in the machine code that can be used by the runtime for its own purposes. A + * mark can reference other marks. + */ + public static final class Mark extends Site { + + public final Object id; + + public Mark(int pcOffset, Object id) { + super(pcOffset); + this.id = id; + } + + @Override + public String toString() { + if (id == null) { + return String.format("%d[]", pcOffset); + } else if (id instanceof Integer) { + return String.format("%d[]", pcOffset, Integer.toHexString((Integer) id)); + } else { + return String.format("%d[]", pcOffset, id.toString()); + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Mark) { + Mark that = (Mark) obj; + if (this.pcOffset == that.pcOffset && Objects.equals(this.id, that.id)) { + return true; + } + } + return false; + } + } + + private int id = -1; + + /** + * Specifies whether this compilation is a {@code +ImmutableCode} {@code +GeneratePIC} + * compilation. + */ + private final boolean isImmutablePIC; + + private int entryBCI = -1; + + private final DataSection dataSection = new DataSection(); + + private final List infopoints = new ArrayList<>(); + private final List dataPatches = new ArrayList<>(); + private final List exceptionHandlers = new ArrayList<>(); + private final List marks = new ArrayList<>(); + + private int totalFrameSize = -1; + private int customStackAreaOffset = -1; + + private final String name; + + /** + * The buffer containing the emitted machine code. + */ + private byte[] targetCode; + + /** + * The leading number of bytes in {@link #targetCode} containing the emitted machine code. + */ + private int targetCodeSize; + + private ArrayList annotations; + + private Assumption[] assumptions; + + /** + * The list of the methods whose bytecodes were used as input to the compilation. If + * {@code null}, then the compilation did not record method dependencies. Otherwise, the first + * element of this array is the root method of the compilation. + */ + private ResolvedJavaMethod[] methods; + + private int bytecodeSize; + + private boolean hasUnsafeAccess; + + public CompilationResult() { + this(null); + } + + public CompilationResult(String name) { + this.name = name; + this.isImmutablePIC = false; + } + + public CompilationResult(boolean isImmutablePIC) { + this.name = null; + this.isImmutablePIC = isImmutablePIC; + } + + @Override + public int hashCode() { + // CompilationResult instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + if (methods != null) { + return getClass().getName() + "[" + methods[0].format("%H.%n(%p)%r") + "]"; + } + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj != null && obj.getClass() == getClass()) { + CompilationResult that = (CompilationResult) obj; + // @formatter:off + if (this.entryBCI == that.entryBCI && + this.id == that.id && + this.customStackAreaOffset == that.customStackAreaOffset && + this.totalFrameSize == that.totalFrameSize && + this.targetCodeSize == that.targetCodeSize && + Objects.equals(this.name, that.name) && + Objects.equals(this.annotations, that.annotations) && + Objects.equals(this.dataSection, that.dataSection) && + Objects.equals(this.exceptionHandlers, that.exceptionHandlers) && + Objects.equals(this.dataPatches, that.dataPatches) && + Objects.equals(this.infopoints, that.infopoints) && + Objects.equals(this.marks, that.marks) && + Arrays.equals(this.assumptions, that.assumptions) && + Arrays.equals(targetCode, that.targetCode)) { + return true; + } + // @formatter:on + } + return false; + } + + /** + * @return the compile id + */ + public int getId() { + return id; + } + + /** + * @param id the compile id to set + */ + public void setId(int id) { + this.id = id; + } + + /** + * @return true is this is a {@code +ImmutableCode} {@code +GeneratePIC} compilation, false + * otherwise. + */ + public boolean isImmutablePIC() { + return isImmutablePIC; + } + + /** + * @return the entryBCI + */ + public int getEntryBCI() { + return entryBCI; + } + + /** + * @param entryBCI the entryBCI to set + */ + public void setEntryBCI(int entryBCI) { + this.entryBCI = entryBCI; + } + + /** + * Sets the assumptions made during compilation. + */ + public void setAssumptions(Assumption[] assumptions) { + this.assumptions = assumptions; + } + + /** + * Gets the assumptions made during compilation. + */ + public Assumption[] getAssumptions() { + return assumptions; + } + + /** + * Sets the methods whose bytecodes were used as input to the compilation. + * + * @param rootMethod the root method of the compilation + * @param inlinedMethods the methods inlined during compilation + */ + public void setMethods(ResolvedJavaMethod rootMethod, Collection inlinedMethods) { + assert rootMethod != null; + assert inlinedMethods != null; + if (inlinedMethods.contains(rootMethod)) { + methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]); + for (int i = 0; i < methods.length; i++) { + if (methods[i].equals(rootMethod)) { + if (i != 0) { + ResolvedJavaMethod tmp = methods[0]; + methods[0] = methods[i]; + methods[i] = tmp; + } + break; + } + } + } else { + methods = new ResolvedJavaMethod[1 + inlinedMethods.size()]; + methods[0] = rootMethod; + int i = 1; + for (ResolvedJavaMethod m : inlinedMethods) { + methods[i++] = m; + } + } + } + + /** + * Gets the methods whose bytecodes were used as input to the compilation. + * + * @return {@code null} if the compilation did not record method dependencies otherwise the + * methods whose bytecodes were used as input to the compilation with the first element + * being the root method of the compilation + */ + public ResolvedJavaMethod[] getMethods() { + return methods; + } + + public void setBytecodeSize(int bytecodeSize) { + this.bytecodeSize = bytecodeSize; + } + + public int getBytecodeSize() { + return bytecodeSize; + } + + public DataSection getDataSection() { + return dataSection; + } + + /** + * The total frame size of the method in bytes. This includes the return address pushed onto the + * stack, if any. + * + * @return the frame size + */ + public int getTotalFrameSize() { + assert totalFrameSize != -1 : "frame size not yet initialized!"; + return totalFrameSize; + } + + /** + * Sets the total frame size in bytes. This includes the return address pushed onto the stack, + * if any. + * + * @param size the size of the frame in bytes + */ + public void setTotalFrameSize(int size) { + totalFrameSize = size; + } + + /** + * Sets the machine that has been generated by the compiler. + * + * @param code the machine code generated + * @param size the size of the machine code + */ + public void setTargetCode(byte[] code, int size) { + targetCode = code; + targetCodeSize = size; + } + + /** + * Records a data patch in the code section. The data patch can refer to something in the + * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined + * constant}. + * + * @param codePos The position in the code that needs to be patched. + * @param ref The reference that should be inserted in the code. + */ + public void recordDataPatch(int codePos, Reference ref) { + assert codePos >= 0 && ref != null; + dataPatches.add(new DataPatch(codePos, ref)); + } + + /** + * Records a data patch in the code section. The data patch can refer to something in the + * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined + * constant}. + * + * @param codePos The position in the code that needs to be patched. + * @param ref The reference that should be inserted in the code. + * @param note The note attached to data patch for use by post-processing tools + */ + public void recordDataPatchWithNote(int codePos, Reference ref, Object note) { + assert codePos >= 0 && ref != null; + dataPatches.add(new DataPatch(codePos, ref, note)); + } + + /** + * Records metaspace access. + */ + public void recordMetaspaceAccess(Object reference, int instructionSize, MetaSpaceAccessType type, int codePos, DebugInfo debugInfo) { + final MetaSpaceAccess metaspace = new MetaSpaceAccess(reference, instructionSize, type, codePos, debugInfo); + addInfopoint(metaspace); + } + + /** + * Records a call in the code array. + * + * @param codePos the position of the call in the code array + * @param size the size of the call instruction + * @param target the being called + * @param debugInfo the debug info for the call + * @param direct specifies if this is a {@linkplain Call#direct direct} call + */ + public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) { + final Call call = new Call(target, codePos, size, direct, debugInfo); + addInfopoint(call); + } + + /** + * Records an exception handler for this method. + * + * @param codePos the position in the code that is covered by the handler + * @param handlerPos the position of the handler + */ + public void recordExceptionHandler(int codePos, int handlerPos) { + assert validateExceptionHandlerAdd(codePos, handlerPos) : String.format("Duplicate exception handler for pc 0x%x handlerPos 0x%x", codePos, handlerPos); + exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos)); + } + + /** + * Validate if the exception handler for codePos already exists and handlerPos is different. + * + * @param codePos + * @param handlerPos + * @return true if the validation is successful + */ + private boolean validateExceptionHandlerAdd(int codePos, int handlerPos) { + ExceptionHandler exHandler = getExceptionHandlerForCodePos(codePos); + return exHandler == null || exHandler.handlerPos == handlerPos; + } + + /** + * Returns the first ExceptionHandler which matches codePos. + * + * @param codePos position to search for + * @return first matching ExceptionHandler + */ + private ExceptionHandler getExceptionHandlerForCodePos(int codePos) { + for (ExceptionHandler h : exceptionHandlers) { + if (h.pcOffset == codePos) { + return h; + } + } + return null; + } + + /** + * Records an infopoint in the code array. + * + * @param codePos the position of the infopoint in the code array + * @param debugInfo the debug info for the infopoint + */ + public void recordInfopoint(int codePos, DebugInfo debugInfo, InfopointReason reason) { + addInfopoint(new Infopoint(codePos, debugInfo, reason)); + } + + /** + * Records a custom infopoint in the code section. + * + * Compiler implementations can use this method to record non-standard infopoints, which are not + * handled by the dedicated methods like {@link #recordCall}. + * + * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint} + */ + public void addInfopoint(Infopoint infopoint) { + // The infopoints list must always be sorted + if (!infopoints.isEmpty()) { + Infopoint previousInfopoint = infopoints.get(infopoints.size() - 1); + if (previousInfopoint.pcOffset > infopoint.pcOffset) { + // This re-sorting should be very rare + Collections.sort(infopoints); + previousInfopoint = infopoints.get(infopoints.size() - 1); + } + if (previousInfopoint.pcOffset == infopoint.pcOffset) { + if (infopoint.reason.canBeOmitted()) { + return; + } + if (previousInfopoint.reason.canBeOmitted()) { + Infopoint removed = infopoints.remove(infopoints.size() - 1); + assert removed == previousInfopoint; + } else { + throw new RuntimeException("Infopoints that can not be omited should have distinct PCs"); + } + } + } + infopoints.add(infopoint); + } + + /** + * Records an instruction mark within this method. + * + * @param codePos the position in the code that is covered by the handler + * @param markId the identifier for this mark + */ + public Mark recordMark(int codePos, Object markId) { + Mark mark = new Mark(codePos, markId); + marks.add(mark); + return mark; + } + + /** + * Offset in bytes for the custom stack area (relative to sp). + * + * @return the offset in bytes + */ + public int getCustomStackAreaOffset() { + return customStackAreaOffset; + } + + /** + * @see #getCustomStackAreaOffset() + * @param offset + */ + public void setCustomStackAreaOffset(int offset) { + customStackAreaOffset = offset; + } + + /** + * @return the machine code generated for this method + */ + public byte[] getTargetCode() { + return targetCode; + } + + /** + * @return the size of the machine code generated for this method + */ + public int getTargetCodeSize() { + return targetCodeSize; + } + + /** + * @return the code annotations or {@code null} if there are none + */ + public List getAnnotations() { + if (annotations == null) { + return Collections.emptyList(); + } + return annotations; + } + + public void addAnnotation(CodeAnnotation annotation) { + assert annotation != null; + if (annotations == null) { + annotations = new ArrayList<>(); + } + annotations.add(annotation); + } + + private static void appendDebugInfo(StringBuilder sb, DebugInfo info) { + if (info != null) { + ReferenceMap refMap = info.getReferenceMap(); + if (refMap != null) { + sb.append(refMap.toString()); + sb.append(']'); + } + RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); + if (calleeSaveInfo != null) { + sb.append(" callee-save-info["); + String sep = ""; + for (Map.Entry e : calleeSaveInfo.registersToSlots(true).entrySet()) { + sb.append(sep).append(e.getKey()).append("->").append(e.getValue()); + sep = ", "; + } + sb.append(']'); + } + BytecodePosition codePos = info.getBytecodePosition(); + if (codePos != null) { + MetaUtil.appendLocation(sb.append(" "), codePos.getMethod(), codePos.getBCI()); + if (info.hasFrame()) { + sb.append(" #locals=").append(info.frame().numLocals).append(" #expr=").append(info.frame().numStack); + if (info.frame().numLocks > 0) { + sb.append(" #locks=").append(info.frame().numLocks); + } + } + } + } + } + + /** + * @return the list of infopoints, sorted by {@link Site#pcOffset} + */ + public List getInfopoints() { + if (infopoints.isEmpty()) { + return emptyList(); + } + return unmodifiableList(infopoints); + } + + /** + * @return the list of data references + */ + public List getDataPatches() { + if (dataPatches.isEmpty()) { + return emptyList(); + } + return unmodifiableList(dataPatches); + } + + /** + * @return the list of exception handlers + */ + public List getExceptionHandlers() { + if (exceptionHandlers.isEmpty()) { + return emptyList(); + } + return unmodifiableList(exceptionHandlers); + } + + /** + * @return the list of marks + */ + public List getMarks() { + if (marks.isEmpty()) { + return emptyList(); + } + return unmodifiableList(marks); + } + + public String getName() { + return name; + } + + public void setHasUnsafeAccess(boolean hasUnsafeAccess) { + this.hasUnsafeAccess = hasUnsafeAccess; + } + + public boolean hasUnsafeAccess() { + return hasUnsafeAccess; + } + + public void reset() { + hasUnsafeAccess = false; + infopoints.clear(); + dataPatches.clear(); + exceptionHandlers.clear(); + marks.clear(); + dataSection.clear(); + if (annotations != null) { + annotations.clear(); + } + } +} --- /dev/null 2015-09-16 15:19:32.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/DataSection.java 2015-09-16 15:19:32.000000000 -0700 @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import static jdk.internal.jvmci.meta.MetaUtil.*; + +import java.nio.*; +import java.util.*; +import java.util.function.*; + +import jdk.internal.jvmci.code.CompilationResult.*; +import jdk.internal.jvmci.code.DataSection.*; +import jdk.internal.jvmci.meta.*; + +public final class DataSection implements Iterable { + + @FunctionalInterface + public interface DataBuilder { + + void emit(ByteBuffer buffer, Consumer patch); + + static DataBuilder raw(byte[] data) { + return (buffer, patch) -> buffer.put(data); + } + + static DataBuilder serializable(SerializableConstant c) { + return (buffer, patch) -> c.serialize(buffer); + } + + static DataBuilder zero(int size) { + switch (size) { + case 1: + return (buffer, patch) -> buffer.put((byte) 0); + case 2: + return (buffer, patch) -> buffer.putShort((short) 0); + case 4: + return (buffer, patch) -> buffer.putInt(0); + case 8: + return (buffer, patch) -> buffer.putLong(0L); + default: + return (buffer, patch) -> { + int rest = size; + while (rest > 8) { + buffer.putLong(0L); + rest -= 8; + } + while (rest > 0) { + buffer.put((byte) 0); + rest--; + } + }; + } + } + } + + public static final class Data { + + private int alignment; + private final int size; + private final DataBuilder builder; + + private DataSectionReference ref; + + public Data(int alignment, int size, DataBuilder builder) { + this.alignment = alignment; + this.size = size; + this.builder = builder; + + // initialized in DataSection.insertData(Data) + ref = null; + } + + public void updateAlignment(int newAlignment) { + if (newAlignment == alignment) { + return; + } + alignment = lcm(alignment, newAlignment); + } + + public int getAlignment() { + return alignment; + } + + public int getSize() { + return size; + } + + public DataBuilder getBuilder() { + return builder; + } + + @Override + public int hashCode() { + // Data instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + assert ref != null; + if (obj == this) { + return true; + } + if (obj instanceof Data) { + Data that = (Data) obj; + if (this.alignment == that.alignment && this.size == that.size && this.ref.equals(that.ref)) { + return true; + } + } + return false; + } + } + + private final ArrayList dataItems = new ArrayList<>(); + + private boolean finalLayout; + private int sectionAlignment; + private int sectionSize; + + @Override + public int hashCode() { + // DataSection instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DataSection) { + DataSection that = (DataSection) obj; + if (this.finalLayout == that.finalLayout && this.sectionAlignment == that.sectionAlignment && this.sectionSize == that.sectionSize && Objects.equals(this.dataItems, that.dataItems)) { + return true; + } + } + return false; + } + + /** + * Insert a {@link Data} item into the data section. If the item is already in the data section, + * the same {@link DataSectionReference} is returned. + * + * @param data the {@link Data} item to be inserted + * @return a unique {@link DataSectionReference} identifying the {@link Data} item + */ + public DataSectionReference insertData(Data data) { + assert !finalLayout; + if (data.ref == null) { + data.ref = new DataSectionReference(); + dataItems.add(data); + } + return data.ref; + } + + /** + * Compute the layout of the data section. This can be called only once, and after it has been + * called, the data section can no longer be modified. + */ + public void finalizeLayout() { + assert !finalLayout; + finalLayout = true; + + // simple heuristic: put items with larger alignment requirement first + dataItems.sort((a, b) -> a.alignment - b.alignment); + + int position = 0; + for (Data d : dataItems) { + sectionAlignment = lcm(sectionAlignment, d.alignment); + position = align(position, d.alignment); + + d.ref.setOffset(position); + position += d.size; + } + + sectionSize = position; + } + + public boolean isFinalized() { + return finalLayout; + } + + /** + * Get the size of the data section. Can only be called after {@link #finalizeLayout}. + */ + public int getSectionSize() { + assert finalLayout; + return sectionSize; + } + + /** + * Get the minimum alignment requirement of the data section. Can only be called after + * {@link #finalizeLayout}. + */ + public int getSectionAlignment() { + assert finalLayout; + return sectionAlignment; + } + + /** + * Build the data section. Can only be called after {@link #finalizeLayout}. + * + * @param buffer The {@link ByteBuffer} where the data section should be built. The buffer must + * hold at least {@link #getSectionSize()} bytes. + * @param patch A {@link Consumer} to receive {@link DataPatch data patches} for relocations in + * the data section. + */ + public void buildDataSection(ByteBuffer buffer, Consumer patch) { + assert finalLayout; + for (Data d : dataItems) { + buffer.position(d.ref.getOffset()); + d.builder.emit(buffer, patch); + } + } + + public Data findData(DataSectionReference ref) { + for (Data d : dataItems) { + if (d.ref == ref) { + return d; + } + } + return null; + } + + public Iterator iterator() { + return dataItems.iterator(); + } + + public static int lcm(int x, int y) { + if (x == 0) { + return y; + } else if (y == 0) { + return x; + } + + int a = Math.max(x, y); + int b = Math.min(x, y); + while (b > 0) { + int tmp = a % b; + a = b; + b = tmp; + } + + int gcd = a; + return x * y / gcd; + } + + private static int align(int position, int alignment) { + return ((position + alignment - 1) / alignment) * alignment; + } + + public void clear() { + assert !finalLayout; + this.dataItems.clear(); + this.sectionAlignment = 0; + this.sectionSize = 0; + } +} --- /dev/null 2015-09-16 15:19:33.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/DebugInfo.java 2015-09-16 15:19:33.000000000 -0700 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.util.*; + +/** + * Represents the debugging information for a particular point of execution. This information + * includes: + *
    + *
  • a {@linkplain #getBytecodePosition() bytecode position}
  • + *
  • a reference map for registers and stack slots in the current frame
  • + *
  • a map from bytecode locals and operand stack slots to their values or locations from which + * their values can be read
  • + *
  • a map from the registers (in the caller's frame) to the slots where they are saved in the + * current frame
  • + *
+ */ +public final class DebugInfo { + + private final BytecodePosition bytecodePosition; + private ReferenceMap referenceMap; + @SuppressWarnings("unused") private final VirtualObject[] virtualObjectMapping; + private RegisterSaveLayout calleeSaveInfo; + + /** + * Creates a new {@link DebugInfo} from the given values. + * + * @param codePos the {@linkplain BytecodePosition code position} or {@linkplain BytecodeFrame + * frame} info + * @param virtualObjectMapping the mapping of {@link VirtualObject}s to their real values + */ + public DebugInfo(BytecodePosition codePos, VirtualObject[] virtualObjectMapping) { + this.bytecodePosition = codePos; + this.virtualObjectMapping = virtualObjectMapping; + } + + public DebugInfo(BytecodePosition codePos) { + this(codePos, null); + } + + public void setReferenceMap(ReferenceMap referenceMap) { + this.referenceMap = referenceMap; + } + + /** + * @return {@code true} if this debug information has a frame + */ + public boolean hasFrame() { + return getBytecodePosition() instanceof BytecodeFrame; + } + + /** + * Gets the deoptimization information for each inlined frame (if available). + * + * @return {@code null} if no frame de-opt info is {@linkplain #hasFrame() available} + */ + public BytecodeFrame frame() { + if (hasFrame()) { + return (BytecodeFrame) getBytecodePosition(); + } + return null; + } + + @Override + public String toString() { + return CodeUtil.append(new StringBuilder(100), this, null).toString(); + } + + /** + * @return The code position (including all inlined methods) of this debug info. If this is a + * {@link BytecodeFrame} instance, then it is also the deoptimization information for + * each inlined frame. + */ + public BytecodePosition getBytecodePosition() { + return bytecodePosition; + } + + public ReferenceMap getReferenceMap() { + return referenceMap; + } + + /** + * Sets the map from the registers (in the caller's frame) to the slots where they are saved in + * the current frame. + */ + public void setCalleeSaveInfo(RegisterSaveLayout calleeSaveInfo) { + this.calleeSaveInfo = calleeSaveInfo; + } + + /** + * Gets the map from the registers (in the caller's frame) to the slots where they are saved in + * the current frame. If no such information is available, {@code null} is returned. + */ + public RegisterSaveLayout getCalleeSaveInfo() { + return calleeSaveInfo; + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DebugInfo) { + DebugInfo that = (DebugInfo) obj; + if (Objects.equals(this.bytecodePosition, that.bytecodePosition) && Objects.equals(this.calleeSaveInfo, that.calleeSaveInfo) && Objects.equals(this.referenceMap, that.referenceMap)) { + return true; + } + } + return false; + } +} --- /dev/null 2015-09-16 15:19:33.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/InfopointReason.java 2015-09-16 15:19:33.000000000 -0700 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +/** + * A reason for infopoint insertion. + */ +public enum InfopointReason { + UNKNOWN(false), + SAFEPOINT(false), + CALL(false), + IMPLICIT_EXCEPTION(false), + METHOD_START(true), + METHOD_END(true), + LINE_NUMBER(true), + METASPACE_ACCESS(true); + + private InfopointReason(boolean canBeOmitted) { + this.canBeOmitted = canBeOmitted; + } + + private final boolean canBeOmitted; + + public boolean canBeOmitted() { + return canBeOmitted; + } +} --- /dev/null 2015-09-16 15:19:34.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/InstalledCode.java 2015-09-16 15:19:34.000000000 -0700 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +/** + * Represents a compiled instance of a method. It may have been invalidated or removed in the + * meantime. + */ +public class InstalledCode { + + /** + * Raw address of this code blob. + */ + private long address; + + /** + * Counts how often the address field was reassigned. + */ + private long version; + + protected final String name; + + public InstalledCode(String name) { + this.name = name; + } + + public final void setAddress(long address) { + this.address = address; + version++; + } + + /** + * @return the address of this code blob + */ + public final long getAddress() { + return address; + } + + /** + * @return the address of this code blob + */ + public final long getVersion() { + return version; + } + + /** + * Returns the name of this code blob. + */ + public String getName() { + return name; + } + + /** + * Returns the start address of this installed code if it is {@linkplain #isValid() valid}, 0 + * otherwise. + */ + public long getStart() { + return 0; + } + + /** + * Returns the number of instruction bytes for this code. + */ + public long getCodeSize() { + return 0; + } + + /** + * Returns a copy of this installed code if it is {@linkplain #isValid() valid}, null otherwise. + */ + public byte[] getCode() { + return null; + } + + /** + * @return true if the code represented by this object is still valid, false otherwise (may + * happen due to deopt, etc.) + */ + public boolean isValid() { + return address != 0; + } + + /** + * Invalidates this installed code such that any subsequent + * {@linkplain #executeVarargs(Object...) invocation} will throw an + * {@link InvalidInstalledCodeException}. + */ + public void invalidate() { + throw new UnsupportedOperationException(); + } + + /** + * Executes the installed code with a variable number of arguments. + * + * @param args the array of object arguments + * @return the value returned by the executed code + */ + @SuppressWarnings("unused") + public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { + throw new UnsupportedOperationException(); + } +} --- /dev/null 2015-09-16 15:19:35.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/InvalidInstalledCodeException.java 2015-09-16 15:19:34.000000000 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +/** + * Exception thrown by the runtime in case an invalidated machine code is called. + */ +public final class InvalidInstalledCodeException extends Exception { + + private static final long serialVersionUID = -3540232440794244844L; +} --- /dev/null 2015-09-16 15:19:35.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/Location.java 2015-09-16 15:19:35.000000000 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +/** + * Represents a location where a value can be stored. This can be either a {@link Register} or a + * stack slot. + */ +public final class Location { + + public final Register reg; + public final int offset; + + private Location(Register reg, int offset) { + this.reg = reg; + this.offset = offset; + } + + /** + * Create a {@link Location} for a register. + */ + public static Location register(Register reg) { + return new Location(reg, 0); + } + + /** + * Create a {@link Location} for a vector subregister. + * + * @param reg the {@link Register vector register} + * @param offset the offset in bytes into the vector register + */ + public static Location subregister(Register reg, int offset) { + return new Location(reg, offset); + } + + /** + * Create a {@link Location} for a stack slot. + */ + public static Location stack(int offset) { + return new Location(null, offset); + } + + public boolean isRegister() { + return reg != null; + } + + public boolean isStack() { + return reg == null; + } + + @Override + public String toString() { + String regName; + if (isRegister()) { + regName = reg.name + ":"; + } else { + regName = "stack:"; + } + return regName + offset; + } +} --- /dev/null 2015-09-16 15:19:36.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/MemoryBarriers.java 2015-09-16 15:19:36.000000000 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011, 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +/** + * Constants and intrinsic definition for memory barriers. + * + * The documentation for each constant is taken from Doug Lea's The JSR-133 Cookbook for Compiler + * Writers. + *

+ * The {@code JMM_*} constants capture the memory barriers necessary to implement the Java Memory + * Model with respect to volatile field accesses. Their values are explained by this comment from + * templateTable_i486.cpp in the HotSpot source code: + * + *

+ * Volatile variables demand their effects be made known to all CPU's in
+ * order.  Store buffers on most chips allow reads & writes to reorder; the
+ * JMM's ReadAfterWrite.java test fails in -Xint mode without some kind of
+ * memory barrier (i.e., it's not sufficient that the interpreter does not
+ * reorder volatile references, the hardware also must not reorder them).
+ *
+ * According to the new Java Memory Model (JMM):
+ * (1) All volatiles are serialized wrt to each other.
+ * ALSO reads & writes act as acquire & release, so:
+ * (2) A read cannot let unrelated NON-volatile memory refs that happen after
+ * the read float up to before the read.  It's OK for non-volatile memory refs
+ * that happen before the volatile read to float down below it.
+ * (3) Similarly, a volatile write cannot let unrelated NON-volatile memory refs
+ * that happen BEFORE the write float down to after the write.  It's OK for
+ * non-volatile memory refs that happen after the volatile write to float up
+ * before it.
+ *
+ * We only put in barriers around volatile refs (they are expensive), not
+ * _between_ memory refs (which would require us to track the flavor of the
+ * previous memory refs).  Requirements (2) and (3) require some barriers
+ * before volatile stores and after volatile loads.  These nearly cover
+ * requirement (1) but miss the volatile-store-volatile-load case.  This final
+ * case is placed after volatile-stores although it could just as well go
+ * before volatile-loads.
+ * 
+ */ +public class MemoryBarriers { + + /** + * The sequence {@code Load1; LoadLoad; Load2} ensures that {@code Load1}'s data are loaded + * before data accessed by {@code Load2} and all subsequent load instructions are loaded. In + * general, explicit {@code LoadLoad} barriers are needed on processors that perform speculative + * loads and/or out-of-order processing in which waiting load instructions can bypass waiting + * stores. On processors that guarantee to always preserve load ordering, these barriers amount + * to no-ops. + */ + public static final int LOAD_LOAD = 0x0001; + + /** + * The sequence {@code Load1; LoadStore; Store2} ensures that {@code Load1}'s data are loaded + * before all data associated with {@code Store2} and subsequent store instructions are flushed. + * {@code LoadStore} barriers are needed only on those out-of-order processors in which waiting + * store instructions can bypass loads. + */ + public static final int LOAD_STORE = 0x0002; + + /** + * The sequence {@code Store1; StoreLoad; Load2} ensures that {@code Store1}'s data are made + * visible to other processors (i.e., flushed to main memory) before data accessed by + * {@code Load2} and all subsequent load instructions are loaded. {@code StoreLoad} barriers + * protect against a subsequent load incorrectly using {@code Store1}'s data value rather than + * that from a more recent store to the same location performed by a different processor. + * Because of this, on the processors discussed below, a {@code StoreLoad} is strictly necessary + * only for separating stores from subsequent loads of the same location(s) as were stored + * before the barrier. {@code StoreLoad} barriers are needed on nearly all recent + * multiprocessors, and are usually the most expensive kind. Part of the reason they are + * expensive is that they must disable mechanisms that ordinarily bypass cache to satisfy loads + * from write-buffers. This might be implemented by letting the buffer fully flush, among other + * possible stalls. + */ + public static final int STORE_LOAD = 0x0004; + + /** + * The sequence {@code Store1; StoreStore; Store2} ensures that {@code Store1}'s data are + * visible to other processors (i.e., flushed to memory) before the data associated with + * {@code Store2} and all subsequent store instructions. In general, {@code StoreStore} barriers + * are needed on processors that do not otherwise guarantee strict ordering of flushes from + * write buffers and/or caches to other processors or main memory. + */ + public static final int STORE_STORE = 0x0008; + + public static final int JMM_PRE_VOLATILE_WRITE = LOAD_STORE | STORE_STORE; + public static final int JMM_POST_VOLATILE_WRITE = STORE_LOAD | STORE_STORE; + public static final int JMM_PRE_VOLATILE_READ = 0; + public static final int JMM_POST_VOLATILE_READ = LOAD_LOAD | LOAD_STORE; + + public static String barriersString(int barriers) { + StringBuilder sb = new StringBuilder(); + sb.append((barriers & LOAD_LOAD) != 0 ? "LOAD_LOAD " : ""); + sb.append((barriers & LOAD_STORE) != 0 ? "LOAD_STORE " : ""); + sb.append((barriers & STORE_LOAD) != 0 ? "STORE_LOAD " : ""); + sb.append((barriers & STORE_STORE) != 0 ? "STORE_STORE " : ""); + return sb.toString().trim(); + } +} --- /dev/null 2015-09-16 15:19:36.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/ReferenceMap.java 2015-09-16 15:19:36.000000000 -0700 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +public abstract class ReferenceMap { +} --- /dev/null 2015-09-16 15:19:37.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/Register.java 2015-09-16 15:19:37.000000000 -0700 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import jdk.internal.jvmci.meta.*; + +/** + * Represents a target machine register. + */ +public final class Register implements Comparable { + + public static final RegisterCategory SPECIAL = new RegisterCategory("SPECIAL"); + + /** + * Invalid register. + */ + public static final Register None = new Register(-1, -1, "noreg", SPECIAL); + + /** + * Frame pointer of the current method. All spill slots and outgoing stack-based arguments are + * addressed relative to this register. + */ + public static final Register Frame = new Register(-2, -2, "framereg", SPECIAL); + + public static final Register CallerFrame = new Register(-3, -3, "callerframereg", SPECIAL); + + /** + * The identifier for this register that is unique across all the registers in a + * {@link Architecture}. A valid register has {@code number > 0}. + */ + public final int number; + + /** + * The mnemonic of this register. + */ + public final String name; + + /** + * The actual encoding in a target machine instruction for this register, which may or may not + * be the same as {@link #number}. + */ + public final int encoding; + + /** + * The assembler calls this method to get the register's encoding. + */ + public int encoding() { + return encoding; + } + + /** + * A platform specific register category that describes which values can be stored in a + * register. + */ + private final RegisterCategory registerCategory; + + /** + * A platform specific register type that describes which values can be stored in a register. + */ + public static class RegisterCategory { + + private final String name; + + private final int referenceMapOffset; + private final int referenceMapShift; + + public RegisterCategory(String name) { + this(name, 0, 0); + } + + public RegisterCategory(String name, int referenceMapOffset) { + this(name, referenceMapOffset, 0); + } + + public RegisterCategory(String name, int referenceMapOffset, int referenceMapShift) { + this.name = name; + this.referenceMapOffset = referenceMapOffset; + this.referenceMapShift = referenceMapShift; + } + + @Override + public String toString() { + return name; + } + + @Override + public int hashCode() { + return 23 + name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RegisterCategory) { + RegisterCategory that = (RegisterCategory) obj; + return this.referenceMapOffset == that.referenceMapOffset && this.referenceMapShift == that.referenceMapShift && this.name.equals(that.name); + } + return false; + } + } + + /** + * Creates a {@link Register} instance. + * + * @param number unique identifier for the register + * @param encoding the target machine encoding for the register + * @param name the mnemonic name for the register + * @param registerCategory the register category + */ + public Register(int number, int encoding, String name, RegisterCategory registerCategory) { + this.number = number; + this.name = name; + this.registerCategory = registerCategory; + this.encoding = encoding; + } + + public RegisterCategory getRegisterCategory() { + return registerCategory; + } + + /** + * Get the start index of this register in the {@link ReferenceMap}. + */ + public int getReferenceMapIndex() { + return (encoding << registerCategory.referenceMapShift) + registerCategory.referenceMapOffset; + } + + /** + * Gets this register as a {@linkplain RegisterValue value} with a specified kind. + * + * @param kind the specified kind + * @return the {@link RegisterValue} + */ + public RegisterValue asValue(LIRKind kind) { + return new RegisterValue(kind, this); + } + + /** + * Gets this register as a {@linkplain RegisterValue value} with no particular kind. + * + * @return a {@link RegisterValue} with {@link JavaKind#Illegal} kind. + */ + public RegisterValue asValue() { + return asValue(LIRKind.Illegal); + } + + /** + * Determines if this is a valid register. + * + * @return {@code true} iff this register is valid + */ + public boolean isValid() { + return number >= 0; + } + + /** + * Gets the maximum register {@linkplain #number number} in a given set of registers. + * + * @param registers the set of registers to process + * @return the maximum register number for any register in {@code registers} + */ + public static int maxRegisterNumber(Register[] registers) { + int max = Integer.MIN_VALUE; + for (Register r : registers) { + if (r.number > max) { + max = r.number; + } + } + return max; + } + + /** + * Gets the maximum register {@linkplain #encoding encoding} in a given set of registers. + * + * @param registers the set of registers to process + * @return the maximum register encoding for any register in {@code registers} + */ + public static int maxRegisterEncoding(Register[] registers) { + int max = Integer.MIN_VALUE; + for (Register r : registers) { + if (r.encoding > max) { + max = r.encoding; + } + } + return max; + } + + @Override + public String toString() { + return name; + } + + @Override + public int compareTo(Register o) { + if (number < o.number) { + return -1; + } + if (number > o.number) { + return 1; + } + return 0; + } + + @Override + public int hashCode() { + return 17 + name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Register) { + Register other = (Register) obj; + if (number == other.number) { + assert name.equals(other.name); + assert encoding == other.encoding; + assert registerCategory.equals(other.registerCategory); + return true; + } + } + return false; + } +} --- /dev/null 2015-09-16 15:19:38.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/RegisterAttributes.java 2015-09-16 15:19:37.000000000 -0700 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2010, 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.util.*; + +/** + * A collection of register attributes. The specific attribute values for a register may be local to + * a compilation context. For example, a {@link RegisterConfig} in use during a compilation will + * determine which registers are callee saved. + */ +public class RegisterAttributes { + + private final boolean callerSave; + private final boolean calleeSave; + private final boolean allocatable; + + public RegisterAttributes(boolean isCallerSave, boolean isCalleeSave, boolean isAllocatable) { + this.callerSave = isCallerSave; + this.calleeSave = isCalleeSave; + this.allocatable = isAllocatable; + } + + public static final RegisterAttributes NONE = new RegisterAttributes(false, false, false); + + /** + * Creates a map from register {@linkplain Register#number numbers} to register + * {@linkplain RegisterAttributes attributes} for a given register configuration and set of + * registers. + * + * @param registerConfig a register configuration + * @param registers a set of registers + * @return an array whose length is the max register number in {@code registers} plus 1. An + * element at index i holds the attributes of the register whose number is i. + */ + public static RegisterAttributes[] createMap(RegisterConfig registerConfig, Register[] registers) { + RegisterAttributes[] map = new RegisterAttributes[registers.length]; + for (Register reg : registers) { + if (reg != null) { + Register[] csr = registerConfig.getCalleeSaveRegisters(); + RegisterAttributes attr = new RegisterAttributes(Arrays.asList(registerConfig.getCallerSaveRegisters()).contains(reg), csr == null ? false : Arrays.asList(csr).contains(reg), + Arrays.asList(registerConfig.getAllocatableRegisters()).contains(reg)); + if (map.length <= reg.number) { + map = Arrays.copyOf(map, reg.number + 1); + } + map[reg.number] = attr; + } + } + for (int i = 0; i < map.length; i++) { + if (map[i] == null) { + map[i] = NONE; + } + } + return map; + } + + /** + * @return Denotes a register that is available for use by a register allocator. + */ + public boolean isAllocatable() { + return allocatable; + } + + /** + * @return Denotes a register whose value preservation (if required) across a call is the + * responsibility of the callee. + */ + public boolean isCalleeSave() { + return calleeSave; + } + + /** + * @return Denotes a register whose value preservation (if required) across a call is the + * responsibility of the caller. + */ + public boolean isCallerSave() { + return callerSave; + } +} --- /dev/null 2015-09-16 15:19:38.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/RegisterConfig.java 2015-09-16 15:19:38.000000000 -0700 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import jdk.internal.jvmci.code.CallingConvention.*; +import jdk.internal.jvmci.meta.*; + +/** + * A register configuration binds roles and {@linkplain RegisterAttributes attributes} to physical + * registers. + */ +public interface RegisterConfig { + + /** + * Gets the register to be used for returning a value of a given kind. + */ + Register getReturnRegister(JavaKind kind); + + /** + * Gets the maximum allowed size of the frame. + */ + default int getMaximumFrameSize() { + return Integer.MAX_VALUE; + } + + /** + * Gets the register to which {@link Register#Frame} and {@link Register#CallerFrame} are bound. + */ + Register getFrameRegister(); + + /** + * Gets the calling convention describing how arguments are passed. + * + * @param type the type of calling convention being requested + * @param returnType the return type (can be null for methods returning {@code void}) + * @param parameterTypes the types of the arguments of the call + * @param target the target platform + * @param stackOnly ignore registers + */ + CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly); + + /** + * Gets the ordered set of registers that are can be used to pass parameters according to a + * given calling convention. + * + * @param type the type of calling convention + * @param kind specifies what kind of registers is being requested + * @return the ordered set of registers that may be used to pass parameters in a call conforming + * to {@code type} + */ + Register[] getCallingConventionRegisters(Type type, JavaKind kind); + + /** + * Gets the set of all registers that might be used by the register allocator. + * + * To get the set of registers the register allocator is allowed to use see + * {@link RegisterAllocationConfig#getAllocatableRegisters()} + */ + @SuppressWarnings("javadoc") + Register[] getAllocatableRegisters(); + + /** + * Filters a set of registers and returns only those that can be used by the register allocator + * for a value of a particular kind. + */ + Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers); + + /** + * Gets the registers whose values must be preserved by a method across any call it makes. + */ + Register[] getCallerSaveRegisters(); + + /** + * Gets the registers whose values must be preserved by the callee. + */ + Register[] getCalleeSaveRegisters(); + + /** + * Gets a map from register {@linkplain Register#number numbers} to register + * {@linkplain RegisterAttributes attributes} for this register configuration. + * + * @return an array where an element at index i holds the attributes of the register whose + * number is i + */ + RegisterAttributes[] getAttributesMap(); + + /** + * Gets the register corresponding to a runtime-defined role. + * + * @param id the identifier of a runtime-defined register role + * @return the register playing the role specified by {@code id} + */ + Register getRegisterForRole(int id); + + /** + * Determines if all {@link #getAllocatableRegisters() allocatable} registers are + * {@link #getCallerSaveRegisters() caller saved}. + */ + boolean areAllAllocatableRegistersCallerSaved(); +} --- /dev/null 2015-09-16 15:19:39.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/RegisterSaveLayout.java 2015-09-16 15:19:39.000000000 -0700 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.util.*; + +/** + * A map from registers to frame slots. This can be used to describe where callee saved registers + * are saved in a callee's frame. + */ +public final class RegisterSaveLayout { + + /** + * Keys. + */ + private final Register[] registers; + + /** + * Slot indexes relative to stack pointer. + */ + private final int[] slots; + + /** + * Creates a map from registers to frame slots. + * + * @param registers the keys in the map + * @param slots frame slot index for each register in {@code registers} + */ + public RegisterSaveLayout(Register[] registers, int[] slots) { + assert registers.length == slots.length; + this.registers = registers; + this.slots = slots; + assert registersToSlots(false).size() == registers.length : "non-unique registers"; + assert new HashSet<>(registersToSlots(false).values()).size() == slots.length : "non-unqiue slots"; + } + + /** + * Gets the frame slot index for a given register. + * + * @param register register to get the frame slot index for + * @return frame slot index + */ + public int registerToSlot(Register register) { + for (int i = 0; i < registers.length; i++) { + if (register.equals(registers[i])) { + return slots[i]; + } + } + throw new IllegalArgumentException(register + " not saved by this layout: " + this); + } + + /** + * Gets this layout information as a {@link Map} from registers to slots. + */ + public Map registersToSlots(boolean sorted) { + Map result; + if (sorted) { + result = new TreeMap<>(); + } else { + result = new HashMap<>(); + } + for (int i = 0; i < registers.length; i++) { + result.put(registers[i], slots[i]); + } + return result; + } + + /** + * Gets this layout information as a {@link Map} from slots to registers. + */ + public Map slotsToRegisters(boolean sorted) { + Map result; + if (sorted) { + result = new TreeMap<>(); + } else { + result = new HashMap<>(); + } + for (int i = 0; i < registers.length; i++) { + result.put(slots[i], registers[i]); + } + return result; + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof RegisterSaveLayout) { + RegisterSaveLayout that = (RegisterSaveLayout) obj; + if (Arrays.equals(registers, that.registers) && Arrays.equals(slots, that.slots)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return registersToSlots(true).toString(); + } +} --- /dev/null 2015-09-16 15:19:39.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/RegisterValue.java 2015-09-16 15:19:39.000000000 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import jdk.internal.jvmci.meta.*; + +/** + * Denotes a register that stores a value of a fixed kind. There is exactly one (canonical) instance + * of {@link RegisterValue} for each ({@link Register}, {@link JavaKind}) pair. Use + * {@link Register#asValue(LIRKind)} to retrieve the canonical {@link RegisterValue} instance for a + * given (register,kind) pair. + */ +public final class RegisterValue extends AllocatableValue { + + private final Register reg; + + /** + * Should only be called from {@link Register#Register} to ensure canonicalization. + */ + protected RegisterValue(LIRKind kind, Register register) { + super(kind); + this.reg = register; + } + + @Override + public String toString() { + return getRegister().name + getKindSuffix(); + } + + /** + * @return the register that contains the value + */ + public Register getRegister() { + return reg; + } + + @Override + public int hashCode() { + return 29 * super.hashCode() + reg.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RegisterValue) { + RegisterValue other = (RegisterValue) obj; + return super.equals(obj) && reg.equals(other.reg); + } + return false; + } +} --- /dev/null 2015-09-16 15:19:40.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/SourceStackTrace.java 2015-09-16 15:19:40.000000000 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +/** + * Class representing a exception with a stack trace of the currently processed position in the + * compiled Java program instead of the stack trace of the compiler. The exception of the compiler + * is saved as the cause of this exception. + */ +public abstract class SourceStackTrace extends BailoutException { + private static final long serialVersionUID = 2144811793442316776L; + + public static SourceStackTrace create(Throwable cause, String format, StackTraceElement[] elements) { + return new SourceStackTrace(cause, format) { + + private static final long serialVersionUID = 6279381376051787907L; + + @Override + public final synchronized Throwable fillInStackTrace() { + assert elements != null; + setStackTrace(elements); + return this; + } + }; + } + + private SourceStackTrace(Throwable cause, String format) { + super(cause, format); + } +} --- /dev/null 2015-09-16 15:19:41.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/StackLockValue.java 2015-09-16 15:19:40.000000000 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import jdk.internal.jvmci.meta.*; +import static jdk.internal.jvmci.code.ValueUtil.*; + +/** + * Represents lock information in the debug information. + */ +public final class StackLockValue implements JavaValue { + + private JavaValue owner; + private StackSlotValue slot; + private final boolean eliminated; + + public StackLockValue(JavaValue object, StackSlotValue slot, boolean eliminated) { + this.owner = object; + this.slot = slot; + this.eliminated = eliminated; + } + + public JavaValue getOwner() { + return owner; + } + + public void setOwner(JavaValue newOwner) { + this.owner = newOwner; + } + + public Value getSlot() { + return slot; + } + + public boolean isEliminated() { + return eliminated; + } + + @Override + public String toString() { + return "monitor[" + owner + (slot != null ? ", " + slot : "") + (eliminated ? ", eliminated" : "") + "]"; + } + + @Override + public int hashCode() { + final int prime = 43; + int result = super.hashCode(); + result = prime * result + (eliminated ? 1231 : 1237); + result = prime * result + owner.hashCode(); + result = prime * result + slot.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof StackLockValue) { + StackLockValue other = (StackLockValue) obj; + return super.equals(obj) && eliminated == other.eliminated && owner.equals(other.owner) && slot.equals(other.slot); + } + return false; + } + + public void setSlot(StackSlotValue stackSlot) { + assert slot == null || (isVirtualStackSlot(slot) && (slot.equals(stackSlot) || isStackSlot(stackSlot))) : String.format("Can not set slot for %s to %s", this, stackSlot); + slot = stackSlot; + } +} --- /dev/null 2015-09-16 15:19:41.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/StackSlot.java 2015-09-16 15:19:41.000000000 -0700 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2010, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import jdk.internal.jvmci.meta.*; + +/** + * Represents a compiler spill slot or an outgoing stack-based argument in a method's frame or an + * incoming stack-based argument in a method's {@linkplain #isInCallerFrame() caller's frame}. + */ +public final class StackSlot extends StackSlotValue { + + private final int offset; + private final boolean addFrameSize; + + /** + * Gets a {@link StackSlot} instance representing a stack slot at a given index holding a value + * of a given kind. + * + * @param kind The kind of the value stored in the stack slot. + * @param offset The offset of the stack slot (in bytes) + * @param addFrameSize Specifies if the offset is relative to the stack pointer, or the + * beginning of the frame (stack pointer + total frame size). + */ + public static StackSlot get(LIRKind kind, int offset, boolean addFrameSize) { + assert addFrameSize || offset >= 0; + return new StackSlot(kind, offset, addFrameSize); + } + + /** + * Private constructor to enforce use of {@link #get(LIRKind, int, boolean)} so that a cache can + * be used. + */ + private StackSlot(LIRKind kind, int offset, boolean addFrameSize) { + super(kind); + this.offset = offset; + this.addFrameSize = addFrameSize; + } + + /** + * Gets the offset of this stack slot, relative to the stack pointer. + * + * @return The offset of this slot (in bytes). + */ + public int getOffset(int totalFrameSize) { + assert totalFrameSize > 0 || !addFrameSize; + int result = offset + (addFrameSize ? totalFrameSize : 0); + assert result >= 0; + return result; + } + + public boolean isInCallerFrame() { + return addFrameSize && offset >= 0; + } + + public int getRawOffset() { + return offset; + } + + public boolean getRawAddFrameSize() { + return addFrameSize; + } + + @Override + public String toString() { + if (!addFrameSize) { + return "out:" + offset + getKindSuffix(); + } else if (offset >= 0) { + return "in:" + offset + getKindSuffix(); + } else { + return "stack:" + (-offset) + getKindSuffix(); + } + } + + /** + * Gets this stack slot used to pass an argument from the perspective of a caller. + */ + public StackSlot asOutArg() { + assert offset >= 0; + if (addFrameSize) { + return get(getLIRKind(), offset, false); + } + return this; + } + + /** + * Gets this stack slot used to pass an argument from the perspective of a callee. + */ + public StackSlot asInArg() { + assert offset >= 0; + if (!addFrameSize) { + return get(getLIRKind(), offset, true); + } + return this; + } + + @Override + public int hashCode() { + final int prime = 37; + int result = super.hashCode(); + result = prime * result + (addFrameSize ? 1231 : 1237); + result = prime * result + offset; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof StackSlot) { + StackSlot other = (StackSlot) obj; + return super.equals(obj) && addFrameSize == other.addFrameSize && offset == other.offset; + } + return false; + } +} --- /dev/null 2015-09-16 15:19:42.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/StackSlotValue.java 2015-09-16 15:19:42.000000000 -0700 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import jdk.internal.jvmci.meta.*; + +/** + * Common base class for {@linkplain StackSlot real} and {@linkplain VirtualStackSlot virtual} stack + * slots. + */ +public abstract class StackSlotValue extends AllocatableValue { + + public StackSlotValue(LIRKind lirKind) { + super(lirKind); + } + +} --- /dev/null 2015-09-16 15:19:42.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/TargetDescription.java 2015-09-16 15:19:42.000000000 -0700 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import jdk.internal.jvmci.meta.*; +import static jdk.internal.jvmci.meta.MetaUtil.*; + +/** + * Represents the target machine for a compiler, including the CPU architecture, the size of + * pointers and references, alignment of stacks, caches, etc. + */ +public class TargetDescription { + + public final Architecture arch; + + /** + * Specifies if this is a multi-processor system. + */ + public final boolean isMP; + + /** + * Specifies if this target supports encoding objects inline in the machine code. + */ + public final boolean inlineObjects; + + /** + * The machine word size on this target. + */ + public final int wordSize; + + /** + * The kind to be used for representing raw pointers and CPU registers. + */ + public final JavaKind wordKind; + + /** + * The stack alignment requirement of the platform. For example, from Appendix D of Intel 64 and IA-32 Architectures + * Optimization Reference Manual: + * + *
+     *     "It is important to ensure that the stack frame is aligned to a
+     *      16-byte boundary upon function entry to keep local __m128 data,
+     *      parameters, and XMM register spill locations aligned throughout
+     *      a function invocation."
+     * 
+ */ + public final int stackAlignment; + + /** + * Maximum constant displacement at which a memory access can no longer be an implicit null + * check. + */ + public final int implicitNullCheckLimit; + + public TargetDescription(Architecture arch, boolean isMP, int stackAlignment, int implicitNullCheckLimit, boolean inlineObjects) { + this.arch = arch; + this.isMP = isMP; + this.wordSize = arch.getWordSize(); + this.wordKind = JavaKind.fromWordSize(wordSize); + this.stackAlignment = stackAlignment; + this.implicitNullCheckLimit = implicitNullCheckLimit; + this.inlineObjects = inlineObjects; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public final boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof TargetDescription) { + TargetDescription that = (TargetDescription) obj; + // @formatter:off + if (this.implicitNullCheckLimit == that.implicitNullCheckLimit && + this.inlineObjects == that.inlineObjects && + this.isMP == that.isMP && + this.stackAlignment == that.stackAlignment && + this.wordKind.equals(that.wordKind) && + this.wordSize == that.wordSize && + this.arch.equals(that.arch)) { + return true; + } + // @formatter:on + } + return false; + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + public int getSizeInBytes(PlatformKind kind) { + return kind.getSizeInBytes(); + } + + public LIRKind getLIRKind(JavaKind javaKind) { + PlatformKind platformKind = arch.getPlatformKind(javaKind); + if (javaKind.isObject()) { + return LIRKind.reference(platformKind); + } else { + return LIRKind.value(platformKind); + } + } +} --- /dev/null 2015-09-16 15:19:43.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/UnsignedMath.java 2015-09-16 15:19:43.000000000 -0700 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011, 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.math.*; + +//JaCoCo Exclude + +/** + * Utilities for unsigned comparisons. All methods have correct, but slow, standard Java + * implementations so that they can be used with compilers not supporting the intrinsics. + */ +public class UnsignedMath { + + private static final long MASK = 0xffffffffL; + + /** + * Unsigned comparison aboveThan for two numbers. + */ + public static boolean aboveThan(int a, int b) { + return (a & MASK) > (b & MASK); + } + + /** + * Unsigned comparison aboveOrEqual for two numbers. + */ + public static boolean aboveOrEqual(int a, int b) { + return (a & MASK) >= (b & MASK); + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + public static boolean belowThan(int a, int b) { + return (a & MASK) < (b & MASK); + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + public static boolean belowOrEqual(int a, int b) { + return (a & MASK) <= (b & MASK); + } + + /** + * Unsigned comparison aboveThan for two numbers. + */ + public static boolean aboveThan(long a, long b) { + return (a > b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned comparison aboveOrEqual for two numbers. + */ + public static boolean aboveOrEqual(long a, long b) { + return (a >= b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + public static boolean belowThan(long a, long b) { + return (a < b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + public static boolean belowOrEqual(long a, long b) { + return (a <= b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned division for two numbers. + */ + public static int divide(int a, int b) { + return (int) ((a & MASK) / (b & MASK)); + } + + /** + * Unsigned remainder for two numbers. + */ + public static int remainder(int a, int b) { + return (int) ((a & MASK) % (b & MASK)); + } + + /** + * Unsigned division for two numbers. + */ + public static long divide(long a, long b) { + return bi(a).divide(bi(b)).longValue(); + } + + /** + * Unsigned remainder for two numbers. + */ + public static long remainder(long a, long b) { + return bi(a).remainder(bi(b)).longValue(); + } + + private static BigInteger bi(long unsigned) { + return unsigned >= 0 ? BigInteger.valueOf(unsigned) : BigInteger.valueOf(unsigned & 0x7fffffffffffffffL).setBit(63); + } +} --- /dev/null 2015-09-16 15:19:44.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/ValueUtil.java 2015-09-16 15:19:43.000000000 -0700 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +/** + * Utility class for working with the {@link Value} class and its subclasses. + */ +public final class ValueUtil { + + public static boolean isIllegal(Value value) { + assert value != null; + return Value.ILLEGAL.equals(value); + } + + public static boolean isIllegalJavaValue(JavaValue value) { + assert value != null; + return Value.ILLEGAL.equals(value); + } + + public static boolean isLegal(Value value) { + return !isIllegal(value); + } + + public static boolean isVirtualObject(JavaValue value) { + assert value != null; + return value instanceof VirtualObject; + } + + public static VirtualObject asVirtualObject(JavaValue value) { + assert value != null; + return (VirtualObject) value; + } + + public static boolean isConstantJavaValue(JavaValue value) { + assert value != null; + return value instanceof JavaConstant; + } + + public static boolean isAllocatableValue(Value value) { + assert value != null; + return value instanceof AllocatableValue; + } + + public static AllocatableValue asAllocatableValue(Value value) { + assert value != null; + return (AllocatableValue) value; + } + + public static boolean isStackSlot(Value value) { + assert value != null; + return value instanceof StackSlot; + } + + public static StackSlot asStackSlot(Value value) { + assert value != null; + return (StackSlot) value; + } + + public static boolean isStackSlotValue(Value value) { + assert value != null; + return value instanceof StackSlotValue; + } + + public static StackSlotValue asStackSlotValue(Value value) { + assert value != null; + return (StackSlotValue) value; + } + + public static boolean isVirtualStackSlot(Value value) { + assert value != null; + return value instanceof VirtualStackSlot; + } + + public static VirtualStackSlot asVirtualStackSlot(Value value) { + assert value != null; + return (VirtualStackSlot) value; + } + + public static boolean isRegister(Value value) { + assert value != null; + return value instanceof RegisterValue; + } + + public static Register asRegister(Value value) { + return asRegisterValue(value).getRegister(); + } + + public static RegisterValue asRegisterValue(Value value) { + assert value != null; + return (RegisterValue) value; + } + + public static Register asRegister(Value value, PlatformKind kind) { + if (value.getPlatformKind() != kind) { + throw new InternalError("needed: " + kind + " got: " + value.getPlatformKind()); + } else { + return asRegister(value); + } + } + + public static boolean sameRegister(Value v1, Value v2) { + return isRegister(v1) && isRegister(v2) && asRegister(v1).equals(asRegister(v2)); + } + + public static boolean sameRegister(Value v1, Value v2, Value v3) { + return sameRegister(v1, v2) && sameRegister(v1, v3); + } + + /** + * Checks if all the provided values are different physical registers. The parameters can be + * either {@link Register registers}, {@link Value values} or arrays of them. All values that + * are not {@link RegisterValue registers} are ignored. + */ + public static boolean differentRegisters(Object... values) { + List registers = collectRegisters(values, new ArrayList()); + for (int i = 1; i < registers.size(); i++) { + Register r1 = registers.get(i); + for (int j = 0; j < i; j++) { + Register r2 = registers.get(j); + if (r1.equals(r2)) { + return false; + } + } + } + return true; + } + + private static List collectRegisters(Object[] values, List registers) { + for (Object o : values) { + if (o instanceof Register) { + registers.add((Register) o); + } else if (o instanceof Value) { + if (isRegister((Value) o)) { + registers.add(asRegister((Value) o)); + } + } else if (o instanceof Object[]) { + collectRegisters((Object[]) o, registers); + } else { + throw new IllegalArgumentException("Not a Register or Value: " + o); + } + } + return registers; + } + + /** + * Subtract sets of registers (x - y). + * + * @param x a set of register to subtract from. + * @param y a set of registers to subtract. + * @return resulting set of registers (x - y). + */ + public static Value[] subtractRegisters(Value[] x, Value[] y) { + ArrayList result = new ArrayList<>(x.length); + for (Value i : x) { + boolean append = true; + for (Value j : y) { + if (ValueUtil.sameRegister(i, j)) { + append = false; + break; + } + } + if (append) { + result.add(i); + } + } + Value[] resultArray = new Value[result.size()]; + return result.toArray(resultArray); + } +} --- /dev/null 2015-09-16 15:19:44.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/VirtualObject.java 2015-09-16 15:19:44.000000000 -0700 @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2010, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +/** + * An instance of this class represents an object whose allocation was removed by escape analysis. + * The information stored in the {@link VirtualObject} is used during deoptimization to recreate the + * object. + */ +public final class VirtualObject implements JavaValue { + + private final ResolvedJavaType type; + private JavaValue[] values; + private JavaKind[] slotKinds; + private final int id; + + /** + * Creates a new {@link VirtualObject} for the given type, with the given fields. If + * {@code type} is an instance class then {@code values} provides the values for the fields + * returned by {@link ResolvedJavaType#getInstanceFields(boolean) getInstanceFields(true)}. If + * {@code type} is an array then the length of the values array determines the reallocated array + * length. + * + * @param type the type of the object whose allocation was removed during compilation. This can + * be either an instance of an array type. + * @param id a unique id that identifies the object within the debug information for one + * position in the compiled code. + * @return a new {@link VirtualObject} instance. + */ + public static VirtualObject get(ResolvedJavaType type, int id) { + return new VirtualObject(type, id); + } + + private VirtualObject(ResolvedJavaType type, int id) { + this.type = type; + this.id = id; + } + + private static StringBuilder appendValue(StringBuilder buf, JavaValue value, Set visited) { + if (value instanceof VirtualObject) { + VirtualObject vo = (VirtualObject) value; + buf.append("vobject:").append(vo.type.toJavaName(false)).append(':').append(vo.id); + if (!visited.contains(vo)) { + visited.add(vo); + buf.append('{'); + if (vo.values == null) { + buf.append(""); + } else { + if (vo.type.isArray()) { + for (int i = 0; i < vo.values.length; i++) { + if (i != 0) { + buf.append(','); + } + buf.append(i).append('='); + appendValue(buf, vo.values[i], visited); + } + } else { + ResolvedJavaField[] fields = vo.type.getInstanceFields(true); + assert fields.length == vo.values.length : vo.type + ", fields=" + Arrays.toString(fields) + ", values=" + Arrays.toString(vo.values); + for (int i = 0; i < vo.values.length; i++) { + if (i != 0) { + buf.append(','); + } + buf.append(fields[i].getName()).append('='); + appendValue(buf, vo.values[i], visited); + } + } + } + buf.append('}'); + } + } else { + buf.append(value); + } + return buf; + } + + @Override + public String toString() { + Set visited = Collections.newSetFromMap(new IdentityHashMap()); + return appendValue(new StringBuilder(), this, visited).toString(); + } + + /** + * Returns the type of the object whose allocation was removed during compilation. This can be + * either an instance of an array type. + */ + public ResolvedJavaType getType() { + return type; + } + + /** + * Returns an array containing all the values to be stored into the object when it is recreated. + */ + public JavaValue[] getValues() { + return values; + } + + /** + * Returns an array containing the Java kind of all values in the object. + */ + public JavaKind[] getSlotKinds() { + return slotKinds; + } + + /** + * Returns the unique id that identifies the object within the debug information for one + * position in the compiled code. + */ + public int getId() { + return id; + } + + private boolean checkValues() { + assert (values == null) == (slotKinds == null); + if (values != null) { + assert values.length == slotKinds.length; + if (!type.isArray()) { + ResolvedJavaField[] fields = type.getInstanceFields(true); + int fieldIndex = 0; + for (int i = 0; i < values.length; i++) { + ResolvedJavaField field = fields[fieldIndex++]; + JavaKind valKind = slotKinds[i].getStackKind(); + if (field.getJavaKind() == JavaKind.Object) { + assert valKind.isObject() : field + ": " + valKind + " != " + field.getJavaKind(); + } else { + if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && field.getJavaKind() == JavaKind.Int) { + assert fields[fieldIndex].getJavaKind() == JavaKind.Int; + fieldIndex++; + } else { + assert valKind == field.getJavaKind().getStackKind() : field + ": " + valKind + " != " + field.getJavaKind(); + } + } + } + assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values); + } else { + JavaKind componentKind = type.getComponentType().getJavaKind().getStackKind(); + if (componentKind == JavaKind.Object) { + for (int i = 0; i < values.length; i++) { + assert slotKinds[i].isObject() : slotKinds[i] + " != " + componentKind; + } + } else { + for (int i = 0; i < values.length; i++) { + assert slotKinds[i] == componentKind || componentKind.getBitCount() >= slotKinds[i].getBitCount() || + (componentKind == JavaKind.Int && slotKinds[i].getBitCount() >= JavaKind.Int.getBitCount()) : slotKinds[i] + " != " + componentKind; + } + } + } + } + return true; + } + + /** + * Overwrites the current set of values with a new one. + * + * @param values an array containing all the values to be stored into the object when it is + * recreated. + * @param slotKinds an array containing the Java kinds of the values. + */ + public void setValues(JavaValue[] values, JavaKind[] slotKinds) { + this.values = values; + this.slotKinds = slotKinds; + assert checkValues(); + } + + @Override + public int hashCode() { + return 42 + type.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof VirtualObject) { + VirtualObject l = (VirtualObject) o; + if (!l.type.equals(type) || l.values.length != values.length) { + return false; + } + for (int i = 0; i < values.length; i++) { + /* + * Virtual objects can form cycles. Calling equals() could therefore lead to + * infinite recursion. + */ + if (!same(values[i], l.values[i])) { + return false; + } + } + return true; + } + return false; + } + + private static boolean same(Object o1, Object o2) { + return o1 == o2; + } +} --- /dev/null 2015-09-16 15:19:45.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/VirtualStackSlot.java 2015-09-16 15:19:45.000000000 -0700 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code; + +import jdk.internal.jvmci.meta.*; + +/** + * {@link VirtualStackSlot}s are stack slots that are not yet fixed to specific frame offset. They + * are replaced by real {@link StackSlot}s with a fixed position in the frame before code emission. + */ +public abstract class VirtualStackSlot extends StackSlotValue { + + private final int id; + + public VirtualStackSlot(int id, LIRKind lirKind) { + super(lirKind); + this.id = id; + } + + public int getId() { + return id; + } + + @Override + public String toString() { + return "vstack:" + id + getKindSuffix(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + id; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + VirtualStackSlot other = (VirtualStackSlot) obj; + if (id != other.id) { + return false; + } + return true; + } + +} --- /dev/null 2015-09-16 15:19:45.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/package-info.java 2015-09-16 15:19:45.000000000 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * Package that defines the interface between a Java application that wants to install code and the runtime. + * The runtime provides in implementation of the {@link jdk.internal.jvmci.code.CodeCacheProvider} interface. + * The method {@link jdk.internal.jvmci.code.CodeCacheProvider#addMethod(jdk.internal.jvmci.meta.ResolvedJavaMethod, CompilationResult, jdk.internal.jvmci.meta.SpeculationLog, InstalledCode)} + * can be used to install code for a given method. + */ +package jdk.internal.jvmci.code; + --- /dev/null 2015-09-16 15:19:46.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/stack/InspectedFrame.java 2015-09-16 15:19:46.000000000 -0700 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code.stack; + +import jdk.internal.jvmci.meta.*; + +public interface InspectedFrame { + + /** + * Returns the value of the local at the given index. Currently only works for object values. + * This value is a copy iff {@link #isVirtual(int)} is true. + */ + Object getLocal(int index); + + /** + * Returns whether the local at the given index is a virtual object, and therefore the object + * returned by {@link #getLocal(int)} is a copy. + */ + boolean isVirtual(int index); + + /** + * Returns true if the stack frame is a compiled stack frame and there are virtual objects + * anywhere in the current state of the compiled method. This can return true even if + * {@link #isVirtual(int)} return false for all locals. + */ + boolean hasVirtualObjects(); + + /** + * This method will materialize all virtual objects, deoptimize the stack frame and make sure + * that subsequent execution of the deoptimized frame uses the materialized values. + */ + void materializeVirtualObjects(boolean invalidateCode); + + /** + * @return the current bytecode index + */ + int getBytecodeIndex(); + + /** + * @return the current method + */ + ResolvedJavaMethod getMethod(); + + /** + * Checks if the current method is equal to the given method. This is semantically equivalent to + * {@code method.equals(getMethod())}, but can be implemented more efficiently. + */ + boolean isMethod(ResolvedJavaMethod method); +} --- /dev/null 2015-09-16 15:19:47.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/stack/InspectedFrameVisitor.java 2015-09-16 15:19:46.000000000 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code.stack; + +/** + * Callback interface for {@link StackIntrospection#iterateFrames}. Implementations of + * {@link #visitFrame} return null to indicate that frame iteration should continue and the next + * caller frame should be visited; and return any non-null value to indicate that frame iteration + * should stop. + */ +public interface InspectedFrameVisitor { + + T visitFrame(InspectedFrame frame); +} --- /dev/null 2015-09-16 15:19:47.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/stack/StackIntrospection.java 2015-09-16 15:19:47.000000000 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.code.stack; + +import jdk.internal.jvmci.meta.*; + +public interface StackIntrospection { + + /** + * Accesses the current stack, providing {@link InspectedFrame}s to the visitor that can be used + * to inspect the stack frames' contents. Iteration continues as long as + * {@link InspectedFrameVisitor#visitFrame}, which is invoked for every {@link InspectedFrame}, + * returns null. Any non-null result of the visitor indicates that frame iteration should stop. + * + * @param initialMethods if this is non-{@code null}, then the stack trace will start at these + * methods + * @param matchingMethods if this is non-{@code null}, then only matching stack frames are + * returned + * @param initialSkip the number of matching methods to skip (including the initial method) + * @param visitor the visitor that is called for every matching method + * @return the last result returned by the visitor (which is non-null to indicate that iteration + * should stop), or null if the whole stack was iterated. + */ + T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor visitor); +} --- /dev/null 2015-09-16 15:19:48.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.common/src/jdk/internal/jvmci/common/JVMCIError.java 2015-09-16 15:19:48.000000000 -0700 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2011, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.common; + +import java.util.*; + +/** + * Indicates a condition in JVMCI related code that should never occur during normal operation. + */ +public class JVMCIError extends Error { + + private static final long serialVersionUID = 531632331813456233L; + private final ArrayList context = new ArrayList<>(); + + public static RuntimeException unimplemented() { + throw new JVMCIError("unimplemented"); + } + + public static RuntimeException unimplemented(String msg) { + throw new JVMCIError("unimplemented: %s", msg); + } + + public static RuntimeException shouldNotReachHere() { + throw new JVMCIError("should not reach here"); + } + + public static RuntimeException shouldNotReachHere(String msg) { + throw new JVMCIError("should not reach here: %s", msg); + } + + public static RuntimeException shouldNotReachHere(Throwable cause) { + throw new JVMCIError(cause); + } + + /** + * Checks a given condition and throws a {@link JVMCIError} if it is false. Guarantees are + * stronger than assertions in that they are always checked. Error messages for guarantee + * violations should clearly indicate the nature of the problem as well as a suggested solution + * if possible. + * + * @param condition the condition to check + * @param msg the message that will be associated with the error, in + * {@link String#format(String, Object...)} syntax + * @param args arguments to the format string + */ + public static void guarantee(boolean condition, String msg, Object... args) { + if (!condition) { + throw new JVMCIError("failed guarantee: " + msg, args); + } + } + + /** + * This constructor creates a {@link JVMCIError} with a given message. + * + * @param msg the message that will be associated with the error + */ + public JVMCIError(String msg) { + super(msg); + } + + /** + * This constructor creates a {@link JVMCIError} with a message assembled via + * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to + * always generate the same output. + * + * @param msg the message that will be associated with the error, in String.format syntax + * @param args parameters to String.format - parameters that implement {@link Iterable} will be + * expanded into a [x, x, ...] representation. + */ + public JVMCIError(String msg, Object... args) { + super(format(msg, args)); + } + + /** + * This constructor creates a {@link JVMCIError} for a given causing Throwable instance. + * + * @param cause the original exception that contains additional information on this error + */ + public JVMCIError(Throwable cause) { + super(cause); + } + + /** + * This constructor creates a {@link JVMCIError} and adds all the + * {@linkplain #addContext(String) context} of another {@link JVMCIError}. + * + * @param e the original {@link JVMCIError} + */ + public JVMCIError(JVMCIError e) { + super(e); + context.addAll(e.context); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append(super.toString()); + for (String s : context) { + str.append("\n\tat ").append(s); + } + return str.toString(); + } + + private static String format(String msg, Object... args) { + if (args != null) { + // expand Iterable parameters into a list representation + for (int i = 0; i < args.length; i++) { + if (args[i] instanceof Iterable) { + ArrayList list = new ArrayList<>(); + for (Object o : (Iterable) args[i]) { + list.add(o); + } + args[i] = list.toString(); + } + } + } + return String.format(Locale.ENGLISH, msg, args); + } + + public JVMCIError addContext(String newContext) { + this.context.add(newContext); + return this; + } + + public JVMCIError addContext(String name, Object obj) { + return addContext(format("%s: %s", name, obj)); + } +} --- /dev/null 2015-09-16 15:19:48.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.common/src/jdk/internal/jvmci/common/UnsafeUtil.java 2015-09-16 15:19:48.000000000 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.common; + +import sun.misc.Unsafe; + +/** + * Utilities for operating on raw memory with {@link Unsafe}. + */ +public class UnsafeUtil { + + /** + * Copies the contents of a {@link String} to a native memory buffer as a {@code '\0'} + * terminated C string. The native memory buffer is allocated via + * {@link Unsafe#allocateMemory(long)}. The caller is responsible for releasing the buffer when + * it is no longer needed via {@link Unsafe#freeMemory(long)}. + * + * @return the native memory pointer of the C string created from {@code s} + */ + public static long createCString(Unsafe unsafe, String s) { + return writeCString(unsafe, s, unsafe.allocateMemory(s.length() + 1)); + } + + /** + * Reads a {@code '\0'} terminated C string from native memory and converts it to a + * {@link String}. + * + * @return a Java string + */ + public static String readCString(Unsafe unsafe, long address) { + if (address == 0) { + return null; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0;; i++) { + char c = (char) unsafe.getByte(address + i); + if (c == 0) { + break; + } + sb.append(c); + } + return sb.toString(); + } + + /** + * Writes the contents of a {@link String} to a native memory buffer as a {@code '\0'} + * terminated C string. The caller is responsible for ensuring the buffer is at least + * {@code s.length() + 1} bytes long. The caller is also responsible for releasing the buffer + * when it is no longer. + * + * @return the value of {@code buf} + */ + public static long writeCString(Unsafe unsafe, String s, long buf) { + int size = s.length(); + for (int i = 0; i < size; i++) { + unsafe.putByte(buf + i, (byte) s.charAt(i)); + } + unsafe.putByte(buf + size, (byte) '\0'); + return buf; + } +} --- /dev/null 2015-09-16 15:19:49.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.compiler/src/jdk/internal/jvmci/compiler/Compiler.java 2015-09-16 15:19:49.000000000 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.compiler; + +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.options.*; + +public interface Compiler { + int INVOCATION_ENTRY_BCI = -1; + + @Option(help = "", type = OptionType.Debug) OptionValue PrintFilter = new OptionValue<>(null); + @Option(help = "", type = OptionType.Debug) OptionValue PrintCompilation = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue PrintAfterCompilation = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue PrintBailout = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue ExitVMOnBailout = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue ExitVMOnException = new OptionValue<>(true); + @Option(help = "", type = OptionType.Debug) OptionValue PrintStackTraceOnException = new OptionValue<>(false); + + /** + * Request the compilation of a method by this JVMCI compiler. The compiler should compile the + * method to machine code and install it in the code cache if the compilation is successful. + * + * @param method the method that should be compiled + * @param entryBCI the BCI at which to start compiling where -1 denotes a non-OSR compilation + * request and all other values denote an OSR compilation request + * @param jvmciEnv pointer to native {@code JVMCIEnv} object + * @param id a unique identifier for this compilation + */ + void compileMethod(ResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id); +} --- /dev/null 2015-09-16 15:19:50.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.compiler/src/jdk/internal/jvmci/compiler/CompilerFactory.java 2015-09-16 15:19:49.000000000 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.compiler; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.runtime.*; + +/** + * Factory for a JVMCI compiler. + */ +public interface CompilerFactory { + + /** + * Get the name of this compiler. The compiler will be selected when the jvmci.compiler system + * property is equal to this name. + */ + String getCompilerName(); + + /** + * Initialize an {@link Architecture}. The compiler has the opportunity to extend the + * {@link Architecture} description with a custom subclass. + */ + Architecture initializeArchitecture(Architecture arch); + + /** + * Create a new instance of the {@link Compiler}. + */ + Compiler createCompiler(JVMCIRuntime runtime); +} --- /dev/null 2015-09-16 15:19:50.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.compiler/src/jdk/internal/jvmci/compiler/StartupEventListener.java 2015-09-16 15:19:50.000000000 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.compiler; + +public interface StartupEventListener { + + /** + * This method is called before any of the {@link CompilerFactory} methods. + */ + void beforeJVMCIStartup(); +} --- /dev/null 2015-09-16 15:19:51.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot.amd64/src/jdk/internal/jvmci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java 2015-09-16 15:19:51.000000000 -0700 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot.amd64; + +import static jdk.internal.jvmci.inittimer.InitTimer.*; + +import java.util.*; + +import jdk.internal.jvmci.amd64.*; +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.compiler.*; +import jdk.internal.jvmci.hotspot.*; +import jdk.internal.jvmci.inittimer.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.runtime.*; +import jdk.internal.jvmci.service.*; + +@ServiceProvider(HotSpotJVMCIBackendFactory.class) +public class AMD64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFactory { + + protected EnumSet computeFeatures(HotSpotVMConfig config) { + // Configure the feature set using the HotSpot flag settings. + EnumSet features = EnumSet.noneOf(AMD64.CPUFeature.class); + assert config.useSSE >= 2 : "minimum config for x64"; + features.add(AMD64.CPUFeature.SSE); + features.add(AMD64.CPUFeature.SSE2); + if ((config.x86CPUFeatures & config.cpuSSE3) != 0) { + features.add(AMD64.CPUFeature.SSE3); + } + if ((config.x86CPUFeatures & config.cpuSSSE3) != 0) { + features.add(AMD64.CPUFeature.SSSE3); + } + if ((config.x86CPUFeatures & config.cpuSSE4A) != 0) { + features.add(AMD64.CPUFeature.SSE4a); + } + if ((config.x86CPUFeatures & config.cpuSSE41) != 0) { + features.add(AMD64.CPUFeature.SSE4_1); + } + if ((config.x86CPUFeatures & config.cpuSSE42) != 0) { + features.add(AMD64.CPUFeature.SSE4_2); + } + if ((config.x86CPUFeatures & config.cpuAVX) != 0) { + features.add(AMD64.CPUFeature.AVX); + } + if ((config.x86CPUFeatures & config.cpuAVX2) != 0) { + features.add(AMD64.CPUFeature.AVX2); + } + if ((config.x86CPUFeatures & config.cpuERMS) != 0) { + features.add(AMD64.CPUFeature.ERMS); + } + if ((config.x86CPUFeatures & config.cpuLZCNT) != 0) { + features.add(AMD64.CPUFeature.LZCNT); + } + if ((config.x86CPUFeatures & config.cpuPOPCNT) != 0) { + features.add(AMD64.CPUFeature.POPCNT); + } + if ((config.x86CPUFeatures & config.cpuAES) != 0) { + features.add(AMD64.CPUFeature.AES); + } + if ((config.x86CPUFeatures & config.cpu3DNOWPREFETCH) != 0) { + features.add(AMD64.CPUFeature.AMD_3DNOW_PREFETCH); + } + if ((config.x86CPUFeatures & config.cpuBMI1) != 0) { + features.add(AMD64.CPUFeature.BMI1); + } + return features; + } + + protected EnumSet computeFlags(HotSpotVMConfig config) { + EnumSet flags = EnumSet.noneOf(AMD64.Flag.class); + if (config.useCountLeadingZerosInstruction) { + flags.add(AMD64.Flag.UseCountLeadingZerosInstruction); + } + if (config.useCountTrailingZerosInstruction) { + flags.add(AMD64.Flag.UseCountTrailingZerosInstruction); + } + return flags; + } + + protected TargetDescription createTarget(HotSpotVMConfig config, CompilerFactory compilerFactory) { + final int stackFrameAlignment = 16; + final int implicitNullCheckLimit = 4096; + final boolean inlineObjects = true; + Architecture arch = new AMD64(computeFeatures(config), computeFlags(config)); + return new TargetDescription(compilerFactory.initializeArchitecture(arch), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); + } + + protected HotSpotConstantReflectionProvider createConstantReflection(HotSpotJVMCIRuntimeProvider runtime) { + return new HotSpotConstantReflectionProvider(runtime); + } + + protected RegisterConfig createRegisterConfig(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target) { + return new AMD64HotSpotRegisterConfig(target.arch, runtime.getConfig()); + } + + protected HotSpotCodeCacheProvider createCodeCache(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { + return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig); + } + + protected HotSpotMetaAccessProvider createMetaAccess(HotSpotJVMCIRuntimeProvider runtime) { + return new HotSpotMetaAccessProvider(runtime); + } + + @Override + public String getArchitecture() { + return "AMD64"; + } + + @Override + public String toString() { + return "JVMCIBackend:" + getArchitecture(); + } + + @SuppressWarnings("try") + public JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntimeProvider runtime, CompilerFactory compilerFactory, JVMCIBackend host) { + + assert host == null; + TargetDescription target = createTarget(runtime.getConfig(), compilerFactory); + + RegisterConfig regConfig; + HotSpotCodeCacheProvider codeCache; + ConstantReflectionProvider constantReflection; + HotSpotMetaAccessProvider metaAccess; + try (InitTimer t = timer("create providers")) { + try (InitTimer rt = timer("create MetaAccess provider")) { + metaAccess = createMetaAccess(runtime); + } + try (InitTimer rt = timer("create RegisterConfig")) { + regConfig = createRegisterConfig(runtime, target); + } + try (InitTimer rt = timer("create CodeCache provider")) { + codeCache = createCodeCache(runtime, target, regConfig); + } + try (InitTimer rt = timer("create ConstantReflection provider")) { + constantReflection = createConstantReflection(runtime); + } + } + try (InitTimer rt = timer("instantiate backend")) { + return createBackend(metaAccess, codeCache, constantReflection); + } + } + + protected JVMCIBackend createBackend(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection) { + return new JVMCIBackend(metaAccess, codeCache, constantReflection); + } +} --- /dev/null 2015-09-16 15:19:51.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot.amd64/src/jdk/internal/jvmci/hotspot/amd64/AMD64HotSpotRegisterConfig.java 2015-09-16 15:19:51.000000000 -0700 @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot.amd64; + +import static jdk.internal.jvmci.amd64.AMD64.*; + +import java.util.*; + +import jdk.internal.jvmci.amd64.*; +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.code.CallingConvention.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.hotspot.*; +import jdk.internal.jvmci.meta.*; + +public class AMD64HotSpotRegisterConfig implements RegisterConfig { + + private final Architecture architecture; + + private final Register[] allocatable; + + private final int maxFrameSize; + + /** + * The caller saved registers always include all parameter registers. + */ + private final Register[] callerSaved; + + private final boolean allAllocatableAreCallerSaved; + + private final RegisterAttributes[] attributesMap; + + public int getMaximumFrameSize() { + return maxFrameSize; + } + + @Override + public Register[] getAllocatableRegisters() { + return allocatable.clone(); + } + + public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { + ArrayList list = new ArrayList<>(); + for (Register reg : registers) { + if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { + list.add(reg); + } + } + + Register[] ret = list.toArray(new Register[list.size()]); + return ret; + } + + @Override + public RegisterAttributes[] getAttributesMap() { + return attributesMap.clone(); + } + + private final Register[] javaGeneralParameterRegisters; + private final Register[] nativeGeneralParameterRegisters; + private final Register[] xmmParameterRegisters = {xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7}; + + /* + * Some ABIs (e.g. Windows) require a so-called "home space", that is a save area on the stack + * to store the argument registers + */ + private final boolean needsNativeStackHomeSpace; + + private static Register[] initAllocatable(boolean reserveForHeapBase) { + Register[] registers = null; + // @formatter:off + if (reserveForHeapBase) { + registers = new Register[] { + rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, /*r12,*/ r13, r14, /*r15, */ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + } else { + registers = new Register[] { + rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, /*r15, */ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + } + // @formatter:on + return registers; + } + + public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config) { + this(architecture, config, initAllocatable(config.useCompressedOops)); + assert callerSaved.length >= allocatable.length; + } + + public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, Register[] allocatable) { + this.architecture = architecture; + this.maxFrameSize = config.maxFrameSize; + + if (config.windowsOs) { + javaGeneralParameterRegisters = new Register[]{rdx, r8, r9, rdi, rsi, rcx}; + nativeGeneralParameterRegisters = new Register[]{rcx, rdx, r8, r9}; + this.needsNativeStackHomeSpace = true; + } else { + javaGeneralParameterRegisters = new Register[]{rsi, rdx, rcx, r8, r9, rdi}; + nativeGeneralParameterRegisters = new Register[]{rdi, rsi, rdx, rcx, r8, r9}; + this.needsNativeStackHomeSpace = false; + } + + this.allocatable = allocatable.clone(); + Set callerSaveSet = new HashSet<>(); + Collections.addAll(callerSaveSet, allocatable); + Collections.addAll(callerSaveSet, xmmParameterRegisters); + Collections.addAll(callerSaveSet, javaGeneralParameterRegisters); + Collections.addAll(callerSaveSet, nativeGeneralParameterRegisters); + callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]); + + allAllocatableAreCallerSaved = true; + attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters); + } + + @Override + public Register[] getCallerSaveRegisters() { + return callerSaved; + } + + public Register[] getCalleeSaveRegisters() { + return null; + } + + @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return allAllocatableAreCallerSaved; + } + + @Override + public Register getRegisterForRole(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) { + if (type == Type.NativeCall) { + return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + // On x64, parameter locations are the same whether viewed + // from the caller or callee perspective + return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + + public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { + switch (kind) { + case Boolean: + case Byte: + case Short: + case Char: + case Int: + case Long: + case Object: + return type == Type.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; + case Float: + case Double: + return xmmParameterRegisters; + default: + throw JVMCIError.shouldNotReachHere(); + } + } + + private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { + AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; + + int currentGeneral = 0; + int currentXMM = 0; + int currentStackOffset = type == Type.NativeCall && needsNativeStackHomeSpace ? generalParameterRegisters.length * target.wordSize : 0; + + for (int i = 0; i < parameterTypes.length; i++) { + final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); + + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Object: + if (!stackOnly && currentGeneral < generalParameterRegisters.length) { + Register register = generalParameterRegisters[currentGeneral++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + case Float: + case Double: + if (!stackOnly && currentXMM < xmmParameterRegisters.length) { + Register register = xmmParameterRegisters[currentXMM++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + default: + throw JVMCIError.shouldNotReachHere(); + } + + if (locations[i] == null) { + LIRKind lirKind = target.getLIRKind(kind); + locations[i] = StackSlot.get(lirKind, currentStackOffset, !type.out); + currentStackOffset += Math.max(target.getSizeInBytes(lirKind.getPlatformKind()), target.wordSize); + } + } + + JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); + AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(target.getLIRKind(returnKind.getStackKind())); + return new CallingConvention(currentStackOffset, returnLocation, locations); + } + + @Override + public Register getReturnRegister(JavaKind kind) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + return rax; + case Float: + case Double: + return xmm0; + case Void: + case Illegal: + return null; + default: + throw new UnsupportedOperationException("no return register for type " + kind); + } + } + + @Override + public Register getFrameRegister() { + return rsp; + } + + @Override + public String toString() { + return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); + } +} --- /dev/null 2015-09-16 15:19:52.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot.sparc/src/jdk/internal/jvmci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java 2015-09-16 15:19:52.000000000 -0700 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot.sparc; + +import static jdk.internal.jvmci.inittimer.InitTimer.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.compiler.*; +import jdk.internal.jvmci.hotspot.*; +import jdk.internal.jvmci.inittimer.*; +import jdk.internal.jvmci.runtime.*; +import jdk.internal.jvmci.service.*; +import jdk.internal.jvmci.sparc.*; +import jdk.internal.jvmci.sparc.SPARC.CPUFeature; + +@ServiceProvider(HotSpotJVMCIBackendFactory.class) +public class SPARCHotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFactory { + + protected TargetDescription createTarget(HotSpotVMConfig config, CompilerFactory compilerFactory) { + final int stackFrameAlignment = 16; + final int implicitNullCheckLimit = 4096; + final boolean inlineObjects = false; + Architecture arch = new SPARC(computeFeatures(config)); + return new TargetDescription(compilerFactory.initializeArchitecture(arch), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); + } + + protected HotSpotCodeCacheProvider createCodeCache(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { + return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig); + } + + protected EnumSet computeFeatures(HotSpotVMConfig config) { + EnumSet features = EnumSet.noneOf(CPUFeature.class); + if ((config.sparcFeatures & config.vis1Instructions) != 0) { + features.add(CPUFeature.VIS1); + } + if ((config.sparcFeatures & config.vis2Instructions) != 0) { + features.add(CPUFeature.VIS2); + } + if ((config.sparcFeatures & config.vis3Instructions) != 0) { + features.add(CPUFeature.VIS3); + } + if ((config.sparcFeatures & config.cbcondInstructions) != 0) { + features.add(CPUFeature.CBCOND); + } + if (config.useBlockZeroing) { + features.add(CPUFeature.BLOCK_ZEROING); + } + return features; + } + + @Override + public String getArchitecture() { + return "SPARC"; + } + + @Override + public String toString() { + return "JVMCIBackend:" + getArchitecture(); + } + + @SuppressWarnings("try") + public JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntimeProvider runtime, CompilerFactory compilerFactory, JVMCIBackend host) { + assert host == null; + TargetDescription target = createTarget(runtime.getConfig(), compilerFactory); + + HotSpotMetaAccessProvider metaAccess = new HotSpotMetaAccessProvider(runtime); + RegisterConfig regConfig = new SPARCHotSpotRegisterConfig(target, runtime.getConfig()); + HotSpotCodeCacheProvider codeCache = createCodeCache(runtime, target, regConfig); + HotSpotConstantReflectionProvider constantReflection = new HotSpotConstantReflectionProvider(runtime); + try (InitTimer rt = timer("instantiate backend")) { + return createBackend(metaAccess, codeCache, constantReflection); + } + } + + protected JVMCIBackend createBackend(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, HotSpotConstantReflectionProvider constantReflection) { + return new JVMCIBackend(metaAccess, codeCache, constantReflection); + } +} --- /dev/null 2015-09-16 15:19:53.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot.sparc/src/jdk/internal/jvmci/hotspot/sparc/SPARCHotSpotRegisterConfig.java 2015-09-16 15:19:52.000000000 -0700 @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2013, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot.sparc; + +import static jdk.internal.jvmci.sparc.SPARC.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.code.CallingConvention.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.hotspot.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.sparc.*; + +public class SPARCHotSpotRegisterConfig implements RegisterConfig { + + private final Architecture architecture; + + private final Register[] allocatable; + + private final RegisterAttributes[] attributesMap; + + @Override + public Register[] getAllocatableRegisters() { + return allocatable.clone(); + } + + public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { + ArrayList list = new ArrayList<>(); + for (Register reg : registers) { + if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { + // Special treatment for double precision + // TODO: This is wasteful it uses only half of the registers as float. + if (kind == JavaKind.Double) { + if (reg.getRegisterCategory().equals(FPUd)) { + list.add(reg); + } + } else if (kind == JavaKind.Float) { + if (reg.getRegisterCategory().equals(FPUs)) { + list.add(reg); + } + } else { + list.add(reg); + } + } + } + + Register[] ret = list.toArray(new Register[list.size()]); + return ret; + } + + @Override + public RegisterAttributes[] getAttributesMap() { + return attributesMap.clone(); + } + + private final Register[] cpuCallerParameterRegisters = {o0, o1, o2, o3, o4, o5}; + private final Register[] cpuCalleeParameterRegisters = {i0, i1, i2, i3, i4, i5}; + + private final Register[] fpuParameterRegisters = {f0, f1, f2, f3, f4, f5, f6, f7}; + private final Register[] fpuDoubleParameterRegisters = {d0, null, d2, null, d4, null, d6, null}; + // @formatter:off + private final Register[] callerSaveRegisters = + {g1, g2, g3, g4, g5, g6, g7, + o0, o1, o2, o3, o4, o5, o7, + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62}; + // @formatter:on + + /** + * Registers saved by the callee. This lists all L and I registers which are saved in the + * register window. + */ + private final Register[] calleeSaveRegisters = {l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, i6, i7}; + + private static Register[] initAllocatable(boolean reserveForHeapBase) { + Register[] registers = null; + if (reserveForHeapBase) { + // @formatter:off + registers = new Register[]{ + // TODO this is not complete + // o7 cannot be used as register because it is always overwritten on call + // and the current register handler would ignore this fact if the called + // method still does not modify registers, in fact o7 is modified by the Call instruction + // There would be some extra handlin necessary to be able to handle the o7 properly for local usage + g1, g4, g5, + o0, o1, o2, o3, o4, o5, /*o6,o7,*/ + l0, l1, l2, l3, l4, l5, l6, l7, + i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ + //f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + } else { + // @formatter:off + registers = new Register[]{ + // TODO this is not complete + g1, g4, g5, + o0, o1, o2, o3, o4, o5, /*o6, o7,*/ + l0, l1, l2, l3, l4, l5, l6, l7, + i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ +// f0, f1, f2, f3, f4, f5, f6, f7 + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + } + + return registers; + } + + public SPARCHotSpotRegisterConfig(TargetDescription target, HotSpotVMConfig config) { + this(target, initAllocatable(config.useCompressedOops)); + } + + public SPARCHotSpotRegisterConfig(TargetDescription target, Register[] allocatable) { + this.architecture = target.arch; + this.allocatable = allocatable.clone(); + attributesMap = RegisterAttributes.createMap(this, SPARC.allRegisters); + } + + @Override + public Register[] getCallerSaveRegisters() { + return callerSaveRegisters; + } + + public Register[] getCalleeSaveRegisters() { + return calleeSaveRegisters; + } + + @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return false; + } + + @Override + public Register getRegisterForRole(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) { + if (type == Type.JavaCall || type == Type.NativeCall) { + return callingConvention(cpuCallerParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + if (type == Type.JavaCallee) { + return callingConvention(cpuCalleeParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + throw JVMCIError.shouldNotReachHere(); + } + + public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { + if (architecture.canStoreValue(FPUs, kind) || architecture.canStoreValue(FPUd, kind)) { + return fpuParameterRegisters; + } + assert architecture.canStoreValue(CPU, kind); + return type == Type.JavaCallee ? cpuCalleeParameterRegisters : cpuCallerParameterRegisters; + } + + private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { + AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; + + int currentGeneral = 0; + int currentFloating = 0; + int currentStackOffset = 0; + + for (int i = 0; i < parameterTypes.length; i++) { + final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); + + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Object: + if (!stackOnly && currentGeneral < generalParameterRegisters.length) { + Register register = generalParameterRegisters[currentGeneral++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + case Double: + if (!stackOnly && currentFloating < fpuParameterRegisters.length) { + if (currentFloating % 2 != 0) { + // Make register number even to be a double reg + currentFloating++; + } + Register register = fpuDoubleParameterRegisters[currentFloating]; + currentFloating += 2; // Only every second is a double register + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + case Float: + if (!stackOnly && currentFloating < fpuParameterRegisters.length) { + Register register = fpuParameterRegisters[currentFloating++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + default: + throw JVMCIError.shouldNotReachHere(); + } + + if (locations[i] == null) { + // Stack slot is always aligned to its size in bytes but minimum wordsize + int typeSize = SPARC.spillSlotSize(target, kind); + currentStackOffset = roundUp(currentStackOffset, typeSize); + int slotOffset = currentStackOffset + SPARC.REGISTER_SAFE_AREA_SIZE; + locations[i] = StackSlot.get(target.getLIRKind(kind.getStackKind()), slotOffset, !type.out); + currentStackOffset += typeSize; + } + } + + JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); + AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind, type).asValue(target.getLIRKind(returnKind.getStackKind())); + return new CallingConvention(currentStackOffset, returnLocation, locations); + } + + private static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } + + @Override + public Register getReturnRegister(JavaKind kind) { + return getReturnRegister(kind, Type.JavaCallee); + } + + private static Register getReturnRegister(JavaKind kind, Type type) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + return type == Type.JavaCallee ? i0 : o0; + case Float: + return f0; + case Double: + return d0; + case Void: + case Illegal: + return null; + default: + throw new UnsupportedOperationException("no return register for type " + kind); + } + } + + @Override + public Register getFrameRegister() { + return sp; + } + + @Override + public String toString() { + return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); + } +} --- /dev/null 2015-09-16 15:19:53.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/CompilerToVM.java 2015-09-16 15:19:53.000000000 -0700 @@ -0,0 +1,568 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.inittimer.InitTimer.timer; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import jdk.internal.jvmci.code.InstalledCode; +import jdk.internal.jvmci.code.InvalidInstalledCodeException; +import jdk.internal.jvmci.code.TargetDescription; +import jdk.internal.jvmci.hotspotvmconfig.HotSpotVMField; +import jdk.internal.jvmci.inittimer.InitTimer; +import jdk.internal.jvmci.meta.JavaType; +import jdk.internal.jvmci.meta.ResolvedJavaMethod; +import jdk.internal.jvmci.meta.ResolvedJavaType; +import jdk.internal.jvmci.meta.SpeculationLog; +import sun.misc.Unsafe; + +/** + * Calls from Java into HotSpot. The behavior of all the methods in this class that take a native + * pointer as an argument (e.g., {@link #getSymbol(long)}) is undefined if the argument does not + * denote a valid native object. + */ +public final class CompilerToVM { + /** + * Initializes the native part of the JVMCI runtime. + */ + private static native void init(); + + static { + initialize(); + } + + @SuppressWarnings("try") + private static void initialize() { + try (InitTimer t = timer("CompilerToVMImpl.init")) { + init(); + } + } + + /** + * Copies the original bytecode of {@code method} into a new byte array and returns it. + * + * @return a new byte array containing the original bytecode of {@code method} + */ + native byte[] getBytecode(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the number of entries in {@code method}'s exception handler table or 0 if it has not + * exception handler table. + */ + native int getExceptionTableLength(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the address of the first entry in {@code method}'s exception handler table. + * + * Each entry is a native object described by these fields: + * + *
    + *
  • {@link HotSpotVMConfig#exceptionTableElementSize}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementStartPcOffset}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementEndPcOffset}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementHandlerPcOffset}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementCatchTypeIndexOffset} + *
+ * + * @return 0 if {@code method} has no exception handlers (i.e. + * {@code getExceptionTableLength(method) == 0}) + */ + native long getExceptionTableStart(HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if {@code method} has balanced monitors. + */ + native boolean hasBalancedMonitors(HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if {@code method} can be inlined. A method may not be inlinable for a number of + * reasons such as: + *
    + *
  • a CompileOracle directive may prevent inlining or compilation of methods
  • + *
  • the method may have a bytecode breakpoint set
  • + *
  • the method may have other bytecode features that require special handling by the VM
  • + *
+ */ + native boolean canInlineMethod(HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if {@code method} should be inlined at any cost. This could be because: + *
    + *
  • a CompileOracle directive may forces inlining of this methods
  • + *
  • an annotation forces inlining of this method
  • + *
+ */ + native boolean shouldInlineMethod(HotSpotResolvedJavaMethodImpl method); + + /** + * Used to implement {@link ResolvedJavaType#findUniqueConcreteMethod(ResolvedJavaMethod)}. + * + * @param method the method on which to base the search + * @param actualHolderType the best known type of receiver + * @return the method result or 0 is there is no unique concrete method for {@code method} + */ + native HotSpotResolvedJavaMethodImpl findUniqueConcreteMethod(HotSpotResolvedObjectTypeImpl actualHolderType, HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the implementor for the interface class {@code type}. + * + * @return the implementor if there is a single implementor, 0 if there is no implementor, or + * {@code type} itself if there is more than one implementor + */ + native HotSpotResolvedObjectTypeImpl getImplementor(HotSpotResolvedObjectTypeImpl type); + + /** + * Determines if {@code method} is ignored by security stack walks. + */ + native boolean methodIsIgnoredBySecurityStackWalk(HotSpotResolvedJavaMethodImpl method); + + /** + * Converts a name to a type. + * + * @param name a well formed Java type in {@linkplain JavaType#getName() internal} format + * @param accessingClass the context of resolution (must not be null) + * @param resolve force resolution to a {@link ResolvedJavaType}. If true, this method will + * either return a {@link ResolvedJavaType} or throw an exception + * @return the type for {@code name} or 0 if resolution failed and {@code resolve == false} + * @throws LinkageError if {@code resolve == true} and the resolution failed + */ + native HotSpotResolvedObjectTypeImpl lookupType(String name, Class accessingClass, boolean resolve); + + /** + * Resolves the entry at index {@code cpi} in {@code constantPool} to an object. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry that can be + * resolved to an object. + */ + native Object resolveConstantInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Resolves the entry at index {@code cpi} in {@code constantPool} to an object, looking in the + * constant pool cache first. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry that can be + * resolved to an object. + */ + native Object resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} index from the entry at index {@code cpi} in + * {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry containing a + * {@code JVM_CONSTANT_NameAndType} index. + */ + native int lookupNameAndTypeRefIndexInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the name of the {@code JVM_CONSTANT_NameAndType} entry at index {@code cpi} in + * {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_NameAndType} entry. + */ + native String lookupNameRefInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the signature of the {@code JVM_CONSTANT_NameAndType} entry at index {@code cpi} in + * {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_NameAndType} entry. + */ + native String lookupSignatureRefInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the {@code JVM_CONSTANT_Class} index from the entry at index {@code cpi} in + * {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry containing a + * {@code JVM_CONSTANT_Class} index. + */ + native int lookupKlassRefIndexInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Looks up a class denoted by the {@code JVM_CONSTANT_Class} entry at index {@code cpi} in + * {@code constantPool}. This method does not perform any resolution. + * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_Class} entry. + * + * @return the resolved class entry or a String otherwise + */ + native Object lookupKlassInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Looks up a method denoted by the entry at index {@code cpi} in {@code constantPool}. This + * method does not perform any resolution. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry representing + * a method. + * + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1}. If non-negative, then resolution checks specific to the bytecode it + * denotes are performed if the method is already resolved. Should any of these + * checks fail, 0 is returned. + * @return the resolved method entry, 0 otherwise + */ + native HotSpotResolvedJavaMethodImpl lookupMethodInPool(HotSpotConstantPool constantPool, int cpi, byte opcode); + + /** + * Ensures that the type referenced by the specified {@code JVM_CONSTANT_InvokeDynamic} entry at + * index {@code cpi} in {@code constantPool} is loaded and initialized. + * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_InvokeDynamic} entry. + */ + native void resolveInvokeDynamicInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Ensures that the type referenced by the entry for a signature + * polymorphic method at index {@code cpi} in {@code constantPool} is loaded and + * initialized. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry representing + * a signature polymorphic method. + */ + native void resolveInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the resolved type denoted by the entry at index {@code cpi} in {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry representing + * a class. + * + * @throws LinkageError if resolution failed + */ + native HotSpotResolvedObjectTypeImpl resolveTypeInPool(HotSpotConstantPool constantPool, int cpi) throws LinkageError; + + /** + * Looks up and attempts to resolve the {@code JVM_CONSTANT_Field} entry at index {@code cpi} in + * {@code constantPool}. The values returned in {@code info} are: + * + *
+     *     [(int) flags,   // only valid if field is resolved
+     *      (int) offset]  // only valid if field is resolved
+     * 
+ * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_Field} entry. + * + * @param info an array in which the details of the field are returned + * @return the type defining the field if resolution is successful, 0 otherwise + */ + native HotSpotResolvedObjectTypeImpl resolveFieldInPool(HotSpotConstantPool constantPool, int cpi, byte opcode, long[] info); + + /** + * Converts {@code cpci} from an index into the cache for {@code constantPool} to an index + * directly into {@code constantPool}. + * + * The behavior of this method is undefined if {@code ccpi} is an invalid constant pool cache + * index. + */ + native int constantPoolRemapInstructionOperandFromCache(HotSpotConstantPool constantPool, int cpci); + + /** + * Gets the appendix object (if any) associated with the entry at index {@code cpi} in + * {@code constantPool}. + */ + native Object lookupAppendixInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Installs the result of a compilation into the code cache. + * + * @param target the target where this code should be installed + * @param compiledCode the result of a compilation + * @param code the details of the installed CodeBlob are written to this object + * @return the outcome of the installation which will be one of + * {@link HotSpotVMConfig#codeInstallResultOk}, + * {@link HotSpotVMConfig#codeInstallResultCacheFull}, + * {@link HotSpotVMConfig#codeInstallResultCodeTooLarge}, + * {@link HotSpotVMConfig#codeInstallResultDependenciesFailed} or + * {@link HotSpotVMConfig#codeInstallResultDependenciesInvalid}. + */ + public native int installCode(TargetDescription target, HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog); + + public native int getMetadata(TargetDescription target, HotSpotCompiledCode compiledCode, HotSpotMetaData metaData); + + /** + * Notifies the VM of statistics for a completed compilation. + * + * @param id the identifier of the compilation + * @param method the method compiled + * @param osr specifies if the compilation was for on-stack-replacement + * @param processedBytecodes the number of bytecodes processed during the compilation, including + * the bytecodes of all inlined methods + * @param time the amount time spent compiling {@code method} + * @param timeUnitsPerSecond the granularity of the units for the {@code time} value + * @param installedCode the nmethod installed as a result of the compilation + */ + public synchronized native void notifyCompilationStatistics(int id, HotSpotResolvedJavaMethodImpl method, boolean osr, int processedBytecodes, long time, long timeUnitsPerSecond, + InstalledCode installedCode); + + /** + * Resets all compilation statistics. + */ + public native void resetCompilationStatistics(); + + /** + * Initializes the fields of {@code config}. + */ + native long initializeConfiguration(); + + /** + * Resolves the implementation of {@code method} for virtual dispatches on objects of dynamic + * type {@code exactReceiver}. This resolution process only searches "up" the class hierarchy of + * {@code exactReceiver}. + * + * @param caller the caller or context type used to perform access checks + * @return the link-time resolved method (might be abstract) or {@code 0} if it can not be + * linked + */ + native HotSpotResolvedJavaMethodImpl resolveMethod(HotSpotResolvedObjectTypeImpl exactReceiver, HotSpotResolvedJavaMethodImpl method, HotSpotResolvedObjectTypeImpl caller); + + /** + * Gets the static initializer of {@code type}. + * + * @return 0 if {@code type} has no static initializer + */ + native HotSpotResolvedJavaMethodImpl getClassInitializer(HotSpotResolvedObjectTypeImpl type); + + /** + * Determines if {@code type} or any of its currently loaded subclasses overrides + * {@code Object.finalize()}. + */ + native boolean hasFinalizableSubclass(HotSpotResolvedObjectTypeImpl type); + + /** + * Gets the method corresponding to {@code holder} and slot number {@code slot} (i.e. + * {@link Method#slot} or {@link Constructor#slot}). + */ + native HotSpotResolvedJavaMethodImpl getResolvedJavaMethodAtSlot(Class holder, int slot); + + /** + * Gets the maximum absolute offset of a PC relative call to {@code address} from any position + * in the code cache. + * + * @param address an address that may be called from any code in the code cache + * @return -1 if {@code address == 0} + */ + public native long getMaxCallTargetOffset(long address); + + /** + * Gets a textual disassembly of {@code codeBlob}. + * + * @return a non-zero length string containing a disassembly of {@code codeBlob} or null if + * {@code codeBlob} could not be disassembled for some reason + */ + // The HotSpot disassembler seems not to be thread safe so it's better to synchronize its usage + public synchronized native String disassembleCodeBlob(long codeBlob); + + /** + * Gets a stack trace element for {@code method} at bytecode index {@code bci}. + */ + native StackTraceElement getStackTraceElement(HotSpotResolvedJavaMethodImpl method, int bci); + + /** + * Executes some {@code installedCode} with arguments {@code args}. + * + * @return the result of executing {@code installedCode} + * @throws InvalidInstalledCodeException if {@code installedCode} has been invalidated + */ + native Object executeInstalledCode(Object[] args, InstalledCode installedCode) throws InvalidInstalledCodeException; + + /** + * Gets the line number table for {@code method}. The line number table is encoded as (bci, + * source line number) pairs. + * + * @return the line number table for {@code method} or null if it doesn't have one + */ + native long[] getLineNumberTable(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the number of entries in the local variable table for {@code method}. + * + * @return the number of entries in the local variable table for {@code method} + */ + native int getLocalVariableTableLength(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the address of the first entry in the local variable table for {@code method}. + * + * Each entry is a native object described by these fields: + * + *
    + *
  • {@link HotSpotVMConfig#localVariableTableElementSize}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementLengthOffset}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementNameCpIndexOffset}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementDescriptorCpIndexOffset}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementSignatureCpIndexOffset} + *
  • {@link HotSpotVMConfig#localVariableTableElementSlotOffset} + *
  • {@link HotSpotVMConfig#localVariableTableElementStartBciOffset} + *
+ * + * @return 0 if {@code method} does not have a local variable table + */ + native long getLocalVariableTableStart(HotSpotResolvedJavaMethodImpl method); + + /** + * Reads an object pointer within a VM data structure. That is, any {@link HotSpotVMField} whose + * {@link HotSpotVMField#type() type} is {@code "oop"} (e.g., + * {@code ArrayKlass::_component_mirror}, {@code Klass::_java_mirror}, + * {@code JavaThread::_threadObj}). + * + * Note that {@link Unsafe#getObject(Object, long)} cannot be used for this since it does a + * {@code narrowOop} read if the VM is using compressed oops whereas oops within VM data + * structures are (currently) always uncompressed. + * + * @param address address of an oop field within a VM data structure + */ + native Object readUncompressedOop(long address); + + /** + * Determines if {@code method} should not be inlined or compiled. + */ + native void doNotInlineOrCompile(HotSpotResolvedJavaMethodImpl method); + + /** + * Invalidates the profiling information for {@code method} and (re)initializes it such that + * profiling restarts upon its next invocation. + */ + native void reprofile(HotSpotResolvedJavaMethodImpl method); + + /** + * Invalidates {@code installedCode} such that {@link InvalidInstalledCodeException} will be + * raised the next time {@code installedCode} is executed. + */ + public native void invalidateInstalledCode(InstalledCode installedCode); + + /** + * Collects the current values of all JVMCI benchmark counters, summed up over all threads. + */ + public native long[] collectCounters(); + + /** + * Determines if {@code metaspaceMethodData} is mature. + */ + native boolean isMature(long metaspaceMethodData); + + /** + * Generate a unique id to identify the result of the compile. + */ + native int allocateCompileId(HotSpotResolvedJavaMethodImpl method, int entryBCI); + + /** + * Determines if {@code method} has OSR compiled code identified by {@code entryBCI} for + * compilation level {@code level}. + */ + native boolean hasCompiledCodeForOSR(HotSpotResolvedJavaMethodImpl method, int entryBCI, int level); + + /** + * Gets the value of {@code metaspaceSymbol} as a String. + */ + native String getSymbol(long metaspaceSymbol); + + /** + * Looks for the next Java stack frame matching an entry in {@code methods}. + * + * @param frame the starting point of the search, where {@code null} refers to the topmost frame + * @param methods the methods to look for, where {@code null} means that any frame is returned + * @return the frame, or {@code null} if the end of the stack was reached during the search + */ + public native HotSpotStackFrameReference getNextStackFrame(HotSpotStackFrameReference frame, HotSpotResolvedJavaMethodImpl[] methods, int initialSkip); + + /** + * Materializes all virtual objects within {@code stackFrame} updates its locals. + * + * @param invalidate if {@code true}, the compiled method for the stack frame will be + * invalidated. + */ + native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate); + + /** + * Gets the v-table index for interface method {@code method} in the receiver {@code type} or + * {@link HotSpotVMConfig#invalidVtableIndex} if {@code method} is not in {@code type}'s + * v-table. + */ + native int getVtableIndexForInterface(HotSpotResolvedObjectTypeImpl type, HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if debug info should also be emitted at non-safepoint locations. + */ + public native boolean shouldDebugNonSafepoints(); + + /** + * Writes {@code length} bytes from {@code buf} starting at offset {@code offset} to the + * HotSpot's log stream. No range checking is performed. + */ + public native void writeDebugOutput(byte[] bytes, int offset, int length); + + /** + * Flush HotSpot's log stream. + */ + public native void flushDebugOutput(); + + /** + * Read a value representing a metaspace Method* and return the + * {@link HotSpotResolvedJavaMethodImpl} wrapping it. This method does no checking that the + * location actually contains a valid Method*. If the {@code base} object is a + * {@link MetaspaceWrapperObject} then the metaspace pointer is fetched from that object and + * used as the base. Otherwise the object itself is used as the base. + * + * @param base an object to read from or null + * @param displacement + * @return null or the resolved method for this location + */ + native HotSpotResolvedJavaMethodImpl getResolvedJavaMethod(Object base, long displacement); + + /** + * Read a value representing a metaspace ConstantPool* and return the + * {@link HotSpotConstantPool} wrapping it. This method does no checking that the location + * actually contains a valid ConstantPool*. If the {@code base} object is a + * {@link MetaspaceWrapperObject} then the metaspace pointer is fetched from that object and + * used as the base. Otherwise the object itself is used as the base. + * + * @param base an object to read from or null + * @param displacement + * @return null or the resolved method for this location + */ + native HotSpotConstantPool getConstantPool(Object base, long displacement); + + /** + * Read a value representing a metaspace Klass* and return the + * {@link HotSpotResolvedObjectTypeImpl} wrapping it. The method does no checking that the + * location actually contains a valid Klass*. If the {@code base} object is a + * {@link MetaspaceWrapperObject} then the metaspace pointer is fetched from that object and + * used as the base. Otherwise the object itself is used as the base. + * + * @param base an object to read from or null + * @param displacement + * @param compressed true if the location contains a compressed Klass* + * @return null or the resolved method for this location + */ + native HotSpotResolvedObjectTypeImpl getResolvedJavaType(Object base, long displacement, boolean compressed); +} --- /dev/null 2015-09-16 15:19:54.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotCodeCacheProvider.java 2015-09-16 15:19:54.000000000 -0700 @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2013, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotCompressedNullConstant.*; + +import java.lang.reflect.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.code.CompilationResult.*; +import jdk.internal.jvmci.code.DataSection.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; + +/** + * HotSpot implementation of {@link CodeCacheProvider}. + */ +public class HotSpotCodeCacheProvider implements CodeCacheProvider { + + protected final HotSpotJVMCIRuntimeProvider runtime; + public final HotSpotVMConfig config; + protected final TargetDescription target; + protected final RegisterConfig regConfig; + + public HotSpotCodeCacheProvider(HotSpotJVMCIRuntimeProvider runtime, HotSpotVMConfig config, TargetDescription target, RegisterConfig regConfig) { + this.runtime = runtime; + this.config = config; + this.target = target; + this.regConfig = regConfig; + } + + @Override + public String getMarkName(Mark mark) { + int markId = (int) mark.id; + Field[] fields = runtime.getConfig().getClass().getDeclaredFields(); + for (Field f : fields) { + if (f.getName().startsWith("MARKID_")) { + f.setAccessible(true); + try { + if (f.getInt(runtime.getConfig()) == markId) { + return f.getName(); + } + } catch (Exception e) { + } + } + } + return CodeCacheProvider.super.getMarkName(mark); + } + + /** + * Decodes a call target to a mnemonic if possible. + */ + @Override + public String getTargetName(Call call) { + Field[] fields = runtime.getConfig().getClass().getDeclaredFields(); + for (Field f : fields) { + if (f.getName().endsWith("Stub")) { + f.setAccessible(true); + try { + Object address = f.get(runtime.getConfig()); + if (address.equals(call.target)) { + return f.getName() + ":0x" + Long.toHexString((Long) address); + } + } catch (Exception e) { + } + } + } + return CodeCacheProvider.super.getTargetName(call); + } + + @Override + public RegisterConfig getRegisterConfig() { + return regConfig; + } + + @Override + public int getMinimumOutgoingSize() { + return runtime.getConfig().runtimeCallStackSize; + } + + public InstalledCode logOrDump(InstalledCode installedCode, CompilationResult compResult) { + HotSpotJVMCIRuntime.runtime().notifyInstall(this, installedCode, compResult); + return installedCode; + } + + public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long jvmciEnv, boolean isDefault) { + if (compResult.getId() == -1) { + compResult.setId(method.allocateCompileId(compResult.getEntryBCI())); + } + HotSpotInstalledCode installedCode = new HotSpotNmethod(method, compResult.getName(), isDefault); + runtime.getCompilerToVM().installCode(target, new HotSpotCompiledNmethod(method, compResult, jvmciEnv), installedCode, method.getSpeculationLog()); + return logOrDump(installedCode, compResult); + } + + @Override + public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, SpeculationLog log, InstalledCode predefinedInstalledCode) { + HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; + if (compResult.getId() == -1) { + compResult.setId(hotspotMethod.allocateCompileId(compResult.getEntryBCI())); + } + InstalledCode installedCode = predefinedInstalledCode; + if (installedCode == null) { + HotSpotInstalledCode code = new HotSpotNmethod(hotspotMethod, compResult.getName(), false); + installedCode = code; + } + HotSpotCompiledNmethod compiledCode = new HotSpotCompiledNmethod(hotspotMethod, compResult); + int result = runtime.getCompilerToVM().installCode(target, compiledCode, installedCode, log); + if (result != config.codeInstallResultOk) { + String msg = compiledCode.getInstallationFailureMessage(); + String resultDesc = config.getCodeInstallResultDescription(result); + if (msg != null) { + msg = String.format("Code installation failed: %s%n%s", resultDesc, msg); + } else { + msg = String.format("Code installation failed: %s", resultDesc); + } + if (result == config.codeInstallResultDependenciesInvalid) { + throw new AssertionError(resultDesc + " " + msg); + } + throw new BailoutException(result != config.codeInstallResultDependenciesFailed, msg); + } + return logOrDump(installedCode, compResult); + } + + @Override + public InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult) { + HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; + return installMethod(hotspotMethod, compResult, 0L, true); + } + + public HotSpotNmethod addExternalMethod(ResolvedJavaMethod method, CompilationResult compResult) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) method; + if (compResult.getId() == -1) { + compResult.setId(javaMethod.allocateCompileId(compResult.getEntryBCI())); + } + HotSpotNmethod code = new HotSpotNmethod(javaMethod, compResult.getName(), false, true); + HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(javaMethod, compResult); + CompilerToVM vm = runtime.getCompilerToVM(); + int result = vm.installCode(target, compiled, code, null); + if (result != runtime.getConfig().codeInstallResultOk) { + return null; + } + return code; + } + + public boolean needsDataPatch(JavaConstant constant) { + return constant instanceof HotSpotMetaspaceConstant; + } + + private Data createSingleDataItem(Constant constant) { + int size; + DataBuilder builder; + if (constant instanceof VMConstant) { + VMConstant vmConstant = (VMConstant) constant; + boolean compressed; + long raw; + if (constant instanceof HotSpotObjectConstant) { + HotSpotObjectConstant c = (HotSpotObjectConstant) vmConstant; + compressed = c.isCompressed(); + raw = 0xDEADDEADDEADDEADL; + } else if (constant instanceof HotSpotMetaspaceConstant) { + HotSpotMetaspaceConstant meta = (HotSpotMetaspaceConstant) constant; + compressed = meta.isCompressed(); + raw = meta.rawValue(); + } else { + throw new JVMCIError(String.valueOf(constant)); + } + + size = target.getSizeInBytes(compressed ? JavaKind.Int : target.wordKind); + if (size == 4) { + builder = (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant))); + buffer.putInt((int) raw); + }; + } else { + assert size == 8; + builder = (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant))); + buffer.putLong(raw); + }; + } + } else if (JavaConstant.isNull(constant)) { + boolean compressed = COMPRESSED_NULL.equals(constant); + size = target.getSizeInBytes(compressed ? JavaKind.Int : target.wordKind); + builder = DataBuilder.zero(size); + } else if (constant instanceof SerializableConstant) { + SerializableConstant s = (SerializableConstant) constant; + size = s.getSerializedSize(); + builder = DataBuilder.serializable(s); + } else { + throw new JVMCIError(String.valueOf(constant)); + } + + return new Data(size, size, builder); + } + + public Data createDataItem(Constant... constants) { + assert constants.length > 0; + if (constants.length == 1) { + return createSingleDataItem(constants[0]); + } else { + DataBuilder[] builders = new DataBuilder[constants.length]; + int size = 0; + int alignment = 1; + for (int i = 0; i < constants.length; i++) { + Data data = createSingleDataItem(constants[i]); + + assert size % data.getAlignment() == 0 : "invalid alignment in packed constants"; + alignment = DataSection.lcm(alignment, data.getAlignment()); + + builders[i] = data.getBuilder(); + size += data.getSize(); + } + DataBuilder ret = (buffer, patches) -> { + for (DataBuilder b : builders) { + b.emit(buffer, patches); + } + }; + return new Data(alignment, size, ret); + } + } + + @Override + public TargetDescription getTarget() { + return target; + } + + public String disassemble(InstalledCode code) { + if (code.isValid()) { + long codeBlob = code.getAddress(); + return runtime.getCompilerToVM().disassembleCodeBlob(codeBlob); + } + return null; + } + + public SpeculationLog createSpeculationLog() { + return new HotSpotSpeculationLog(); + } +} --- /dev/null 2015-09-16 15:19:55.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotCompiledCode.java 2015-09-16 15:19:54.000000000 -0700 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import java.nio.*; +import java.util.*; +import java.util.stream.*; +import java.util.stream.Stream.Builder; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.code.CompilationResult.CodeAnnotation; +import jdk.internal.jvmci.code.CompilationResult.CodeComment; +import jdk.internal.jvmci.code.CompilationResult.DataPatch; +import jdk.internal.jvmci.code.CompilationResult.ExceptionHandler; +import jdk.internal.jvmci.code.CompilationResult.Infopoint; +import jdk.internal.jvmci.code.CompilationResult.JumpTable; +import jdk.internal.jvmci.code.CompilationResult.Mark; +import jdk.internal.jvmci.code.CompilationResult.Site; +import jdk.internal.jvmci.meta.Assumptions.Assumption; +import jdk.internal.jvmci.meta.*; + +/** + * A {@link CompilationResult} with additional HotSpot-specific information required for installing + * the code in HotSpot's code cache. + */ +public abstract class HotSpotCompiledCode { + + public final String name; + public final Site[] sites; + public final ExceptionHandler[] exceptionHandlers; + public final Comment[] comments; + public final Assumption[] assumptions; + + public final byte[] targetCode; + public final int targetCodeSize; + + public final byte[] dataSection; + public final int dataSectionAlignment; + public final DataPatch[] dataSectionPatches; + public final boolean isImmutablePIC; + + public final int totalFrameSize; + public final int customStackAreaOffset; + + /** + * The list of the methods whose bytecodes were used as input to the compilation. If + * {@code null}, then the compilation did not record method dependencies. Otherwise, the first + * element of this array is the root method of the compilation. + */ + public final ResolvedJavaMethod[] methods; + + public static class Comment { + + public final String text; + public final int pcOffset; + + public Comment(int pcOffset, String text) { + this.text = text; + this.pcOffset = pcOffset; + } + } + + public HotSpotCompiledCode(CompilationResult compResult) { + name = compResult.getName(); + sites = getSortedSites(compResult); + if (compResult.getExceptionHandlers().isEmpty()) { + exceptionHandlers = null; + } else { + exceptionHandlers = compResult.getExceptionHandlers().toArray(new ExceptionHandler[compResult.getExceptionHandlers().size()]); + } + List annotations = compResult.getAnnotations(); + comments = new Comment[annotations.size()]; + if (!annotations.isEmpty()) { + for (int i = 0; i < comments.length; i++) { + CodeAnnotation annotation = annotations.get(i); + String text; + if (annotation instanceof CodeComment) { + CodeComment codeComment = (CodeComment) annotation; + text = codeComment.value; + } else if (annotation instanceof JumpTable) { + JumpTable jumpTable = (JumpTable) annotation; + text = "JumpTable [" + jumpTable.low + " .. " + jumpTable.high + "]"; + } else { + text = annotation.toString(); + } + comments[i] = new Comment(annotation.position, text); + } + } + assumptions = compResult.getAssumptions(); + assert validateFrames(); + + targetCode = compResult.getTargetCode(); + targetCodeSize = compResult.getTargetCodeSize(); + + DataSection data = compResult.getDataSection(); + if (!data.isFinalized()) { + data.finalizeLayout(); + } + dataSection = new byte[data.getSectionSize()]; + + ByteBuffer buffer = ByteBuffer.wrap(dataSection).order(ByteOrder.nativeOrder()); + Builder patchBuilder = Stream.builder(); + data.buildDataSection(buffer, patchBuilder); + + dataSectionAlignment = data.getSectionAlignment(); + dataSectionPatches = patchBuilder.build().toArray(len -> new DataPatch[len]); + + isImmutablePIC = compResult.isImmutablePIC(); + + totalFrameSize = compResult.getTotalFrameSize(); + customStackAreaOffset = compResult.getCustomStackAreaOffset(); + + methods = compResult.getMethods(); + } + + /** + * Ensure that all the frames passed into HotSpot are properly formatted with an empty or + * illegal slot following double word slots. + */ + private boolean validateFrames() { + for (Site site : sites) { + if (site instanceof Infopoint) { + Infopoint info = (Infopoint) site; + if (info.debugInfo != null) { + BytecodeFrame frame = info.debugInfo.frame(); + assert frame == null || frame.validateFormat(); + } + } + } + return true; + } + + static class SiteComparator implements Comparator { + + public int compare(Site s1, Site s2) { + if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { + return s1 instanceof Mark ? -1 : 1; + } + return s1.pcOffset - s2.pcOffset; + } + } + + private static Site[] getSortedSites(CompilationResult target) { + List[] lists = new List[]{target.getInfopoints(), target.getDataPatches(), target.getMarks()}; + int count = 0; + for (List list : lists) { + count += list.size(); + } + Site[] result = new Site[count]; + int pos = 0; + for (List list : lists) { + for (Object elem : list) { + result[pos++] = (Site) elem; + } + } + Arrays.sort(result, new SiteComparator()); + return result; + } +} --- /dev/null 2015-09-16 15:19:55.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotCompiledNmethod.java 2015-09-16 15:19:55.000000000 -0700 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.inittimer.*; + +/** + * {@link HotSpotCompiledCode} destined for installation as an nmethod. + */ +public final class HotSpotCompiledNmethod extends HotSpotCompiledCode { + + public final HotSpotResolvedJavaMethod method; + public final int entryBCI; + public final int id; + public final long jvmciEnv; + public final boolean hasUnsafeAccess; + + /** + * May be set by VM if code installation fails. It will describe in more detail why installation + * failed (e.g., exactly which dependency failed). + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "set by the VM") private String installationFailureMessage; + + public HotSpotCompiledNmethod(HotSpotResolvedJavaMethod method, CompilationResult compResult) { + this(method, compResult, 0L); + } + + public HotSpotCompiledNmethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long jvmciEnv) { + super(compResult); + this.method = method; + this.entryBCI = compResult.getEntryBCI(); + this.id = compResult.getId(); + this.jvmciEnv = jvmciEnv; + this.hasUnsafeAccess = compResult.hasUnsafeAccess(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + id + ":" + method.format("%H.%n(%p)%r@") + entryBCI + "]"; + } + + public String getInstallationFailureMessage() { + return installationFailureMessage; + } +} --- /dev/null 2015-09-16 15:19:56.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotCompressedNullConstant.java 2015-09-16 15:19:56.000000000 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +/** + * The compressed representation of the {@link JavaConstant#NULL_POINTER null constant}. + */ +public final class HotSpotCompressedNullConstant implements JavaConstant, HotSpotConstant { + + public static final JavaConstant COMPRESSED_NULL = new HotSpotCompressedNullConstant(); + + private HotSpotCompressedNullConstant() { + } + + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public boolean isCompressed() { + return true; + } + + @Override + public boolean isDefaultForKind() { + return true; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public String toString() { + return JavaConstant.toString(this); + } + + @Override + public String toValueString() { + return "null"; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object o) { + return o instanceof HotSpotCompressedNullConstant; + } +} --- /dev/null 2015-09-16 15:19:56.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotConstant.java 2015-09-16 15:19:56.000000000 -0700 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +/** + * Marker interface for hotspot specific constants. + */ +public interface HotSpotConstant extends Constant { + + boolean isCompressed(); +} --- /dev/null 2015-09-16 15:19:57.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotConstantPool.java 2015-09-16 15:19:57.000000000 -0700 @@ -0,0 +1,716 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.internal.jvmci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.invoke.*; + +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; + +/** + * Implementation of {@link ConstantPool} for HotSpot. + */ +public final class HotSpotConstantPool implements ConstantPool, HotSpotProxified, MetaspaceWrapperObject { + + /** + * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}. + */ + public static class Bytecodes { + public static final int LDC = 18; // 0x12 + public static final int LDC_W = 19; // 0x13 + public static final int LDC2_W = 20; // 0x14 + public static final int GETSTATIC = 178; // 0xB2 + public static final int PUTSTATIC = 179; // 0xB3 + public static final int GETFIELD = 180; // 0xB4 + public static final int PUTFIELD = 181; // 0xB5 + public static final int INVOKEVIRTUAL = 182; // 0xB6 + public static final int INVOKESPECIAL = 183; // 0xB7 + public static final int INVOKESTATIC = 184; // 0xB8 + public static final int INVOKEINTERFACE = 185; // 0xB9 + public static final int INVOKEDYNAMIC = 186; // 0xBA + public static final int NEW = 187; // 0xBB + public static final int NEWARRAY = 188; // 0xBC + public static final int ANEWARRAY = 189; // 0xBD + public static final int CHECKCAST = 192; // 0xC0 + public static final int INSTANCEOF = 193; // 0xC1 + public static final int MULTIANEWARRAY = 197; // 0xC5 + + static boolean isInvoke(int opcode) { + switch (opcode) { + case INVOKEVIRTUAL: + case INVOKESPECIAL: + case INVOKESTATIC: + case INVOKEINTERFACE: + case INVOKEDYNAMIC: + return true; + default: + return false; + } + } + + /** + * See: {@code Rewriter::maybe_rewrite_invokehandle}. + */ + static boolean isInvokeHandleAlias(int opcode) { + switch (opcode) { + case INVOKEVIRTUAL: + case INVOKESPECIAL: + return true; + default: + return false; + } + } + } + + /** + * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and + * internal ones. + */ + private enum JVM_CONSTANT { + // @formatter:off + Utf8(config().jvmConstantUtf8), + Integer(config().jvmConstantInteger), + Long(config().jvmConstantLong), + Float(config().jvmConstantFloat), + Double(config().jvmConstantDouble), + Class(config().jvmConstantClass), + UnresolvedClass(config().jvmConstantUnresolvedClass), + UnresolvedClassInError(config().jvmConstantUnresolvedClassInError), + String(config().jvmConstantString), + Fieldref(config().jvmConstantFieldref), + MethodRef(config().jvmConstantMethodref), + InterfaceMethodref(config().jvmConstantInterfaceMethodref), + NameAndType(config().jvmConstantNameAndType), + MethodHandle(config().jvmConstantMethodHandle), + MethodHandleInError(config().jvmConstantMethodHandleInError), + MethodType(config().jvmConstantMethodType), + MethodTypeInError(config().jvmConstantMethodTypeInError), + InvokeDynamic(config().jvmConstantInvokeDynamic); + // @formatter:on + + private final int tag; + + private static final int ExternalMax = config().jvmConstantExternalMax; + private static final int InternalMin = config().jvmConstantInternalMin; + private static final int InternalMax = config().jvmConstantInternalMax; + + private JVM_CONSTANT(int tag) { + this.tag = tag; + } + + private static HotSpotVMConfig config() { + return runtime().getConfig(); + } + + /** + * Maps JVM_CONSTANT tags to {@link JVM_CONSTANT} values. Using a separate class for lazy + * initialization. + */ + static class TagValueMap { + private static final JVM_CONSTANT[] table = new JVM_CONSTANT[ExternalMax + 1 + (InternalMax - InternalMin) + 1]; + + static { + assert InternalMin > ExternalMax; + for (JVM_CONSTANT e : values()) { + table[indexOf(e.tag)] = e; + } + } + + private static int indexOf(int tag) { + if (tag >= InternalMin) { + return tag - InternalMin + ExternalMax + 1; + } else { + assert tag <= ExternalMax; + } + return tag; + } + + static JVM_CONSTANT get(int tag) { + JVM_CONSTANT res = table[indexOf(tag)]; + if (res != null) { + return res; + } + throw new JVMCIError("Unknown JVM_CONSTANT tag %s", tag); + } + } + + public static JVM_CONSTANT getEnum(int tag) { + return TagValueMap.get(tag); + } + } + + private static class LookupTypeCacheElement { + int lastCpi = Integer.MIN_VALUE; + JavaType javaType; + + public LookupTypeCacheElement(int lastCpi, JavaType javaType) { + super(); + this.lastCpi = lastCpi; + this.javaType = javaType; + } + } + + /** + * Reference to the C++ ConstantPool object. + */ + private final long metaspaceConstantPool; + private volatile LookupTypeCacheElement lastLookupType; + + /** + * Gets the JVMCI mirror from a HotSpot constant pool.The VM is responsible for ensuring that + * the ConstantPool is kept alive for the duration of this call and the + * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. + * + * Called from the VM. + * + * @param metaspaceConstantPool a metaspace ConstantPool object + * @return the {@link HotSpotConstantPool} corresponding to {@code metaspaceConstantPool} + */ + @SuppressWarnings("unused") + private static HotSpotConstantPool fromMetaspace(long metaspaceConstantPool) { + return new HotSpotConstantPool(metaspaceConstantPool); + } + + private HotSpotConstantPool(long metaspaceConstantPool) { + this.metaspaceConstantPool = metaspaceConstantPool; + } + + /** + * Gets the holder for this constant pool as {@link HotSpotResolvedObjectTypeImpl}. + * + * @return holder for this constant pool + */ + private HotSpotResolvedObjectType getHolder() { + return runtime().getCompilerToVM().getResolvedJavaType(this, runtime().getConfig().constantPoolHolderOffset, false); + } + + /** + * Converts a raw index from the bytecodes to a constant pool index by adding a + * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}. + * + * @param rawIndex index from the bytecode + * @param opcode bytecode to convert the index for + * @return constant pool index + */ + private static int rawIndexToConstantPoolIndex(int rawIndex, int opcode) { + int index; + if (opcode == Bytecodes.INVOKEDYNAMIC) { + index = rawIndex; + // See: ConstantPool::is_invokedynamic_index + assert index < 0 : "not an invokedynamic constant pool index " + index; + } else { + assert opcode == Bytecodes.GETFIELD || opcode == Bytecodes.PUTFIELD || opcode == Bytecodes.GETSTATIC || opcode == Bytecodes.PUTSTATIC || opcode == Bytecodes.INVOKEINTERFACE || + opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL || opcode == Bytecodes.INVOKESTATIC : "unexpected invoke opcode " + opcode; + index = rawIndex + runtime().getConfig().constantPoolCpCacheIndexTag; + } + return index; + } + + /** + * Decode a constant pool cache index to a constant pool index. + * + * See {@code ConstantPool::decode_cpcache_index}. + * + * @param index constant pool cache index + * @return decoded index + */ + private static int decodeConstantPoolCacheIndex(int index) { + if (isInvokedynamicIndex(index)) { + return decodeInvokedynamicIndex(index); + } else { + return index - runtime().getConfig().constantPoolCpCacheIndexTag; + } + } + + /** + * See {@code ConstantPool::is_invokedynamic_index}. + */ + private static boolean isInvokedynamicIndex(int index) { + return index < 0; + } + + /** + * See {@code ConstantPool::decode_invokedynamic_index}. + */ + private static int decodeInvokedynamicIndex(int i) { + assert isInvokedynamicIndex(i) : i; + return ~i; + } + + public long getMetaspaceConstantPool() { + return metaspaceConstantPool; + } + + public long getMetaspacePointer() { + return getMetaspaceConstantPool(); + } + + /** + * Gets the constant pool tag at index {@code index}. + * + * @param index constant pool index + * @return constant pool tag + */ + private JVM_CONSTANT getTagAt(int index) { + assertBounds(index); + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceConstantPoolTags = UNSAFE.getAddress(getMetaspaceConstantPool() + config.constantPoolTagsOffset); + final int tag = UNSAFE.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index); + if (tag == 0) { + return null; + } + return JVM_CONSTANT.getEnum(tag); + } + + /** + * Gets the constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return constant pool entry + */ + private long getEntryAt(int index) { + assertBounds(index); + return UNSAFE.getAddress(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the integer constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return integer constant pool entry at index + */ + private int getIntAt(int index) { + assertTag(index, JVM_CONSTANT.Integer); + return UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the long constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return long constant pool entry + */ + private long getLongAt(int index) { + assertTag(index, JVM_CONSTANT.Long); + return UNSAFE.getLong(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the float constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return float constant pool entry + */ + private float getFloatAt(int index) { + assertTag(index, JVM_CONSTANT.Float); + return UNSAFE.getFloat(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the double constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return float constant pool entry + */ + private double getDoubleAt(int index) { + assertTag(index, JVM_CONSTANT.Double); + return UNSAFE.getDouble(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return {@code JVM_CONSTANT_NameAndType} constant pool entry + */ + private int getNameAndTypeAt(int index) { + assertTag(index, JVM_CONSTANT.NameAndType); + return UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} reference index constant pool entry at index + * {@code index}. + * + * @param index constant pool index + * @return {@code JVM_CONSTANT_NameAndType} reference constant pool entry + */ + private int getNameAndTypeRefIndexAt(int index) { + return runtime().getCompilerToVM().lookupNameAndTypeRefIndexInPool(this, index); + } + + /** + * Gets the name of a {@code JVM_CONSTANT_NameAndType} constant pool entry at index + * {@code index}. + * + * @param index constant pool index + * @return name as {@link String} + */ + private String getNameRefAt(int index) { + return runtime().getCompilerToVM().lookupNameRefInPool(this, index); + } + + /** + * Gets the name reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry at + * index {@code index}. + * + * @param index constant pool index + * @return name reference index + */ + private int getNameRefIndexAt(int index) { + final int refIndex = getNameAndTypeAt(index); + // name ref index is in the low 16-bits. + return refIndex & 0xFFFF; + } + + /** + * Gets the signature of a {@code JVM_CONSTANT_NameAndType} constant pool entry at index + * {@code index}. + * + * @param index constant pool index + * @return signature as {@link String} + */ + private String getSignatureRefAt(int index) { + return runtime().getCompilerToVM().lookupSignatureRefInPool(this, index); + } + + /** + * Gets the signature reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry + * at index {@code index}. + * + * @param index constant pool index + * @return signature reference index + */ + private int getSignatureRefIndexAt(int index) { + final int refIndex = getNameAndTypeAt(index); + // signature ref index is in the high 16-bits. + return refIndex >>> 16; + } + + /** + * Gets the klass reference index constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return klass reference index + */ + private int getKlassRefIndexAt(int index) { + return runtime().getCompilerToVM().lookupKlassRefIndexInPool(this, index); + } + + /** + * Gets the uncached klass reference index constant pool entry at index {@code index}. See: + * {@code ConstantPool::uncached_klass_ref_index_at}. + * + * @param index constant pool index + * @return klass reference index + */ + private int getUncachedKlassRefIndexAt(int index, JVM_CONSTANT tag) { + int resultIndex; + if (tag == JVM_CONSTANT.MethodRef || tag == JVM_CONSTANT.Fieldref || tag == JVM_CONSTANT.InterfaceMethodref) { + assertTagIsFieldOrMethod(index); + final int refIndex = UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + // klass ref index is in the low 16-bits. + resultIndex = refIndex & 0xFFFF; + } else { + resultIndex = index; + } + + // Read the tag only once because it could change between multiple reads. + final JVM_CONSTANT klassTag = getTagAt(resultIndex); + assert klassTag == JVM_CONSTANT.Class || klassTag == JVM_CONSTANT.UnresolvedClass || klassTag == JVM_CONSTANT.UnresolvedClassInError : klassTag; + + return resultIndex; + } + + /** + * Asserts that the constant pool index {@code index} is in the bounds of the constant pool. + * + * @param index constant pool index + */ + private void assertBounds(int index) { + assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length(); + } + + /** + * Asserts that the constant pool tag at index {@code index} is equal to {@code tag}. + * + * @param index constant pool index + * @param tag expected tag + */ + private void assertTag(int index, JVM_CONSTANT tag) { + final JVM_CONSTANT tagAt = getTagAt(index); + assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag; + } + + /** + * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref}, + * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}. + * + * @param index constant pool index + */ + private void assertTagIsFieldOrMethod(int index) { + final JVM_CONSTANT tagAt = getTagAt(index); + assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt; + } + + @Override + public int length() { + return UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolLengthOffset); + } + + @Override + public Object lookupConstant(int cpi) { + assert cpi != 0; + final JVM_CONSTANT tag = getTagAt(cpi); + switch (tag) { + case Integer: + return JavaConstant.forInt(getIntAt(cpi)); + case Long: + return JavaConstant.forLong(getLongAt(cpi)); + case Float: + return JavaConstant.forFloat(getFloatAt(cpi)); + case Double: + return JavaConstant.forDouble(getDoubleAt(cpi)); + case Class: + case UnresolvedClass: + case UnresolvedClassInError: + final int opcode = -1; // opcode is not used + return lookupType(cpi, opcode); + case String: + /* + * Normally, we would expect a String here, but anonymous classes can have + * "pseudo strings" (arbitrary live objects) patched into a String entry. Such + * entries do not have a symbol in the constant pool slot. + */ + Object string = runtime().getCompilerToVM().resolvePossiblyCachedConstantInPool(this, cpi); + return HotSpotObjectConstantImpl.forObject(string); + case MethodHandle: + case MethodHandleInError: + case MethodType: + case MethodTypeInError: + Object obj = runtime().getCompilerToVM().resolveConstantInPool(this, cpi); + return HotSpotObjectConstantImpl.forObject(obj); + default: + throw new JVMCIError("Unknown constant pool tag %s", tag); + } + } + + @Override + public String lookupUtf8(int cpi) { + assertTag(cpi, JVM_CONSTANT.Utf8); + return runtime().getCompilerToVM().getSymbol(getEntryAt(cpi)); + } + + @Override + public Signature lookupSignature(int cpi) { + return new HotSpotSignature(runtime(), lookupUtf8(cpi)); + } + + @Override + public JavaConstant lookupAppendix(int cpi, int opcode) { + assert Bytecodes.isInvoke(opcode); + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + Object appendix = runtime().getCompilerToVM().lookupAppendixInPool(this, index); + if (appendix == null) { + return null; + } else { + return HotSpotObjectConstantImpl.forObject(appendix); + } + } + + /** + * Gets a {@link JavaType} corresponding a given resolved or unresolved type. + * + * @param type either a ResolvedJavaType or a String naming a unresolved type. + */ + private static JavaType getJavaType(final Object type) { + if (type instanceof String) { + String name = (String) type; + return HotSpotUnresolvedJavaType.create(runtime(), "L" + name + ";"); + } else { + return (JavaType) type; + } + } + + @Override + public JavaMethod lookupMethod(int cpi, int opcode) { + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final HotSpotResolvedJavaMethod method = runtime().getCompilerToVM().lookupMethodInPool(this, index, (byte) opcode); + if (method != null) { + return method; + } else { + // Get the method's name and signature. + String name = getNameRefAt(index); + HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureRefAt(index)); + if (opcode == Bytecodes.INVOKEDYNAMIC) { + HotSpotResolvedObjectType holder = HotSpotResolvedObjectTypeImpl.fromObjectClass(MethodHandle.class); + return new HotSpotMethodUnresolved(name, signature, holder); + } else { + final int klassIndex = getKlassRefIndexAt(index); + final Object type = runtime().getCompilerToVM().lookupKlassInPool(this, klassIndex); + JavaType holder = getJavaType(type); + return new HotSpotMethodUnresolved(name, signature, holder); + } + } + } + + @Override + public JavaType lookupType(int cpi, int opcode) { + final LookupTypeCacheElement elem = this.lastLookupType; + if (elem != null && elem.lastCpi == cpi) { + return elem.javaType; + } else { + final Object type = runtime().getCompilerToVM().lookupKlassInPool(this, cpi); + JavaType result = getJavaType(type); + if (result instanceof ResolvedJavaType) { + this.lastLookupType = new LookupTypeCacheElement(cpi, result); + } + return result; + } + } + + @Override + public JavaField lookupField(int cpi, int opcode) { + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index); + final int nameIndex = getNameRefIndexAt(nameAndTypeIndex); + String name = lookupUtf8(nameIndex); + final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex); + String typeName = lookupUtf8(typeIndex); + JavaType type = runtime().lookupType(typeName, getHolder(), false); + + final int holderIndex = getKlassRefIndexAt(index); + JavaType holder = lookupType(holderIndex, opcode); + + if (holder instanceof HotSpotResolvedObjectTypeImpl) { + long[] info = new long[2]; + HotSpotResolvedObjectTypeImpl resolvedHolder; + try { + resolvedHolder = runtime().getCompilerToVM().resolveFieldInPool(this, index, (byte) opcode, info); + } catch (Throwable t) { + /* + * If there was an exception resolving the field we give up and return an unresolved + * field. + */ + return new HotSpotUnresolvedField(holder, name, type); + } + final int flags = (int) info[0]; + final long offset = info[1]; + HotSpotResolvedJavaField result = resolvedHolder.createField(name, type, offset, flags); + return result; + } else { + return new HotSpotUnresolvedField(holder, name, type); + } + } + + @Override + @SuppressWarnings("fallthrough") + public void loadReferencedType(int cpi, int opcode) { + int index; + switch (opcode) { + case Bytecodes.CHECKCAST: + case Bytecodes.INSTANCEOF: + case Bytecodes.NEW: + case Bytecodes.ANEWARRAY: + case Bytecodes.MULTIANEWARRAY: + case Bytecodes.LDC: + case Bytecodes.LDC_W: + case Bytecodes.LDC2_W: + index = cpi; + break; + case Bytecodes.INVOKEDYNAMIC: { + // invokedynamic instructions point to a constant pool cache entry. + index = decodeConstantPoolCacheIndex(cpi) + runtime().getConfig().constantPoolCpCacheIndexTag; + index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); + break; + } + case Bytecodes.GETSTATIC: + case Bytecodes.PUTSTATIC: + case Bytecodes.GETFIELD: + case Bytecodes.PUTFIELD: + case Bytecodes.INVOKEVIRTUAL: + case Bytecodes.INVOKESPECIAL: + case Bytecodes.INVOKESTATIC: + case Bytecodes.INVOKEINTERFACE: { + // invoke and field instructions point to a constant pool cache entry. + index = rawIndexToConstantPoolIndex(cpi, opcode); + index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); + break; + } + default: + throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode); + } + + final JVM_CONSTANT tag = getTagAt(index); + if (tag == null) { + assert getTagAt(index - 1) == JVM_CONSTANT.Double || getTagAt(index - 1) == JVM_CONSTANT.Long; + return; + } + switch (tag) { + case MethodRef: + case Fieldref: + case InterfaceMethodref: + case Class: + case UnresolvedClass: + case UnresolvedClassInError: + index = getUncachedKlassRefIndexAt(index, tag); + final HotSpotResolvedObjectTypeImpl type = runtime().getCompilerToVM().resolveTypeInPool(this, index); + Class klass = type.mirror(); + if (!klass.isPrimitive() && !klass.isArray()) { + UNSAFE.ensureClassInitialized(klass); + } + switch (tag) { + case MethodRef: + if (Bytecodes.isInvokeHandleAlias(opcode)) { + final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode); + if (isInvokeHandle(methodRefCacheIndex, type)) { + runtime().getCompilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex); + } + } + } + break; + case InvokeDynamic: + if (isInvokedynamicIndex(cpi)) { + runtime().getCompilerToVM().resolveInvokeDynamicInPool(this, cpi); + } + break; + default: + // nothing + break; + } + } + + private boolean isInvokeHandle(int methodRefCacheIndex, HotSpotResolvedObjectTypeImpl klass) { + assertTag(runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef); + return ResolvedJavaMethod.isSignaturePolymorphic(klass, getNameRefAt(methodRefCacheIndex), runtime().getHostJVMCIBackend().getMetaAccess()); + } + + @Override + public String toString() { + HotSpotResolvedObjectType holder = getHolder(); + return "HotSpotConstantPool<" + holder.toJavaName() + ">"; + } +} --- /dev/null 2015-09-16 15:19:58.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotConstantReflectionProvider.java 2015-09-16 15:19:57.000000000 -0700 @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotConstantReflectionProvider.Options.*; + +import java.lang.reflect.*; + +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.options.*; + +/** + * HotSpot implementation of {@link ConstantReflectionProvider}. + */ +public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified { + + static class Options { + //@formatter:off + @Option(help = "Constant fold final fields with default values.", type = OptionType.Debug) + public static final OptionValue TrustFinalDefaultFields = new OptionValue<>(true); + //@formatter:on + } + + protected final HotSpotJVMCIRuntimeProvider runtime; + protected final HotSpotMethodHandleAccessProvider methodHandleAccess; + protected final HotSpotMemoryAccessProviderImpl memoryAccess; + + public HotSpotConstantReflectionProvider(HotSpotJVMCIRuntimeProvider runtime) { + this.runtime = runtime; + this.methodHandleAccess = new HotSpotMethodHandleAccessProvider(this); + this.memoryAccess = new HotSpotMemoryAccessProviderImpl(runtime); + } + + public MethodHandleAccessProvider getMethodHandleAccess() { + return methodHandleAccess; + } + + @Override + public MemoryAccessProvider getMemoryAccessProvider() { + return memoryAccess; + } + + @Override + public boolean isEmbeddable(Constant constant) { + return true; + } + + @Override + public Boolean constantEquals(Constant x, Constant y) { + if (x == y) { + return true; + } else if (x instanceof HotSpotObjectConstantImpl) { + return y instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) x).object() == ((HotSpotObjectConstantImpl) y).object(); + } else { + return x.equals(y); + } + } + + @Override + public Integer readArrayLength(JavaConstant array) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return null; + } + + Object arrayObject = ((HotSpotObjectConstantImpl) array).object(); + if (!arrayObject.getClass().isArray()) { + return null; + } + return Array.getLength(arrayObject); + } + + public JavaConstant readConstantArrayElement(JavaConstant array, int index) { + if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) { + JavaConstant element = readArrayElement(array, index); + if (element != null && (((HotSpotObjectConstantImpl) array).isDefaultStable() || !element.isDefaultForKind())) { + return element; + } + } + return null; + } + + /** + * Try to convert {@code offset} into an an index into {@code array}. + * + * @return the computed index or -1 if the offset isn't within the array + */ + private int indexForOffset(JavaConstant array, long offset) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return -1; + } + Class componentType = ((HotSpotObjectConstantImpl) array).object().getClass().getComponentType(); + JavaKind kind = runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(componentType).getJavaKind(); + int arraybase = runtime.getArrayBaseOffset(kind); + int scale = runtime.getArrayIndexScale(kind); + if (offset < arraybase) { + return -1; + } + long index = offset - arraybase; + if (index % scale != 0) { + return -1; + } + long result = index / scale; + if (result >= Integer.MAX_VALUE) { + return -1; + } + return (int) result; + } + + public JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset) { + if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) { + return readConstantArrayElement(array, indexForOffset(array, offset)); + } + return null; + } + + @Override + public JavaConstant readArrayElement(JavaConstant array, int index) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return null; + } + Object a = ((HotSpotObjectConstantImpl) array).object(); + + if (index < 0 || index >= Array.getLength(a)) { + return null; + } + + if (a instanceof Object[]) { + Object element = ((Object[]) a)[index]; + if (((HotSpotObjectConstantImpl) array).getStableDimension() > 1) { + return HotSpotObjectConstantImpl.forStableArray(element, ((HotSpotObjectConstantImpl) array).getStableDimension() - 1, ((HotSpotObjectConstantImpl) array).isDefaultStable()); + } else { + return HotSpotObjectConstantImpl.forObject(element); + } + } else { + return JavaConstant.forBoxedPrimitive(Array.get(a, index)); + } + } + + /** + * Check if the constant is a boxed value that is guaranteed to be cached by the platform. + * Otherwise the generated code might be the only reference to the boxed value and since object + * references from nmethods are weak this can cause GC problems. + * + * @param source + * @return true if the box is cached + */ + private static boolean isBoxCached(JavaConstant source) { + switch (source.getJavaKind()) { + case Boolean: + return true; + case Char: + return source.asInt() <= 127; + case Byte: + case Short: + case Int: + return source.asInt() >= -128 && source.asInt() <= 127; + case Long: + return source.asLong() >= -128 && source.asLong() <= 127; + case Float: + case Double: + return false; + default: + throw new IllegalArgumentException("unexpected kind " + source.getJavaKind()); + } + } + + @Override + public JavaConstant boxPrimitive(JavaConstant source) { + if (!source.getJavaKind().isPrimitive() || !isBoxCached(source)) { + return null; + } + return HotSpotObjectConstantImpl.forObject(source.asBoxedPrimitive()); + } + + @Override + public JavaConstant unboxPrimitive(JavaConstant source) { + if (!source.getJavaKind().isObject()) { + return null; + } + if (source.isNull()) { + return null; + } + return JavaConstant.forBoxedPrimitive(((HotSpotObjectConstantImpl) source).object()); + } + + public JavaConstant forString(String value) { + return HotSpotObjectConstantImpl.forObject(value); + } + + @Override + public ResolvedJavaType asJavaType(Constant constant) { + if (constant instanceof HotSpotObjectConstant) { + Object obj = ((HotSpotObjectConstantImpl) constant).object(); + if (obj instanceof Class) { + return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType((Class) obj); + } + } + if (constant instanceof HotSpotMetaspaceConstant) { + Object obj = HotSpotMetaspaceConstantImpl.getMetaspaceObject(constant); + if (obj instanceof HotSpotResolvedObjectTypeImpl) { + return (ResolvedJavaType) obj; + } + } + return null; + } + + private static final String SystemClassName = "Ljava/lang/System;"; + + /** + * Determines if a static field is constant for the purpose of + * {@link #readConstantFieldValue(JavaField, JavaConstant)}. + */ + protected boolean isStaticFieldConstant(HotSpotResolvedJavaField staticField) { + if (staticField.isFinal() || staticField.isStable()) { + ResolvedJavaType holder = staticField.getDeclaringClass(); + if (holder.isInitialized() && !holder.getName().equals(SystemClassName)) { + return true; + } + } + return false; + } + + /** + * Determines if a value read from a {@code final} instance field is considered constant. The + * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is + * not the {@link JavaConstant#isDefaultForKind default value} for its kind or if + * {@link Options#TrustFinalDefaultFields} is true. + * + * @param value a value read from a {@code final} instance field + * @param receiverClass the {@link Object#getClass() class} of object from which the + * {@code value} was read + */ + protected boolean isFinalInstanceFieldValueConstant(JavaConstant value, Class receiverClass) { + return !value.isDefaultForKind() || TrustFinalDefaultFields.getValue(); + } + + /** + * Determines if a value read from a {@link Stable} instance field is considered constant. The + * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is + * not the {@link JavaConstant#isDefaultForKind default value} for its kind. + * + * @param value a value read from a {@link Stable} field + * @param receiverClass the {@link Object#getClass() class} of object from which the + * {@code value} was read + */ + protected boolean isStableInstanceFieldValueConstant(JavaConstant value, Class receiverClass) { + return !value.isDefaultForKind(); + } + + /** + * {@inheritDoc} + *

+ * The {@code value} field in {@link OptionValue} is considered constant if the type of + * {@code receiver} is (assignable to) {@link StableOptionValue}. + */ + public JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver) { + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + + if (hotspotField.isStatic()) { + if (isStaticFieldConstant(hotspotField)) { + JavaConstant value = readFieldValue(field, receiver); + if (hotspotField.isFinal() || !value.isDefaultForKind()) { + return value; + } + } + } else { + /* + * for non-static final fields, we must assume that they are only initialized if they + * have a non-default value. + */ + Object object = receiver.isNull() ? null : ((HotSpotObjectConstantImpl) receiver).object(); + + // Canonicalization may attempt to process an unsafe read before + // processing a guard (e.g. a null check or a type check) for this read + // so we need to check the object being read + if (object != null) { + if (hotspotField.isFinal()) { + if (hotspotField.isInObject(object)) { + JavaConstant value = readFieldValue(field, receiver); + if (isFinalInstanceFieldValueConstant(value, object.getClass())) { + return value; + } + } + } else if (hotspotField.isStable()) { + if (hotspotField.isInObject(object)) { + JavaConstant value = readFieldValue(field, receiver); + if (isStableInstanceFieldValueConstant(value, object.getClass())) { + return value; + } + } + } else { + Class clazz = object.getClass(); + if (StableOptionValue.class.isAssignableFrom(clazz)) { + if (hotspotField.isInObject(object) && hotspotField.getName().equals("value")) { + StableOptionValue option = (StableOptionValue) object; + return HotSpotObjectConstantImpl.forObject(option.getValue()); + } + } + } + } + } + return null; + } + + public JavaConstant readFieldValue(JavaField field, JavaConstant receiver) { + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + if (!hotspotField.isStable()) { + return readNonStableFieldValue(field, receiver); + } else { + return readStableFieldValue(field, receiver, false); + } + } + + private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) { + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + if (hotspotField.isStatic()) { + HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass(); + if (holder.isInitialized()) { + return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset()); + } + } else { + if (receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object())) { + return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), receiver, hotspotField.offset()); + } + } + return null; + } + + public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) { + JavaConstant fieldValue = readNonStableFieldValue(field, receiver); + if (fieldValue.isNonNull()) { + JavaType declaredType = field.getType(); + if (declaredType.getComponentType() != null) { + int stableDimension = getArrayDimension(declaredType); + return HotSpotObjectConstantImpl.forStableArray(((HotSpotObjectConstantImpl) fieldValue).object(), stableDimension, isDefaultStable); + } + } + return fieldValue; + } + + private static int getArrayDimension(JavaType type) { + int dimensions = 0; + JavaType componentType = type; + while ((componentType = componentType.getComponentType()) != null) { + dimensions++; + } + return dimensions; + } +} --- /dev/null 2015-09-16 15:19:58.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotForeignCallTarget.java 2015-09-16 15:19:58.000000000 -0700 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +public class HotSpotForeignCallTarget { + + /** + * The entry point address of this call's target. + */ + protected long address; + + public HotSpotForeignCallTarget(long address) { + this.address = address; + } +} --- /dev/null 2015-09-16 15:19:59.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotInstalledCode.java 2015-09-16 15:19:59.000000000 -0700 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.UnsafeAccess.UNSAFE; +import jdk.internal.jvmci.code.InstalledCode; +import jdk.internal.jvmci.inittimer.SuppressFBWarnings; +import sun.misc.Unsafe; + +/** + * Implementation of {@link InstalledCode} for HotSpot. + */ +public abstract class HotSpotInstalledCode extends InstalledCode { + + /** + * Total size of the code blob. + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int size; + + /** + * Start address of the code. + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private long codeStart; + + /** + * Size of the code. + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int codeSize; + + public HotSpotInstalledCode(String name) { + super(name); + } + + /** + * @return the total size of this code blob + */ + public int getSize() { + return size; + } + + /** + * @return a copy of this code blob if it is {@linkplain #isValid() valid}, null otherwise. + */ + public byte[] getBlob() { + if (!isValid()) { + return null; + } + byte[] blob = new byte[size]; + UNSAFE.copyMemory(null, getAddress(), blob, Unsafe.ARRAY_BYTE_BASE_OFFSET, size); + return blob; + } + + @Override + public abstract String toString(); + + @Override + public long getStart() { + return codeStart; + } + + @Override + public long getCodeSize() { + return codeSize; + } + + @Override + public byte[] getCode() { + if (!isValid()) { + return null; + } + byte[] code = new byte[codeSize]; + UNSAFE.copyMemory(null, codeStart, code, Unsafe.ARRAY_BYTE_BASE_OFFSET, codeSize); + return code; + } +} --- /dev/null 2015-09-16 15:19:59.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotJVMCIBackendFactory.java 2015-09-16 15:19:59.000000000 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.compiler.*; +import jdk.internal.jvmci.runtime.*; + +public interface HotSpotJVMCIBackendFactory { + + JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntimeProvider runtime, CompilerFactory compilerFactory, JVMCIBackend host); + + /** + * Gets the CPU architecture of this backend. + */ + String getArchitecture(); +} --- /dev/null 2015-09-16 15:20:00.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotJVMCICompilerConfig.java 2015-09-16 15:20:00.000000000 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.compiler.*; +import jdk.internal.jvmci.compiler.Compiler; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.runtime.*; +import jdk.internal.jvmci.service.*; + +final class HotSpotJVMCICompilerConfig { + + private static class DummyCompilerFactory implements CompilerFactory, Compiler { + + public void compileMethod(ResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) { + throw new JVMCIError("no JVMCI compiler selected"); + } + + public String getCompilerName() { + return ""; + } + + public Architecture initializeArchitecture(Architecture arch) { + return arch; + } + + public Compiler createCompiler(JVMCIRuntime runtime) { + return this; + } + } + + private static CompilerFactory compilerFactory; + + /** + * Selects the system compiler. + * + * Called from VM. This method has an object return type to allow it to be called with a VM + * utility function used to call other static initialization methods. + */ + static Boolean selectCompiler(String compilerName) { + assert compilerFactory == null; + for (CompilerFactory factory : Services.load(CompilerFactory.class)) { + if (factory.getCompilerName().equals(compilerName)) { + compilerFactory = factory; + return Boolean.TRUE; + } + } + + throw new JVMCIError("JVMCI compiler '%s' not found", compilerName); + } + + static CompilerFactory getCompilerFactory() { + if (compilerFactory == null) { + compilerFactory = new DummyCompilerFactory(); + } + return compilerFactory; + } +} --- /dev/null 2015-09-16 15:20:01.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotJVMCIMetaAccessContext.java 2015-09-16 15:20:00.000000000 -0700 @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import java.lang.ref.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +/** + * This class manages the set of metadata roots that must be scanned during garbage collection. + * Because of class redefinition Method* and ConstantPool* can be freed if they don't appear to be + * in use so they must be tracked when there are live references to them from Java. + * + * The general theory of operation is that all {@link MetaspaceWrapperObject}s are created by + * calling into the VM which calls back out to actually create the wrapper instance. During the call + * the VM keeps the metadata reference alive through the use of metadata handles. Once the call + * completes the wrapper object is registered here and will be scanned during metadata scanning. The + * weakness of the reference to the wrapper object allows them to be reclaimed when they are no + * longer used. + * + */ +public class HotSpotJVMCIMetaAccessContext implements JVMCIMetaAccessContext { + + /** + * The set of currently live contexts used for tracking of live metadata. Examined from the VM + * during garbage collection. + */ + private static WeakReference[] allContexts = new WeakReference[0]; + + /** + * This is a chunked list of metadata roots. It can be read from VM native code so it's been + * marked volatile to ensure the order of updates are respected. + */ + private volatile Object[] metadataRoots; + + private ChunkedList> list = new ChunkedList<>(); + + /** + * The number of weak references freed since the last time the list was shrunk. + */ + private int freed; + + /** + * The {@link ReferenceQueue} tracking the weak references created by this context. + */ + private final ReferenceQueue queue = new ReferenceQueue<>(); + + static synchronized void add(HotSpotJVMCIMetaAccessContext context) { + for (int i = 0; i < allContexts.length; i++) { + if (allContexts[i] == null || allContexts[i].get() == null) { + allContexts[i] = new WeakReference<>(context); + return; + } + } + int index = allContexts.length; + allContexts = Arrays.copyOf(allContexts, index + 2); + allContexts[index] = new WeakReference<>(context); + } + + HotSpotJVMCIMetaAccessContext() { + add(this); + } + + /** + * Periodically trim the list of tracked metadata. A new list is created to replace the old to + * avoid concurrent scanning issues. + */ + private void clean() { + Reference ref = queue.poll(); + if (ref == null) { + return; + } + while (ref != null) { + freed++; + ref = queue.poll(); + } + if (freed > list.size() / 2) { + ChunkedList> newList = new ChunkedList<>(); + for (WeakReference element : list) { + /* + * The referent could become null anywhere in here but it doesn't matter. It will + * get cleaned up next time. + */ + if (element != null && element.get() != null) { + newList.add(element); + } + } + list = newList; + metadataRoots = list.getHead(); + freed = 0; + } + } + + /** + * Add a {@link MetaspaceWrapperObject} to tracked by the GC. It's assumed that the caller is + * responsible for keeping the reference alive for the duration of the call. Once registration + * is complete then the VM will ensure it's kept alive. + * + * @param metaspaceObject + */ + + public synchronized void add(MetaspaceWrapperObject metaspaceObject) { + clean(); + list.add(new WeakReference<>(metaspaceObject, queue)); + if (list.getHead() != metadataRoots) { + /* + * The list enlarged so update the head. + */ + metadataRoots = list.getHead(); + } + } + + protected ResolvedJavaType createClass(Class javaClass) { + if (javaClass.isPrimitive()) { + JavaKind kind = JavaKind.fromJavaClass(javaClass); + return new HotSpotResolvedPrimitiveType(kind); + } else { + return new HotSpotResolvedObjectTypeImpl(javaClass, this); + } + } + + private final Map, WeakReference> typeMap = new WeakHashMap<>(); + + @Override + public synchronized ResolvedJavaType fromClass(Class javaClass) { + WeakReference typeRef = typeMap.get(javaClass); + ResolvedJavaType type = typeRef != null ? typeRef.get() : null; + if (type == null) { + type = createClass(javaClass); + typeMap.put(javaClass, new WeakReference<>(type)); + } + return type; + } + + /** + * A very simple append only chunked list implementation. + */ + static class ChunkedList implements Iterable { + private static final int CHUNK_SIZE = 32; + + private static final int NEXT_CHUNK_INDEX = CHUNK_SIZE - 1; + + private Object[] head; + private int index; + private int size; + + ChunkedList() { + head = new Object[CHUNK_SIZE]; + index = 0; + } + + void add(T element) { + if (index == NEXT_CHUNK_INDEX) { + Object[] newHead = new Object[CHUNK_SIZE]; + newHead[index] = head; + head = newHead; + index = 0; + } + head[index++] = element; + size++; + } + + Object[] getHead() { + return head; + } + + public Iterator iterator() { + return new ChunkIterator<>(); + } + + int size() { + return size; + } + + class ChunkIterator implements Iterator { + + ChunkIterator() { + currentChunk = head; + currentIndex = -1; + findNext(); + } + + Object[] currentChunk; + int currentIndex; + V next; + + @SuppressWarnings("unchecked") + V findNext() { + V result; + do { + currentIndex++; + if (currentIndex == NEXT_CHUNK_INDEX) { + currentChunk = (Object[]) currentChunk[currentIndex]; + currentIndex = 0; + if (currentChunk == null) { + return null; + } + } + result = (V) currentChunk[currentIndex]; + } while (result == null); + return result; + } + + public boolean hasNext() { + return next != null; + } + + public V next() { + V result = next; + next = findNext(); + return result; + } + + } + + } +} --- /dev/null 2015-09-16 15:20:01.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotJVMCIRuntime.java 2015-09-16 15:20:01.000000000 -0700 @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.inittimer.InitTimer.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.compiler.*; +import jdk.internal.jvmci.compiler.Compiler; +import jdk.internal.jvmci.inittimer.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.runtime.*; +import jdk.internal.jvmci.service.*; + +//JaCoCo Exclude + +public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider, HotSpotProxified { + + /** + * The proper initialization of this class is complex because it's tangled up with the + * initialization of the JVMCI and really should only ever be triggered through + * {@link JVMCI#getRuntime}. However since {@link #runtime} can also be called directly it + * should also trigger proper initialization. To ensure proper ordering, the static initializer + * of this class initializes {@link JVMCI} and then access to {@link DelayedInit#instance} + * triggers the final initialization of the {@link HotSpotJVMCIRuntime}. + */ + static { + JVMCI.initialize(); + } + + @SuppressWarnings("try") + static class DelayedInit { + private static final HotSpotJVMCIRuntime instance; + + static { + try (InitTimer t0 = timer("HotSpotJVMCIRuntime.")) { + try (InitTimer t = timer("StartupEventListener.beforeJVMCIStartup")) { + for (StartupEventListener l : Services.load(StartupEventListener.class)) { + l.beforeJVMCIStartup(); + } + } + + try (InitTimer t = timer("HotSpotJVMCIRuntime.")) { + instance = new HotSpotJVMCIRuntime(); + } + + try (InitTimer t = timer("HotSpotJVMCIRuntime.completeInitialization")) { + instance.completeInitialization(); + } + } + } + } + + /** + * Gets the singleton {@link HotSpotJVMCIRuntime} object. + */ + public static HotSpotJVMCIRuntime runtime() { + assert DelayedInit.instance != null; + return DelayedInit.instance; + } + + /** + * Do deferred initialization. + */ + public void completeInitialization() { + compiler = HotSpotJVMCICompilerConfig.getCompilerFactory().createCompiler(this); + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + vmEventListener.completeInitialization(this); + } + } + + public static HotSpotJVMCIBackendFactory findFactory(String architecture) { + for (HotSpotJVMCIBackendFactory factory : Services.load(HotSpotJVMCIBackendFactory.class)) { + if (factory.getArchitecture().equalsIgnoreCase(architecture)) { + return factory; + } + } + + throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture); + } + + /** + * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend. + */ + public static JavaKind getHostWordKind() { + return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordKind; + } + + protected final CompilerToVM compilerToVm; + + protected final HotSpotVMConfig config; + private final JVMCIBackend hostBackend; + + private Compiler compiler; + protected final JVMCIMetaAccessContext metaAccessContext; + + private final Map, JVMCIBackend> backends = new HashMap<>(); + + private final Iterable vmEventListeners; + + @SuppressWarnings("try") + private HotSpotJVMCIRuntime() { + compilerToVm = new CompilerToVM(); + try (InitTimer t = timer("HotSpotVMConfig")) { + config = new HotSpotVMConfig(compilerToVm); + } + + String hostArchitecture = config.getHostArchitectureName(); + + HotSpotJVMCIBackendFactory factory; + try (InitTimer t = timer("find factory:", hostArchitecture)) { + factory = findFactory(hostArchitecture); + } + + CompilerFactory compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory(); + + try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) { + hostBackend = registerBackend(factory.createJVMCIBackend(this, compilerFactory, null)); + } + + vmEventListeners = Services.load(HotSpotVMEventListener.class); + + JVMCIMetaAccessContext context = null; + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + context = vmEventListener.createMetaAccessContext(this); + if (context != null) { + break; + } + } + if (context == null) { + context = new HotSpotJVMCIMetaAccessContext(); + } + metaAccessContext = context; + } + + private JVMCIBackend registerBackend(JVMCIBackend backend) { + Class arch = backend.getCodeCache().getTarget().arch.getClass(); + JVMCIBackend oldValue = backends.put(arch, backend); + assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); + return backend; + } + + public ResolvedJavaType fromClass(Class javaClass) { + return metaAccessContext.fromClass(javaClass); + } + + public HotSpotVMConfig getConfig() { + return config; + } + + public CompilerToVM getCompilerToVM() { + return compilerToVm; + } + + public JVMCIMetaAccessContext getMetaAccessContext() { + return metaAccessContext; + } + + public Compiler getCompiler() { + return compiler; + } + + public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { + Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); + // If the name represents a primitive type we can short-circuit the lookup. + if (name.length() == 1) { + JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); + return fromClass(kind.toJavaClass()); + } + + // Resolve non-primitive types in the VM. + HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; + final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve); + + if (klass == null) { + assert resolve == false; + return HotSpotUnresolvedJavaType.create(this, name); + } + return klass; + } + + public JVMCIBackend getHostJVMCIBackend() { + return hostBackend; + } + + public JVMCIBackend getJVMCIBackend(Class arch) { + assert arch != Architecture.class; + return backends.get(arch); + } + + public Map, JVMCIBackend> getBackends() { + return Collections.unmodifiableMap(backends); + } + + /** + * Called from the VM. + */ + @SuppressWarnings({"unused"}) + private void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) { + compiler.compileMethod(method, entryBCI, jvmciEnv, id); + } + + /** + * Shuts down the runtime. + * + * Called from the VM. + */ + @SuppressWarnings({"unused"}) + private void shutdown() throws Exception { + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + vmEventListener.notifyShutdown(); + } + } + + /** + * Shuts down the runtime. + * + * Called from the VM. + * + * @param hotSpotCodeCacheProvider + */ + void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompilationResult compResult) { + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compResult); + } + } +} --- /dev/null 2015-09-16 15:20:02.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotJVMCIRuntimeProvider.java 2015-09-16 15:20:02.000000000 -0700 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.compiler.Compiler; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.runtime.*; +import sun.misc.*; + +//JaCoCo Exclude + +/** + * Configuration information for the HotSpot JVMCI runtime. + */ +public interface HotSpotJVMCIRuntimeProvider extends JVMCIRuntime { + + HotSpotVMConfig getConfig(); + + CompilerToVM getCompilerToVM(); + + Compiler getCompiler(); + + /** + * Converts a name to a Java type. This method attempts to resolve {@code name} to a + * {@link ResolvedJavaType}. + * + * @param name a well formed Java type in {@linkplain JavaType#getName() internal} format + * @param accessingType the context of resolution which must be non-null + * @param resolve specifies whether resolution failure results in an unresolved type being + * return or a {@link LinkageError} being thrown + * @return a Java type for {@code name} which is guaranteed to be of type + * {@link ResolvedJavaType} if {@code resolve == true} + * @throws LinkageError if {@code resolve == true} and the resolution failed + * @throws NullPointerException if {@code accessingClass} is {@code null} + */ + JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve); + + /** + * Gets the JVMCI mirror for a {@link Class} object. + * + * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} + */ + ResolvedJavaType fromClass(Class clazz); + + JVMCIMetaAccessContext getMetaAccessContext(); + + /** + * The offset from the origin of an array to the first element. + * + * @return the offset in bytes + */ + default int getArrayBaseOffset(JavaKind kind) { + switch (kind) { + case Boolean: + return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; + case Byte: + return Unsafe.ARRAY_BYTE_BASE_OFFSET; + case Char: + return Unsafe.ARRAY_CHAR_BASE_OFFSET; + case Short: + return Unsafe.ARRAY_SHORT_BASE_OFFSET; + case Int: + return Unsafe.ARRAY_INT_BASE_OFFSET; + case Long: + return Unsafe.ARRAY_LONG_BASE_OFFSET; + case Float: + return Unsafe.ARRAY_FLOAT_BASE_OFFSET; + case Double: + return Unsafe.ARRAY_DOUBLE_BASE_OFFSET; + case Object: + return Unsafe.ARRAY_OBJECT_BASE_OFFSET; + default: + throw new JVMCIError("%s", kind); + } + } + + /** + * The scale used for the index when accessing elements of an array of this kind. + * + * @return the scale in order to convert the index into a byte offset + */ + default int getArrayIndexScale(JavaKind kind) { + switch (kind) { + case Boolean: + return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; + case Byte: + return Unsafe.ARRAY_BYTE_INDEX_SCALE; + case Char: + return Unsafe.ARRAY_CHAR_INDEX_SCALE; + case Short: + return Unsafe.ARRAY_SHORT_INDEX_SCALE; + case Int: + return Unsafe.ARRAY_INT_INDEX_SCALE; + case Long: + return Unsafe.ARRAY_LONG_INDEX_SCALE; + case Float: + return Unsafe.ARRAY_FLOAT_INDEX_SCALE; + case Double: + return Unsafe.ARRAY_DOUBLE_INDEX_SCALE; + case Object: + return Unsafe.ARRAY_OBJECT_INDEX_SCALE; + default: + throw new JVMCIError("%s", kind); + } + } +} --- /dev/null 2015-09-16 15:20:02.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotJavaType.java 2015-09-16 15:20:02.000000000 -0700 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +/** + * Common base class for all HotSpot {@link JavaType} implementations. + */ +public abstract class HotSpotJavaType implements JavaType { + + private final String name; + + public HotSpotJavaType(String name) { + this.name = name; + } + + @Override + public final String getName() { + return name; + } + +} --- /dev/null 2015-09-16 15:20:03.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMemoryAccessProvider.java 2015-09-16 15:20:03.000000000 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.hotspot.HotSpotVMConfig.*; +import jdk.internal.jvmci.meta.*; + +/** + * HotSpot specific extension of {@link MemoryAccessProvider}. + */ +public interface HotSpotMemoryAccessProvider extends MemoryAccessProvider { + + JavaConstant readNarrowOopConstant(Constant base, long displacement, CompressEncoding encoding); + + Constant readKlassPointerConstant(Constant base, long displacement); + + Constant readNarrowKlassPointerConstant(Constant base, long displacement, CompressEncoding encoding); + + Constant readMethodPointerConstant(Constant base, long displacement); +} --- /dev/null 2015-09-16 15:20:04.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMemoryAccessProviderImpl.java 2015-09-16 15:20:03.000000000 -0700 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.UnsafeAccess.UNSAFE; +import jdk.internal.jvmci.code.TargetDescription; +import jdk.internal.jvmci.common.JVMCIError; +import jdk.internal.jvmci.hotspot.HotSpotVMConfig.CompressEncoding; +import jdk.internal.jvmci.meta.Constant; +import jdk.internal.jvmci.meta.JavaConstant; +import jdk.internal.jvmci.meta.JavaKind; +import jdk.internal.jvmci.meta.MemoryAccessProvider; +import jdk.internal.jvmci.meta.PrimitiveConstant; + +/** + * HotSpot implementation of {@link MemoryAccessProvider}. + */ +public class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider, HotSpotProxified { + + protected final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotMemoryAccessProviderImpl(HotSpotJVMCIRuntimeProvider runtime) { + this.runtime = runtime; + } + + private static Object asObject(Constant base) { + if (base instanceof HotSpotObjectConstantImpl) { + return ((HotSpotObjectConstantImpl) base).object(); + } else { + return null; + } + } + + private boolean isValidObjectFieldDisplacement(Constant base, long displacement) { + if (base instanceof HotSpotMetaspaceConstant) { + Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { + if (displacement == runtime.getConfig().classMirrorOffset) { + // Klass::_java_mirror is valid for all Klass* values + return true; + } + } else { + throw new JVMCIError("%s", metaspaceObject); + } + } + return false; + } + + private static long asRawPointer(Constant base) { + if (base instanceof HotSpotMetaspaceConstant) { + return ((HotSpotMetaspaceConstant) base).rawValue(); + } else if (base instanceof PrimitiveConstant) { + PrimitiveConstant prim = (PrimitiveConstant) base; + if (prim.getJavaKind().isNumericInteger()) { + return prim.asLong(); + } + } + throw new JVMCIError("%s", base); + } + + private static long readRawValue(Constant baseConstant, long displacement, int bits) { + Object base = asObject(baseConstant); + if (base != null) { + switch (bits) { + case 8: + return UNSAFE.getByte(base, displacement); + case 16: + return UNSAFE.getShort(base, displacement); + case 32: + return UNSAFE.getInt(base, displacement); + case 64: + return UNSAFE.getLong(base, displacement); + default: + throw new JVMCIError("%d", bits); + } + } else { + long pointer = asRawPointer(baseConstant); + switch (bits) { + case 8: + return UNSAFE.getByte(pointer + displacement); + case 16: + return UNSAFE.getShort(pointer + displacement); + case 32: + return UNSAFE.getInt(pointer + displacement); + case 64: + return UNSAFE.getLong(pointer + displacement); + default: + throw new JVMCIError("%d", bits); + } + } + } + + private boolean verifyReadRawObject(Object expected, Constant base, long displacement, boolean compressed) { + if (compressed == runtime.getConfig().useCompressedOops) { + Object obj = asObject(base); + if (obj != null) { + assert expected == UNSAFE.getObject(obj, displacement) : "readUnsafeOop doesn't agree with unsafe.getObject"; + } + } + if (base instanceof HotSpotMetaspaceConstant) { + Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { + if (displacement == runtime.getConfig().classMirrorOffset) { + assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror(); + } + } + } + return true; + } + + private Object readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) { + long displacement = initialDisplacement; + + Object ret; + Object base = asObject(baseConstant); + if (base == null) { + assert !compressed; + displacement += asRawPointer(baseConstant); + ret = runtime.getCompilerToVM().readUncompressedOop(displacement); + } else { + assert runtime.getConfig().useCompressedOops == compressed; + ret = UNSAFE.getObject(base, displacement); + } + assert verifyReadRawObject(ret, baseConstant, initialDisplacement, compressed); + return ret; + } + + @Override + public JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant baseConstant, long displacement) { + if (kind == JavaKind.Object) { + Object o = readRawObject(baseConstant, displacement, runtime.getConfig().useCompressedOops); + return HotSpotObjectConstantImpl.forObject(o); + } else { + return readPrimitiveConstant(kind, baseConstant, displacement, kind.getByteCount() * 8); + } + } + + @Override + public JavaConstant readPrimitiveConstant(JavaKind kind, Constant baseConstant, long initialDisplacement, int bits) { + try { + long rawValue = readRawValue(baseConstant, initialDisplacement, bits); + switch (kind) { + case Boolean: + return JavaConstant.forBoolean(rawValue != 0); + case Byte: + return JavaConstant.forByte((byte) rawValue); + case Char: + return JavaConstant.forChar((char) rawValue); + case Short: + return JavaConstant.forShort((short) rawValue); + case Int: + return JavaConstant.forInt((int) rawValue); + case Long: + return JavaConstant.forLong(rawValue); + case Float: + return JavaConstant.forFloat(Float.intBitsToFloat((int) rawValue)); + case Double: + return JavaConstant.forDouble(Double.longBitsToDouble(rawValue)); + default: + throw new JVMCIError("Unsupported kind: %s", kind); + } + } catch (NullPointerException e) { + return null; + } + } + + @Override + public JavaConstant readObjectConstant(Constant base, long displacement) { + if (!isValidObjectFieldDisplacement(base, displacement)) { + return null; + } + return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, false)); + } + + @Override + public JavaConstant readNarrowOopConstant(Constant base, long displacement, CompressEncoding encoding) { + assert encoding.equals(runtime.getConfig().getOopEncoding()) : "unexpected oop encoding: " + encoding + " != " + runtime.getConfig().getOopEncoding(); + return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, true), true); + } + + private HotSpotResolvedObjectTypeImpl readKlass(Constant base, long displacement, boolean compressed) { + assert (base instanceof HotSpotMetaspaceConstantImpl) || (base instanceof HotSpotObjectConstantImpl) : base.getClass(); + Object baseObject = (base instanceof HotSpotMetaspaceConstantImpl) ? ((HotSpotMetaspaceConstantImpl) base).asResolvedJavaType() : ((HotSpotObjectConstantImpl) base).object(); + return runtime.getCompilerToVM().getResolvedJavaType(baseObject, displacement, compressed); + } + + @Override + public Constant readKlassPointerConstant(Constant base, long displacement) { + HotSpotResolvedObjectTypeImpl klass = readKlass(base, displacement, false); + if (klass == null) { + return JavaConstant.NULL_POINTER; + } + TargetDescription target = runtime.getHostJVMCIBackend().getCodeCache().getTarget(); + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(target.wordKind, klass.getMetaspaceKlass(), klass, false); + } + + @Override + public Constant readNarrowKlassPointerConstant(Constant base, long displacement, CompressEncoding encoding) { + HotSpotResolvedObjectTypeImpl klass = readKlass(base, displacement, true); + if (klass == null) { + return HotSpotCompressedNullConstant.COMPRESSED_NULL; + } + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(JavaKind.Int, encoding.compress(klass.getMetaspaceKlass()), klass, true); + } + + @Override + public Constant readMethodPointerConstant(Constant base, long displacement) { + TargetDescription target = runtime.getHostJVMCIBackend().getCodeCache().getTarget(); + assert (base instanceof HotSpotObjectConstantImpl); + Object baseObject = ((HotSpotObjectConstantImpl) base).object(); + HotSpotResolvedJavaMethodImpl method = runtime.getCompilerToVM().getResolvedJavaMethod(baseObject, displacement); + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(target.wordKind, method.getMetaspaceMethod(), method, false); + } +} --- /dev/null 2015-09-16 15:20:04.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMetaAccessProvider.java 2015-09-16 15:20:04.000000000 -0700 @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotResolvedObjectTypeImpl.*; +import static jdk.internal.jvmci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.reflect.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; + +// JaCoCo Exclude + +/** + * HotSpot implementation of {@link MetaAccessProvider}. + */ +public class HotSpotMetaAccessProvider implements MetaAccessProvider, HotSpotProxified { + + protected final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotMetaAccessProvider(HotSpotJVMCIRuntimeProvider runtime) { + this.runtime = runtime; + } + + public ResolvedJavaType lookupJavaType(Class clazz) { + if (clazz == null) { + throw new IllegalArgumentException("Class parameter was null"); + } + return runtime.fromClass(clazz); + } + + public HotSpotResolvedObjectType lookupJavaType(JavaConstant constant) { + if (constant.isNull() || !(constant instanceof HotSpotObjectConstant)) { + return null; + } + return ((HotSpotObjectConstant) constant).getType(); + } + + public Signature parseMethodDescriptor(String signature) { + return new HotSpotSignature(runtime, signature); + } + + /** + * {@link Field} object of {@link Method#slot}. + */ + private Field reflectionMethodSlot = getReflectionSlotField(Method.class); + + /** + * {@link Field} object of {@link Constructor#slot}. + */ + private Field reflectionConstructorSlot = getReflectionSlotField(Constructor.class); + + private static Field getReflectionSlotField(Class reflectionClass) { + try { + Field field = reflectionClass.getDeclaredField("slot"); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException | SecurityException e) { + throw new JVMCIError(e); + } + } + + public ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod) { + try { + Class holder = reflectionMethod.getDeclaringClass(); + Field slotField = reflectionMethod instanceof Constructor ? reflectionConstructorSlot : reflectionMethodSlot; + final int slot = slotField.getInt(reflectionMethod); + return runtime.getCompilerToVM().getResolvedJavaMethodAtSlot(holder, slot); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new JVMCIError(e); + } + } + + public ResolvedJavaField lookupJavaField(Field reflectionField) { + String name = reflectionField.getName(); + Class fieldHolder = reflectionField.getDeclaringClass(); + Class fieldType = reflectionField.getType(); + // java.lang.reflect.Field's modifiers should be enough here since VM internal modifier bits + // are not used (yet). + final int modifiers = reflectionField.getModifiers(); + final long offset = Modifier.isStatic(modifiers) ? UNSAFE.staticFieldOffset(reflectionField) : UNSAFE.objectFieldOffset(reflectionField); + + HotSpotResolvedObjectType holder = fromObjectClass(fieldHolder); + JavaType type = runtime.fromClass(fieldType); + + if (offset != -1) { + HotSpotResolvedObjectType resolved = holder; + return resolved.createField(name, type, offset, modifiers); + } else { + throw new JVMCIError("unresolved field %s", reflectionField); + } + } + + private static int intMaskRight(int n) { + assert n <= 32; + return n == 32 ? -1 : (1 << n) - 1; + } + + @Override + public JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int debugId) { + HotSpotVMConfig config = runtime.getConfig(); + int actionValue = convertDeoptAction(action); + int reasonValue = convertDeoptReason(reason); + int debugValue = debugId & intMaskRight(config.deoptimizationDebugIdBits); + JavaConstant c = JavaConstant.forInt(~((debugValue << config.deoptimizationDebugIdShift) | (reasonValue << config.deoptimizationReasonShift) | (actionValue << config.deoptimizationActionShift))); + assert c.asInt() < 0; + return c; + } + + public DeoptimizationReason decodeDeoptReason(JavaConstant constant) { + HotSpotVMConfig config = runtime.getConfig(); + int reasonValue = ((~constant.asInt()) >> config.deoptimizationReasonShift) & intMaskRight(config.deoptimizationReasonBits); + DeoptimizationReason reason = convertDeoptReason(reasonValue); + return reason; + } + + public DeoptimizationAction decodeDeoptAction(JavaConstant constant) { + HotSpotVMConfig config = runtime.getConfig(); + int actionValue = ((~constant.asInt()) >> config.deoptimizationActionShift) & intMaskRight(config.deoptimizationActionBits); + DeoptimizationAction action = convertDeoptAction(actionValue); + return action; + } + + public int decodeDebugId(JavaConstant constant) { + HotSpotVMConfig config = runtime.getConfig(); + return ((~constant.asInt()) >> config.deoptimizationDebugIdShift) & intMaskRight(config.deoptimizationDebugIdBits); + } + + public int convertDeoptAction(DeoptimizationAction action) { + HotSpotVMConfig config = runtime.getConfig(); + switch (action) { + case None: + return config.deoptActionNone; + case RecompileIfTooManyDeopts: + return config.deoptActionMaybeRecompile; + case InvalidateReprofile: + return config.deoptActionReinterpret; + case InvalidateRecompile: + return config.deoptActionMakeNotEntrant; + case InvalidateStopCompiling: + return config.deoptActionMakeNotCompilable; + default: + throw new JVMCIError("%s", action); + } + } + + public DeoptimizationAction convertDeoptAction(int action) { + HotSpotVMConfig config = runtime.getConfig(); + if (action == config.deoptActionNone) { + return DeoptimizationAction.None; + } + if (action == config.deoptActionMaybeRecompile) { + return DeoptimizationAction.RecompileIfTooManyDeopts; + } + if (action == config.deoptActionReinterpret) { + return DeoptimizationAction.InvalidateReprofile; + } + if (action == config.deoptActionMakeNotEntrant) { + return DeoptimizationAction.InvalidateRecompile; + } + if (action == config.deoptActionMakeNotCompilable) { + return DeoptimizationAction.InvalidateStopCompiling; + } + throw new JVMCIError("%d", action); + } + + public int convertDeoptReason(DeoptimizationReason reason) { + HotSpotVMConfig config = runtime.getConfig(); + switch (reason) { + case None: + return config.deoptReasonNone; + case NullCheckException: + return config.deoptReasonNullCheck; + case BoundsCheckException: + return config.deoptReasonRangeCheck; + case ClassCastException: + return config.deoptReasonClassCheck; + case ArrayStoreException: + return config.deoptReasonArrayCheck; + case UnreachedCode: + return config.deoptReasonUnreached0; + case TypeCheckedInliningViolated: + return config.deoptReasonTypeCheckInlining; + case OptimizedTypeCheckViolated: + return config.deoptReasonOptimizedTypeCheck; + case NotCompiledExceptionHandler: + return config.deoptReasonNotCompiledExceptionHandler; + case Unresolved: + return config.deoptReasonUnresolved; + case JavaSubroutineMismatch: + return config.deoptReasonJsrMismatch; + case ArithmeticException: + return config.deoptReasonDiv0Check; + case RuntimeConstraint: + return config.deoptReasonConstraint; + case LoopLimitCheck: + return config.deoptReasonLoopLimitCheck; + case Aliasing: + return config.deoptReasonAliasing; + case TransferToInterpreter: + return config.deoptReasonTransferToInterpreter; + default: + throw new JVMCIError("%s", reason); + } + } + + public DeoptimizationReason convertDeoptReason(int reason) { + HotSpotVMConfig config = runtime.getConfig(); + if (reason == config.deoptReasonNone) { + return DeoptimizationReason.None; + } + if (reason == config.deoptReasonNullCheck) { + return DeoptimizationReason.NullCheckException; + } + if (reason == config.deoptReasonRangeCheck) { + return DeoptimizationReason.BoundsCheckException; + } + if (reason == config.deoptReasonClassCheck) { + return DeoptimizationReason.ClassCastException; + } + if (reason == config.deoptReasonArrayCheck) { + return DeoptimizationReason.ArrayStoreException; + } + if (reason == config.deoptReasonUnreached0) { + return DeoptimizationReason.UnreachedCode; + } + if (reason == config.deoptReasonTypeCheckInlining) { + return DeoptimizationReason.TypeCheckedInliningViolated; + } + if (reason == config.deoptReasonOptimizedTypeCheck) { + return DeoptimizationReason.OptimizedTypeCheckViolated; + } + if (reason == config.deoptReasonNotCompiledExceptionHandler) { + return DeoptimizationReason.NotCompiledExceptionHandler; + } + if (reason == config.deoptReasonUnresolved) { + return DeoptimizationReason.Unresolved; + } + if (reason == config.deoptReasonJsrMismatch) { + return DeoptimizationReason.JavaSubroutineMismatch; + } + if (reason == config.deoptReasonDiv0Check) { + return DeoptimizationReason.ArithmeticException; + } + if (reason == config.deoptReasonConstraint) { + return DeoptimizationReason.RuntimeConstraint; + } + if (reason == config.deoptReasonLoopLimitCheck) { + return DeoptimizationReason.LoopLimitCheck; + } + if (reason == config.deoptReasonAliasing) { + return DeoptimizationReason.Aliasing; + } + if (reason == config.deoptReasonTransferToInterpreter) { + return DeoptimizationReason.TransferToInterpreter; + } + throw new JVMCIError("%x", reason); + } + + @Override + public long getMemorySize(JavaConstant constant) { + if (constant.getJavaKind() == JavaKind.Object) { + HotSpotResolvedObjectType lookupJavaType = lookupJavaType(constant); + + if (lookupJavaType == null) { + return 0; + } else { + if (lookupJavaType.isArray()) { + // TODO(tw): Add compressed pointer support. + int length = Array.getLength(((HotSpotObjectConstantImpl) constant).object()); + ResolvedJavaType elementType = lookupJavaType.getComponentType(); + JavaKind elementKind = elementType.getJavaKind(); + final int headerSize = runtime.getArrayBaseOffset(elementKind); + TargetDescription target = runtime.getHostJVMCIBackend().getTarget(); + int sizeOfElement = target.getSizeInBytes(elementKind); + int alignment = target.wordSize; + int log2ElementSize = CodeUtil.log2(sizeOfElement); + return computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); + } + return lookupJavaType.instanceSize(); + } + } else { + return constant.getJavaKind().getByteCount(); + } + } + + /** + * Computes the size of the memory chunk allocated for an array. This size accounts for the + * array header size, body size and any padding after the last element to satisfy object + * alignment requirements. + * + * @param length the number of elements in the array + * @param alignment the object alignment requirement + * @param headerSize the size of the array header + * @param log2ElementSize log2 of the size of an element in the array + */ + public static int computeArrayAllocationSize(int length, int alignment, int headerSize, int log2ElementSize) { + int size = (length << log2ElementSize) + headerSize + (alignment - 1); + int mask = ~(alignment - 1); + return size & mask; + } +} --- /dev/null 2015-09-16 15:20:05.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMetaData.java 2015-09-16 15:20:05.000000000 -0700 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +public class HotSpotMetaData { + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] pcDescBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] scopesDescBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] relocBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] exceptionBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] oopMaps; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private String[] metadata; + + public byte[] pcDescBytes() { + return pcDescBytes != null ? pcDescBytes : new byte[0]; + } + + public byte[] scopesDescBytes() { + return scopesDescBytes != null ? scopesDescBytes : new byte[0]; + } + + public byte[] relocBytes() { + return relocBytes != null ? relocBytes : new byte[0]; + } + + public byte[] exceptionBytes() { + return exceptionBytes != null ? exceptionBytes : new byte[0]; + } + + public byte[] oopMaps() { + return oopMaps != null ? oopMaps : new byte[0]; + } + + public String[] metadataEntries() { + return metadata != null ? metadata : new String[0]; + } +} --- /dev/null 2015-09-16 15:20:05.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMetaspaceConstant.java 2015-09-16 15:20:05.000000000 -0700 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.hotspot.HotSpotVMConfig.*; +import jdk.internal.jvmci.meta.*; + +public interface HotSpotMetaspaceConstant extends HotSpotConstant, VMConstant { + + Constant compress(CompressEncoding encoding); + + Constant uncompress(CompressEncoding encoding); + + HotSpotResolvedObjectType asResolvedJavaType(); + + HotSpotResolvedJavaMethod asResolvedJavaMethod(); + + long rawValue(); +} --- /dev/null 2015-09-16 15:20:06.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMetaspaceConstantImpl.java 2015-09-16 15:20:06.000000000 -0700 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import java.util.*; + +import jdk.internal.jvmci.hotspot.HotSpotVMConfig.*; +import jdk.internal.jvmci.meta.*; + +public final class HotSpotMetaspaceConstantImpl extends PrimitiveConstant implements HotSpotMetaspaceConstant, VMConstant, HotSpotProxified { + + static HotSpotMetaspaceConstantImpl forMetaspaceObject(JavaKind kind, long primitive, Object metaspaceObject, boolean compressed) { + return new HotSpotMetaspaceConstantImpl(kind, primitive, metaspaceObject, compressed); + } + + static Object getMetaspaceObject(Constant constant) { + return ((HotSpotMetaspaceConstantImpl) constant).metaspaceObject; + } + + private final Object metaspaceObject; + private final boolean compressed; + + private HotSpotMetaspaceConstantImpl(JavaKind kind, long primitive, Object metaspaceObject, boolean compressed) { + super(kind, primitive); + this.metaspaceObject = metaspaceObject; + this.compressed = compressed; + } + + @Override + public int hashCode() { + return super.hashCode() ^ System.identityHashCode(metaspaceObject); + } + + @Override + public boolean equals(Object o) { + return o == this || (o instanceof HotSpotMetaspaceConstantImpl && super.equals(o) && Objects.equals(metaspaceObject, ((HotSpotMetaspaceConstantImpl) o).metaspaceObject)); + } + + @Override + public String toString() { + return super.toString() + "{" + metaspaceObject + (compressed ? ";compressed}" : "}"); + } + + public boolean isCompressed() { + return compressed; + } + + public JavaConstant compress(CompressEncoding encoding) { + assert !isCompressed(); + HotSpotMetaspaceConstantImpl res = HotSpotMetaspaceConstantImpl.forMetaspaceObject(JavaKind.Int, encoding.compress(asLong()), metaspaceObject, true); + assert res.isCompressed(); + return res; + } + + public JavaConstant uncompress(CompressEncoding encoding) { + assert isCompressed(); + HotSpotMetaspaceConstantImpl res = HotSpotMetaspaceConstantImpl.forMetaspaceObject(JavaKind.Long, encoding.uncompress(asInt()), metaspaceObject, false); + assert !res.isCompressed(); + return res; + } + + public HotSpotResolvedObjectType asResolvedJavaType() { + if (metaspaceObject instanceof HotSpotResolvedObjectType) { + return (HotSpotResolvedObjectType) metaspaceObject; + } + return null; + } + + public HotSpotResolvedJavaMethod asResolvedJavaMethod() { + if (metaspaceObject instanceof HotSpotResolvedJavaMethod) { + return (HotSpotResolvedJavaMethod) metaspaceObject; + } + return null; + } + + public long rawValue() { + return asLong(); + } +} --- /dev/null 2015-09-16 15:20:07.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMethod.java 2015-09-16 15:20:06.000000000 -0700 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static java.util.FormattableFlags.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +public abstract class HotSpotMethod implements JavaMethod, Formattable /* , JavaMethodContex */{ + + public static String applyFormattingFlagsAndWidth(String s, int flags, int width) { + if (flags == 0 && width < 0) { + return s; + } + StringBuilder sb = new StringBuilder(s); + + // apply width and justification + int len = sb.length(); + if (len < width) { + for (int i = 0; i < width - len; i++) { + if ((flags & LEFT_JUSTIFY) == LEFT_JUSTIFY) { + sb.append(' '); + } else { + sb.insert(0, ' '); + } + } + } + + String res = sb.toString(); + if ((flags & UPPERCASE) == UPPERCASE) { + res = res.toUpperCase(); + } + return res; + } + + protected String name; + + /** + * Controls whether {@link #toString()} includes the qualified or simple name of the class in + * which the method is declared. + */ + public static final boolean FULLY_QUALIFIED_METHOD_NAME = false; + + protected HotSpotMethod(String name) { + this.name = name; + } + + @Override + public final String getName() { + return name; + } + + @Override + public final String toString() { + char h = FULLY_QUALIFIED_METHOD_NAME ? 'H' : 'h'; + String suffix = this instanceof ResolvedJavaMethod ? "" : ", unresolved"; + String fmt = String.format("HotSpotMethod<%%%c.%%n(%%p)%s>", h, suffix); + return format(fmt); + } + + public void formatTo(Formatter formatter, int flags, int width, int precision) { + String base = (flags & ALTERNATE) == ALTERNATE ? getName() : toString(); + formatter.format(applyFormattingFlagsAndWidth(base, flags & ~ALTERNATE, width)); + } + + public JavaMethod asJavaMethod() { + return this; + } +} --- /dev/null 2015-09-16 15:20:07.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMethodData.java 2015-09-16 15:20:07.000000000 -0700 @@ -0,0 +1,864 @@ +/* + * Copyright (c) 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static java.lang.String.*; +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.internal.jvmci.hotspot.UnsafeAccess.UNSAFE; + +import java.util.*; + +import jdk.internal.jvmci.hotspot.HotSpotMethodDataAccessor.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.meta.JavaMethodProfile.*; +import jdk.internal.jvmci.meta.JavaTypeProfile.*; +import sun.misc.*; + +/** + * Access to a HotSpot MethodData structure (defined in methodData.hpp). + */ +public final class HotSpotMethodData { + + private static final HotSpotVMConfig config = runtime().getConfig(); + private static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(TriState.FALSE); + private static final HotSpotMethodDataAccessor NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR = new NoMethodData(TriState.UNKNOWN); + + // sorted by tag + // @formatter:off + private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = { + null, + new BitData(), + new CounterData(), + new JumpData(), + new TypeCheckData(), + new VirtualCallData(), + new RetData(), + new BranchData(), + new MultiBranchData(), + new ArgInfoData(), + null, // call_type_data_tag + null, // virtual_call_type_data_tag + null, // parameters_type_data_tag + null, // speculative_trap_data_tag + }; + // @formatter:on + + /** + * Reference to the C++ MethodData object. + */ + private final long metaspaceMethodData; + @SuppressWarnings("unused") private final HotSpotResolvedJavaMethodImpl method; + + public HotSpotMethodData(long metaspaceMethodData, HotSpotResolvedJavaMethodImpl method) { + this.metaspaceMethodData = metaspaceMethodData; + this.method = method; + } + + /** + * @return value of the MethodData::_data_size field + */ + private int normalDataSize() { + return UNSAFE.getInt(metaspaceMethodData + config.methodDataDataSize); + } + + /** + * Returns the size of the extra data records. This method does the same calculation as + * MethodData::extra_data_size(). + * + * @return size of extra data records + */ + private int extraDataSize() { + final int extraDataBase = config.methodDataOopDataOffset + normalDataSize(); + final int extraDataLimit = UNSAFE.getInt(metaspaceMethodData + config.methodDataSize); + return extraDataLimit - extraDataBase; + } + + public boolean hasNormalData() { + return normalDataSize() > 0; + } + + public boolean hasExtraData() { + return extraDataSize() > 0; + } + + public int getExtraDataBeginOffset() { + return normalDataSize(); + } + + public boolean isWithin(int position) { + return position >= 0 && position < normalDataSize() + extraDataSize(); + } + + public int getDeoptimizationCount(DeoptimizationReason reason) { + HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); + int reasonIndex = metaAccess.convertDeoptReason(reason); + return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF; + } + + public int getOSRDeoptimizationCount(DeoptimizationReason reason) { + HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); + int reasonIndex = metaAccess.convertDeoptReason(reason); + return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + config.deoptReasonOSROffset + reasonIndex) & 0xFF; + } + + public HotSpotMethodDataAccessor getNormalData(int position) { + if (position >= normalDataSize()) { + return null; + } + + HotSpotMethodDataAccessor result = getData(position); + assert result != null : "NO_DATA tag is not allowed"; + return result; + } + + public HotSpotMethodDataAccessor getExtraData(int position) { + if (position >= normalDataSize() + extraDataSize()) { + return null; + } + HotSpotMethodDataAccessor data = getData(position); + if (data != null) { + return data; + } + return data; + } + + public static HotSpotMethodDataAccessor getNoDataAccessor(boolean exceptionPossiblyNotRecorded) { + if (exceptionPossiblyNotRecorded) { + return NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR; + } else { + return NO_DATA_NO_EXCEPTION_ACCESSOR; + } + } + + private HotSpotMethodDataAccessor getData(int position) { + assert position >= 0 : "out of bounds"; + final Tag tag = AbstractMethodData.readTag(this, position); + HotSpotMethodDataAccessor accessor = PROFILE_DATA_ACCESSORS[tag.getValue()]; + assert accessor == null || accessor.getTag() == tag : "wrong data accessor " + accessor + " for tag " + tag; + return accessor; + } + + private int readUnsignedByte(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return UNSAFE.getByte(metaspaceMethodData + fullOffsetInBytes) & 0xFF; + } + + private int readUnsignedShort(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return UNSAFE.getShort(metaspaceMethodData + fullOffsetInBytes) & 0xFFFF; + } + + /** + * Since the values are stored in cells (platform words) this method uses + * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. + */ + private long readUnsignedInt(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes) & 0xFFFFFFFFL; + } + + private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) { + long value = readUnsignedInt(position, offsetInBytes); + return truncateLongToInt(value); + } + + /** + * Since the values are stored in cells (platform words) this method uses + * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. + */ + private int readInt(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return (int) UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes); + } + + private HotSpotResolvedJavaMethod readMethod(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return runtime().compilerToVm.getResolvedJavaMethod(null, metaspaceMethodData + fullOffsetInBytes); + } + + private HotSpotResolvedObjectTypeImpl readKlass(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return runtime().compilerToVm.getResolvedJavaType(null, metaspaceMethodData + fullOffsetInBytes, false); + } + + private static int truncateLongToInt(long value) { + return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value; + } + + private static int computeFullOffset(int position, int offsetInBytes) { + return config.methodDataOopDataOffset + position + offsetInBytes; + } + + private static int cellIndexToOffset(int cells) { + return config.dataLayoutHeaderSize + cellsToBytes(cells); + } + + private static int cellsToBytes(int cells) { + return cells * config.dataLayoutCellSize; + } + + /** + * Returns whether profiling ran long enough that the profile information is mature. Other + * informational data will still be valid even if the profile isn't mature. + */ + public boolean isProfileMature() { + return runtime().getCompilerToVM().isMature(metaspaceMethodData); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + String nl = String.format("%n"); + String nlIndent = String.format("%n%38s", ""); + if (hasNormalData()) { + int pos = 0; + HotSpotMethodDataAccessor data; + while ((data = getNormalData(pos)) != null) { + if (pos != 0) { + sb.append(nl); + } + int bci = data.getBCI(this, pos); + sb.append(String.format("%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); + sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); + pos = pos + data.getSize(this, pos); + } + } + + if (hasExtraData()) { + int pos = getExtraDataBeginOffset(); + HotSpotMethodDataAccessor data; + while ((data = getExtraData(pos)) != null) { + if (pos == getExtraDataBeginOffset()) { + sb.append(nl).append("--- Extra data:"); + } + int bci = data.getBCI(this, pos); + sb.append(String.format("%n%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); + sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); + pos = pos + data.getSize(this, pos); + } + + } + return sb.toString(); + } + + private abstract static class AbstractMethodData implements HotSpotMethodDataAccessor { + + /** + * Corresponds to {@code exception_seen_flag}. + */ + private static final int EXCEPTIONS_MASK = 0x2; + + private final Tag tag; + private final int staticSize; + + protected AbstractMethodData(Tag tag, int staticSize) { + this.tag = tag; + this.staticSize = staticSize; + } + + public Tag getTag() { + return tag; + } + + public static Tag readTag(HotSpotMethodData data, int position) { + final int tag = data.readUnsignedByte(position, config.dataLayoutTagOffset); + return Tag.getEnum(tag); + } + + @Override + public int getBCI(HotSpotMethodData data, int position) { + return data.readUnsignedShort(position, config.dataLayoutBCIOffset); + } + + @Override + public int getSize(HotSpotMethodData data, int position) { + return staticSize + getDynamicSize(data, position); + } + + @Override + public TriState getExceptionSeen(HotSpotMethodData data, int position) { + return TriState.get((getFlags(data, position) & EXCEPTIONS_MASK) != 0); + } + + @Override + public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { + return null; + } + + @Override + public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { + return null; + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + return -1; + } + + @Override + public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { + return null; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return -1; + } + + @Override + public TriState getNullSeen(HotSpotMethodData data, int position) { + return TriState.UNKNOWN; + } + + protected int getFlags(HotSpotMethodData data, int position) { + return data.readUnsignedByte(position, config.dataLayoutFlagsOffset); + } + + /** + * @param data + * @param position + */ + protected int getDynamicSize(HotSpotMethodData data, int position) { + return 0; + } + + public abstract StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos); + } + + private static class NoMethodData extends AbstractMethodData { + + private static final int NO_DATA_SIZE = cellIndexToOffset(0); + + private final TriState exceptionSeen; + + protected NoMethodData(TriState exceptionSeen) { + super(Tag.No, NO_DATA_SIZE); + this.exceptionSeen = exceptionSeen; + } + + @Override + public int getBCI(HotSpotMethodData data, int position) { + return -1; + } + + @Override + public TriState getExceptionSeen(HotSpotMethodData data, int position) { + return exceptionSeen; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb; + } + } + + private static class BitData extends AbstractMethodData { + + private static final int BIT_DATA_SIZE = cellIndexToOffset(0); + private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01; + + private BitData() { + super(Tag.BitData, BIT_DATA_SIZE); + } + + protected BitData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public TriState getNullSeen(HotSpotMethodData data, int position) { + return TriState.get((getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("exception_seen(%s)", getExceptionSeen(data, pos))); + } + } + + private static class CounterData extends BitData { + + private static final int COUNTER_DATA_SIZE = cellIndexToOffset(1); + private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(0); + + public CounterData() { + super(Tag.CounterData, COUNTER_DATA_SIZE); + } + + protected CounterData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return getCounterValue(data, position); + } + + protected int getCounterValue(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, COUNTER_DATA_COUNT_OFFSET); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("count(%d) null_seen(%s) exception_seen(%s)", getCounterValue(data, pos), getNullSeen(data, pos), getExceptionSeen(data, pos))); + } + } + + private static class JumpData extends AbstractMethodData { + + private static final int JUMP_DATA_SIZE = cellIndexToOffset(2); + protected static final int TAKEN_COUNT_OFFSET = cellIndexToOffset(0); + protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(1); + + public JumpData() { + super(Tag.JumpData, JUMP_DATA_SIZE); + } + + protected JumpData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + return getExecutionCount(data, position) != 0 ? 1 : 0; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET); + } + + public int getTakenDisplacement(HotSpotMethodData data, int position) { + return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("taken(%d) displacement(%d)", getExecutionCount(data, pos), getTakenDisplacement(data, pos))); + } + } + + static class RawItemProfile { + final int entries; + final T[] items; + final long[] counts; + final long totalCount; + + public RawItemProfile(int entries, T[] items, long[] counts, long totalCount) { + this.entries = entries; + this.items = items; + this.counts = counts; + this.totalCount = totalCount; + } + } + + private abstract static class AbstractTypeData extends CounterData { + + protected static final int TYPE_DATA_ROW_SIZE = cellsToBytes(2); + + protected static final int NONPROFILED_COUNT_OFFSET = cellIndexToOffset(1); + protected static final int TYPE_DATA_FIRST_TYPE_OFFSET = cellIndexToOffset(2); + protected static final int TYPE_DATA_FIRST_TYPE_COUNT_OFFSET = cellIndexToOffset(3); + + protected AbstractTypeData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { + return createTypeProfile(getNullSeen(data, position), getRawTypeProfile(data, position)); + } + + private RawItemProfile getRawTypeProfile(HotSpotMethodData data, int position) { + int typeProfileWidth = config.typeProfileWidth; + + ResolvedJavaType[] types = new ResolvedJavaType[typeProfileWidth]; + long[] counts = new long[typeProfileWidth]; + long totalCount = 0; + int entries = 0; + + outer: for (int i = 0; i < typeProfileWidth; i++) { + HotSpotResolvedObjectTypeImpl receiverKlass = data.readKlass(position, getTypeOffset(i)); + if (receiverKlass != null) { + HotSpotResolvedObjectTypeImpl klass = receiverKlass; + long count = data.readUnsignedInt(position, getTypeCountOffset(i)); + /* + * Because of races in the profile collection machinery it's possible for a + * class to appear multiple times so merge them to make the profile look + * rational. + */ + for (int j = 0; j < entries; j++) { + if (types[j].equals(klass)) { + totalCount += count; + counts[j] += count; + continue outer; + } + } + types[entries] = klass; + totalCount += count; + counts[entries] = count; + entries++; + } + } + + totalCount += getTypesNotRecordedExecutionCount(data, position); + return new RawItemProfile<>(entries, types, counts, totalCount); + } + + protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); + + private static JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile profile) { + if (profile.entries <= 0 || profile.totalCount <= 0) { + return null; + } + + ProfiledType[] ptypes = new ProfiledType[profile.entries]; + double totalProbability = 0.0; + for (int i = 0; i < profile.entries; i++) { + double p = profile.counts[i]; + p = p / profile.totalCount; + totalProbability += p; + ptypes[i] = new ProfiledType(profile.items[i], p); + } + + Arrays.sort(ptypes); + + double notRecordedTypeProbability = profile.entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); + assert notRecordedTypeProbability == 0 || profile.entries == config.typeProfileWidth; + return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes); + } + + private static int getTypeOffset(int row) { + return TYPE_DATA_FIRST_TYPE_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + protected static int getTypeCountOffset(int row) { + return TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + RawItemProfile profile = getRawTypeProfile(data, pos); + TriState nullSeen = getNullSeen(data, pos); + TriState exceptionSeen = getExceptionSeen(data, pos); + sb.append(format("count(%d) null_seen(%s) exception_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen, + getTypesNotRecordedExecutionCount(data, pos), profile.entries)); + for (int i = 0; i < profile.entries; i++) { + long count = profile.counts[i]; + sb.append(format("%n %s (%d, %4.2f)", profile.items[i].toJavaName(), count, (double) count / profile.totalCount)); + } + return sb; + } + } + + private static class TypeCheckData extends AbstractTypeData { + + private static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; + + public TypeCheckData() { + super(Tag.ReceiverTypeData, TYPE_CHECK_DATA_SIZE); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return -1; + } + + @Override + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); + } + } + + private static class VirtualCallData extends AbstractTypeData { + + private static final int VIRTUAL_CALL_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * (config.typeProfileWidth + config.methodProfileWidth); + private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET = TYPE_DATA_FIRST_TYPE_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; + private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; + + public VirtualCallData() { + super(Tag.VirtualCallData, VIRTUAL_CALL_DATA_SIZE); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + final int typeProfileWidth = config.typeProfileWidth; + + long total = 0; + for (int i = 0; i < typeProfileWidth; i++) { + total += data.readUnsignedInt(position, getTypeCountOffset(i)); + } + + total += getCounterValue(data, position); + return truncateLongToInt(total); + } + + @Override + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return getCounterValue(data, position); + } + + private static long getMethodsNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); + } + + @Override + public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { + return createMethodProfile(getRawMethodProfile(data, position)); + } + + private static RawItemProfile getRawMethodProfile(HotSpotMethodData data, int position) { + int profileWidth = config.methodProfileWidth; + + ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth]; + long[] counts = new long[profileWidth]; + long totalCount = 0; + int entries = 0; + + for (int i = 0; i < profileWidth; i++) { + HotSpotResolvedJavaMethod method = data.readMethod(position, getMethodOffset(i)); + if (method != null) { + methods[entries] = method; + long count = data.readUnsignedInt(position, getMethodCountOffset(i)); + totalCount += count; + counts[entries] = count; + + entries++; + } + } + + totalCount += getMethodsNotRecordedExecutionCount(data, position); + return new RawItemProfile<>(entries, methods, counts, totalCount); + } + + private static JavaMethodProfile createMethodProfile(RawItemProfile profile) { + if (profile.entries <= 0 || profile.totalCount <= 0) { + return null; + } + + ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries]; + double totalProbability = 0.0; + for (int i = 0; i < profile.entries; i++) { + double p = profile.counts[i]; + p = p / profile.totalCount; + totalProbability += p; + pmethods[i] = new ProfiledMethod(profile.items[i], p); + } + + Arrays.sort(pmethods); + + double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); + assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth; + return new JavaMethodProfile(notRecordedMethodProbability, pmethods); + } + + private static int getMethodOffset(int row) { + return VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + private static int getMethodCountOffset(int row) { + return VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + RawItemProfile profile = getRawMethodProfile(data, pos); + super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries)); + for (int i = 0; i < profile.entries; i++) { + long count = profile.counts[i]; + sb.append(format("%n %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount)); + } + return sb; + } + } + + private static class RetData extends CounterData { + + private static final int RET_DATA_ROW_SIZE = cellsToBytes(3); + private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth; + + public RetData() { + super(Tag.RetData, RET_DATA_SIZE); + } + } + + private static class BranchData extends JumpData { + + private static final int BRANCH_DATA_SIZE = cellIndexToOffset(3); + private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(2); + + public BranchData() { + super(Tag.BranchData, BRANCH_DATA_SIZE); + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET); + long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); + long total = takenCount + notTakenCount; + + return total <= 0 ? -1 : takenCount / (double) total; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); + return truncateLongToInt(count); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + long taken = data.readUnsignedInt(pos, TAKEN_COUNT_OFFSET); + long notTaken = data.readUnsignedInt(pos, NOT_TAKEN_COUNT_OFFSET); + double takenProbability = getBranchTakenProbability(data, pos); + return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos))); + } + } + + private static class ArrayData extends AbstractMethodData { + + private static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(0); + protected static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(1); + + public ArrayData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + protected int getDynamicSize(HotSpotMethodData data, int position) { + return cellsToBytes(getLength(data, position)); + } + + protected static int getLength(HotSpotMethodData data, int position) { + return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("length(%d)", getLength(data, pos))); + } + } + + private static class MultiBranchData extends ArrayData { + + private static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1); + private static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = 2; + private static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS); + private static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0); + private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1); + + public MultiBranchData() { + super(Tag.MultiBranchData, MULTI_BRANCH_DATA_SIZE); + } + + @Override + public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { + int arrayLength = getLength(data, position); + assert arrayLength > 0 : "switch must have at least the default case"; + assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; + + int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + long totalCount = 0; + double[] result = new double[length]; + + // default case is first in HotSpot but last for the compiler + long count = readCount(data, position, 0); + totalCount += count; + result[length - 1] = count; + + for (int i = 1; i < length; i++) { + count = readCount(data, position, i); + totalCount += count; + result[i - 1] = count; + } + + if (totalCount <= 0) { + return null; + } else { + for (int i = 0; i < length; i++) { + result[i] = result[i] / totalCount; + } + return result; + } + } + + private static long readCount(HotSpotMethodData data, int position, int i) { + int offset; + long count; + offset = getCountOffset(i); + count = data.readUnsignedInt(position, offset); + return count; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + int arrayLength = getLength(data, position); + assert arrayLength > 0 : "switch must have at least the default case"; + assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; + + int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + long totalCount = 0; + for (int i = 0; i < length; i++) { + int offset = getCountOffset(i); + totalCount += data.readUnsignedInt(position, offset); + } + + return truncateLongToInt(totalCount); + } + + private static int getCountOffset(int index) { + return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; + } + + private static int getDisplacementOffset(int index) { + return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + int entries = getLength(data, pos) / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + sb.append(format("entries(%d)", entries)); + for (int i = 0; i < entries; i++) { + sb.append(format("%n %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i)))); + } + return sb; + } + } + + private static class ArgInfoData extends ArrayData { + + private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1); + + public ArgInfoData() { + super(Tag.ArgInfoData, ARG_INFO_DATA_SIZE); + } + } + + public void setCompiledIRSize(int size) { + UNSAFE.putInt(metaspaceMethodData + config.methodDataIRSizeOffset, size); + } + + public int getCompiledIRSize() { + return UNSAFE.getInt(metaspaceMethodData + config.methodDataIRSizeOffset); + } +} --- /dev/null 2015-09-16 15:20:08.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMethodDataAccessor.java 2015-09-16 15:20:08.000000000 -0700 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import jdk.internal.jvmci.meta.*; + +/** + * Interface for accessor objects that encapsulate the logic for accessing the different kinds of + * data in a HotSpot methodDataOop. This interface is similar to the interface {@link ProfilingInfo} + * , but most methods require a MethodDataObject and the exact position within the methodData. + */ +public interface HotSpotMethodDataAccessor { + + /** + * {@code DataLayout} tag values. + */ + enum Tag { + No(config().dataLayoutNoTag), + BitData(config().dataLayoutBitDataTag), + CounterData(config().dataLayoutCounterDataTag), + JumpData(config().dataLayoutJumpDataTag), + ReceiverTypeData(config().dataLayoutReceiverTypeDataTag), + VirtualCallData(config().dataLayoutVirtualCallDataTag), + RetData(config().dataLayoutRetDataTag), + BranchData(config().dataLayoutBranchDataTag), + MultiBranchData(config().dataLayoutMultiBranchDataTag), + ArgInfoData(config().dataLayoutArgInfoDataTag), + CallTypeData(config().dataLayoutCallTypeDataTag), + VirtualCallTypeData(config().dataLayoutVirtualCallTypeDataTag), + ParametersTypeData(config().dataLayoutParametersTypeDataTag), + SpeculativeTrapData(config().dataLayoutSpeculativeTrapDataTag); + + private final int value; + + private Tag(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + private static HotSpotVMConfig config() { + return runtime().getConfig(); + } + + public static Tag getEnum(int value) { + Tag result = values()[value]; + assert value == result.value; + return result; + } + } + + /** + * Returns the {@link Tag} stored in the LayoutData header. + * + * @return tag stored in the LayoutData header + */ + Tag getTag(); + + /** + * Returns the BCI stored in the LayoutData header. + * + * @return An integer ≥ 0 and ≤ Short.MAX_VALUE, or -1 if not supported. + */ + int getBCI(HotSpotMethodData data, int position); + + /** + * Computes the size for the specific data at the given position. + * + * @return An integer > 0. + */ + int getSize(HotSpotMethodData data, int position); + + JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position); + + JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position); + + double getBranchTakenProbability(HotSpotMethodData data, int position); + + double[] getSwitchProbabilities(HotSpotMethodData data, int position); + + TriState getExceptionSeen(HotSpotMethodData data, int position); + + TriState getNullSeen(HotSpotMethodData data, int position); + + int getExecutionCount(HotSpotMethodData data, int position); + + StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos); +} --- /dev/null 2015-09-16 15:20:08.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMethodHandleAccessProvider.java 2015-09-16 15:20:08.000000000 -0700 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2014, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.internal.jvmci.hotspot.HotSpotResolvedObjectTypeImpl.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; + +public class HotSpotMethodHandleAccessProvider implements MethodHandleAccessProvider, HotSpotProxified { + + private final ConstantReflectionProvider constantReflection; + + public HotSpotMethodHandleAccessProvider(ConstantReflectionProvider constantReflection) { + this.constantReflection = constantReflection; + } + + /** + * Lazy initialization to break class initialization cycle. Field and method lookup is only + * possible after the {@link HotSpotJVMCIRuntime} is fully initialized. + */ + static class LazyInitialization { + static final ResolvedJavaField methodHandleFormField; + static final ResolvedJavaField lambdaFormVmentryField; + static final ResolvedJavaMethod lambdaFormCompileToBytecodeMethod; + static final HotSpotResolvedJavaField memberNameVmtargetField; + + /** + * Search for an instance field with the given name in a class. + * + * @param className name of the class to search in + * @param fieldName name of the field to be searched + * @return resolved java field + * @throws ClassNotFoundException + */ + private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException { + Class clazz = Class.forName(className); + ResolvedJavaType type = runtime().fromClass(clazz); + ResolvedJavaField[] fields = type.getInstanceFields(false); + for (ResolvedJavaField field : fields) { + if (field.getName().equals(fieldName)) { + return field; + } + } + return null; + } + + private static ResolvedJavaMethod findMethodInClass(String className, String methodName) throws ClassNotFoundException { + Class clazz = Class.forName(className); + HotSpotResolvedObjectTypeImpl type = fromObjectClass(clazz); + ResolvedJavaMethod result = null; + for (ResolvedJavaMethod method : type.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + assert result == null : "more than one method found: " + className + "." + methodName; + result = method; + } + } + assert result != null : "method not found: " + className + "." + methodName; + return result; + } + + static { + try { + methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form"); + lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry"); + lambdaFormCompileToBytecodeMethod = findMethodInClass("java.lang.invoke.LambdaForm", "compileToBytecode"); + memberNameVmtargetField = (HotSpotResolvedJavaField) findFieldInClass("java.lang.invoke.MemberName", "vmtarget"); + } catch (Throwable ex) { + throw new JVMCIError(ex); + } + } + } + + @Override + public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) { + int intrinsicId = ((HotSpotResolvedJavaMethodImpl) method).intrinsicId(); + if (intrinsicId != 0) { + return getMethodHandleIntrinsic(intrinsicId); + } + return null; + } + + public static IntrinsicMethod getMethodHandleIntrinsic(int intrinsicId) { + HotSpotVMConfig config = runtime().getConfig(); + if (intrinsicId == config.vmIntrinsicInvokeBasic) { + return IntrinsicMethod.INVOKE_BASIC; + } else if (intrinsicId == config.vmIntrinsicLinkToInterface) { + return IntrinsicMethod.LINK_TO_INTERFACE; + } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) { + return IntrinsicMethod.LINK_TO_SPECIAL; + } else if (intrinsicId == config.vmIntrinsicLinkToStatic) { + return IntrinsicMethod.LINK_TO_STATIC; + } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) { + return IntrinsicMethod.LINK_TO_VIRTUAL; + } + return null; + } + + @Override + public ResolvedJavaMethod resolveInvokeBasicTarget(JavaConstant methodHandle, boolean forceBytecodeGeneration) { + if (methodHandle.isNull()) { + return null; + } + + /* Load non-public field: LambdaForm MethodHandle.form */ + JavaConstant lambdaForm = constantReflection.readFieldValue(LazyInitialization.methodHandleFormField, methodHandle); + if (lambdaForm.isNull()) { + return null; + } + + JavaConstant memberName; + if (forceBytecodeGeneration) { + /* Invoke non-public method: MemberName LambdaForm.compileToBytecode() */ + memberName = LazyInitialization.lambdaFormCompileToBytecodeMethod.invoke(lambdaForm, new JavaConstant[0]); + } else { + /* Load non-public field: MemberName LambdaForm.vmentry */ + memberName = constantReflection.readFieldValue(LazyInitialization.lambdaFormVmentryField, lambdaForm); + } + return getTargetMethod(memberName); + } + + @Override + public ResolvedJavaMethod resolveLinkToTarget(JavaConstant memberName) { + return getTargetMethod(memberName); + } + + /** + * Returns the {@link ResolvedJavaMethod} for the vmtarget of a java.lang.invoke.MemberName. + */ + private static ResolvedJavaMethod getTargetMethod(JavaConstant memberName) { + if (memberName.isNull()) { + return null; + } + + Object object = ((HotSpotObjectConstantImpl) memberName).object(); + /* Read the ResolvedJavaMethod from the injected field MemberName.vmtarget */ + return runtime().compilerToVm.getResolvedJavaMethod(object, LazyInitialization.memberNameVmtargetField.offset()); + } +} --- /dev/null 2015-09-16 15:20:09.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotMethodUnresolved.java 2015-09-16 15:20:09.000000000 -0700 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +/** + * Implementation of {@link JavaMethod} for unresolved HotSpot methods. + */ +public final class HotSpotMethodUnresolved extends HotSpotMethod { + + private final Signature signature; + protected JavaType holder; + + public HotSpotMethodUnresolved(String name, Signature signature, JavaType holder) { + super(name); + this.holder = holder; + this.signature = signature; + } + + @Override + public Signature getSignature() { + return signature; + } + + @Override + public JavaType getDeclaringClass() { + return holder; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof HotSpotMethodUnresolved)) { + return false; + } + HotSpotMethodUnresolved that = (HotSpotMethodUnresolved) obj; + return this.name.equals(that.name) && this.signature.equals(that.signature) && this.holder.equals(that.holder); + } +} --- /dev/null 2015-09-16 15:20:10.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotNmethod.java 2015-09-16 15:20:09.000000000 -0700 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.meta.*; + +/** + * Implementation of {@link InstalledCode} for code installed as an nmethod. The nmethod stores a + * weak reference to an instance of this class. This is necessary to keep the nmethod from being + * unloaded while the associated {@link HotSpotNmethod} instance is alive. + *

+ * Note that there is no (current) way for the reference from an nmethod to a {@link HotSpotNmethod} + * instance to be anything but weak. This is due to the fact that HotSpot does not treat nmethods as + * strong GC roots. + */ +public class HotSpotNmethod extends HotSpotInstalledCode { + + /** + * This (indirect) Method* reference is safe since class redefinition preserves all methods + * associated with nmethods in the code cache. + */ + private final HotSpotResolvedJavaMethod method; + + private final boolean isDefault; + private final boolean isExternal; + + public HotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault) { + this(method, name, isDefault, false); + } + + public HotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault, boolean isExternal) { + super(name); + this.method = method; + this.isDefault = isDefault; + this.isExternal = isExternal; + } + + public boolean isDefault() { + return isDefault; + } + + public boolean isExternal() { + return isExternal; + } + + public ResolvedJavaMethod getMethod() { + return method; + } + + @Override + public void invalidate() { + runtime().getCompilerToVM().invalidateInstalledCode(this); + } + + @Override + public String toString() { + return String.format("InstalledNmethod[method=%s, codeBlob=0x%x, isDefault=%b, name=%s]", method, getAddress(), isDefault, name); + } + + protected boolean checkThreeObjectArgs() { + assert method.getSignature().getParameterCount(!method.isStatic()) == 3; + assert method.getSignature().getParameterKind(0) == JavaKind.Object; + assert method.getSignature().getParameterKind(1) == JavaKind.Object; + assert !method.isStatic() || method.getSignature().getParameterKind(2) == JavaKind.Object; + return true; + } + + private boolean checkArgs(Object... args) { + JavaType[] sig = method.toParameterTypes(); + assert args.length == sig.length : method.format("%H.%n(%p): expected ") + sig.length + " args, got " + args.length; + for (int i = 0; i < sig.length; i++) { + Object arg = args[i]; + if (arg == null) { + assert sig[i].getJavaKind() == JavaKind.Object : method.format("%H.%n(%p): expected arg ") + i + " to be Object, not " + sig[i]; + } else if (sig[i].getJavaKind() != JavaKind.Object) { + assert sig[i].getJavaKind().toBoxedJavaClass() == arg.getClass() : method.format("%H.%n(%p): expected arg ") + i + " to be " + sig[i] + ", not " + arg.getClass(); + } + } + return true; + } + + @Override + public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { + assert checkArgs(args); + assert !isExternal(); + return runtime().getCompilerToVM().executeInstalledCode(args, this); + } + + @Override + public long getStart() { + return isValid() ? super.getStart() : 0; + } +} --- /dev/null 2015-09-16 15:20:10.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotObjectConstant.java 2015-09-16 15:20:10.000000000 -0700 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import java.lang.invoke.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +/** + * Represents a constant non-{@code null} object reference, within the compiler and across the + * compiler/runtime interface. + */ +public interface HotSpotObjectConstant extends JavaConstant, HotSpotConstant, VMConstant { + + JavaConstant compress(); + + JavaConstant uncompress(); + + /** + * Gets the resolved Java type of the object represented by this constant. + */ + HotSpotResolvedObjectType getType(); + + /** + * Gets the result of {@link Class#getClassLoader()} for the {@link Class} object represented by + * this constant. + * + * @return {@code null} if this constant does not represent a {@link Class} object + */ + JavaConstant getClassLoader(); + + /** + * Gets the {@linkplain System#identityHashCode(Object) identity} has code for the object + * represented by this constant. + */ + int getIdentityHashCode(); + + /** + * Gets the result of {@link Class#getComponentType()} for the {@link Class} object represented + * by this constant. + * + * @return {@code null} if this constant does not represent a {@link Class} object + */ + JavaConstant getComponentType(); + + /** + * Gets the result of {@link Class#getSuperclass()} for the {@link Class} object represented by + * this constant. + * + * @return {@code null} if this constant does not represent a {@link Class} object + */ + JavaConstant getSuperclass(); + + /** + * Gets the result of {@link CallSite#getTarget()} for the {@link CallSite} object represented + * by this constant. + * + * @param assumptions used to register an assumption that the {@link CallSite}'s target does not + * change + * @return {@code null} if this constant does not represent a {@link CallSite} object + */ + JavaConstant getCallSiteTarget(Assumptions assumptions); + + /** + * Determines if this constant represents an {@linkplain String#intern() interned} string. + */ + boolean isInternedString(); + + /** + * Gets the object represented by this constant represents if it is of a given type. + * + * @param type the expected type of the object represented by this constant. If the object is + * required to be of this type, then wrap the call to this method in + * {@link Objects#requireNonNull(Object)}. + * @return the object value represented by this constant if it is an + * {@link ResolvedJavaType#isInstance(JavaConstant) instance of} {@code type} otherwise + * {@code null} + */ + T asObject(Class type); + + /** + * Gets the object represented by this constant represents if it is of a given type. + * + * @param type the expected type of the object represented by this constant. If the object is + * required to be of this type, then wrap the call to this method in + * {@link Objects#requireNonNull(Object)}. + * @return the object value represented by this constant if it is an + * {@link ResolvedJavaType#isInstance(JavaConstant) instance of} {@code type} otherwise + * {@code null} + */ + Object asObject(ResolvedJavaType type); +} --- /dev/null 2015-09-16 15:20:11.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotObjectConstantImpl.java 2015-09-16 15:20:11.000000000 -0700 @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotResolvedObjectTypeImpl.*; + +import java.lang.invoke.*; + +import jdk.internal.jvmci.inittimer.*; +import jdk.internal.jvmci.meta.*; + +/** + * Represents a constant non-{@code null} object reference, within the compiler and across the + * compiler/runtime interface. + */ +public final class HotSpotObjectConstantImpl implements HotSpotObjectConstant, HotSpotProxified { + + public static JavaConstant forObject(Object object) { + return forObject(object, false); + } + + static JavaConstant forObject(Object object, boolean compressed) { + if (object == null) { + return compressed ? HotSpotCompressedNullConstant.COMPRESSED_NULL : JavaConstant.NULL_POINTER; + } else { + return new HotSpotObjectConstantImpl(object, compressed); + } + } + + static JavaConstant forStableArray(Object object, int stableDimension, boolean isDefaultStable) { + if (object == null) { + return JavaConstant.NULL_POINTER; + } else { + assert object.getClass().isArray(); + return new HotSpotObjectConstantImpl(object, false, stableDimension, isDefaultStable); + } + } + + public static JavaConstant forBoxedValue(JavaKind kind, Object value) { + if (kind == JavaKind.Object) { + return HotSpotObjectConstantImpl.forObject(value); + } else { + return JavaConstant.forBoxedPrimitive(value); + } + } + + static Object asBoxedValue(Constant constant) { + if (JavaConstant.isNull(constant)) { + return null; + } else if (constant instanceof HotSpotObjectConstantImpl) { + return ((HotSpotObjectConstantImpl) constant).object; + } else { + return ((JavaConstant) constant).asBoxedPrimitive(); + } + } + + private final Object object; + private final boolean compressed; + private final byte stableDimension; + private final boolean isDefaultStable; + + private HotSpotObjectConstantImpl(Object object, boolean compressed, int stableDimension, boolean isDefaultStable) { + this.object = object; + this.compressed = compressed; + this.stableDimension = (byte) stableDimension; + this.isDefaultStable = isDefaultStable; + assert object != null; + assert stableDimension == 0 || (object != null && object.getClass().isArray()); + assert stableDimension >= 0 && stableDimension <= 255; + assert !isDefaultStable || stableDimension > 0; + } + + private HotSpotObjectConstantImpl(Object object, boolean compressed) { + this(object, compressed, 0, false); + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + /** + * Package-private accessor for the object represented by this constant. + */ + Object object() { + return object; + } + + /** + * Determines if the object represented by this constant is {@link Object#equals(Object) equal} + * to a given object. + */ + public boolean isEqualTo(Object obj) { + return object.equals(obj); + } + + /** + * Gets the class of the object represented by this constant. + */ + public Class getObjectClass() { + return object.getClass(); + } + + public boolean isCompressed() { + return compressed; + } + + public JavaConstant compress() { + assert !compressed; + return new HotSpotObjectConstantImpl(object, true, stableDimension, isDefaultStable); + } + + public JavaConstant uncompress() { + assert compressed; + return new HotSpotObjectConstantImpl(object, false, stableDimension, isDefaultStable); + } + + public HotSpotResolvedObjectType getType() { + return fromObjectClass(object.getClass()); + } + + public JavaConstant getClassLoader() { + if (object instanceof Class) { + /* + * This is an intrinsic for getClassLoader0, which occurs after any security checks. We + * can't call that directly so just call getClassLoader. + */ + return HotSpotObjectConstantImpl.forObject(((Class) object).getClassLoader()); + } + return null; + } + + public int getIdentityHashCode() { + return System.identityHashCode(object); + } + + public JavaConstant getComponentType() { + if (object instanceof Class) { + return HotSpotObjectConstantImpl.forObject(((Class) object).getComponentType()); + } + return null; + } + + public JavaConstant getSuperclass() { + if (object instanceof Class) { + return HotSpotObjectConstantImpl.forObject(((Class) object).getSuperclass()); + } + return null; + } + + public JavaConstant getCallSiteTarget(Assumptions assumptions) { + if (object instanceof CallSite) { + CallSite callSite = (CallSite) object; + MethodHandle target = callSite.getTarget(); + if (!(callSite instanceof ConstantCallSite)) { + if (assumptions == null) { + return null; + } + assumptions.record(new Assumptions.CallSiteTargetValue(callSite, target)); + } + return HotSpotObjectConstantImpl.forObject(target); + } + return null; + } + + @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality is what we want") + public boolean isInternedString() { + if (object instanceof String) { + String s = (String) object; + return s.intern() == s; + } + return false; + } + + public T asObject(Class type) { + if (type.isInstance(object)) { + return type.cast(object); + } + return null; + } + + public Object asObject(ResolvedJavaType type) { + if (type.isInstance(this)) { + return object; + } + return null; + } + + @Override + public boolean isNull() { + return false; + } + + @Override + public boolean isDefaultForKind() { + return false; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public int hashCode() { + return System.identityHashCode(object); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof HotSpotObjectConstantImpl) { + HotSpotObjectConstantImpl other = (HotSpotObjectConstantImpl) o; + return object == other.object && compressed == other.compressed && stableDimension == other.stableDimension && isDefaultStable == other.isDefaultStable; + } + return false; + } + + @Override + public String toValueString() { + if (object instanceof String) { + return "\"" + (String) object + "\""; + } else { + return JavaKind.Object.format(object); + } + } + + @Override + public String toString() { + return (compressed ? "NarrowOop" : getJavaKind().getJavaName()) + "[" + JavaKind.Object.format(object) + "]"; + } + + /** + * Number of stable dimensions if this constant is a stable array. + */ + public int getStableDimension() { + return stableDimension & 0xff; + } + + /** + * Returns {@code true} if this is a stable array constant and its elements should be considered + * as stable regardless of whether they are default values. + */ + public boolean isDefaultStable() { + return isDefaultStable; + } +} --- /dev/null 2015-09-16 15:20:11.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotOopMap.java 2015-09-16 15:20:11.000000000 -0700 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +public class HotSpotOopMap { + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int offset; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int count; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] data; + + public byte[] data() { + return data; + } + + public int count() { + return count; + } + + public int offset() { + return offset; + } +} --- /dev/null 2015-09-16 15:20:12.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotProfilingInfo.java 2015-09-16 15:20:12.000000000 -0700 @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +public final class HotSpotProfilingInfo implements ProfilingInfo, HotSpotProxified { + + // private static final DebugMetric metricInsufficentSpace = + // Debug.metric("InsufficientSpaceForProfilingData"); + + private final HotSpotMethodData methodData; + private final HotSpotResolvedJavaMethod method; + + private boolean isMature; + private int position; + private int hintPosition; + private int hintBCI; + private HotSpotMethodDataAccessor dataAccessor; + + private boolean includeNormal; + private boolean includeOSR; + + public HotSpotProfilingInfo(HotSpotMethodData methodData, HotSpotResolvedJavaMethod method, boolean includeNormal, boolean includeOSR) { + this.methodData = methodData; + this.method = method; + this.includeNormal = includeNormal; + this.includeOSR = includeOSR; + this.isMature = methodData.isProfileMature(); + hintPosition = 0; + hintBCI = -1; + } + + @Override + public int getCodeSize() { + return method.getCodeSize(); + } + + @Override + public JavaTypeProfile getTypeProfile(int bci) { + if (!isMature) { + return null; + } + findBCI(bci, false); + return dataAccessor.getTypeProfile(methodData, position); + } + + @Override + public JavaMethodProfile getMethodProfile(int bci) { + if (!isMature) { + return null; + } + findBCI(bci, false); + return dataAccessor.getMethodProfile(methodData, position); + } + + @Override + public double getBranchTakenProbability(int bci) { + if (!isMature) { + return -1; + } + findBCI(bci, false); + return dataAccessor.getBranchTakenProbability(methodData, position); + } + + @Override + public double[] getSwitchProbabilities(int bci) { + if (!isMature) { + return null; + } + findBCI(bci, false); + return dataAccessor.getSwitchProbabilities(methodData, position); + } + + @Override + public TriState getExceptionSeen(int bci) { + findBCI(bci, true); + return dataAccessor.getExceptionSeen(methodData, position); + } + + @Override + public TriState getNullSeen(int bci) { + findBCI(bci, false); + return dataAccessor.getNullSeen(methodData, position); + } + + @Override + public int getExecutionCount(int bci) { + if (!isMature) { + return -1; + } + findBCI(bci, false); + return dataAccessor.getExecutionCount(methodData, position); + } + + @Override + public int getDeoptimizationCount(DeoptimizationReason reason) { + int count = 0; + if (includeNormal) { + count += methodData.getDeoptimizationCount(reason); + } + if (includeOSR) { + count += methodData.getOSRDeoptimizationCount(reason); + } + return count; + } + + private void findBCI(int targetBCI, boolean searchExtraData) { + assert targetBCI >= 0 : "invalid BCI"; + + if (methodData.hasNormalData()) { + int currentPosition = targetBCI < hintBCI ? 0 : hintPosition; + HotSpotMethodDataAccessor currentAccessor; + while ((currentAccessor = methodData.getNormalData(currentPosition)) != null) { + int currentBCI = currentAccessor.getBCI(methodData, currentPosition); + if (currentBCI == targetBCI) { + normalDataFound(currentAccessor, currentPosition, currentBCI); + return; + } else if (currentBCI > targetBCI) { + break; + } + currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); + } + } + + boolean exceptionPossiblyNotRecorded = false; + if (searchExtraData && methodData.hasExtraData()) { + int currentPosition = methodData.getExtraDataBeginOffset(); + HotSpotMethodDataAccessor currentAccessor; + while ((currentAccessor = methodData.getExtraData(currentPosition)) != null) { + int currentBCI = currentAccessor.getBCI(methodData, currentPosition); + if (currentBCI == targetBCI) { + extraDataFound(currentAccessor, currentPosition); + return; + } + currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); + } + + if (!methodData.isWithin(currentPosition)) { + exceptionPossiblyNotRecorded = true; + // metricInsufficentSpace.increment(); + } + } + + noDataFound(exceptionPossiblyNotRecorded); + } + + private void normalDataFound(HotSpotMethodDataAccessor data, int pos, int bci) { + setCurrentData(data, pos); + this.hintPosition = position; + this.hintBCI = bci; + } + + private void extraDataFound(HotSpotMethodDataAccessor data, int pos) { + setCurrentData(data, pos); + } + + private void noDataFound(boolean exceptionPossiblyNotRecorded) { + HotSpotMethodDataAccessor accessor = HotSpotMethodData.getNoDataAccessor(exceptionPossiblyNotRecorded); + setCurrentData(accessor, -1); + } + + private void setCurrentData(HotSpotMethodDataAccessor dataAccessor, int position) { + this.dataAccessor = dataAccessor; + this.position = position; + } + + @Override + public boolean isMature() { + return isMature; + } + + public void ignoreMature() { + isMature = true; + } + + @Override + public String toString() { + return "HotSpotProfilingInfo<" + this.toString(null, "; ") + ">"; + } + + @Override + public void setMature() { + isMature = true; + } + + /** + * {@code MethodData::_jvmci_ir_size} (currently) supports at most one JVMCI compiler IR type + * which will be determined by the first JVMCI compiler that calls + * {@link #setCompilerIRSize(Class, int)}. + */ + private static volatile Class supportedCompilerIRType; + + @Override + public boolean setCompilerIRSize(Class irType, int size) { + if (supportedCompilerIRType == null) { + synchronized (HotSpotProfilingInfo.class) { + if (supportedCompilerIRType == null) { + supportedCompilerIRType = irType; + } + } + } + if (supportedCompilerIRType != irType) { + return false; + } + methodData.setCompiledIRSize(size); + return true; + } + + @Override + public int getCompilerIRSize(Class irType) { + if (irType == supportedCompilerIRType) { + return methodData.getCompiledIRSize(); + } + return -1; + } +} --- /dev/null 2015-09-16 15:20:13.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotProxified.java 2015-09-16 15:20:12.000000000 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +/** + * Marker interface for classes whose values are proxied during replay compilation capture. + */ +public interface HotSpotProxified { +} --- /dev/null 2015-09-16 15:20:13.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotReferenceMap.java 2015-09-16 15:20:13.000000000 -0700 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import java.util.*; + +import jdk.internal.jvmci.code.*; + +public final class HotSpotReferenceMap extends ReferenceMap { + + final Location[] objects; + final Location[] derivedBase; + final int[] sizeInBytes; + final int maxRegisterSize; + + public HotSpotReferenceMap(Location[] objects, Location[] derivedBase, int[] sizeInBytes, int maxRegisterSize) { + this.objects = objects; + this.derivedBase = derivedBase; + this.sizeInBytes = sizeInBytes; + this.maxRegisterSize = maxRegisterSize; + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotReferenceMap) { + HotSpotReferenceMap that = (HotSpotReferenceMap) obj; + if (Arrays.equals(objects, that.objects)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return Arrays.toString(objects); + } +} --- /dev/null 2015-09-16 15:20:14.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedJavaField.java 2015-09-16 15:20:14.000000000 -0700 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +/** + * Represents a field in a HotSpot type. + */ +public interface HotSpotResolvedJavaField extends ResolvedJavaField { + + /** + * Determines if a given object contains this field. + * + * @return true iff this is a non-static field and its declaring class is assignable from + * {@code object}'s class + */ + boolean isInObject(Object object); + + int offset(); + + /** + * Checks if this field has the {@link Stable} annotation. + * + * @return true if field has {@link Stable} annotation, false otherwise + */ + boolean isStable(); +} --- /dev/null 2015-09-16 15:20:14.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedJavaFieldImpl.java 2015-09-16 15:20:14.000000000 -0700 @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2011, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.internal.jvmci.hotspot.HotSpotResolvedJavaFieldImpl.Options.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; + +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.options.*; + +/** + * Represents a field in a HotSpot type. + */ +public class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotProxified { + + static class Options { + //@formatter:off + @Option(help = "Mark well-known stable fields as such.", type = OptionType.Debug) + public static final OptionValue ImplicitStableValues = new OptionValue<>(true); + //@formatter:on + } + + private final HotSpotResolvedObjectTypeImpl holder; + private final String name; + private JavaType type; + private final int offset; + + /** + * This value contains all flags as stored in the VM including internal ones. + */ + private final int modifiers; + private final LocationIdentity locationIdentity = new FieldLocationIdentity(this); + + public static class FieldLocationIdentity extends LocationIdentity { + HotSpotResolvedJavaField inner; + + public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) { + this.inner = inner; + } + + @Override + public boolean isImmutable() { + return false; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof FieldLocationIdentity) { + FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj; + return inner.equals(fieldLocationIdentity.inner); + + } + return false; + } + + @Override + public int hashCode() { + return inner.hashCode(); + } + + @Override + public String toString() { + return inner.getName(); + } + } + + public HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, String name, JavaType type, long offset, int modifiers) { + this.holder = holder; + this.name = name; + this.type = type; + assert offset != -1; + assert offset == (int) offset : "offset larger than int"; + this.offset = (int) offset; + this.modifiers = modifiers; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotResolvedJavaField) { + HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; + if (that.offset != this.offset || that.isStatic() != this.isStatic()) { + return false; + } else if (this.holder.equals(that.holder)) { + assert this.name.equals(that.name) && this.type.equals(that.type); + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public int getModifiers() { + return modifiers & ModifiersProvider.jvmFieldModifiers(); + } + + @Override + public boolean isInternal() { + return (modifiers & runtime().getConfig().jvmAccFieldInternal) != 0; + } + + /** + * Determines if a given object contains this field. + * + * @return true iff this is a non-static field and its declaring class is assignable from + * {@code object}'s class + */ + public boolean isInObject(Object object) { + if (isStatic()) { + return false; + } + return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectTypeImpl.fromObjectClass(object.getClass())); + } + + @Override + public HotSpotResolvedObjectTypeImpl getDeclaringClass() { + return holder; + } + + @Override + public String getName() { + return name; + } + + @Override + public JavaType getType() { + // Pull field into local variable to prevent a race causing + // a ClassCastException below + JavaType currentType = type; + if (currentType instanceof HotSpotUnresolvedJavaType) { + // Don't allow unresolved types to hang around forever + HotSpotUnresolvedJavaType unresolvedType = (HotSpotUnresolvedJavaType) currentType; + ResolvedJavaType resolved = unresolvedType.reresolve(holder); + if (resolved != null) { + type = resolved; + } + } + return type; + } + + public int offset() { + return offset; + } + + @Override + public String toString() { + return format("HotSpotField<%H.%n %t:") + offset + ">"; + } + + @Override + public boolean isSynthetic() { + return (runtime().getConfig().syntheticFlag & modifiers) != 0; + } + + /** + * Checks if this field has the {@link Stable} annotation. + * + * @return true if field has {@link Stable} annotation, false otherwise + */ + public boolean isStable() { + if ((runtime().getConfig().jvmAccFieldStable & modifiers) != 0) { + return true; + } + assert getAnnotation(Stable.class) == null; + if (ImplicitStableValues.getValue() && isImplicitStableField()) { + return true; + } + return false; + } + + @Override + public Annotation[] getAnnotations() { + Field javaField = toJava(); + if (javaField != null) { + return javaField.getAnnotations(); + } + return new Annotation[0]; + } + + @Override + public T getAnnotation(Class annotationClass) { + Field javaField = toJava(); + if (javaField != null) { + return javaField.getAnnotation(annotationClass); + } + return null; + } + + private Field toJavaCache; + + private Field toJava() { + if (toJavaCache != null) { + return toJavaCache; + } + + if (isInternal()) { + return null; + } + try { + return toJavaCache = holder.mirror().getDeclaredField(name); + } catch (NoSuchFieldException | NoClassDefFoundError e) { + return null; + } + } + + private boolean isArray() { + JavaType fieldType = getType(); + return fieldType instanceof ResolvedJavaType && ((ResolvedJavaType) fieldType).isArray(); + } + + private boolean isImplicitStableField() { + if (isSynthetic()) { + if (isSyntheticImplicitStableField()) { + return true; + } + } else if (isWellKnownImplicitStableField()) { + return true; + } + return false; + } + + private boolean isSyntheticImplicitStableField() { + assert this.isSynthetic(); + if (isStatic() && isArray()) { + if (isFinal() && name.equals("$VALUES") || name.equals("ENUM$VALUES")) { + // generated int[] field for EnumClass::values() + return true; + } else if (name.startsWith("$SwitchMap$") || name.startsWith("$SWITCH_TABLE$")) { + // javac and ecj generate a static field in an inner class for a switch on an enum + // named $SwitchMap$p$k$g$EnumClass and $SWITCH_TABLE$p$k$g$EnumClass, respectively + return true; + } + } + return false; + } + + private boolean isWellKnownImplicitStableField() { + return WellKnownImplicitStableField.test(this); + } + + static class WellKnownImplicitStableField { + /** + * @return {@code true} if the field is a well-known stable field. + */ + public static boolean test(HotSpotResolvedJavaField field) { + return field.equals(STRING_VALUE_FIELD); + } + + private static final ResolvedJavaField STRING_VALUE_FIELD; + static { + try { + MetaAccessProvider metaAccess = runtime().getHostJVMCIBackend().getMetaAccess(); + STRING_VALUE_FIELD = metaAccess.lookupJavaField(String.class.getDeclaredField("value")); + } catch (SecurityException | NoSuchFieldException e) { + throw new JVMCIError(e); + } + } + } + + public LocationIdentity getLocationIdentity() { + return locationIdentity; + } +} --- /dev/null 2015-09-16 15:20:15.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedJavaMethod.java 2015-09-16 15:20:15.000000000 -0700 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import java.lang.reflect.*; + +import jdk.internal.jvmci.meta.*; + +/** + * Implementation of {@link JavaMethod} for resolved HotSpot methods. + */ +public interface HotSpotResolvedJavaMethod extends ResolvedJavaMethod { + + /** + * Returns true if this method has a {@code CallerSensitive} annotation. + * + * @return true if CallerSensitive annotation present, false otherwise + */ + boolean isCallerSensitive(); + + HotSpotResolvedObjectType getDeclaringClass(); + + /** + * Returns true if this method has a {@code ForceInline} annotation. + * + * @return true if ForceInline annotation present, false otherwise + */ + boolean isForceInline(); + + /** + * Returns true if this method has a {@code DontInline} annotation. + * + * @return true if DontInline annotation present, false otherwise + */ + boolean isDontInline(); + + /** + * Manually adds a DontInline annotation to this method. + */ + void setNotInlineable(); + + /** + * Returns true if this method is one of the special methods that is ignored by security stack + * walks. + * + * @return true if special method ignored by security stack walks, false otherwise + */ + boolean ignoredBySecurityStackWalk(); + + boolean hasBalancedMonitors(); + + ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver); + + /** + * Returns whether this method has compiled code. + * + * @return true if this method has compiled code, false otherwise + */ + boolean hasCompiledCode(); + + /** + * @param level + * @return true if the currently installed code was generated at {@code level}. + */ + boolean hasCompiledCodeAtLevel(int level); + + default boolean isDefault() { + if (isConstructor()) { + return false; + } + // Copied from java.lang.Method.isDefault() + int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC; + return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface(); + } + + /** + * Returns the offset of this method into the v-table. The method must have a v-table entry as + * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is + * thrown. + * + * @return the offset of this method into the v-table + */ + int vtableEntryOffset(ResolvedJavaType resolved); + + int intrinsicId(); + + /** + * Allocates a compile id for this method by asking the VM for one. + * + * @param entryBCI entry bci + * @return compile id + */ + int allocateCompileId(int entryBCI); + + boolean hasCodeAtLevel(int entryBCI, int level); +} --- /dev/null 2015-09-16 15:20:16.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedJavaMethodImpl.java 2015-09-16 15:20:15.000000000 -0700 @@ -0,0 +1,744 @@ +/* + * Copyright (c) 2011, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.internal.jvmci.hotspot.HotSpotResolvedJavaMethodImpl.Options.*; +import static jdk.internal.jvmci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.options.*; + +/** + * Implementation of {@link JavaMethod} for resolved HotSpot methods. + */ +public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, MetaspaceWrapperObject { + + public static class Options { + // @formatter:off + @Option(help = "", type = OptionType.Debug) + public static final OptionValue UseProfilingInformation = new OptionValue<>(true); + // @formatter:on + } + + /** + * Reference to metaspace Method object. + */ + private final long metaspaceMethod; + + private final HotSpotResolvedObjectTypeImpl holder; + private final HotSpotConstantPool constantPool; + private final HotSpotSignature signature; + private HotSpotMethodData methodData; + private byte[] code; + private Member toJavaCache; + + /** + * Gets the holder of a HotSpot metaspace method native object. + * + * @param metaspaceMethod a metaspace Method object + * @return the {@link ResolvedJavaType} corresponding to the holder of the + * {@code metaspaceMethod} + */ + private static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceMethod) { + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceConstMethod = UNSAFE.getAddress(metaspaceMethod + config.methodConstMethodOffset); + final long metaspaceConstantPool = UNSAFE.getAddress(metaspaceConstMethod + config.constMethodConstantsOffset); + return runtime().getCompilerToVM().getResolvedJavaType(null, metaspaceConstantPool + config.constantPoolHolderOffset, false); + } + + /** + * Gets the JVMCI mirror from a HotSpot method. The VM is responsible for ensuring that the + * Method* is kept alive for the duration of this call and the + * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. + * + * Called from the VM. + * + * @param metaspaceMethod a metaspace Method object + * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod} + */ + @SuppressWarnings("unused") + private static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceMethod) { + HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceMethod); + return holder.createMethod(metaspaceMethod); + } + + HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceMethod) { + // It would be too much work to get the method name here so we fill it in later. + super(null); + this.metaspaceMethod = metaspaceMethod; + this.holder = holder; + + HotSpotVMConfig config = runtime().getConfig(); + final long constMethod = getConstMethod(); + + /* + * Get the constant pool from the metaspace method. Some methods (e.g. intrinsics for + * signature-polymorphic method handle methods) have their own constant pool instead of the + * one from their holder. + */ + final long metaspaceConstantPool = UNSAFE.getAddress(constMethod + config.constMethodConstantsOffset); + if (metaspaceConstantPool == holder.getConstantPool().getMetaspaceConstantPool()) { + this.constantPool = holder.getConstantPool(); + } else { + this.constantPool = runtime().getCompilerToVM().getConstantPool(null, constMethod + config.constMethodConstantsOffset); + } + + final int nameIndex = UNSAFE.getChar(constMethod + config.constMethodNameIndexOffset); + this.name = constantPool.lookupUtf8(nameIndex); + + final int signatureIndex = UNSAFE.getChar(constMethod + config.constMethodSignatureIndexOffset); + this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex); + } + + /** + * Returns a pointer to this method's constant method data structure ( + * {@code Method::_constMethod}). This pointer isn't wrapped since it should be safe to use it + * within the context of this HotSpotResolvedJavaMethodImpl since the Method* and ConstMethod* + * are kept alive as a pair. + * + * @return pointer to this method's ConstMethod + */ + private long getConstMethod() { + assert metaspaceMethod != 0; + return UNSAFE.getAddress(metaspaceMethod + runtime().getConfig().methodConstMethodOffset); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotResolvedJavaMethodImpl) { + HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj; + return that.metaspaceMethod == metaspaceMethod; + } + return false; + } + + @Override + public int hashCode() { + return (int) metaspaceMethod; + } + + /** + * Returns this method's flags ({@code Method::_flags}). + * + * @return flags of this method + */ + private int getFlags() { + return UNSAFE.getByte(metaspaceMethod + runtime().getConfig().methodFlagsOffset); + } + + /** + * Returns this method's constant method flags ({@code ConstMethod::_flags}). + * + * @return flags of this method's ConstMethod + */ + private int getConstMethodFlags() { + return UNSAFE.getChar(getConstMethod() + runtime().getConfig().constMethodFlagsOffset); + } + + @Override + public HotSpotResolvedObjectTypeImpl getDeclaringClass() { + return holder; + } + + /** + * Gets the address of the C++ Method object for this method. + */ + public JavaConstant getMetaspaceMethodConstant() { + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(getHostWordKind(), metaspaceMethod, this, false); + } + + public long getMetaspaceMethod() { + return metaspaceMethod; + } + + public long getMetaspacePointer() { + return getMetaspaceMethod(); + } + + @Override + public JavaConstant getEncoding() { + return getMetaspaceMethodConstant(); + } + + /** + * Gets the complete set of modifiers for this method which includes the JVM specification + * modifiers as well as the HotSpot internal modifiers. + */ + public int getAllModifiers() { + return UNSAFE.getInt(metaspaceMethod + runtime().getConfig().methodAccessFlagsOffset); + } + + @Override + public int getModifiers() { + return getAllModifiers() & ModifiersProvider.jvmMethodModifiers(); + } + + @Override + public boolean canBeStaticallyBound() { + return (isFinal() || isPrivate() || isStatic() || holder.isLeaf()) && isConcrete(); + } + + @Override + public byte[] getCode() { + if (getCodeSize() == 0) { + return null; + } + if (code == null && holder.isLinked()) { + code = runtime().getCompilerToVM().getBytecode(this); + assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length; + } + return code; + } + + @Override + public int getCodeSize() { + return UNSAFE.getChar(getConstMethod() + runtime().getConfig().constMethodCodeSizeOffset); + } + + @Override + public ExceptionHandler[] getExceptionHandlers() { + final boolean hasExceptionTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasExceptionTable) != 0; + if (!hasExceptionTable) { + return new ExceptionHandler[0]; + } + + HotSpotVMConfig config = runtime().getConfig(); + final int exceptionTableLength = runtime().getCompilerToVM().getExceptionTableLength(this); + ExceptionHandler[] handlers = new ExceptionHandler[exceptionTableLength]; + long exceptionTableElement = runtime().getCompilerToVM().getExceptionTableStart(this); + + for (int i = 0; i < exceptionTableLength; i++) { + final int startPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementStartPcOffset); + final int endPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementEndPcOffset); + final int handlerPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementHandlerPcOffset); + int catchTypeIndex = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementCatchTypeIndexOffset); + + JavaType catchType; + if (catchTypeIndex == 0) { + catchType = null; + } else { + final int opcode = -1; // opcode is not used + catchType = constantPool.lookupType(catchTypeIndex, opcode); + + // Check for Throwable which catches everything. + if (catchType instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType; + if (resolvedType.mirror() == Throwable.class) { + catchTypeIndex = 0; + catchType = null; + } + } + } + handlers[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType); + + // Go to the next ExceptionTableElement + exceptionTableElement += config.exceptionTableElementSize; + } + + return handlers; + } + + /** + * Returns true if this method has a {@code CallerSensitive} annotation. + * + * @return true if CallerSensitive annotation present, false otherwise + */ + public boolean isCallerSensitive() { + return (getFlags() & runtime().getConfig().methodFlagsCallerSensitive) != 0; + } + + /** + * Returns true if this method has a {@code ForceInline} annotation. + * + * @return true if ForceInline annotation present, false otherwise + */ + public boolean isForceInline() { + return (getFlags() & runtime().getConfig().methodFlagsForceInline) != 0; + } + + /** + * Returns true if this method has a {@code DontInline} annotation. + * + * @return true if DontInline annotation present, false otherwise + */ + public boolean isDontInline() { + return (getFlags() & runtime().getConfig().methodFlagsDontInline) != 0; + } + + /** + * Manually adds a DontInline annotation to this method. + */ + public void setNotInlineable() { + runtime().getCompilerToVM().doNotInlineOrCompile(this); + } + + /** + * Returns true if this method is one of the special methods that is ignored by security stack + * walks. + * + * @return true if special method ignored by security stack walks, false otherwise + */ + public boolean ignoredBySecurityStackWalk() { + return runtime().getCompilerToVM().methodIsIgnoredBySecurityStackWalk(this); + } + + public boolean hasBalancedMonitors() { + HotSpotVMConfig config = runtime().getConfig(); + final int modifiers = getAllModifiers(); + + // Method has no monitorenter/exit bytecodes. + if ((modifiers & config.jvmAccHasMonitorBytecodes) == 0) { + return false; + } + + // Check to see if a previous compilation computed the monitor-matching analysis. + if ((modifiers & config.jvmAccMonitorMatch) != 0) { + return true; + } + + // This either happens only once if monitors are balanced or very rarely multiple-times. + return runtime().getCompilerToVM().hasBalancedMonitors(this); + } + + @Override + public boolean isClassInitializer() { + return "".equals(name) && isStatic(); + } + + @Override + public boolean isConstructor() { + return "".equals(name) && !isStatic(); + } + + @Override + public int getMaxLocals() { + if (isAbstract() || isNative()) { + return 0; + } + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getChar(getConstMethod() + config.methodMaxLocalsOffset); + } + + @Override + public int getMaxStackSize() { + if (isAbstract() || isNative()) { + return 0; + } + HotSpotVMConfig config = runtime().getConfig(); + return config.extraStackEntries + UNSAFE.getChar(getConstMethod() + config.constMethodMaxStackOffset); + } + + @Override + public StackTraceElement asStackTraceElement(int bci) { + if (bci < 0 || bci >= getCodeSize()) { + // HotSpot code can only construct stack trace elements for valid bcis + StackTraceElement ste = runtime().getCompilerToVM().getStackTraceElement(this, 0); + return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1); + } + return runtime().getCompilerToVM().getStackTraceElement(this, bci); + } + + public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) { + if (receiver.isInterface()) { + // Cannot trust interfaces. Because of: + // interface I { void foo(); } + // class A { public void foo() {} } + // class B extends A implements I { } + // class C extends B { public void foo() { } } + // class D extends B { } + // Would lead to identify C.foo() as the unique concrete method for I.foo() without + // seeing A.foo(). + return null; + } + return runtime().getCompilerToVM().findUniqueConcreteMethod(((HotSpotResolvedObjectTypeImpl) receiver), this); + } + + @Override + public HotSpotSignature getSignature() { + return signature; + } + + /** + * Gets the value of {@code Method::_code}. + * + * @return the value of {@code Method::_code} + */ + private long getCompiledCode() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getAddress(metaspaceMethod + config.methodCodeOffset); + } + + /** + * Returns whether this method has compiled code. + * + * @return true if this method has compiled code, false otherwise + */ + public boolean hasCompiledCode() { + return getCompiledCode() != 0L; + } + + /** + * @param level + * @return true if the currently installed code was generated at {@code level}. + */ + public boolean hasCompiledCodeAtLevel(int level) { + long compiledCode = getCompiledCode(); + if (compiledCode != 0) { + return UNSAFE.getInt(compiledCode + runtime().getConfig().nmethodCompLevelOffset) == level; + } + return false; + } + + private static final String TraceMethodDataFilter = System.getProperty("jvmci.traceMethodDataFilter"); + + @Override + public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { + ProfilingInfo info; + + if (UseProfilingInformation.getValue() && methodData == null) { + long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + runtime().getConfig().methodDataOffset); + if (metaspaceMethodData != 0) { + methodData = new HotSpotMethodData(metaspaceMethodData, this); + if (TraceMethodDataFilter != null && this.format("%H.%n").contains(TraceMethodDataFilter)) { + System.out.println("Raw method data for " + this.format("%H.%n(%p)") + ":"); + System.out.println(methodData.toString()); + } + } + } + + if (methodData == null || (!methodData.hasNormalData() && !methodData.hasExtraData())) { + // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in + // case of a deoptimization. + info = DefaultProfilingInfo.get(TriState.FALSE); + } else { + info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR); + } + return info; + } + + @Override + public void reprofile() { + runtime().getCompilerToVM().reprofile(this); + } + + @Override + public ConstantPool getConstantPool() { + return constantPool; + } + + @Override + public Annotation[][] getParameterAnnotations() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getParameterAnnotations(); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getParameterAnnotations(); + } + + @Override + public Annotation[] getAnnotations() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? new Annotation[0] : javaConstructor.getAnnotations(); + } + Method javaMethod = toJava(); + return javaMethod == null ? new Annotation[0] : javaMethod.getAnnotations(); + } + + @Override + public T getAnnotation(Class annotationClass) { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getAnnotation(annotationClass); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass); + } + + public boolean isDefault() { + if (isConstructor()) { + return false; + } + // Copied from java.lang.Method.isDefault() + int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC; + return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface(); + } + + @Override + public Type[] getGenericParameterTypes() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getGenericParameterTypes(); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getGenericParameterTypes(); + } + + public Class[] signatureToTypes() { + Signature sig = getSignature(); + int count = sig.getParameterCount(false); + Class[] result = new Class[count]; + for (int i = 0; i < result.length; ++i) { + JavaType parameterType = sig.getParameterType(i, holder); + HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder); + result[i] = resolvedParameterType.mirror(); + } + return result; + } + + private Method toJava() { + if (toJavaCache != null) { + return (Method) toJavaCache; + } + try { + Method result = holder.mirror().getDeclaredMethod(name, signatureToTypes()); + toJavaCache = result; + return result; + } catch (NoSuchMethodException | NoClassDefFoundError e) { + return null; + } + } + + private Constructor toJavaConstructor() { + if (toJavaCache != null) { + return (Constructor) toJavaCache; + } + try { + Constructor result = holder.mirror().getDeclaredConstructor(signatureToTypes()); + toJavaCache = result; + return result; + } catch (NoSuchMethodException | NoClassDefFoundError e) { + return null; + } + } + + @Override + public boolean canBeInlined() { + if (isDontInline()) { + return false; + } + return runtime().getCompilerToVM().canInlineMethod(this); + } + + @Override + public boolean shouldBeInlined() { + if (isForceInline()) { + return true; + } + return runtime().getCompilerToVM().shouldInlineMethod(this); + } + + @Override + public LineNumberTable getLineNumberTable() { + final boolean hasLineNumberTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLineNumberTable) != 0; + if (!hasLineNumberTable) { + return null; + } + + long[] values = runtime().getCompilerToVM().getLineNumberTable(this); + if (values == null || values.length == 0) { + // Empty table so treat is as non-existent + return null; + } + assert values.length % 2 == 0; + int[] bci = new int[values.length / 2]; + int[] line = new int[values.length / 2]; + + for (int i = 0; i < values.length / 2; i++) { + bci[i] = (int) values[i * 2]; + line[i] = (int) values[i * 2 + 1]; + } + + return new LineNumberTableImpl(line, bci); + } + + @Override + public LocalVariableTable getLocalVariableTable() { + final boolean hasLocalVariableTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLocalVariableTable) != 0; + if (!hasLocalVariableTable) { + return null; + } + + HotSpotVMConfig config = runtime().getConfig(); + long localVariableTableElement = runtime().getCompilerToVM().getLocalVariableTableStart(this); + final int localVariableTableLength = runtime().getCompilerToVM().getLocalVariableTableLength(this); + Local[] locals = new Local[localVariableTableLength]; + + for (int i = 0; i < localVariableTableLength; i++) { + final int startBci = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset); + final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset); + final int nameCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset); + final int typeCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset); + final int slot = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset); + + String localName = getConstantPool().lookupUtf8(nameCpIndex); + String localType = getConstantPool().lookupUtf8(typeCpIndex); + + locals[i] = new LocalImpl(localName, runtime().lookupType(localType, holder, false), startBci, endBci, slot); + + // Go to the next LocalVariableTableElement + localVariableTableElement += config.localVariableTableElementSize; + } + + return new LocalVariableTableImpl(locals); + } + + /** + * Returns the offset of this method into the v-table. The method must have a v-table entry as + * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is + * thrown. + * + * @return the offset of this method into the v-table + */ + public int vtableEntryOffset(ResolvedJavaType resolved) { + if (!isInVirtualMethodTable(resolved)) { + throw new JVMCIError("%s does not have a vtable entry in type %s", this, resolved); + } + HotSpotVMConfig config = runtime().getConfig(); + final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved); + return config.instanceKlassVtableStartOffset() + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset; + } + + @Override + public boolean isInVirtualMethodTable(ResolvedJavaType resolved) { + if (resolved instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved; + int vtableIndex = getVtableIndex(hotspotResolved); + return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength(); + } + return false; + } + + private int getVtableIndex(HotSpotResolvedObjectTypeImpl resolved) { + if (!holder.isLinked()) { + return runtime().getConfig().invalidVtableIndex; + } + if (holder.isInterface()) { + if (resolved.isInterface()) { + return runtime().getConfig().invalidVtableIndex; + } + return getVtableIndexForInterface(resolved); + } + return getVtableIndex(); + } + + /** + * Returns this method's virtual table index. + * + * @return virtual table index + */ + private int getVtableIndex() { + assert !holder.isInterface(); + HotSpotVMConfig config = runtime().getConfig(); + int result = UNSAFE.getInt(metaspaceMethod + config.methodVtableIndexOffset); + assert result >= config.nonvirtualVtableIndex : "must be linked"; + return result; + } + + private int getVtableIndexForInterface(ResolvedJavaType resolved) { + HotSpotResolvedObjectTypeImpl hotspotType = (HotSpotResolvedObjectTypeImpl) resolved; + return runtime().getCompilerToVM().getVtableIndexForInterface(hotspotType, this); + } + + /** + * The {@link SpeculationLog} for methods compiled by JVMCI hang off this per-declaring-type + * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is + * never moves and b) we never read from it. + *

+ * One implication is that we will preserve {@link SpeculationLog}s for methods that have been + * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot + * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods + * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal). + */ + private static final ClassValue> SpeculationLogs = new ClassValue>() { + @Override + protected Map computeValue(java.lang.Class type) { + return new HashMap<>(4); + } + }; + + public SpeculationLog getSpeculationLog() { + Map map = SpeculationLogs.get(holder.mirror()); + synchronized (map) { + SpeculationLog log = map.get(this.metaspaceMethod); + if (log == null) { + log = new HotSpotSpeculationLog(); + map.put(metaspaceMethod, log); + } + return log; + } + } + + public int intrinsicId() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getByte(metaspaceMethod + config.methodIntrinsicIdOffset) & 0xff; + } + + @Override + public JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments) { + assert !isConstructor(); + Method javaMethod = toJava(); + javaMethod.setAccessible(true); + + Object[] objArguments = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + objArguments[i] = HotSpotObjectConstantImpl.asBoxedValue(arguments[i]); + } + Object objReceiver = receiver != null && !receiver.isNull() ? ((HotSpotObjectConstantImpl) receiver).object() : null; + + try { + Object objResult = javaMethod.invoke(objReceiver, objArguments); + return javaMethod.getReturnType() == void.class ? null : HotSpotObjectConstantImpl.forBoxedValue(getSignature().getReturnKind(), objResult); + + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new IllegalArgumentException(ex); + } + } + + /** + * Allocates a compile id for this method by asking the VM for one. + * + * @param entryBCI entry bci + * @return compile id + */ + public int allocateCompileId(int entryBCI) { + return runtime().getCompilerToVM().allocateCompileId(this, entryBCI); + } + + public boolean hasCodeAtLevel(int entryBCI, int level) { + if (entryBCI == runtime().getConfig().invocationEntryBci) { + return hasCompiledCodeAtLevel(level); + } + return runtime().getCompilerToVM().hasCompiledCodeForOSR(this, entryBCI, level); + } +} --- /dev/null 2015-09-16 15:20:16.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedJavaType.java 2015-09-16 15:20:16.000000000 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { + + public HotSpotResolvedJavaType(String name) { + super(name); + } + + public abstract Class mirror(); + + @Override + public final boolean equals(Object obj) { + if (!(obj instanceof HotSpotResolvedJavaType)) { + return false; + } + HotSpotResolvedJavaType that = (HotSpotResolvedJavaType) obj; + return this.mirror().equals(that.mirror()); + } + + @Override + public final int hashCode() { + return getName().hashCode(); + } + +} --- /dev/null 2015-09-16 15:20:17.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedObjectType.java 2015-09-16 15:20:17.000000000 -0700 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.meta.Assumptions.*; + +/** + * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. + */ +public interface HotSpotResolvedObjectType extends ResolvedJavaType { + + HotSpotResolvedObjectType getArrayClass(); + + ResolvedJavaType getComponentType(); + + AssumptionResult findLeafConcreteSubtype(); + + HotSpotResolvedObjectType getSuperclass(); + + HotSpotResolvedObjectType[] getInterfaces(); + + HotSpotResolvedObjectType getSupertype(); + + HotSpotResolvedObjectType findLeastCommonAncestor(ResolvedJavaType otherType); + + HotSpotResolvedObjectType asExactType(); + + default boolean isPrimitive() { + return false; + } + + default JavaKind getJavaKind() { + return JavaKind.Object; + } + + ConstantPool getConstantPool(); + + /** + * Gets the instance size of this type. If an instance of this type cannot be fast path + * allocated, then the returned value is negative (its absolute value gives the size). Must not + * be called if this is an array or interface type. + */ + int instanceSize(); + + int getVtableLength(); + + @Override + AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method); + + /** + * Performs a fast-path check that this type is resolved in the context of a given accessing + * class. A negative result does not mean this type is not resolved with respect to + * {@code accessingClass}. That can only be determined by + * {@linkplain HotSpotJVMCIRuntime#lookupType(String, HotSpotResolvedObjectType, boolean) + * re-resolving} the type. + */ + boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass); + + /** + * Gets the metaspace Klass boxed in a {@link JavaConstant}. + */ + Constant klass(); + + boolean isPrimaryType(); + + int superCheckOffset(); + + long prototypeMarkWord(); + + int layoutHelper(); + + HotSpotResolvedObjectType getEnclosingType(); + + ResolvedJavaMethod getClassInitializer(); + + ResolvedJavaField createField(String name, JavaType type, long offset, int modifiers); +} --- /dev/null 2015-09-16 15:20:17.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedObjectTypeImpl.java 2015-09-16 15:20:17.000000000 -0700 @@ -0,0 +1,889 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static java.util.Objects.*; +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.internal.jvmci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.*; +import java.nio.*; +import java.util.*; + +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.meta.Assumptions.*; + +/** + * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. + */ +public final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, HotSpotProxified, MetaspaceWrapperObject { + + /** + * The Java class this type represents. + */ + private final Class javaClass; + private HashMap fieldCache; + private HashMap methodCache; + private HotSpotResolvedJavaField[] instanceFields; + private HotSpotResolvedObjectTypeImpl[] interfaces; + private HotSpotConstantPool constantPool; + final HotSpotJVMCIMetaAccessContext context; + private HotSpotResolvedObjectType arrayOfType; + + /** + * Gets the JVMCI mirror for a {@link Class} object. + * + * @return the {@link HotSpotResolvedJavaType} corresponding to {@code javaClass} + */ + public static HotSpotResolvedObjectTypeImpl fromObjectClass(Class javaClass) { + return (HotSpotResolvedObjectTypeImpl) runtime().fromClass(javaClass); + } + + /** + * Gets the JVMCI mirror from a HotSpot type. Since {@link Class} is already a proxy for the + * underlying Klass*, it is used instead of the raw Klass*. + * + * Called from the VM. + * + * @param javaClass a {@link Class} object + * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} + */ + @SuppressWarnings("unused") + private static HotSpotResolvedObjectTypeImpl fromMetaspace(Class javaClass) { + return fromObjectClass(javaClass); + } + + /** + * Creates the JVMCI mirror for a {@link Class} object. + * + *

+ * NOTE: Creating an instance of this class does not install the mirror for the + * {@link Class} type. Use {@link #fromObjectClass(Class)} or {@link #fromMetaspace(Class)} + * instead. + *

+ * + * @param javaClass the Class to create the mirror for + * @param context + */ + HotSpotResolvedObjectTypeImpl(Class javaClass, HotSpotJVMCIMetaAccessContext context) { + super(getSignatureName(javaClass)); + this.javaClass = javaClass; + this.context = context; + assert getName().charAt(0) != '[' || isArray() : getName(); + } + + /** + * Returns the name of this type as it would appear in a signature. + */ + private static String getSignatureName(Class javaClass) { + if (javaClass.isArray()) { + return javaClass.getName().replace('.', '/'); + } + return "L" + javaClass.getName().replace('.', '/') + ";"; + } + + /** + * Gets the metaspace Klass for this type. + */ + public long getMetaspaceKlass() { + if (HotSpotJVMCIRuntime.getHostWordKind() == JavaKind.Long) { + return UNSAFE.getLong(javaClass, (long) runtime().getConfig().klassOffset); + } + return UNSAFE.getInt(javaClass, (long) runtime().getConfig().klassOffset) & 0xFFFFFFFFL; + } + + public long getMetaspacePointer() { + return getMetaspaceKlass(); + } + + @Override + public int getModifiers() { + if (isArray()) { + return (getElementalType().getModifiers() & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED)) | Modifier.FINAL | Modifier.ABSTRACT; + } else { + return getAccessFlags() & ModifiersProvider.jvmClassModifiers(); + } + } + + public int getAccessFlags() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset); + } + + @Override + public HotSpotResolvedObjectType getArrayClass() { + if (arrayOfType == null) { + arrayOfType = fromObjectClass(Array.newInstance(mirror(), 0).getClass()); + } + return arrayOfType; + } + + @Override + public ResolvedJavaType getComponentType() { + Class javaComponentType = mirror().getComponentType(); + return javaComponentType == null ? null : runtime().fromClass(javaComponentType); + } + + @Override + public AssumptionResult findLeafConcreteSubtype() { + HotSpotVMConfig config = runtime().getConfig(); + if (isArray()) { + return getElementalType().isLeaf() ? new AssumptionResult<>(this) : null; + } else if (isInterface()) { + HotSpotResolvedObjectTypeImpl implementor = getSingleImplementor(); + /* + * If the implementor field contains itself that indicates that the interface has more + * than one implementors (see: InstanceKlass::add_implementor). + */ + if (implementor == null || implementor.equals(this)) { + return null; + } + + assert !implementor.isInterface(); + if (implementor.isAbstract() || !implementor.isLeafClass()) { + AssumptionResult leafConcreteSubtype = implementor.findLeafConcreteSubtype(); + if (leafConcreteSubtype != null) { + assert !leafConcreteSubtype.getResult().equals(implementor); + AssumptionResult newResult = new AssumptionResult<>(leafConcreteSubtype.getResult(), new ConcreteSubtype(this, implementor)); + // Accumulate leaf assumptions and return the combined result. + newResult.add(leafConcreteSubtype); + return newResult; + } + return null; + } + + return new AssumptionResult<>(implementor, new LeafType(implementor), new ConcreteSubtype(this, implementor)); + } else { + HotSpotResolvedObjectTypeImpl type = this; + while (type.isAbstract()) { + HotSpotResolvedObjectTypeImpl subklass = type.getSubklass(); + if (subklass == null || UNSAFE.getAddress(subklass.getMetaspaceKlass() + config.nextSiblingOffset) != 0) { + return null; + } + type = subklass; + } + if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) { + return null; + } + if (this.isAbstract()) { + return new AssumptionResult<>(type, new LeafType(type), new ConcreteSubtype(this, type)); + } else { + assert this.equals(type); + return new AssumptionResult<>(type, new LeafType(type)); + } + } + } + + /** + * Returns if type {@code type} is a leaf class. This is the case if the + * {@code Klass::_subklass} field of the underlying class is zero. + * + * @return true if the type is a leaf class + */ + private boolean isLeafClass() { + return getSubklass() == null; + } + + /** + * Returns the {@code Klass::_subklass} field of the underlying metaspace klass for the given + * type {@code type}. + * + * @return value of the subklass field as metaspace klass pointer + */ + private HotSpotResolvedObjectTypeImpl getSubklass() { + return runtime().getCompilerToVM().getResolvedJavaType(this, runtime().getConfig().subklassOffset, false); + } + + @Override + public HotSpotResolvedObjectTypeImpl getSuperclass() { + Class javaSuperclass = mirror().getSuperclass(); + return javaSuperclass == null ? null : fromObjectClass(javaSuperclass); + } + + @Override + public HotSpotResolvedObjectTypeImpl[] getInterfaces() { + if (interfaces == null) { + Class[] javaInterfaces = mirror().getInterfaces(); + HotSpotResolvedObjectTypeImpl[] result = new HotSpotResolvedObjectTypeImpl[javaInterfaces.length]; + for (int i = 0; i < javaInterfaces.length; i++) { + result[i] = fromObjectClass(javaInterfaces[i]); + } + interfaces = result; + } + return interfaces; + } + + @Override + public HotSpotResolvedObjectTypeImpl getSingleImplementor() { + if (!isInterface()) { + throw new JVMCIError("Cannot call getSingleImplementor() on a non-interface type: %s", this); + } + return runtime().getCompilerToVM().getImplementor(this); + } + + public HotSpotResolvedObjectTypeImpl getSupertype() { + if (isArray()) { + ResolvedJavaType componentType = getComponentType(); + if (mirror() == Object[].class || componentType.isPrimitive()) { + return fromObjectClass(Object.class); + } + return (HotSpotResolvedObjectTypeImpl) ((HotSpotResolvedObjectTypeImpl) componentType).getSupertype().getArrayClass(); + } + if (isInterface()) { + return fromObjectClass(Object.class); + } + return getSuperclass(); + } + + @Override + public HotSpotResolvedObjectType findLeastCommonAncestor(ResolvedJavaType otherType) { + if (otherType.isPrimitive()) { + return null; + } else { + HotSpotResolvedObjectTypeImpl t1 = this; + HotSpotResolvedObjectTypeImpl t2 = (HotSpotResolvedObjectTypeImpl) otherType; + while (true) { + if (t1.isAssignableFrom(t2)) { + return t1; + } + if (t2.isAssignableFrom(t1)) { + return t2; + } + t1 = t1.getSupertype(); + t2 = t2.getSupertype(); + } + } + } + + @Override + public HotSpotResolvedObjectType asExactType() { + return isLeaf() ? this : null; + } + + @Override + public JavaConstant getJavaClass() { + return HotSpotObjectConstantImpl.forObject(mirror()); + } + + @Override + public JavaConstant getObjectHub() { + return klass(); + } + + @Override + public AssumptionResult hasFinalizableSubclass() { + assert !isArray(); + if (!runtime().getCompilerToVM().hasFinalizableSubclass(this)) { + return new AssumptionResult<>(false, new NoFinalizableSubclass(this)); + } + return new AssumptionResult<>(true); + } + + @Override + public boolean hasFinalizer() { + HotSpotVMConfig config = runtime().getConfig(); + return (getAccessFlags() & config.klassHasFinalizerFlag) != 0; + } + + @Override + public boolean isPrimitive() { + return false; + } + + @Override + public boolean isArray() { + return mirror().isArray(); + } + + @Override + public boolean isInitialized() { + return isArray() ? true : getInitState() == runtime().getConfig().instanceKlassStateFullyInitialized; + } + + @Override + public boolean isLinked() { + return isArray() ? true : getInitState() >= runtime().getConfig().instanceKlassStateLinked; + } + + /** + * Returns the value of the state field {@code InstanceKlass::_init_state} of the metaspace + * klass. + * + * @return state field value of this type + */ + private int getInitState() { + assert !isArray() : "_init_state only exists in InstanceKlass"; + return UNSAFE.getByte(getMetaspaceKlass() + runtime().getConfig().instanceKlassInitStateOffset) & 0xFF; + } + + @Override + public void initialize() { + if (!isInitialized()) { + UNSAFE.ensureClassInitialized(mirror()); + assert isInitialized(); + } + } + + @Override + public boolean isInstance(JavaConstant obj) { + if (obj.getJavaKind() == JavaKind.Object && !obj.isNull()) { + return mirror().isInstance(((HotSpotObjectConstantImpl) obj).object()); + } + return false; + } + + @Override + public boolean isInstanceClass() { + return !isArray() && !isInterface(); + } + + @Override + public boolean isInterface() { + return mirror().isInterface(); + } + + @Override + public boolean isAssignableFrom(ResolvedJavaType other) { + assert other != null; + if (other instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl otherType = (HotSpotResolvedObjectTypeImpl) other; + return mirror().isAssignableFrom(otherType.mirror()); + } + return false; + } + + @Override + public boolean isJavaLangObject() { + return javaClass.equals(Object.class); + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + ResolvedJavaMethod resolvedMethod = resolveMethod(method, callerType); + if (resolvedMethod == null || resolvedMethod.isAbstract()) { + return null; + } + return resolvedMethod; + } + + @Override + public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + assert !callerType.isArray(); + if (method.isConcrete() && method.getDeclaringClass().equals(this) && method.isPublic()) { + return method; + } + if (!method.getDeclaringClass().isAssignableFrom(this)) { + return null; + } + HotSpotResolvedJavaMethodImpl hotSpotMethod = (HotSpotResolvedJavaMethodImpl) method; + HotSpotResolvedObjectTypeImpl hotSpotCallerType = (HotSpotResolvedObjectTypeImpl) callerType; + return runtime().getCompilerToVM().resolveMethod(this, hotSpotMethod, hotSpotCallerType); + } + + public HotSpotConstantPool getConstantPool() { + if (constantPool == null) { + constantPool = runtime().getCompilerToVM().getConstantPool(this, runtime().getConfig().instanceKlassConstantsOffset); + } + return constantPool; + } + + /** + * Gets the instance size of this type. If an instance of this type cannot be fast path + * allocated, then the returned value is negative (its absolute value gives the size). Must not + * be called if this is an array or interface type. + */ + public int instanceSize() { + assert !isArray(); + assert !isInterface(); + + HotSpotVMConfig config = runtime().getConfig(); + final int layoutHelper = layoutHelper(); + assert layoutHelper > config.klassLayoutHelperNeutralValue : "must be instance"; + + // See: Klass::layout_helper_size_in_bytes + int size = layoutHelper & ~config.klassLayoutHelperInstanceSlowPathBit; + + // See: Klass::layout_helper_needs_slow_path + boolean needsSlowPath = (layoutHelper & config.klassLayoutHelperInstanceSlowPathBit) != 0; + + return needsSlowPath ? -size : size; + } + + public int layoutHelper() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset); + } + + synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) { + HotSpotResolvedJavaMethodImpl method = null; + if (methodCache == null) { + methodCache = new HashMap<>(8); + } else { + method = methodCache.get(metaspaceMethod); + } + if (method == null) { + method = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod); + methodCache.put(metaspaceMethod, method); + context.add(method); + } + return method; + } + + public int getVtableLength() { + HotSpotVMConfig config = runtime().getConfig(); + if (isInterface() || isArray()) { + /* Everything has the core vtable of java.lang.Object */ + return config.baseVtableLength(); + } + int result = UNSAFE.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) / (config.vtableEntrySize / config.heapWordSize); + assert result >= config.baseVtableLength() : UNSAFE.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) + " " + config.vtableEntrySize; + return result; + } + + public synchronized HotSpotResolvedJavaField createField(String fieldName, JavaType type, long offset, int rawFlags) { + HotSpotResolvedJavaField result = null; + + final int flags = rawFlags & ModifiersProvider.jvmFieldModifiers(); + + final long id = offset + ((long) flags << 32); + + // Must cache the fields, because the local load elimination only works if the + // objects from two field lookups are identical. + if (fieldCache == null) { + fieldCache = new HashMap<>(8); + } else { + result = fieldCache.get(id); + } + + if (result == null) { + result = new HotSpotResolvedJavaFieldImpl(this, fieldName, type, offset, rawFlags); + fieldCache.put(id, result); + } else { + assert result.getName().equals(fieldName); + // assert result.getType().equals(type); + assert result.offset() == offset; + assert result.getModifiers() == flags; + } + + return result; + } + + @Override + public AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method) { + HotSpotResolvedJavaMethod hmethod = (HotSpotResolvedJavaMethod) method; + HotSpotResolvedObjectType declaredHolder = hmethod.getDeclaringClass(); + /* + * Sometimes the receiver type in the graph hasn't stabilized to a subtype of declared + * holder, usually because of phis, so make sure that the type is related to the declared + * type before using it for lookup. Unlinked types should also be ignored because we can't + * resolve the proper method to invoke. Generally unlinked types in invokes should result in + * a deopt instead since they can't really be used if they aren't linked yet. + */ + if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder) || !isLinked() || isInterface()) { + ResolvedJavaMethod result = hmethod.uniqueConcreteMethod(declaredHolder); + if (result != null) { + return new AssumptionResult<>(result, new ConcreteMethod(method, declaredHolder, result)); + } + return null; + } + /* + * The holder may be a subtype of the declaredHolder so make sure to resolve the method to + * the correct method for the subtype. + */ + HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) resolveMethod(hmethod, this); + if (resolvedMethod == null) { + // The type isn't known to implement the method. + return null; + } + + ResolvedJavaMethod result = resolvedMethod.uniqueConcreteMethod(this); + if (result != null) { + return new AssumptionResult<>(result, new ConcreteMethod(method, this, result)); + } + return null; + } + + /** + * This class represents the field information for one field contained in the fields array of an + * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. + */ + private class FieldInfo { + /** + * Native pointer into the array of Java shorts. + */ + private final long metaspaceData; + + /** + * Creates a field info for the field in the fields array at index {@code index}. + * + * @param index index to the fields array + */ + public FieldInfo(int index) { + HotSpotVMConfig config = runtime().getConfig(); + // Get Klass::_fields + final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); + assert config.fieldInfoFieldSlots == 6 : "revisit the field parsing code"; + metaspaceData = metaspaceFields + config.arrayU2DataOffset + config.fieldInfoFieldSlots * Short.BYTES * index; + } + + private int getAccessFlags() { + return readFieldSlot(runtime().getConfig().fieldInfoAccessFlagsOffset); + } + + private int getNameIndex() { + return readFieldSlot(runtime().getConfig().fieldInfoNameIndexOffset); + } + + private int getSignatureIndex() { + return readFieldSlot(runtime().getConfig().fieldInfoSignatureIndexOffset); + } + + public int getOffset() { + HotSpotVMConfig config = runtime().getConfig(); + final int lowPacked = readFieldSlot(config.fieldInfoLowPackedOffset); + final int highPacked = readFieldSlot(config.fieldInfoHighPackedOffset); + final int offset = ((highPacked << Short.SIZE) | lowPacked) >> config.fieldInfoTagSize; + return offset; + } + + /** + * Helper method to read an entry (slot) from the field array. Currently field info is laid + * on top an array of Java shorts. + */ + private int readFieldSlot(int index) { + return UNSAFE.getChar(metaspaceData + Short.BYTES * index); + } + + /** + * Returns the name of this field as a {@link String}. If the field is an internal field the + * name index is pointing into the vmSymbols table. + */ + public String getName() { + final int nameIndex = getNameIndex(); + return isInternal() ? HotSpotVmSymbols.symbolAt(nameIndex) : getConstantPool().lookupUtf8(nameIndex); + } + + /** + * Returns the signature of this field as {@link String}. If the field is an internal field + * the signature index is pointing into the vmSymbols table. + */ + public String getSignature() { + final int signatureIndex = getSignatureIndex(); + return isInternal() ? HotSpotVmSymbols.symbolAt(signatureIndex) : getConstantPool().lookupUtf8(signatureIndex); + } + + public JavaType getType() { + String signature = getSignature(); + return runtime().lookupType(signature, HotSpotResolvedObjectTypeImpl.this, false); + } + + private boolean isInternal() { + return (getAccessFlags() & runtime().getConfig().jvmAccFieldInternal) != 0; + } + + public boolean isStatic() { + return Modifier.isStatic(getAccessFlags()); + } + + public boolean hasGenericSignature() { + return (getAccessFlags() & runtime().getConfig().jvmAccFieldHasGenericSignature) != 0; + } + } + + private static class OffsetComparator implements java.util.Comparator { + @Override + public int compare(HotSpotResolvedJavaField o1, HotSpotResolvedJavaField o2) { + return o1.offset() - o2.offset(); + } + } + + @Override + public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { + if (instanceFields == null) { + if (isArray() || isInterface()) { + instanceFields = new HotSpotResolvedJavaField[0]; + } else { + final int fieldCount = getFieldCount(); + ArrayList fieldsArray = new ArrayList<>(fieldCount); + + for (int i = 0; i < fieldCount; i++) { + FieldInfo field = new FieldInfo(i); + + // We are only interested in instance fields. + if (!field.isStatic()) { + HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); + fieldsArray.add(resolvedJavaField); + } + } + + fieldsArray.sort(new OffsetComparator()); + + HotSpotResolvedJavaField[] myFields = fieldsArray.toArray(new HotSpotResolvedJavaField[0]); + + if (mirror() != Object.class) { + HotSpotResolvedJavaField[] superFields = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); + HotSpotResolvedJavaField[] fields = Arrays.copyOf(superFields, superFields.length + myFields.length); + System.arraycopy(myFields, 0, fields, superFields.length, myFields.length); + instanceFields = fields; + } else { + assert myFields.length == 0 : "java.lang.Object has fields!"; + instanceFields = myFields; + } + + } + } + if (!includeSuperclasses) { + int myFieldsStart = 0; + while (myFieldsStart < instanceFields.length && !instanceFields[myFieldsStart].getDeclaringClass().equals(this)) { + myFieldsStart++; + } + if (myFieldsStart == 0) { + return instanceFields; + } + if (myFieldsStart == instanceFields.length) { + return new HotSpotResolvedJavaField[0]; + } + return Arrays.copyOfRange(instanceFields, myFieldsStart, instanceFields.length); + } + return instanceFields; + } + + @Override + public ResolvedJavaField[] getStaticFields() { + if (isArray()) { + return new HotSpotResolvedJavaField[0]; + } else { + final int fieldCount = getFieldCount(); + ArrayList fieldsArray = new ArrayList<>(fieldCount); + + for (int i = 0; i < fieldCount; i++) { + FieldInfo field = new FieldInfo(i); + + // We are only interested in static fields. + if (field.isStatic()) { + HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); + fieldsArray.add(resolvedJavaField); + } + } + + fieldsArray.sort(new OffsetComparator()); + return fieldsArray.toArray(new HotSpotResolvedJavaField[fieldsArray.size()]); + } + } + + /** + * Returns the actual field count of this class's internal {@code InstanceKlass::_fields} array + * by walking the array and discounting the generic signature slots at the end of the array. + * + *

+ * See {@code FieldStreamBase::init_generic_signature_start_slot} + */ + private int getFieldCount() { + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); + int metaspaceFieldsLength = UNSAFE.getInt(metaspaceFields + config.arrayU1LengthOffset); + int fieldCount = 0; + + for (int i = 0, index = 0; i < metaspaceFieldsLength; i += config.fieldInfoFieldSlots, index++) { + FieldInfo field = new FieldInfo(index); + if (field.hasGenericSignature()) { + metaspaceFieldsLength--; + } + fieldCount++; + } + return fieldCount; + } + + @Override + public Class mirror() { + return javaClass; + } + + @Override + public String getSourceFileName() { + HotSpotVMConfig config = runtime().getConfig(); + final int sourceFileNameIndex = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassSourceFileNameIndexOffset); + if (sourceFileNameIndex == 0) { + return null; + } + return getConstantPool().lookupUtf8(sourceFileNameIndex); + } + + @Override + public Annotation[] getAnnotations() { + return mirror().getAnnotations(); + } + + @Override + public T getAnnotation(Class annotationClass) { + return mirror().getAnnotation(annotationClass); + } + + /** + * Performs a fast-path check that this type is resolved in the context of a given accessing + * class. A negative result does not mean this type is not resolved with respect to + * {@code accessingClass}. That can only be determined by + * {@linkplain HotSpotJVMCIRuntime#lookupType(String, HotSpotResolvedObjectType, boolean) + * re-resolving} the type. + */ + public boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass) { + assert accessingClass != null; + ResolvedJavaType elementType = getElementalType(); + if (elementType.isPrimitive()) { + // Primitive type resolution is context free. + return true; + } + if (elementType.getName().startsWith("Ljava/")) { + // Classes in a java.* package can only be defined by the + // boot class loader. This is enforced by ClassLoader.preDefineClass() + assert mirror().getClassLoader() == null; + return true; + } + ClassLoader thisCl = mirror().getClassLoader(); + ClassLoader accessingClassCl = ((HotSpotResolvedObjectTypeImpl) accessingClass).mirror().getClassLoader(); + return thisCl == accessingClassCl; + } + + @Override + public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { + if (isDefinitelyResolvedWithRespectTo(requireNonNull(accessingClass))) { + return this; + } + HotSpotResolvedObjectTypeImpl accessingType = (HotSpotResolvedObjectTypeImpl) accessingClass; + return (ResolvedJavaType) runtime().lookupType(getName(), accessingType, true); + } + + /** + * Gets the metaspace Klass boxed in a {@link JavaConstant}. + */ + public JavaConstant klass() { + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(runtime().getHostJVMCIBackend().getTarget().wordKind, getMetaspaceKlass(), this, false); + } + + public boolean isPrimaryType() { + return runtime().getConfig().secondarySuperCacheOffset != superCheckOffset(); + } + + public int superCheckOffset() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getInt(getMetaspaceKlass() + config.superCheckOffsetOffset); + } + + public long prototypeMarkWord() { + HotSpotVMConfig config = runtime().getConfig(); + if (isArray()) { + return config.arrayPrototypeMarkWord(); + } else { + return UNSAFE.getAddress(getMetaspaceKlass() + config.prototypeMarkWordOffset); + } + } + + @Override + public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedEntryKind) { + ResolvedJavaField[] declaredFields = getInstanceFields(true); + for (ResolvedJavaField field : declaredFields) { + HotSpotResolvedJavaField resolvedField = (HotSpotResolvedJavaField) field; + long resolvedFieldOffset = resolvedField.offset(); + // @formatter:off + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && + expectedEntryKind.isPrimitive() && + !expectedEntryKind.equals(JavaKind.Void) && + resolvedField.getJavaKind().isPrimitive()) { + resolvedFieldOffset += + resolvedField.getJavaKind().getByteCount() - + Math.min(resolvedField.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()); + } + if (resolvedFieldOffset == offset) { + return field; + } + // @formatter:on + } + return null; + } + + @Override + public URL getClassFilePath() { + Class cls = mirror(); + return cls.getResource(MetaUtil.getSimpleName(cls, true).replace('.', '$') + ".class"); + } + + @Override + public boolean isLocal() { + return mirror().isLocalClass(); + } + + @Override + public boolean isMember() { + return mirror().isMemberClass(); + } + + @Override + public HotSpotResolvedObjectTypeImpl getEnclosingType() { + final Class encl = mirror().getEnclosingClass(); + return encl == null ? null : fromObjectClass(encl); + } + + @Override + public ResolvedJavaMethod[] getDeclaredConstructors() { + Constructor[] constructors = mirror().getDeclaredConstructors(); + ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length]; + for (int i = 0; i < constructors.length; i++) { + result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(constructors[i]); + assert result[i].isConstructor(); + } + return result; + } + + @Override + public ResolvedJavaMethod[] getDeclaredMethods() { + Method[] methods = mirror().getDeclaredMethods(); + ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length]; + for (int i = 0; i < methods.length; i++) { + result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(methods[i]); + assert !result[i].isConstructor(); + } + return result; + } + + public ResolvedJavaMethod getClassInitializer() { + return runtime().getCompilerToVM().getClassInitializer(this); + } + + @Override + public String toString() { + return "HotSpotType<" + getName() + ", resolved>"; + } + + @Override + public boolean isTrustedInterfaceType() { + return TrustedInterface.class.isAssignableFrom(mirror()); + } +} --- /dev/null 2015-09-16 15:20:18.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedPrimitiveType.java 2015-09-16 15:20:18.000000000 -0700 @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static java.util.Objects.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.*; + +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.Assumptions.AssumptionResult; +import jdk.internal.jvmci.meta.*; + +/** + * Implementation of {@link JavaType} for primitive HotSpot types. + */ +public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType implements HotSpotProxified { + + private final JavaKind kind; + + /** + * Creates the JVMCI mirror for a primitive {@link JavaKind}. + * + *

+ * NOTE: Creating an instance of this class does not install the mirror for the + * {@link Class} type. Use {@link HotSpotJVMCIRuntimeProvider#fromClass(Class)} instead. + *

+ * + * @param kind the Kind to create the mirror for + */ + public HotSpotResolvedPrimitiveType(JavaKind kind) { + super(String.valueOf(Character.toUpperCase(kind.getTypeChar()))); + this.kind = kind; + assert mirror().isPrimitive() : mirror() + " not a primitive type"; + } + + @Override + public int getModifiers() { + return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; + } + + @Override + public HotSpotResolvedObjectTypeImpl getArrayClass() { + if (kind == JavaKind.Void) { + return null; + } + Class javaArrayMirror = Array.newInstance(mirror(), 0).getClass(); + return HotSpotResolvedObjectTypeImpl.fromObjectClass(javaArrayMirror); + } + + public ResolvedJavaType getElementalType() { + return this; + } + + @Override + public ResolvedJavaType getComponentType() { + return null; + } + + @Override + public ResolvedJavaType asExactType() { + return this; + } + + @Override + public ResolvedJavaType getSuperclass() { + return null; + } + + @Override + public ResolvedJavaType[] getInterfaces() { + return new ResolvedJavaType[0]; + } + + @Override + public ResolvedJavaType getSingleImplementor() { + throw new JVMCIError("Cannot call getSingleImplementor() on a non-interface type: %s", this); + } + + @Override + public ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType) { + return null; + } + + @Override + public JavaConstant getObjectHub() { + throw JVMCIError.unimplemented(); + } + + @Override + public JavaConstant getJavaClass() { + throw JVMCIError.unimplemented(); + } + + @Override + public AssumptionResult hasFinalizableSubclass() { + return new AssumptionResult<>(false); + } + + @Override + public boolean hasFinalizer() { + return false; + } + + @Override + public boolean isArray() { + return false; + } + + @Override + public boolean isPrimitive() { + return true; + } + + @Override + public boolean isInitialized() { + return true; + } + + public boolean isLinked() { + return true; + } + + @Override + public boolean isInstance(JavaConstant obj) { + return false; + } + + @Override + public boolean isInstanceClass() { + return false; + } + + @Override + public boolean isInterface() { + return false; + } + + @Override + public boolean isAssignableFrom(ResolvedJavaType other) { + assert other != null; + return other.equals(this); + } + + @Override + public JavaKind getJavaKind() { + return kind; + } + + @Override + public boolean isJavaLangObject() { + return false; + } + + @Override + public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + return null; + } + + @Override + public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + return null; + } + + @Override + public String toString() { + return "HotSpotResolvedPrimitiveType<" + kind + ">"; + } + + @Override + public AssumptionResult findLeafConcreteSubtype() { + return new AssumptionResult<>(this); + } + + @Override + public AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method) { + return null; + } + + @Override + public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { + return new ResolvedJavaField[0]; + } + + @Override + public ResolvedJavaField[] getStaticFields() { + return new ResolvedJavaField[0]; + } + + @Override + public Annotation[] getAnnotations() { + return new Annotation[0]; + } + + @Override + public T getAnnotation(Class annotationClass) { + return null; + } + + @Override + public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { + requireNonNull(accessingClass); + return this; + } + + @Override + public void initialize() { + } + + @Override + public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedType) { + return null; + } + + @Override + public String getSourceFileName() { + throw JVMCIError.unimplemented(); + } + + @Override + public Class mirror() { + return kind.toJavaClass(); + } + + @Override + public URL getClassFilePath() { + return null; + } + + @Override + public boolean isLocal() { + return false; + } + + @Override + public boolean isMember() { + return false; + } + + @Override + public ResolvedJavaType getEnclosingType() { + return null; + } + + @Override + public ResolvedJavaMethod[] getDeclaredConstructors() { + return new ResolvedJavaMethod[0]; + } + + @Override + public ResolvedJavaMethod[] getDeclaredMethods() { + return new ResolvedJavaMethod[0]; + } + + @Override + public ResolvedJavaMethod getClassInitializer() { + return null; + } + + @Override + public boolean isTrustedInterfaceType() { + return false; + } +} --- /dev/null 2015-09-16 15:20:19.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotSentinelConstant.java 2015-09-16 15:20:18.000000000 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +public final class HotSpotSentinelConstant extends Value implements JavaConstant, VMConstant { + + public HotSpotSentinelConstant(JavaKind kind) { + super(LIRKind.reference(kind)); + } + + public JavaKind getJavaKind() { + return (JavaKind) getLIRKind().getPlatformKind(); + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public boolean isDefaultForKind() { + return true; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public String toString() { + return JavaConstant.toString(this); + } + + @Override + public String toValueString() { + return "sentinel"; + } + + @Override + public int hashCode() { + return 13; + } + + @Override + public boolean equals(Object o) { + return o instanceof HotSpotSentinelConstant; + } +} --- /dev/null 2015-09-16 15:20:19.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotSignature.java 2015-09-16 15:20:19.000000000 -0700 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import java.util.*; + +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; + +/** + * Represents a method signature. + */ +public class HotSpotSignature implements Signature { + + private final List parameters = new ArrayList<>(); + private final String returnType; + private final String originalString; + private ResolvedJavaType[] parameterTypes; + private ResolvedJavaType returnTypeCache; + private final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotSignature(HotSpotJVMCIRuntimeProvider runtime, String signature) { + this.runtime = runtime; + assert signature.length() > 0; + this.originalString = signature; + + if (signature.charAt(0) == '(') { + int cur = 1; + while (cur < signature.length() && signature.charAt(cur) != ')') { + int nextCur = parseSignature(signature, cur); + parameters.add(signature.substring(cur, nextCur)); + cur = nextCur; + } + + cur++; + int nextCur = parseSignature(signature, cur); + returnType = signature.substring(cur, nextCur); + assert nextCur == signature.length(); + } else { + returnType = null; + } + } + + public HotSpotSignature(HotSpotJVMCIRuntimeProvider runtime, ResolvedJavaType returnType, ResolvedJavaType... parameterTypes) { + this.runtime = runtime; + this.parameterTypes = parameterTypes.clone(); + this.returnTypeCache = returnType; + this.returnType = returnType.getName(); + StringBuilder sb = new StringBuilder("("); + for (JavaType type : parameterTypes) { + parameters.add(type.getName()); + sb.append(type.getName()); + } + sb.append(")").append(returnType.getName()); + this.originalString = sb.toString(); + assert new HotSpotSignature(runtime, originalString).equals(this); + } + + private static int parseSignature(String signature, int start) { + int cur = start; + char first; + do { + first = signature.charAt(cur++); + } while (first == '['); + + switch (first) { + case 'L': + while (signature.charAt(cur) != ';') { + cur++; + } + cur++; + break; + case 'V': + case 'I': + case 'B': + case 'C': + case 'D': + case 'F': + case 'J': + case 'S': + case 'Z': + break; + default: + throw new JVMCIError("Invalid character at index %d in signature: %s", cur, signature); + } + return cur; + } + + @Override + public int getParameterCount(boolean withReceiver) { + return parameters.size() + (withReceiver ? 1 : 0); + } + + @Override + public JavaKind getParameterKind(int index) { + return JavaKind.fromTypeString(parameters.get(index)); + } + + private static boolean checkValidCache(ResolvedJavaType type, ResolvedJavaType accessingClass) { + assert accessingClass != null; + if (type == null) { + return false; + } else if (type instanceof HotSpotResolvedObjectTypeImpl) { + return ((HotSpotResolvedObjectTypeImpl) type).isDefinitelyResolvedWithRespectTo(accessingClass); + } + return true; + } + + private static JavaType getUnresolvedOrPrimitiveType(HotSpotJVMCIRuntimeProvider runtime, String name) { + if (name.length() == 1) { + JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); + return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(kind.toJavaClass()); + } + return new HotSpotUnresolvedJavaType(name, runtime); + } + + @Override + public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { + if (accessingClass == null) { + // Caller doesn't care about resolution context so return an unresolved + // or primitive type (primitive type resolution is context free) + return getUnresolvedOrPrimitiveType(runtime, parameters.get(index)); + } + if (parameterTypes == null) { + parameterTypes = new ResolvedJavaType[parameters.size()]; + } + + ResolvedJavaType type = parameterTypes[index]; + if (!checkValidCache(type, accessingClass)) { + JavaType result = runtime.lookupType(parameters.get(index), (HotSpotResolvedObjectType) accessingClass, false); + if (result instanceof ResolvedJavaType) { + type = (ResolvedJavaType) result; + parameterTypes[index] = type; + } else { + return result; + } + } + return type; + } + + @Override + public String toMethodDescriptor() { + assert originalString.equals(Signature.super.toMethodDescriptor()); + return originalString; + } + + @Override + public JavaKind getReturnKind() { + return JavaKind.fromTypeString(returnType); + } + + @Override + public JavaType getReturnType(ResolvedJavaType accessingClass) { + if (accessingClass == null) { + // Caller doesn't care about resolution context so return an unresolved + // or primitive type (primitive type resolution is context free) + return getUnresolvedOrPrimitiveType(runtime, returnType); + } + if (!checkValidCache(returnTypeCache, accessingClass)) { + JavaType result = runtime.lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false); + if (result instanceof ResolvedJavaType) { + returnTypeCache = (ResolvedJavaType) result; + } else { + return result; + } + } + return returnTypeCache; + } + + @Override + public String toString() { + return "HotSpotSignature<" + originalString + ">"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof HotSpotSignature) { + HotSpotSignature other = (HotSpotSignature) obj; + if (other.originalString.equals(originalString)) { + assert other.parameters.equals(parameters); + assert other.returnType.equals(returnType); + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return originalString.hashCode(); + } +} --- /dev/null 2015-09-16 15:20:20.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotSpeculationLog.java 2015-09-16 15:20:20.000000000 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +public class HotSpotSpeculationLog extends SpeculationLog { + + @Override + public JavaConstant speculate(Object reason) { + addSpeculation(reason); + return HotSpotObjectConstantImpl.forObject(reason); + } +} --- /dev/null 2015-09-16 15:20:20.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotStackFrameReference.java 2015-09-16 15:20:20.000000000 -0700 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import java.util.*; + +import jdk.internal.jvmci.code.stack.*; +import jdk.internal.jvmci.meta.*; + +public class HotSpotStackFrameReference implements InspectedFrame { + + private CompilerToVM compilerToVM; + + // information used to find the stack frame + private long stackPointer; + private int frameNumber; + + // information about the stack frame's contents + private int bci; + private HotSpotResolvedJavaMethod method; + private Object[] locals; + private boolean[] localIsVirtual; + + public long getStackPointer() { + return stackPointer; + } + + public int getFrameNumber() { + return frameNumber; + } + + @Override + public Object getLocal(int index) { + return locals[index]; + } + + @Override + public boolean isVirtual(int index) { + return localIsVirtual == null ? false : localIsVirtual[index]; + } + + @Override + public void materializeVirtualObjects(boolean invalidateCode) { + compilerToVM.materializeVirtualObjects(this, invalidateCode); + } + + @Override + public int getBytecodeIndex() { + return bci; + } + + @Override + public ResolvedJavaMethod getMethod() { + return method; + } + + @Override + public boolean isMethod(ResolvedJavaMethod otherMethod) { + return method.equals(otherMethod); + } + + @Override + public boolean hasVirtualObjects() { + return localIsVirtual != null; + } + + @Override + public String toString() { + return "HotSpotStackFrameReference [stackPointer=" + stackPointer + ", frameNumber=" + frameNumber + ", bci=" + bci + ", method=" + getMethod() + ", locals=" + Arrays.toString(locals) + + ", localIsVirtual=" + Arrays.toString(localIsVirtual) + "]"; + } +} --- /dev/null 2015-09-16 15:20:21.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotUnresolvedField.java 2015-09-16 15:20:21.000000000 -0700 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2009, 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +/** + * A implementation of {@link JavaField} for an unresolved field. + */ +public class HotSpotUnresolvedField implements JavaField { + + private final String name; + private final JavaType holder; + private final JavaType type; + + public HotSpotUnresolvedField(JavaType holder, String name, JavaType type) { + this.name = name; + this.type = type; + this.holder = holder; + } + + public String getName() { + return name; + } + + public JavaType getType() { + return type; + } + + public JavaType getDeclaringClass() { + return holder; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof HotSpotUnresolvedField)) { + return false; + } + HotSpotUnresolvedField that = (HotSpotUnresolvedField) obj; + return this.holder.equals(that.holder) && this.name.equals(that.name) && this.type.equals(that.type); + } + + /** + * Converts this compiler interface field to a string. + */ + @Override + public String toString() { + return format("HotSpotField<%H.%n %t, unresolved>"); + } +} --- /dev/null 2015-09-16 15:20:22.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotUnresolvedJavaType.java 2015-09-16 15:20:22.000000000 -0700 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.meta.*; + +/** + * Implementation of {@link JavaType} for unresolved HotSpot classes. + */ +public class HotSpotUnresolvedJavaType extends HotSpotJavaType { + + private final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotUnresolvedJavaType(String name, HotSpotJVMCIRuntimeProvider runtime) { + super(name); + assert name.charAt(0) == '[' || name.charAt(name.length() - 1) == ';' : name; + this.runtime = runtime; + } + + /** + * Creates an unresolved type for a valid {@link JavaType#getName() type name}. + */ + public static HotSpotUnresolvedJavaType create(HotSpotJVMCIRuntimeProvider runtime, String name) { + return new HotSpotUnresolvedJavaType(name, runtime); + } + + @Override + public JavaType getComponentType() { + assert getName().charAt(0) == '[' : "no array class" + getName(); + return new HotSpotUnresolvedJavaType(getName().substring(1), runtime); + } + + @Override + public JavaType getArrayClass() { + return new HotSpotUnresolvedJavaType('[' + getName(), runtime); + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public int hashCode() { + return getName().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof HotSpotUnresolvedJavaType)) { + return false; + } + HotSpotUnresolvedJavaType that = (HotSpotUnresolvedJavaType) obj; + return this.getName().equals(that.getName()); + } + + @Override + public String toString() { + return "HotSpotType<" + getName() + ", unresolved>"; + } + + @Override + public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { + return (ResolvedJavaType) runtime.lookupType(getName(), (HotSpotResolvedObjectType) accessingClass, true); + } + + /** + * Try to find a loaded version of this class. + * + * @param accessingClass + * @return the resolved class or null. + */ + ResolvedJavaType reresolve(HotSpotResolvedObjectType accessingClass) { + JavaType type = runtime.lookupType(getName(), accessingClass, false); + if (type instanceof ResolvedJavaType) { + return (ResolvedJavaType) type; + } + return null; + } +} --- /dev/null 2015-09-16 15:20:22.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVMConfig.java 2015-09-16 15:20:22.000000000 -0700 @@ -0,0 +1,1765 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.common.UnsafeUtil.readCString; +import static jdk.internal.jvmci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.reflect.*; +import java.util.*; + +import sun.misc.*; + +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.hotspotvmconfig.*; + +//JaCoCo Exclude + +/** + * Used to access native configuration details. + * + * All non-static, public fields in this class are so that they can be compiled as constants. + */ +public class HotSpotVMConfig { + + /** + * Maximum allowed size of allocated area for a frame. + */ + public final int maxFrameSize = 16 * 1024; + + public HotSpotVMConfig(CompilerToVM compilerToVm) { + // Get raw pointer to the array that contains all gHotSpotVM values. + final long gHotSpotVMData = compilerToVm.initializeConfiguration(); + assert gHotSpotVMData != 0; + + // Initialize the gHotSpotVM fields. + for (Field f : HotSpotVMConfig.class.getDeclaredFields()) { + if (f.isAnnotationPresent(HotSpotVMData.class)) { + HotSpotVMData annotation = f.getAnnotation(HotSpotVMData.class); + final int index = annotation.index(); + final long value = UNSAFE.getAddress(gHotSpotVMData + Unsafe.ADDRESS_SIZE * index); + try { + f.setLong(this, value); + } catch (IllegalAccessException e) { + throw new JVMCIError("index=" + index, e); + } + } + } + + // Quick sanity check. + assert gHotSpotVMStructs != 0; + assert gHotSpotVMTypes != 0; + assert gHotSpotVMIntConstants != 0; + assert gHotSpotVMLongConstants != 0; + assert gHotSpotVMAddresses != 0; + + initialize(); + + oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment()); + klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment); + + final long barrierSetAddress = UNSAFE.getAddress(universeCollectedHeap + collectedHeapBarrierSetOffset); + final int kind = UNSAFE.getInt(barrierSetAddress + barrierSetFakeRttiOffset + fakeRttiConcreteTagOffset); + if ((kind == barrierSetCardTableModRef) || (kind == barrierSetCardTableExtension) || (kind == barrierSetG1SATBCT) || (kind == barrierSetG1SATBCTLogging)) { + final long base = UNSAFE.getAddress(barrierSetAddress + cardTableModRefBSByteMapBaseOffset); + assert base != 0 : "unexpected byte_map_base: " + base; + cardtableStartAddress = base; + cardtableShift = cardTableModRefBSCardShift; + } else if (kind == barrierSetCardTableForRS) { + throw JVMCIError.unimplemented(); + } else if (kind == barrierSetModRef) { + // No post barriers + cardtableStartAddress = 0; + cardtableShift = 0; + } else { + cardtableStartAddress = -1; + cardtableShift = -1; + } + + // Now handle all HotSpotVMManual fields. + inlineCacheMissStub = inlineCacheMissBlob + UNSAFE.getInt(inlineCacheMissBlob + codeBlobCodeOffsetOffset); + handleWrongMethodStub = wrongMethodBlob + UNSAFE.getInt(wrongMethodBlob + codeBlobCodeOffsetOffset); + handleDeoptStub = deoptBlob + UNSAFE.getInt(deoptBlob + codeBlobCodeOffsetOffset) + UNSAFE.getInt(deoptBlob + deoptimizationBlobUnpackOffsetOffset); + uncommonTrapStub = deoptBlob + UNSAFE.getInt(deoptBlob + codeBlobCodeOffsetOffset) + UNSAFE.getInt(deoptBlob + deoptimizationBlobUncommonTrapOffsetOffset); + + assert check(); + assert HotSpotVMConfigVerifier.check(); + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + + /** + * Initialize fields by reading their values from vmStructs. + */ + private void initialize() { + // Fill the VM fields hash map. + HashMap vmFields = new HashMap<>(); + for (VMFields.Field e : new VMFields(gHotSpotVMStructs)) { + vmFields.put(e.getName(), e); + } + + // Fill the VM types hash map. + HashMap vmTypes = new HashMap<>(); + for (VMTypes.Type e : new VMTypes(gHotSpotVMTypes)) { + vmTypes.put(e.getTypeName(), e); + } + + // Fill the VM constants hash map. + HashMap vmConstants = new HashMap<>(); + for (AbstractConstant e : new VMIntConstants(gHotSpotVMIntConstants)) { + vmConstants.put(e.getName(), e); + } + for (AbstractConstant e : new VMAddresses(gHotSpotVMLongConstants)) { + vmConstants.put(e.getName(), e); + } + + // Fill the VM addresses hash map. + HashMap vmAddresses = new HashMap<>(); + for (VMAddresses.Address e : new VMAddresses(gHotSpotVMAddresses)) { + vmAddresses.put(e.getName(), e); + } + + // Fill the flags hash map. + HashMap flags = new HashMap<>(); + for (Flags.Flag e : new Flags(vmFields, vmTypes)) { + flags.put(e.getName(), e); + } + + String osName = getHostOSName(); + String osArch = getHostArchitectureName(); + + for (Field f : HotSpotVMConfig.class.getDeclaredFields()) { + if (f.isAnnotationPresent(HotSpotVMField.class)) { + HotSpotVMField annotation = f.getAnnotation(HotSpotVMField.class); + String name = annotation.name(); + String type = annotation.type(); + VMFields.Field entry = vmFields.get(name); + if (entry == null) { + if (!isRequired(osArch, annotation.archs())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM field not found: " + name); + } + + // Make sure the native type is still the type we expect. + if (!type.isEmpty()) { + if (!type.equals(entry.getTypeString())) { + throw new JVMCIError(f.getName() +": compiler expects type " + type + " but VM field " + name + " is of type " + entry.getTypeString()); + } + } + + switch (annotation.get()) { + case OFFSET: + setField(f, entry.getOffset()); + break; + case ADDRESS: + setField(f, entry.getAddress()); + break; + case VALUE: + setField(f, entry.getValue()); + break; + default: + throw new JVMCIError(f.getName() + ": unknown kind: " + annotation.get()); + } + } else if (f.isAnnotationPresent(HotSpotVMType.class)) { + HotSpotVMType annotation = f.getAnnotation(HotSpotVMType.class); + String name = annotation.name(); + VMTypes.Type entry = vmTypes.get(name); + if (entry == null) { + throw new JVMCIError(f.getName() + ": expected VM type not found: " + name); + } + switch (annotation.get()) { + case SIZE: + setField(f, entry.getSize()); + break; + default: + throw new JVMCIError(f.getName() + ": unknown kind: " + annotation.get()); + } + } else if (f.isAnnotationPresent(HotSpotVMConstant.class)) { + HotSpotVMConstant annotation = f.getAnnotation(HotSpotVMConstant.class); + String name = annotation.name(); + AbstractConstant entry = vmConstants.get(name); + if (entry == null) { + if (!isRequired(osArch, annotation.archs())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM constant not found: " + name); + } + setField(f, entry.getValue()); + } else if (f.isAnnotationPresent(HotSpotVMAddress.class)) { + HotSpotVMAddress annotation = f.getAnnotation(HotSpotVMAddress.class); + String name = annotation.name(); + VMAddresses.Address entry = vmAddresses.get(name); + if (entry == null) { + if (!isRequired(osName, annotation.os())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM address not found: " + name); + } + setField(f, entry.getValue()); + } else if (f.isAnnotationPresent(HotSpotVMFlag.class)) { + HotSpotVMFlag annotation = f.getAnnotation(HotSpotVMFlag.class); + String name = annotation.name(); + Flags.Flag entry = flags.get(name); + if (entry == null) { + if (annotation.optional() || !isRequired(osArch, annotation.archs())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM flag not found: " + name); + + } + setField(f, entry.getValue()); + } + } + } + + private final CompressEncoding oopEncoding; + private final CompressEncoding klassEncoding; + + public CompressEncoding getOopEncoding() { + return oopEncoding; + } + + public CompressEncoding getKlassEncoding() { + return klassEncoding; + } + + private void setField(Field field, Object value) { + try { + Class fieldType = field.getType(); + if (fieldType == boolean.class) { + if (value instanceof String) { + field.setBoolean(this, Boolean.valueOf((String) value)); + } else if (value instanceof Boolean) { + field.setBoolean(this, (boolean) value); + } else if (value instanceof Long) { + field.setBoolean(this, ((long) value) != 0); + } else { + throw new JVMCIError(value.getClass().getSimpleName()); + } + } else if (fieldType == byte.class) { + if (value instanceof Long) { + field.setByte(this, (byte) (long) value); + } else { + throw new JVMCIError(value.getClass().getSimpleName()); + } + } else if (fieldType == int.class) { + if (value instanceof Integer) { + field.setInt(this, (int) value); + } else if (value instanceof Long) { + field.setInt(this, (int) (long) value); + } else { + throw new JVMCIError(value.getClass().getSimpleName()); + } + } else if (fieldType == long.class) { + field.setLong(this, (long) value); + } else { + throw new JVMCIError(field.toString()); + } + } catch (IllegalAccessException e) { + throw new JVMCIError("%s: %s", field, e); + } + } + + /** + * Gets the host operating system name. + */ + private static String getHostOSName() { + String osName = System.getProperty("os.name"); + switch (osName) { + case "Linux": + osName = "linux"; + break; + case "SunOS": + osName = "solaris"; + break; + case "Mac OS X": + osName = "bsd"; + break; + default: + throw new JVMCIError("Unexpected OS name: " + osName); + } + return osName; + } + + /** + * Gets the host architecture name for the purpose of finding the corresponding + * {@linkplain HotSpotJVMCIBackendFactory backend}. + */ + public String getHostArchitectureName() { + String arch = System.getProperty("os.arch"); + switch (arch) { + case "x86_64": + arch = "amd64"; + break; + case "sparcv9": + arch = "sparc"; + break; + } + return arch; + } + + /** + * Determines if the current specification is included in a given set of specifications. + * + * @param current + * @param specification specifies a set of specifications, e.g. architectures or operating + * systems. A zero length value implies all. + */ + private static boolean isRequired(String current, String[] specification) { + if (specification.length == 0) { + return true; + } + for (String arch : specification) { + if (arch.equals(current)) { + return true; + } + } + return false; + } + + /** + * VMStructEntry (see {@code vmStructs.hpp}). + */ + @HotSpotVMData(index = 0) @Stable private long gHotSpotVMStructs; + @HotSpotVMData(index = 1) @Stable private long gHotSpotVMStructEntryTypeNameOffset; + @HotSpotVMData(index = 2) @Stable private long gHotSpotVMStructEntryFieldNameOffset; + @HotSpotVMData(index = 3) @Stable private long gHotSpotVMStructEntryTypeStringOffset; + @HotSpotVMData(index = 4) @Stable private long gHotSpotVMStructEntryIsStaticOffset; + @HotSpotVMData(index = 5) @Stable private long gHotSpotVMStructEntryOffsetOffset; + @HotSpotVMData(index = 6) @Stable private long gHotSpotVMStructEntryAddressOffset; + @HotSpotVMData(index = 7) @Stable private long gHotSpotVMStructEntryArrayStride; + + final class VMFields implements Iterable { + + private final long address; + + public VMFields(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Field current() { + return new Field(address + gHotSpotVMStructEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL fieldName. + */ + public boolean hasNext() { + Field entry = current(); + return entry.getFieldName() != null; + } + + public Field next() { + Field entry = current(); + index++; + return entry; + } + }; + } + + final class Field { + + private final long entryAddress; + + Field(long address) { + this.entryAddress = address; + } + + public String getTypeName() { + long typeNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryTypeNameOffset); + return readCString(UNSAFE, typeNameAddress); + } + + public String getFieldName() { + long fieldNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryFieldNameOffset); + return readCString(UNSAFE, fieldNameAddress); + } + + public String getTypeString() { + long typeStringAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryTypeStringOffset); + return readCString(UNSAFE, typeStringAddress); + } + + public boolean isStatic() { + return UNSAFE.getInt(entryAddress + gHotSpotVMStructEntryIsStaticOffset) != 0; + } + + public long getOffset() { + return UNSAFE.getLong(entryAddress + gHotSpotVMStructEntryOffsetOffset); + } + + public long getAddress() { + return UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryAddressOffset); + } + + public String getName() { + String typeName = getTypeName(); + String fieldName = getFieldName(); + return typeName + "::" + fieldName; + } + + public long getValue() { + String type = getTypeString(); + switch (type) { + case "bool": + return UNSAFE.getByte(getAddress()); + case "int": + return UNSAFE.getInt(getAddress()); + case "uint64_t": + return UNSAFE.getLong(getAddress()); + case "address": + case "intptr_t": + case "uintptr_t": + return UNSAFE.getAddress(getAddress()); + default: + // All foo* types are addresses. + if (type.endsWith("*")) { + return UNSAFE.getAddress(getAddress()); + } + throw new JVMCIError(type); + } + } + + @Override + public String toString() { + return String.format("Field[typeName=%s, fieldName=%s, typeString=%s, isStatic=%b, offset=%d, address=0x%x]", getTypeName(), getFieldName(), getTypeString(), isStatic(), getOffset(), + getAddress()); + } + } + } + + /** + * VMTypeEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 8) @Stable private long gHotSpotVMTypes; + @HotSpotVMData(index = 9) @Stable private long gHotSpotVMTypeEntryTypeNameOffset; + @HotSpotVMData(index = 10) @Stable private long gHotSpotVMTypeEntrySuperclassNameOffset; + @HotSpotVMData(index = 11) @Stable private long gHotSpotVMTypeEntryIsOopTypeOffset; + @HotSpotVMData(index = 12) @Stable private long gHotSpotVMTypeEntryIsIntegerTypeOffset; + @HotSpotVMData(index = 13) @Stable private long gHotSpotVMTypeEntryIsUnsignedOffset; + @HotSpotVMData(index = 14) @Stable private long gHotSpotVMTypeEntrySizeOffset; + @HotSpotVMData(index = 15) @Stable private long gHotSpotVMTypeEntryArrayStride; + + final class VMTypes implements Iterable { + + private final long address; + + public VMTypes(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Type current() { + return new Type(address + gHotSpotVMTypeEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL type name. + */ + public boolean hasNext() { + Type entry = current(); + return entry.getTypeName() != null; + } + + public Type next() { + Type entry = current(); + index++; + return entry; + } + }; + } + + final class Type { + + private final long entryAddress; + + Type(long address) { + this.entryAddress = address; + } + + public String getTypeName() { + long typeNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMTypeEntryTypeNameOffset); + return readCString(UNSAFE, typeNameAddress); + } + + public String getSuperclassName() { + long superclassNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMTypeEntrySuperclassNameOffset); + return readCString(UNSAFE, superclassNameAddress); + } + + public boolean isOopType() { + return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsOopTypeOffset) != 0; + } + + public boolean isIntegerType() { + return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsIntegerTypeOffset) != 0; + } + + public boolean isUnsigned() { + return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsUnsignedOffset) != 0; + } + + public long getSize() { + return UNSAFE.getLong(entryAddress + gHotSpotVMTypeEntrySizeOffset); + } + + @Override + public String toString() { + return String.format("Type[typeName=%s, superclassName=%s, isOopType=%b, isIntegerType=%b, isUnsigned=%b, size=%d]", getTypeName(), getSuperclassName(), isOopType(), isIntegerType(), + isUnsigned(), getSize()); + } + } + } + + public abstract class AbstractConstant { + + protected final long address; + protected final long nameOffset; + protected final long valueOffset; + + AbstractConstant(long address, long nameOffset, long valueOffset) { + this.address = address; + this.nameOffset = nameOffset; + this.valueOffset = valueOffset; + } + + public String getName() { + long nameAddress = UNSAFE.getAddress(address + nameOffset); + return readCString(UNSAFE, nameAddress); + } + + public abstract long getValue(); + } + + /** + * VMIntConstantEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 16) @Stable private long gHotSpotVMIntConstants; + @HotSpotVMData(index = 17) @Stable private long gHotSpotVMIntConstantEntryNameOffset; + @HotSpotVMData(index = 18) @Stable private long gHotSpotVMIntConstantEntryValueOffset; + @HotSpotVMData(index = 19) @Stable private long gHotSpotVMIntConstantEntryArrayStride; + + final class VMIntConstants implements Iterable { + + private final long address; + + public VMIntConstants(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Constant current() { + return new Constant(address + gHotSpotVMIntConstantEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Constant entry = current(); + return entry.getName() != null; + } + + public Constant next() { + Constant entry = current(); + index++; + return entry; + } + }; + } + + final class Constant extends AbstractConstant { + + Constant(long address) { + super(address, gHotSpotVMIntConstantEntryNameOffset, gHotSpotVMIntConstantEntryValueOffset); + } + + @Override + public long getValue() { + return UNSAFE.getInt(address + valueOffset); + } + + @Override + public String toString() { + return String.format("IntConstant[name=%s, value=%d (0x%x)]", getName(), getValue(), getValue()); + } + } + } + + /** + * VMLongConstantEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 20) @Stable private long gHotSpotVMLongConstants; + @HotSpotVMData(index = 21) @Stable private long gHotSpotVMLongConstantEntryNameOffset; + @HotSpotVMData(index = 22) @Stable private long gHotSpotVMLongConstantEntryValueOffset; + @HotSpotVMData(index = 23) @Stable private long gHotSpotVMLongConstantEntryArrayStride; + + final class VMLongConstants implements Iterable { + + private final long address; + + public VMLongConstants(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Constant currentEntry() { + return new Constant(address + gHotSpotVMLongConstantEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Constant entry = currentEntry(); + return entry.getName() != null; + } + + public Constant next() { + Constant entry = currentEntry(); + index++; + return entry; + } + }; + } + + final class Constant extends AbstractConstant { + + Constant(long address) { + super(address, gHotSpotVMLongConstantEntryNameOffset, gHotSpotVMLongConstantEntryValueOffset); + } + + @Override + public long getValue() { + return UNSAFE.getLong(address + valueOffset); + } + + @Override + public String toString() { + return String.format("LongConstant[name=%s, value=%d (0x%x)]", getName(), getValue(), getValue()); + } + } + } + + /** + * VMAddressEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 24) @Stable private long gHotSpotVMAddresses; + @HotSpotVMData(index = 25) @Stable private long gHotSpotVMAddressEntryNameOffset; + @HotSpotVMData(index = 26) @Stable private long gHotSpotVMAddressEntryValueOffset; + @HotSpotVMData(index = 27) @Stable private long gHotSpotVMAddressEntryArrayStride; + + final class VMAddresses implements Iterable { + + private final long address; + + public VMAddresses(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Address currentEntry() { + return new Address(address + gHotSpotVMAddressEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Address entry = currentEntry(); + return entry.getName() != null; + } + + public Address next() { + Address entry = currentEntry(); + index++; + return entry; + } + }; + } + + final class Address extends AbstractConstant { + + Address(long address) { + super(address, gHotSpotVMAddressEntryNameOffset, gHotSpotVMAddressEntryValueOffset); + } + + @Override + public long getValue() { + return UNSAFE.getLong(address + valueOffset); + } + + @Override + public String toString() { + return String.format("Address[name=%s, value=%d (0x%x)]", getName(), getValue(), getValue()); + } + } + } + + final class Flags implements Iterable { + + private final long address; + private final long entrySize; + private final long typeOffset; + private final long nameOffset; + private final long addrOffset; + + public Flags(HashMap vmStructs, HashMap vmTypes) { + address = vmStructs.get("Flag::flags").getValue(); + entrySize = vmTypes.get("Flag").getSize(); + typeOffset = vmStructs.get("Flag::_type").getOffset(); + nameOffset = vmStructs.get("Flag::_name").getOffset(); + addrOffset = vmStructs.get("Flag::_addr").getOffset(); + + assert vmTypes.get("bool").getSize() == Byte.BYTES; + assert vmTypes.get("intx").getSize() == Long.BYTES; + assert vmTypes.get("uintx").getSize() == Long.BYTES; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Flag current() { + return new Flag(address + entrySize * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Flag entry = current(); + return entry.getName() != null; + } + + public Flag next() { + Flag entry = current(); + index++; + return entry; + } + }; + } + + final class Flag { + + private final long entryAddress; + + Flag(long address) { + this.entryAddress = address; + } + + public String getType() { + long typeAddress = UNSAFE.getAddress(entryAddress + typeOffset); + return readCString(UNSAFE, typeAddress); + } + + public String getName() { + long nameAddress = UNSAFE.getAddress(entryAddress + nameOffset); + return readCString(UNSAFE, nameAddress); + } + + public long getAddr() { + return UNSAFE.getAddress(entryAddress + addrOffset); + } + + public Object getValue() { + switch (getType()) { + case "bool": + return Boolean.valueOf(UNSAFE.getByte(getAddr()) != 0); + case "intx": + case "uintx": + case "uint64_t": + return Long.valueOf(UNSAFE.getLong(getAddr())); + case "double": + return Double.valueOf(UNSAFE.getDouble(getAddr())); + case "ccstr": + case "ccstrlist": + return readCString(UNSAFE, getAddr()); + default: + throw new JVMCIError(getType()); + } + } + + @Override + public String toString() { + return String.format("Flag[type=%s, name=%s, value=%s]", getType(), getName(), getValue()); + } + } + } + + @HotSpotVMConstant(name = "ASSERT") @Stable public boolean cAssertions; + public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); + + @HotSpotVMFlag(name = "CodeEntryAlignment") @Stable public int codeEntryAlignment; + @HotSpotVMFlag(name = "VerifyOops") @Stable public boolean verifyOops; + @HotSpotVMFlag(name = "CITime") @Stable public boolean ciTime; + @HotSpotVMFlag(name = "CITimeEach") @Stable public boolean ciTimeEach; + @HotSpotVMFlag(name = "CompileTheWorldStartAt", optional = true) @Stable public int compileTheWorldStartAt; + @HotSpotVMFlag(name = "CompileTheWorldStopAt", optional = true) @Stable public int compileTheWorldStopAt; + @HotSpotVMFlag(name = "DontCompileHugeMethods") @Stable public boolean dontCompileHugeMethods; + @HotSpotVMFlag(name = "HugeMethodLimit") @Stable public int hugeMethodLimit; + @HotSpotVMFlag(name = "PrintInlining") @Stable public boolean printInlining; + @HotSpotVMFlag(name = "JVMCIUseFastLocking") @Stable public boolean useFastLocking; + @HotSpotVMFlag(name = "ForceUnreachable") @Stable public boolean forceUnreachable; + @HotSpotVMFlag(name = "CodeCacheSegmentSize") @Stable public int codeSegmentSize; + + @HotSpotVMFlag(name = "UseTLAB") @Stable public boolean useTLAB; + @HotSpotVMFlag(name = "UseBiasedLocking") @Stable public boolean useBiasedLocking; + @HotSpotVMFlag(name = "UsePopCountInstruction") @Stable public boolean usePopCountInstruction; + @HotSpotVMFlag(name = "UseCountLeadingZerosInstruction", archs = {"amd64"}) @Stable public boolean useCountLeadingZerosInstruction; + @HotSpotVMFlag(name = "UseCountTrailingZerosInstruction", archs = {"amd64"}) @Stable public boolean useCountTrailingZerosInstruction; + @HotSpotVMFlag(name = "UseAESIntrinsics") @Stable public boolean useAESIntrinsics; + @HotSpotVMFlag(name = "UseCRC32Intrinsics") @Stable public boolean useCRC32Intrinsics; + @HotSpotVMFlag(name = "UseG1GC") @Stable public boolean useG1GC; + @HotSpotVMFlag(name = "UseConcMarkSweepGC") @Stable public boolean useCMSGC; + + @HotSpotVMFlag(name = "AllocatePrefetchStyle") @Stable public int allocatePrefetchStyle; + @HotSpotVMFlag(name = "AllocatePrefetchInstr") @Stable public int allocatePrefetchInstr; + @HotSpotVMFlag(name = "AllocatePrefetchLines") @Stable public int allocatePrefetchLines; + @HotSpotVMFlag(name = "AllocateInstancePrefetchLines") @Stable public int allocateInstancePrefetchLines; + @HotSpotVMFlag(name = "AllocatePrefetchStepSize") @Stable public int allocatePrefetchStepSize; + @HotSpotVMFlag(name = "AllocatePrefetchDistance") @Stable public int allocatePrefetchDistance; + + @HotSpotVMFlag(name = "FlightRecorder", optional = true) @Stable public boolean flightRecorder; + + @HotSpotVMField(name = "Universe::_collectedHeap", type = "CollectedHeap*", get = HotSpotVMField.Type.VALUE) @Stable private long universeCollectedHeap; + @HotSpotVMField(name = "CollectedHeap::_total_collections", type = "unsigned int", get = HotSpotVMField.Type.OFFSET) @Stable private int collectedHeapTotalCollectionsOffset; + + public long gcTotalCollectionsAddress() { + return universeCollectedHeap + collectedHeapTotalCollectionsOffset; + } + + @HotSpotVMFlag(name = "ReduceInitialCardMarks") @Stable public boolean useDeferredInitBarriers; + + // Compressed Oops related values. + @HotSpotVMFlag(name = "UseCompressedOops") @Stable public boolean useCompressedOops; + @HotSpotVMFlag(name = "UseCompressedClassPointers") @Stable public boolean useCompressedClassPointers; + + @HotSpotVMField(name = "Universe::_narrow_oop._base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowOopBase; + @HotSpotVMField(name = "Universe::_narrow_oop._shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowOopShift; + @HotSpotVMFlag(name = "ObjectAlignmentInBytes") @Stable public int objectAlignment; + + public final int minObjAlignment() { + return objectAlignment / heapWordSize; + } + + public final int logMinObjAlignment() { + return (int) (Math.log(objectAlignment) / Math.log(2)); + } + + @HotSpotVMType(name = "narrowKlass", get = HotSpotVMType.Type.SIZE) @Stable public int narrowKlassSize; + @HotSpotVMField(name = "Universe::_narrow_klass._base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowKlassBase; + @HotSpotVMField(name = "Universe::_narrow_klass._shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowKlassShift; + @HotSpotVMConstant(name = "LogKlassAlignmentInBytes") @Stable public int logKlassAlignment; + + // CPU capabilities + @HotSpotVMFlag(name = "UseSSE") @Stable public int useSSE; + @HotSpotVMFlag(name = "UseAVX", archs = {"amd64"}) @Stable public int useAVX; + + @HotSpotVMField(name = "Abstract_VM_Version::_reserve_for_allocation_prefetch", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int abstractVmVersionReserveForAllocationPrefetch; + + // X86 specific values + @HotSpotVMField(name = "VM_Version::_cpuFeatures", type = "uint64_t", get = HotSpotVMField.Type.VALUE, archs = {"amd64"}) @Stable public long x86CPUFeatures; + @HotSpotVMConstant(name = "VM_Version::CPU_CX8", archs = {"amd64"}) @Stable public long cpuCX8; + @HotSpotVMConstant(name = "VM_Version::CPU_CMOV", archs = {"amd64"}) @Stable public long cpuCMOV; + @HotSpotVMConstant(name = "VM_Version::CPU_FXSR", archs = {"amd64"}) @Stable public long cpuFXSR; + @HotSpotVMConstant(name = "VM_Version::CPU_HT", archs = {"amd64"}) @Stable public long cpuHT; + @HotSpotVMConstant(name = "VM_Version::CPU_MMX", archs = {"amd64"}) @Stable public long cpuMMX; + @HotSpotVMConstant(name = "VM_Version::CPU_3DNOW_PREFETCH", archs = {"amd64"}) @Stable public long cpu3DNOWPREFETCH; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE", archs = {"amd64"}) @Stable public long cpuSSE; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE2", archs = {"amd64"}) @Stable public long cpuSSE2; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE3", archs = {"amd64"}) @Stable public long cpuSSE3; + @HotSpotVMConstant(name = "VM_Version::CPU_SSSE3", archs = {"amd64"}) @Stable public long cpuSSSE3; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4A", archs = {"amd64"}) @Stable public long cpuSSE4A; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4_1", archs = {"amd64"}) @Stable public long cpuSSE41; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4_2", archs = {"amd64"}) @Stable public long cpuSSE42; + @HotSpotVMConstant(name = "VM_Version::CPU_POPCNT", archs = {"amd64"}) @Stable public long cpuPOPCNT; + @HotSpotVMConstant(name = "VM_Version::CPU_LZCNT", archs = {"amd64"}) @Stable public long cpuLZCNT; + @HotSpotVMConstant(name = "VM_Version::CPU_TSC", archs = {"amd64"}) @Stable public long cpuTSC; + @HotSpotVMConstant(name = "VM_Version::CPU_TSCINV", archs = {"amd64"}) @Stable public long cpuTSCINV; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX", archs = {"amd64"}) @Stable public long cpuAVX; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX2", archs = {"amd64"}) @Stable public long cpuAVX2; + @HotSpotVMConstant(name = "VM_Version::CPU_AES", archs = {"amd64"}) @Stable public long cpuAES; + @HotSpotVMConstant(name = "VM_Version::CPU_ERMS", archs = {"amd64"}) @Stable public long cpuERMS; + @HotSpotVMConstant(name = "VM_Version::CPU_CLMUL", archs = {"amd64"}) @Stable public long cpuCLMUL; + @HotSpotVMConstant(name = "VM_Version::CPU_BMI1", archs = {"amd64"}) @Stable public long cpuBMI1; + + // SPARC specific values + @HotSpotVMField(name = "VM_Version::_features", type = "int", get = HotSpotVMField.Type.VALUE, archs = {"sparc"}) @Stable public int sparcFeatures; + @HotSpotVMConstant(name = "VM_Version::vis3_instructions_m", archs = {"sparc"}) @Stable public int vis3Instructions; + @HotSpotVMConstant(name = "VM_Version::vis2_instructions_m", archs = {"sparc"}) @Stable public int vis2Instructions; + @HotSpotVMConstant(name = "VM_Version::vis1_instructions_m", archs = {"sparc"}) @Stable public int vis1Instructions; + @HotSpotVMConstant(name = "VM_Version::cbcond_instructions_m", archs = {"sparc"}) @Stable public int cbcondInstructions; + @HotSpotVMFlag(name = "UseBlockZeroing", archs = {"sparc"}) @Stable public boolean useBlockZeroing; + @HotSpotVMFlag(name = "BlockZeroingLowLimit", archs = {"sparc"}) @Stable public int blockZeroingLowLimit; + + // offsets, ... + @HotSpotVMFlag(name = "StackShadowPages") @Stable public int stackShadowPages; + @HotSpotVMFlag(name = "UseStackBanging") @Stable public boolean useStackBanging; + @HotSpotVMConstant(name = "STACK_BIAS") @Stable public int stackBias; + + @HotSpotVMField(name = "oopDesc::_mark", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int markOffset; + @HotSpotVMField(name = "oopDesc::_metadata._klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int hubOffset; + + @HotSpotVMField(name = "Klass::_prototype_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int prototypeMarkWordOffset; + @HotSpotVMField(name = "Klass::_subklass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int subklassOffset; + @HotSpotVMField(name = "Klass::_next_sibling", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int nextSiblingOffset; + @HotSpotVMField(name = "Klass::_super_check_offset", type = "juint", get = HotSpotVMField.Type.OFFSET) @Stable public int superCheckOffsetOffset; + @HotSpotVMField(name = "Klass::_secondary_super_cache", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int secondarySuperCacheOffset; + @HotSpotVMField(name = "Klass::_secondary_supers", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int secondarySupersOffset; + + /** + * The offset of the _java_mirror field (of type {@link Class}) in a Klass. + */ + @HotSpotVMField(name = "Klass::_java_mirror", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int classMirrorOffset; + + @HotSpotVMField(name = "Klass::_super", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int klassSuperKlassOffset; + @HotSpotVMField(name = "Klass::_modifier_flags", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassModifierFlagsOffset; + @HotSpotVMField(name = "Klass::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int klassAccessFlagsOffset; + @HotSpotVMField(name = "Klass::_layout_helper", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassLayoutHelperOffset; + + @HotSpotVMConstant(name = "Klass::_lh_neutral_value") @Stable public int klassLayoutHelperNeutralValue; + @HotSpotVMConstant(name = "Klass::_lh_instance_slow_path_bit") @Stable public int klassLayoutHelperInstanceSlowPathBit; + @HotSpotVMConstant(name = "Klass::_lh_log2_element_size_shift") @Stable public int layoutHelperLog2ElementSizeShift; + @HotSpotVMConstant(name = "Klass::_lh_log2_element_size_mask") @Stable public int layoutHelperLog2ElementSizeMask; + @HotSpotVMConstant(name = "Klass::_lh_element_type_shift") @Stable public int layoutHelperElementTypeShift; + @HotSpotVMConstant(name = "Klass::_lh_element_type_mask") @Stable public int layoutHelperElementTypeMask; + @HotSpotVMConstant(name = "Klass::_lh_header_size_shift") @Stable public int layoutHelperHeaderSizeShift; + @HotSpotVMConstant(name = "Klass::_lh_header_size_mask") @Stable public int layoutHelperHeaderSizeMask; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_shift") @Stable public int layoutHelperArrayTagShift; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_type_value") @Stable public int layoutHelperArrayTagTypeValue; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_obj_value") @Stable public int layoutHelperArrayTagObjectValue; + + /** + * This filters out the bit that differentiates a type array from an object array. + */ + public int layoutHelperElementTypePrimitiveInPlace() { + return (layoutHelperArrayTagTypeValue & ~layoutHelperArrayTagObjectValue) << layoutHelperArrayTagShift; + } + + /** + * Bit pattern in the klass layout helper that can be used to identify arrays. + */ + public final int arrayKlassLayoutHelperIdentifier = 0x80000000; + + @HotSpotVMType(name = "vtableEntry", get = HotSpotVMType.Type.SIZE) @Stable public int vtableEntrySize; + @HotSpotVMField(name = "vtableEntry::_method", type = "Method*", get = HotSpotVMField.Type.OFFSET) @Stable public int vtableEntryMethodOffset; + + @HotSpotVMType(name = "InstanceKlass", get = HotSpotVMType.Type.SIZE) @Stable public int instanceKlassSize; + @HotSpotVMField(name = "InstanceKlass::_source_file_name_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassSourceFileNameIndexOffset; + @HotSpotVMField(name = "InstanceKlass::_init_state", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassInitStateOffset; + @HotSpotVMField(name = "InstanceKlass::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassConstantsOffset; + @HotSpotVMField(name = "InstanceKlass::_fields", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassFieldsOffset; + @HotSpotVMField(name = "InstanceKlass::_vtable_len", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassVtableLengthOffset; + + @HotSpotVMConstant(name = "InstanceKlass::linked") @Stable public int instanceKlassStateLinked; + @HotSpotVMConstant(name = "InstanceKlass::fully_initialized") @Stable public int instanceKlassStateFullyInitialized; + + /** + * See {@code InstanceKlass::vtable_start_offset()}. + */ + public final int instanceKlassVtableStartOffset() { + return roundUp(instanceKlassSize, heapWordSize); + } + + // TODO use CodeUtil method once it's moved from NumUtil + private static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } + + @HotSpotVMType(name = "arrayOopDesc", get = HotSpotVMType.Type.SIZE) @Stable public int arrayOopDescSize; + + /** + * The offset of the array length word in an array object's header. + * + * See {@code arrayOopDesc::length_offset_in_bytes()}. + */ + public final int arrayOopDescLengthOffset() { + return useCompressedClassPointers ? hubOffset + narrowKlassSize : arrayOopDescSize; + } + + @HotSpotVMField(name = "Array::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1LengthOffset; + @HotSpotVMField(name = "Array::_data", type = "", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1DataOffset; + @HotSpotVMField(name = "Array::_data", type = "", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU2DataOffset; + @HotSpotVMField(name = "Array::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayLengthOffset; + @HotSpotVMField(name = "Array::_data[0]", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayBaseOffset; + + @HotSpotVMField(name = "ObjArrayKlass::_element_klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayClassElementOffset; + + @HotSpotVMConstant(name = "FieldInfo::access_flags_offset") @Stable public int fieldInfoAccessFlagsOffset; + @HotSpotVMConstant(name = "FieldInfo::name_index_offset") @Stable public int fieldInfoNameIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::signature_index_offset") @Stable public int fieldInfoSignatureIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::initval_index_offset") @Stable public int fieldInfoInitvalIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::low_packed_offset") @Stable public int fieldInfoLowPackedOffset; + @HotSpotVMConstant(name = "FieldInfo::high_packed_offset") @Stable public int fieldInfoHighPackedOffset; + @HotSpotVMConstant(name = "FieldInfo::field_slots") @Stable public int fieldInfoFieldSlots; + + @HotSpotVMConstant(name = "FIELDINFO_TAG_SIZE") @Stable public int fieldInfoTagSize; + + @HotSpotVMConstant(name = "JVM_ACC_FIELD_INTERNAL") @Stable public int jvmAccFieldInternal; + @HotSpotVMConstant(name = "JVM_ACC_FIELD_STABLE") @Stable public int jvmAccFieldStable; + @HotSpotVMConstant(name = "JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE") @Stable public int jvmAccFieldHasGenericSignature; + @HotSpotVMConstant(name = "JVM_ACC_WRITTEN_FLAGS") @Stable public int jvmAccWrittenFlags; + + @HotSpotVMField(name = "Thread::_tlab", type = "ThreadLocalAllocBuffer", get = HotSpotVMField.Type.OFFSET) @Stable public int threadTlabOffset; + + @HotSpotVMField(name = "JavaThread::_anchor", type = "JavaFrameAnchor", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadAnchorOffset; + @HotSpotVMField(name = "JavaThread::_threadObj", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectOffset; + @HotSpotVMField(name = "JavaThread::_osthread", type = "OSThread*", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadOffset; + @HotSpotVMField(name = "JavaThread::_dirty_card_queue", type = "DirtyCardQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadDirtyCardQueueOffset; + @HotSpotVMField(name = "JavaThread::_is_method_handle_return", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int threadIsMethodHandleReturnOffset; + @HotSpotVMField(name = "JavaThread::_satb_mark_queue", type = "ObjPtrQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadSatbMarkQueueOffset; + @HotSpotVMField(name = "JavaThread::_vm_result", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectResultOffset; + @HotSpotVMField(name = "JavaThread::_jvmci_counters", type = "jlong*", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciCountersThreadOffset; + + /** + * An invalid value for {@link #rtldDefault}. + */ + public static final long INVALID_RTLD_DEFAULT_HANDLE = 0xDEADFACE; + + /** + * Address of the library lookup routine. The C signature of this routine is: + * + *
+     *     void* (const char *filename, char *ebuf, int ebuflen)
+     * 
+ */ + @HotSpotVMAddress(name = "os::dll_load") @Stable public long dllLoad; + + /** + * Address of the library lookup routine. The C signature of this routine is: + * + *
+     *     void* (void* handle, const char* name)
+     * 
+ */ + @HotSpotVMAddress(name = "os::dll_lookup") @Stable public long dllLookup; + + /** + * A pseudo-handle which when used as the first argument to {@link #dllLookup} means lookup will + * return the first occurrence of the desired symbol using the default library search order. If + * this field is {@value #INVALID_RTLD_DEFAULT_HANDLE}, then this capability is not supported on + * the current platform. + */ + @HotSpotVMAddress(name = "RTLD_DEFAULT", os = {"bsd", "linux"}) @Stable public long rtldDefault = INVALID_RTLD_DEFAULT_HANDLE; + + /** + * This field is used to pass exception objects into and out of the runtime system during + * exception handling for compiled code. + */ + @HotSpotVMField(name = "JavaThread::_exception_oop", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadExceptionOopOffset; + @HotSpotVMField(name = "JavaThread::_exception_pc", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int threadExceptionPcOffset; + @HotSpotVMField(name = "ThreadShadow::_pending_exception", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingExceptionOffset; + + @HotSpotVMField(name = "JavaThread::_pending_deoptimization", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingDeoptimizationOffset; + @HotSpotVMField(name = "JavaThread::_pending_failed_speculation", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingFailedSpeculationOffset; + @HotSpotVMField(name = "JavaThread::_pending_transfer_to_interpreter", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingTransferToInterpreterOffset; + + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_sp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaSpOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_pc", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaPcOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_fp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET, archs = {"amd64"}) @Stable private int javaFrameAnchorLastJavaFpOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_flags", type = "int", get = HotSpotVMField.Type.OFFSET, archs = {"sparc"}) @Stable private int javaFrameAnchorFlagsOffset; + + public int threadLastJavaSpOffset() { + return javaThreadAnchorOffset + javaFrameAnchorLastJavaSpOffset; + } + + public int threadLastJavaPcOffset() { + return javaThreadAnchorOffset + javaFrameAnchorLastJavaPcOffset; + } + + /** + * This value is only valid on AMD64. + */ + public int threadLastJavaFpOffset() { + // TODO add an assert for AMD64 + return javaThreadAnchorOffset + javaFrameAnchorLastJavaFpOffset; + } + + /** + * This value is only valid on SPARC. + */ + public int threadJavaFrameAnchorFlagsOffset() { + // TODO add an assert for SPARC + return javaThreadAnchorOffset + javaFrameAnchorFlagsOffset; + } + + // These are only valid on AMD64. + @HotSpotVMConstant(name = "frame::arg_reg_save_area_bytes", archs = {"amd64"}) @Stable public int runtimeCallStackSize; + @HotSpotVMConstant(name = "frame::interpreter_frame_sender_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameSenderSpOffset; + @HotSpotVMConstant(name = "frame::interpreter_frame_last_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameLastSpOffset; + + @HotSpotVMField(name = "PtrQueue::_active", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueActiveOffset; + @HotSpotVMField(name = "PtrQueue::_buf", type = "void**", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueBufferOffset; + @HotSpotVMField(name = "PtrQueue::_index", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueIndexOffset; + + @HotSpotVMField(name = "OSThread::_interrupted", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadInterruptedOffset; + + @HotSpotVMConstant(name = "markOopDesc::unlocked_value") @Stable public int unlockedMask; + @HotSpotVMConstant(name = "markOopDesc::biased_lock_mask_in_place") @Stable public int biasedLockMaskInPlace; + @HotSpotVMConstant(name = "markOopDesc::age_mask_in_place") @Stable public int ageMaskInPlace; + @HotSpotVMConstant(name = "markOopDesc::epoch_mask_in_place") @Stable public int epochMaskInPlace; + + @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public long markOopDescHashShift; + @HotSpotVMConstant(name = "markOopDesc::hash_mask") @Stable public long markOopDescHashMask; + @HotSpotVMConstant(name = "markOopDesc::hash_mask_in_place") @Stable public long markOopDescHashMaskInPlace; + + @HotSpotVMConstant(name = "markOopDesc::biased_lock_pattern") @Stable public int biasedLockPattern; + @HotSpotVMConstant(name = "markOopDesc::no_hash_in_place") @Stable public int markWordNoHashInPlace; + @HotSpotVMConstant(name = "markOopDesc::no_lock_in_place") @Stable public int markWordNoLockInPlace; + + /** + * See {@code markOopDesc::prototype()}. + */ + public long arrayPrototypeMarkWord() { + return markWordNoHashInPlace | markWordNoLockInPlace; + } + + /** + * See {@code markOopDesc::copy_set_hash()}. + */ + public long tlabIntArrayMarkWord() { + long tmp = arrayPrototypeMarkWord() & (~markOopDescHashMaskInPlace); + tmp |= ((0x2 & markOopDescHashMask) << markOopDescHashShift); + return tmp; + } + + /** + * Mark word right shift to get identity hash code. + */ + @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public int identityHashCodeShift; + + /** + * Identity hash code value when uninitialized. + */ + @HotSpotVMConstant(name = "markOopDesc::no_hash") @Stable public int uninitializedIdentityHashCodeValue; + + @HotSpotVMField(name = "Method::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int methodAccessFlagsOffset; + @HotSpotVMField(name = "Method::_constMethod", type = "ConstMethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodConstMethodOffset; + @HotSpotVMField(name = "Method::_intrinsic_id", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodIntrinsicIdOffset; + @HotSpotVMField(name = "Method::_flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodFlagsOffset; + @HotSpotVMField(name = "Method::_vtable_index", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodVtableIndexOffset; + + @HotSpotVMConstant(name = "Method::_jfr_towrite") @Stable public int methodFlagsJfrTowrite; + @HotSpotVMConstant(name = "Method::_caller_sensitive") @Stable public int methodFlagsCallerSensitive; + @HotSpotVMConstant(name = "Method::_force_inline") @Stable public int methodFlagsForceInline; + @HotSpotVMConstant(name = "Method::_dont_inline") @Stable public int methodFlagsDontInline; + @HotSpotVMConstant(name = "Method::_hidden") @Stable public int methodFlagsHidden; + @HotSpotVMConstant(name = "Method::nonvirtual_vtable_index") @Stable public int nonvirtualVtableIndex; + @HotSpotVMConstant(name = "Method::invalid_vtable_index") @Stable public int invalidVtableIndex; + + @HotSpotVMConstant(name = "InvocationEntryBci") @Stable public int invocationEntryBci; + + @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch; + @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes; + + @HotSpotVMField(name = "JVMCIEnv::_task", type = "CompileTask*", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciEnvTaskOffset; + @HotSpotVMField(name = "JVMCIEnv::_jvmti_can_hotswap_or_post_breakpoint", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciEnvJvmtiCanHotswapOrPostBreakpointOffset; + @HotSpotVMField(name = "CompileTask::_num_inlined_bytecodes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskNumInlinedBytecodesOffset; + + /** + * See {@code Method::extra_stack_entries()}. + */ + @HotSpotVMConstant(name = "Method::extra_stack_entries_for_jsr292") @Stable public int extraStackEntries; + + @HotSpotVMField(name = "ConstMethod::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodConstantsOffset; + @HotSpotVMField(name = "ConstMethod::_flags", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodFlagsOffset; + @HotSpotVMField(name = "ConstMethod::_code_size", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodCodeSizeOffset; + @HotSpotVMField(name = "ConstMethod::_name_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodNameIndexOffset; + @HotSpotVMField(name = "ConstMethod::_signature_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodSignatureIndexOffset; + @HotSpotVMField(name = "ConstMethod::_max_stack", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodMaxStackOffset; + @HotSpotVMField(name = "ConstMethod::_max_locals", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int methodMaxLocalsOffset; + + @HotSpotVMConstant(name = "ConstMethod::_has_linenumber_table") @Stable public int constMethodHasLineNumberTable; + @HotSpotVMConstant(name = "ConstMethod::_has_localvariable_table") @Stable public int constMethodHasLocalVariableTable; + @HotSpotVMConstant(name = "ConstMethod::_has_exception_table") @Stable public int constMethodHasExceptionTable; + + @HotSpotVMType(name = "ExceptionTableElement", get = HotSpotVMType.Type.SIZE) @Stable public int exceptionTableElementSize; + @HotSpotVMField(name = "ExceptionTableElement::start_pc", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementStartPcOffset; + @HotSpotVMField(name = "ExceptionTableElement::end_pc", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementEndPcOffset; + @HotSpotVMField(name = "ExceptionTableElement::handler_pc", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementHandlerPcOffset; + @HotSpotVMField(name = "ExceptionTableElement::catch_type_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementCatchTypeIndexOffset; + + @HotSpotVMType(name = "LocalVariableTableElement", get = HotSpotVMType.Type.SIZE) @Stable public int localVariableTableElementSize; + @HotSpotVMField(name = "LocalVariableTableElement::start_bci", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementStartBciOffset; + @HotSpotVMField(name = "LocalVariableTableElement::length", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementLengthOffset; + @HotSpotVMField(name = "LocalVariableTableElement::name_cp_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementNameCpIndexOffset; + @HotSpotVMField(name = "LocalVariableTableElement::descriptor_cp_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementDescriptorCpIndexOffset; + @HotSpotVMField(name = "LocalVariableTableElement::signature_cp_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementSignatureCpIndexOffset; + @HotSpotVMField(name = "LocalVariableTableElement::slot", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementSlotOffset; + + @HotSpotVMType(name = "ConstantPool", get = HotSpotVMType.Type.SIZE) @Stable public int constantPoolSize; + @HotSpotVMField(name = "ConstantPool::_tags", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolTagsOffset; + @HotSpotVMField(name = "ConstantPool::_pool_holder", type = "InstanceKlass*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolHolderOffset; + @HotSpotVMField(name = "ConstantPool::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolLengthOffset; + + @HotSpotVMConstant(name = "ConstantPool::CPCACHE_INDEX_TAG") @Stable public int constantPoolCpCacheIndexTag; + + @HotSpotVMConstant(name = "JVM_CONSTANT_Utf8") @Stable public int jvmConstantUtf8; + @HotSpotVMConstant(name = "JVM_CONSTANT_Integer") @Stable public int jvmConstantInteger; + @HotSpotVMConstant(name = "JVM_CONSTANT_Long") @Stable public int jvmConstantLong; + @HotSpotVMConstant(name = "JVM_CONSTANT_Float") @Stable public int jvmConstantFloat; + @HotSpotVMConstant(name = "JVM_CONSTANT_Double") @Stable public int jvmConstantDouble; + @HotSpotVMConstant(name = "JVM_CONSTANT_Class") @Stable public int jvmConstantClass; + @HotSpotVMConstant(name = "JVM_CONSTANT_UnresolvedClass") @Stable public int jvmConstantUnresolvedClass; + @HotSpotVMConstant(name = "JVM_CONSTANT_UnresolvedClassInError") @Stable public int jvmConstantUnresolvedClassInError; + @HotSpotVMConstant(name = "JVM_CONSTANT_String") @Stable public int jvmConstantString; + @HotSpotVMConstant(name = "JVM_CONSTANT_Fieldref") @Stable public int jvmConstantFieldref; + @HotSpotVMConstant(name = "JVM_CONSTANT_Methodref") @Stable public int jvmConstantMethodref; + @HotSpotVMConstant(name = "JVM_CONSTANT_InterfaceMethodref") @Stable public int jvmConstantInterfaceMethodref; + @HotSpotVMConstant(name = "JVM_CONSTANT_NameAndType") @Stable public int jvmConstantNameAndType; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodHandle") @Stable public int jvmConstantMethodHandle; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodHandleInError") @Stable public int jvmConstantMethodHandleInError; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodType") @Stable public int jvmConstantMethodType; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodTypeInError") @Stable public int jvmConstantMethodTypeInError; + @HotSpotVMConstant(name = "JVM_CONSTANT_InvokeDynamic") @Stable public int jvmConstantInvokeDynamic; + + @HotSpotVMConstant(name = "JVM_CONSTANT_ExternalMax") @Stable public int jvmConstantExternalMax; + @HotSpotVMConstant(name = "JVM_CONSTANT_InternalMin") @Stable public int jvmConstantInternalMin; + @HotSpotVMConstant(name = "JVM_CONSTANT_InternalMax") @Stable public int jvmConstantInternalMax; + + @HotSpotVMConstant(name = "HeapWordSize") @Stable public int heapWordSize; + + @HotSpotVMType(name = "Symbol*", get = HotSpotVMType.Type.SIZE) @Stable public int symbolPointerSize; + @HotSpotVMField(name = "Symbol::_length", type = "unsigned short", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolLengthOffset; + @HotSpotVMField(name = "Symbol::_body[0]", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolBodyOffset; + + @HotSpotVMField(name = "vmSymbols::_symbols[0]", type = "Symbol*", get = HotSpotVMField.Type.ADDRESS) @Stable public long vmSymbolsSymbols; + @HotSpotVMConstant(name = "vmSymbols::FIRST_SID") @Stable public int vmSymbolsFirstSID; + @HotSpotVMConstant(name = "vmSymbols::SID_LIMIT") @Stable public int vmSymbolsSIDLimit; + + @HotSpotVMConstant(name = "JVM_ACC_HAS_FINALIZER") @Stable public int klassHasFinalizerFlag; + + // Modifier.SYNTHETIC is not public so we get it via vmStructs. + @HotSpotVMConstant(name = "JVM_ACC_SYNTHETIC") @Stable public int syntheticFlag; + + /** + * @see HotSpotResolvedObjectTypeImpl#createField + */ + @HotSpotVMConstant(name = "JVM_RECOGNIZED_FIELD_MODIFIERS") @Stable public int recognizedFieldModifiers; + + /** + * Bit pattern that represents a non-oop. Neither the high bits nor the low bits of this value + * are allowed to look like (respectively) the high or low bits of a real oop. + */ + @HotSpotVMField(name = "Universe::_non_oop_bits", type = "intptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long nonOopBits; + + @HotSpotVMField(name = "StubRoutines::_verify_oop_count", type = "jint", get = HotSpotVMField.Type.ADDRESS) @Stable public long verifyOopCounterAddress; + @HotSpotVMField(name = "Universe::_verify_oop_mask", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopMask; + @HotSpotVMField(name = "Universe::_verify_oop_bits", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopBits; + @HotSpotVMField(name = "Universe::_base_vtable_size", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int universeBaseVtableSize; + + public final int baseVtableLength() { + return universeBaseVtableSize / vtableEntrySize; + } + + @HotSpotVMField(name = "CollectedHeap::_barrier_set", type = "BarrierSet*", get = HotSpotVMField.Type.OFFSET) @Stable public int collectedHeapBarrierSetOffset; + + @HotSpotVMField(name = "HeapRegion::LogOfHRGrainBytes", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int logOfHRGrainBytes; + + @HotSpotVMField(name = "BarrierSet::_fake_rtti", type = "BarrierSet::FakeRtti", get = HotSpotVMField.Type.OFFSET) @Stable private int barrierSetFakeRttiOffset; + @HotSpotVMConstant(name = "BarrierSet::CardTableModRef") @Stable public int barrierSetCardTableModRef; + @HotSpotVMConstant(name = "BarrierSet::CardTableForRS") @Stable public int barrierSetCardTableForRS; + @HotSpotVMConstant(name = "BarrierSet::CardTableExtension") @Stable public int barrierSetCardTableExtension; + @HotSpotVMConstant(name = "BarrierSet::G1SATBCT") @Stable public int barrierSetG1SATBCT; + @HotSpotVMConstant(name = "BarrierSet::G1SATBCTLogging") @Stable public int barrierSetG1SATBCTLogging; + @HotSpotVMConstant(name = "BarrierSet::ModRef") @Stable public int barrierSetModRef; + + @HotSpotVMField(name = "BarrierSet::FakeRtti::_concrete_tag", type = "BarrierSet::Name", get = HotSpotVMField.Type.OFFSET) @Stable private int fakeRttiConcreteTagOffset; + + @HotSpotVMField(name = "CardTableModRefBS::byte_map_base", type = "jbyte*", get = HotSpotVMField.Type.OFFSET) @Stable private int cardTableModRefBSByteMapBaseOffset; + @HotSpotVMConstant(name = "CardTableModRefBS::card_shift") @Stable public int cardTableModRefBSCardShift; + + @HotSpotVMConstant(name = "CardTableModRefBS::dirty_card") @Stable public byte dirtyCardValue; + @HotSpotVMConstant(name = "G1SATBCardTableModRefBS::g1_young_gen") @Stable public byte g1YoungCardValue; + + private final long cardtableStartAddress; + private final int cardtableShift; + + public long cardtableStartAddress() { + if (cardtableStartAddress == -1) { + throw JVMCIError.shouldNotReachHere(); + } + return cardtableStartAddress; + } + + public int cardtableShift() { + if (cardtableShift == -1) { + throw JVMCIError.shouldNotReachHere(); + } + return cardtableShift; + } + + @HotSpotVMField(name = "os::_polling_page", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long safepointPollingAddress; + + // G1 Collector Related Values. + + public int g1CardQueueIndexOffset() { + return javaThreadDirtyCardQueueOffset + ptrQueueIndexOffset; + } + + public int g1CardQueueBufferOffset() { + return javaThreadDirtyCardQueueOffset + ptrQueueBufferOffset; + } + + public int g1SATBQueueMarkingOffset() { + return javaThreadSatbMarkQueueOffset + ptrQueueActiveOffset; + } + + public int g1SATBQueueIndexOffset() { + return javaThreadSatbMarkQueueOffset + ptrQueueIndexOffset; + } + + public int g1SATBQueueBufferOffset() { + return javaThreadSatbMarkQueueOffset + ptrQueueBufferOffset; + } + + @HotSpotVMField(name = "java_lang_Class::_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int klassOffset; + @HotSpotVMField(name = "java_lang_Class::_array_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int arrayKlassOffset; + + @HotSpotVMField(name = "Method::_method_counters", type = "MethodCounters*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCountersOffset; + @HotSpotVMField(name = "Method::_method_data", type = "MethodData*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOffset; + @HotSpotVMField(name = "Method::_from_compiled_entry", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCompiledEntryOffset; + @HotSpotVMField(name = "Method::_code", type = "nmethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCodeOffset; + + @HotSpotVMField(name = "MethodCounters::_invocation_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int invocationCounterOffset; + @HotSpotVMField(name = "MethodCounters::_backedge_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int backedgeCounterOffset; + @HotSpotVMConstant(name = "InvocationCounter::count_increment") @Stable public int invocationCounterIncrement; + @HotSpotVMConstant(name = "InvocationCounter::count_shift") @Stable public int invocationCounterShift; + + @HotSpotVMField(name = "MethodData::_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataSize; + @HotSpotVMField(name = "MethodData::_data_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataDataSize; + @HotSpotVMField(name = "MethodData::_data[0]", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopDataOffset; + @HotSpotVMField(name = "MethodData::_trap_hist._array[0]", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopTrapHistoryOffset; + @HotSpotVMField(name = "MethodData::_jvmci_ir_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataIRSizeOffset; + + @HotSpotVMField(name = "nmethod::_verified_entry_point", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodEntryOffset; + @HotSpotVMField(name = "nmethod::_comp_level", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodCompLevelOffset; + + @HotSpotVMConstant(name = "CompLevel_full_optimization") @Stable public int compilationLevelFullOptimization; + + @HotSpotVMType(name = "BasicLock", get = HotSpotVMType.Type.SIZE) @Stable public int basicLockSize; + @HotSpotVMField(name = "BasicLock::_displaced_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int basicLockDisplacedHeaderOffset; + + @HotSpotVMField(name = "Thread::_allocated_bytes", type = "jlong", get = HotSpotVMField.Type.OFFSET) @Stable public int threadAllocatedBytesOffset; + + @HotSpotVMFlag(name = "TLABWasteIncrement") @Stable public int tlabRefillWasteIncrement; + + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_start", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferStartOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_end", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferEndOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_top", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferTopOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_pf_top", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferPfTopOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_slow_allocations", type = "unsigned", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferSlowAllocationsOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_fast_refill_waste", type = "unsigned", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferFastRefillWasteOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_number_of_refills", type = "unsigned", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferNumberOfRefillsOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_refill_waste_limit", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferRefillWasteLimitOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_desired_size", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferDesiredSizeOffset; + + public int tlabSlowAllocationsOffset() { + return threadTlabOffset + threadLocalAllocBufferSlowAllocationsOffset; + } + + public int tlabFastRefillWasteOffset() { + return threadTlabOffset + threadLocalAllocBufferFastRefillWasteOffset; + } + + public int tlabNumberOfRefillsOffset() { + return threadTlabOffset + threadLocalAllocBufferNumberOfRefillsOffset; + } + + public int tlabRefillWasteLimitOffset() { + return threadTlabOffset + threadLocalAllocBufferRefillWasteLimitOffset; + } + + public int threadTlabSizeOffset() { + return threadTlabOffset + threadLocalAllocBufferDesiredSizeOffset; + } + + public int threadTlabStartOffset() { + return threadTlabOffset + threadLocalAllocBufferStartOffset; + } + + public int threadTlabEndOffset() { + return threadTlabOffset + threadLocalAllocBufferEndOffset; + } + + public int threadTlabTopOffset() { + return threadTlabOffset + threadLocalAllocBufferTopOffset; + } + + public int threadTlabPfTopOffset() { + return threadTlabOffset + threadLocalAllocBufferPfTopOffset; + } + + /** + * See: {@code ThreadLocalAllocBuffer::end_reserve()}. + */ + public final int threadLocalAllocBufferEndReserve() { + final int typeSizeInBytes = roundUp(arrayOopDescLengthOffset() + Integer.BYTES, heapWordSize); + // T_INT arrays need not be 8 byte aligned. + final int reserveSize = typeSizeInBytes / heapWordSize; + return Integer.max(reserveSize, abstractVmVersionReserveForAllocationPrefetch); + } + + /** + * See: {@code ThreadLocalAllocBuffer::alignment_reserve()}. + */ + public final int tlabAlignmentReserve() { + return roundUp(threadLocalAllocBufferEndReserve(), minObjAlignment()); + } + + @HotSpotVMFlag(name = "TLABStats") @Stable public boolean tlabStats; + + // FIXME This is only temporary until the GC code is changed. + @HotSpotVMField(name = "CompilerToVM::_supports_inline_contig_alloc", type = "bool", get = HotSpotVMField.Type.VALUE) @Stable public boolean inlineContiguousAllocationSupported; + @HotSpotVMField(name = "CompilerToVM::_heap_end_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapEndAddress; + @HotSpotVMField(name = "CompilerToVM::_heap_top_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapTopAddress; + + /** + * The DataLayout header size is the same as the cell size. + */ + @HotSpotVMConstant(name = "DataLayout::cell_size") @Stable public int dataLayoutHeaderSize; + @HotSpotVMField(name = "DataLayout::_header._struct._tag", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutTagOffset; + @HotSpotVMField(name = "DataLayout::_header._struct._flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutFlagsOffset; + @HotSpotVMField(name = "DataLayout::_header._struct._bci", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutBCIOffset; + @HotSpotVMField(name = "DataLayout::_cells[0]", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutCellsOffset; + @HotSpotVMConstant(name = "DataLayout::cell_size") @Stable public int dataLayoutCellSize; + + @HotSpotVMConstant(name = "DataLayout::no_tag") @Stable public int dataLayoutNoTag; + @HotSpotVMConstant(name = "DataLayout::bit_data_tag") @Stable public int dataLayoutBitDataTag; + @HotSpotVMConstant(name = "DataLayout::counter_data_tag") @Stable public int dataLayoutCounterDataTag; + @HotSpotVMConstant(name = "DataLayout::jump_data_tag") @Stable public int dataLayoutJumpDataTag; + @HotSpotVMConstant(name = "DataLayout::receiver_type_data_tag") @Stable public int dataLayoutReceiverTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::virtual_call_data_tag") @Stable public int dataLayoutVirtualCallDataTag; + @HotSpotVMConstant(name = "DataLayout::ret_data_tag") @Stable public int dataLayoutRetDataTag; + @HotSpotVMConstant(name = "DataLayout::branch_data_tag") @Stable public int dataLayoutBranchDataTag; + @HotSpotVMConstant(name = "DataLayout::multi_branch_data_tag") @Stable public int dataLayoutMultiBranchDataTag; + @HotSpotVMConstant(name = "DataLayout::arg_info_data_tag") @Stable public int dataLayoutArgInfoDataTag; + @HotSpotVMConstant(name = "DataLayout::call_type_data_tag") @Stable public int dataLayoutCallTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::virtual_call_type_data_tag") @Stable public int dataLayoutVirtualCallTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::parameters_type_data_tag") @Stable public int dataLayoutParametersTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::speculative_trap_data_tag") @Stable public int dataLayoutSpeculativeTrapDataTag; + + @HotSpotVMFlag(name = "BciProfileWidth") @Stable public int bciProfileWidth; + @HotSpotVMFlag(name = "TypeProfileWidth") @Stable public int typeProfileWidth; + @HotSpotVMFlag(name = "MethodProfileWidth") @Stable public int methodProfileWidth; + + @HotSpotVMField(name = "CodeBlob::_code_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int codeBlobCodeOffsetOffset; + @HotSpotVMField(name = "DeoptimizationBlob::_unpack_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int deoptimizationBlobUnpackOffsetOffset; + @HotSpotVMField(name = "DeoptimizationBlob::_uncommon_trap_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int deoptimizationBlobUncommonTrapOffsetOffset; + + @HotSpotVMField(name = "SharedRuntime::_ic_miss_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long inlineCacheMissBlob; + @HotSpotVMField(name = "SharedRuntime::_wrong_method_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long wrongMethodBlob; + @HotSpotVMField(name = "SharedRuntime::_deopt_blob", type = "DeoptimizationBlob*", get = HotSpotVMField.Type.VALUE) @Stable private long deoptBlob; + + @HotSpotVMManual(name = "SharedRuntime::get_ic_miss_stub()") public final long inlineCacheMissStub; + @HotSpotVMManual(name = "SharedRuntime::get_handle_wrong_method_stub()") public final long handleWrongMethodStub; + + @HotSpotVMManual(name = "SharedRuntime::deopt_blob()->unpack()") public final long handleDeoptStub; + @HotSpotVMManual(name = "SharedRuntime::deopt_blob()->uncommon_trap()") public final long uncommonTrapStub; + + @HotSpotVMField(name = "CodeCache::_low_bound", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long codeCacheLowBound; + @HotSpotVMField(name = "CodeCache::_high_bound", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long codeCacheHighBound; + + @HotSpotVMField(name = "StubRoutines::_aescrypt_encryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptEncryptBlockStub; + @HotSpotVMField(name = "StubRoutines::_aescrypt_decryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptDecryptBlockStub; + @HotSpotVMField(name = "StubRoutines::_cipherBlockChaining_encryptAESCrypt", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long cipherBlockChainingEncryptAESCryptStub; + @HotSpotVMField(name = "StubRoutines::_cipherBlockChaining_decryptAESCrypt", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long cipherBlockChainingDecryptAESCryptStub; + @HotSpotVMField(name = "StubRoutines::_updateBytesCRC32", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long updateBytesCRC32Stub; + @HotSpotVMField(name = "StubRoutines::_crc_table_adr", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long crcTableAddress; + + @HotSpotVMField(name = "StubRoutines::_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteArraycopy; + @HotSpotVMField(name = "StubRoutines::_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortArraycopy; + @HotSpotVMField(name = "StubRoutines::_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintArraycopy; + @HotSpotVMField(name = "StubRoutines::_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopDisjointArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedDisjointArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopy; + @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_unsafe_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long unsafeArraycopy; + @HotSpotVMField(name = "StubRoutines::_generic_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long genericArraycopy; + + @HotSpotVMAddress(name = "JVMCIRuntime::new_instance") @Stable public long newInstanceAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::new_array") @Stable public long newArrayAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::new_multi_array") @Stable public long newMultiArrayAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::dynamic_new_array") @Stable public long dynamicNewArrayAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::dynamic_new_instance") @Stable public long dynamicNewInstanceAddress; + + @HotSpotVMAddress(name = "JVMCIRuntime::thread_is_interrupted") @Stable public long threadIsInterruptedAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::vm_message") @Stable public long vmMessageAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::identity_hash_code") @Stable public long identityHashCodeAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::exception_handler_for_pc") @Stable public long exceptionHandlerForPcAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::monitorenter") @Stable public long monitorenterAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::monitorexit") @Stable public long monitorexitAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::create_null_exception") @Stable public long createNullPointerExceptionAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::create_out_of_bounds_exception") @Stable public long createOutOfBoundsExceptionAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::log_primitive") @Stable public long logPrimitiveAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::log_object") @Stable public long logObjectAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::log_printf") @Stable public long logPrintfAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::vm_error") @Stable public long vmErrorAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::load_and_clear_exception") @Stable public long loadAndClearExceptionAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::write_barrier_pre") @Stable public long writeBarrierPreAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::write_barrier_post") @Stable public long writeBarrierPostAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::validate_object") @Stable public long validateObject; + + @HotSpotVMAddress(name = "JVMCIRuntime::test_deoptimize_call_int") @Stable public long testDeoptimizeCallInt; + + @HotSpotVMAddress(name = "SharedRuntime::register_finalizer") @Stable public long registerFinalizerAddress; + @HotSpotVMAddress(name = "SharedRuntime::exception_handler_for_return_address") @Stable public long exceptionHandlerForReturnAddressAddress; + @HotSpotVMAddress(name = "SharedRuntime::OSR_migration_end") @Stable public long osrMigrationEndAddress; + + @HotSpotVMAddress(name = "os::javaTimeMillis") @Stable public long javaTimeMillisAddress; + @HotSpotVMAddress(name = "os::javaTimeNanos") @Stable public long javaTimeNanosAddress; + @HotSpotVMAddress(name = "SharedRuntime::dsin") @Stable public long arithmeticSinAddress; + @HotSpotVMAddress(name = "SharedRuntime::dcos") @Stable public long arithmeticCosAddress; + @HotSpotVMAddress(name = "SharedRuntime::dtan") @Stable public long arithmeticTanAddress; + @HotSpotVMAddress(name = "SharedRuntime::dexp") @Stable public long arithmeticExpAddress; + @HotSpotVMAddress(name = "SharedRuntime::dlog") @Stable public long arithmeticLogAddress; + @HotSpotVMAddress(name = "SharedRuntime::dlog10") @Stable public long arithmeticLog10Address; + @HotSpotVMAddress(name = "SharedRuntime::dpow") @Stable public long arithmeticPowAddress; + + @HotSpotVMFlag(name = "JVMCICounterSize") @Stable public int jvmciCountersSize; + + @HotSpotVMAddress(name = "Deoptimization::fetch_unroll_info") @Stable public long deoptimizationFetchUnrollInfo; + @HotSpotVMAddress(name = "Deoptimization::uncommon_trap") @Stable public long deoptimizationUncommonTrap; + @HotSpotVMAddress(name = "Deoptimization::unpack_frames") @Stable public long deoptimizationUnpackFrames; + + @HotSpotVMConstant(name = "Deoptimization::Reason_none") @Stable public int deoptReasonNone; + @HotSpotVMConstant(name = "Deoptimization::Reason_null_check") @Stable public int deoptReasonNullCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_range_check") @Stable public int deoptReasonRangeCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_class_check") @Stable public int deoptReasonClassCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_array_check") @Stable public int deoptReasonArrayCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_unreached0") @Stable public int deoptReasonUnreached0; + @HotSpotVMConstant(name = "Deoptimization::Reason_type_checked_inlining") @Stable public int deoptReasonTypeCheckInlining; + @HotSpotVMConstant(name = "Deoptimization::Reason_optimized_type_check") @Stable public int deoptReasonOptimizedTypeCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_not_compiled_exception_handler") @Stable public int deoptReasonNotCompiledExceptionHandler; + @HotSpotVMConstant(name = "Deoptimization::Reason_unresolved") @Stable public int deoptReasonUnresolved; + @HotSpotVMConstant(name = "Deoptimization::Reason_jsr_mismatch") @Stable public int deoptReasonJsrMismatch; + @HotSpotVMConstant(name = "Deoptimization::Reason_div0_check") @Stable public int deoptReasonDiv0Check; + @HotSpotVMConstant(name = "Deoptimization::Reason_constraint") @Stable public int deoptReasonConstraint; + @HotSpotVMConstant(name = "Deoptimization::Reason_loop_limit_check") @Stable public int deoptReasonLoopLimitCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_aliasing") @Stable public int deoptReasonAliasing; + @HotSpotVMConstant(name = "Deoptimization::Reason_transfer_to_interpreter") @Stable public int deoptReasonTransferToInterpreter; + @HotSpotVMConstant(name = "Deoptimization::Reason_LIMIT") @Stable public int deoptReasonOSROffset; + + @HotSpotVMConstant(name = "Deoptimization::Action_none") @Stable public int deoptActionNone; + @HotSpotVMConstant(name = "Deoptimization::Action_maybe_recompile") @Stable public int deoptActionMaybeRecompile; + @HotSpotVMConstant(name = "Deoptimization::Action_reinterpret") @Stable public int deoptActionReinterpret; + @HotSpotVMConstant(name = "Deoptimization::Action_make_not_entrant") @Stable public int deoptActionMakeNotEntrant; + @HotSpotVMConstant(name = "Deoptimization::Action_make_not_compilable") @Stable public int deoptActionMakeNotCompilable; + + @HotSpotVMConstant(name = "Deoptimization::_action_bits") @Stable public int deoptimizationActionBits; + @HotSpotVMConstant(name = "Deoptimization::_reason_bits") @Stable public int deoptimizationReasonBits; + @HotSpotVMConstant(name = "Deoptimization::_debug_id_bits") @Stable public int deoptimizationDebugIdBits; + @HotSpotVMConstant(name = "Deoptimization::_action_shift") @Stable public int deoptimizationActionShift; + @HotSpotVMConstant(name = "Deoptimization::_reason_shift") @Stable public int deoptimizationReasonShift; + @HotSpotVMConstant(name = "Deoptimization::_debug_id_shift") @Stable public int deoptimizationDebugIdShift; + + @HotSpotVMConstant(name = "Deoptimization::Unpack_deopt") @Stable public int deoptimizationUnpackDeopt; + @HotSpotVMConstant(name = "Deoptimization::Unpack_exception") @Stable public int deoptimizationUnpackException; + @HotSpotVMConstant(name = "Deoptimization::Unpack_uncommon_trap") @Stable public int deoptimizationUnpackUncommonTrap; + @HotSpotVMConstant(name = "Deoptimization::Unpack_reexecute") @Stable public int deoptimizationUnpackReexecute; + + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_size_of_deoptimized_frame", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_caller_adjustment", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockCallerAdjustmentOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_number_of_frames", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockNumberOfFramesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_total_frame_sizes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockTotalFrameSizesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_sizes", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFrameSizesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_pcs", type = "address*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFramePcsOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_initial_info", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockInitialInfoOffset; + + @HotSpotVMConstant(name = "vmIntrinsics::_invokeBasic") @Stable public int vmIntrinsicInvokeBasic; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToVirtual") @Stable public int vmIntrinsicLinkToVirtual; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToStatic") @Stable public int vmIntrinsicLinkToStatic; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToSpecial") @Stable public int vmIntrinsicLinkToSpecial; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToInterface") @Stable public int vmIntrinsicLinkToInterface; + + @HotSpotVMConstant(name = "JVMCIEnv::ok") @Stable public int codeInstallResultOk; + @HotSpotVMConstant(name = "JVMCIEnv::dependencies_failed") @Stable public int codeInstallResultDependenciesFailed; + @HotSpotVMConstant(name = "JVMCIEnv::dependencies_invalid") @Stable public int codeInstallResultDependenciesInvalid; + @HotSpotVMConstant(name = "JVMCIEnv::cache_full") @Stable public int codeInstallResultCacheFull; + @HotSpotVMConstant(name = "JVMCIEnv::code_too_large") @Stable public int codeInstallResultCodeTooLarge; + + public String getCodeInstallResultDescription(int codeInstallResult) { + if (codeInstallResult == codeInstallResultOk) { + return "ok"; + } + if (codeInstallResult == codeInstallResultDependenciesFailed) { + return "dependencies failed"; + } + if (codeInstallResult == codeInstallResultDependenciesInvalid) { + return "dependencies invalid"; + } + if (codeInstallResult == codeInstallResultCacheFull) { + return "code cache is full"; + } + if (codeInstallResult == codeInstallResultCodeTooLarge) { + return "code is too large"; + } + assert false : codeInstallResult; + return "unknown"; + } + + @HotSpotVMConstant(name = "CompilerToVM::KLASS_TAG") @Stable public int compilerToVMKlassTag; + @HotSpotVMConstant(name = "CompilerToVM::SYMBOL_TAG") @Stable public int compilerToVMSymbolTag; + + // Checkstyle: stop + @HotSpotVMConstant(name = "CodeInstaller::VERIFIED_ENTRY") @Stable public int MARKID_VERIFIED_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::UNVERIFIED_ENTRY") @Stable public int MARKID_UNVERIFIED_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::OSR_ENTRY") @Stable public int MARKID_OSR_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::EXCEPTION_HANDLER_ENTRY") @Stable public int MARKID_EXCEPTION_HANDLER_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::DEOPT_HANDLER_ENTRY") @Stable public int MARKID_DEOPT_HANDLER_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::INVOKEINTERFACE") @Stable public int MARKID_INVOKEINTERFACE; + @HotSpotVMConstant(name = "CodeInstaller::INVOKEVIRTUAL") @Stable public int MARKID_INVOKEVIRTUAL; + @HotSpotVMConstant(name = "CodeInstaller::INVOKESTATIC") @Stable public int MARKID_INVOKESTATIC; + @HotSpotVMConstant(name = "CodeInstaller::INVOKESPECIAL") @Stable public int MARKID_INVOKESPECIAL; + @HotSpotVMConstant(name = "CodeInstaller::INLINE_INVOKE") @Stable public int MARKID_INLINE_INVOKE; + @HotSpotVMConstant(name = "CodeInstaller::POLL_NEAR") @Stable public int MARKID_POLL_NEAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_NEAR") @Stable public int MARKID_POLL_RETURN_NEAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_FAR") @Stable public int MARKID_POLL_FAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_FAR") @Stable public int MARKID_POLL_RETURN_FAR; + @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_ADDRESS") @Stable public int MARKID_CARD_TABLE_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::HEAP_TOP_ADDRESS") @Stable public int MARKID_HEAP_TOP_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::HEAP_END_ADDRESS") @Stable public int MARKID_HEAP_END_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::NARROW_KLASS_BASE_ADDRESS") @Stable public int MARKID_NARROW_KLASS_BASE_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::CRC_TABLE_ADDRESS") @Stable public int MARKID_CRC_TABLE_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::INVOKE_INVALID") @Stable public int MARKID_INVOKE_INVALID; + + // Checkstyle: resume + + private boolean check() { + for (Field f : getClass().getDeclaredFields()) { + int modifiers = f.getModifiers(); + if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) { + assert Modifier.isFinal(modifiers) || f.getAnnotation(Stable.class) != null : "field should either be final or @Stable: " + f; + } + } + + assert codeEntryAlignment > 0 : codeEntryAlignment; + assert (layoutHelperArrayTagObjectValue & (1 << (Integer.SIZE - 1))) != 0 : "object array must have first bit set"; + assert (layoutHelperArrayTagTypeValue & (1 << (Integer.SIZE - 1))) != 0 : "type array must have first bit set"; + + return true; + } + + /** + * A compact representation of the different encoding strategies for Objects and metadata. + */ + public static class CompressEncoding { + public final long base; + public final int shift; + public final int alignment; + + CompressEncoding(long base, int shift, int alignment) { + this.base = base; + this.shift = shift; + this.alignment = alignment; + } + + public int compress(long ptr) { + if (ptr == 0L) { + return 0; + } else { + return (int) ((ptr - base) >>> shift); + } + } + + public long uncompress(int ptr) { + if (ptr == 0) { + return 0L; + } else { + return ((ptr & 0xFFFFFFFFL) << shift) + base; + } + } + + @Override + public String toString() { + return "base: " + base + " shift: " + shift + " alignment: " + alignment; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + alignment; + result = prime * result + (int) (base ^ (base >>> 32)); + result = prime * result + shift; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CompressEncoding) { + CompressEncoding other = (CompressEncoding) obj; + return alignment == other.alignment && base == other.base && shift == other.shift; + } else { + return false; + } + } + } + +} --- /dev/null 2015-09-16 15:20:23.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVMConfigVerifier.java 2015-09-16 15:20:23.000000000 -0700 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static java.lang.String.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.common.*; +import jdk.internal.org.objectweb.asm.*; +import jdk.internal.org.objectweb.asm.Type; +import sun.misc.*; + +/** + * A {@link ClassVisitor} that verifies {@link HotSpotVMConfig} does not access {@link Unsafe} from + * any of its non-static, non-constructor methods. This ensures that a deserialized + * {@link HotSpotVMConfig} object does not perform any unsafe reads on addresses that are only valid + * in the context in which the object was serialized. Note that this does not catch cases where a + * client uses an address stored in a {@link HotSpotVMConfig} field. + */ +final class HotSpotVMConfigVerifier extends ClassVisitor { + + public static boolean check() { + Class cls = HotSpotVMConfig.class; + String classFilePath = "/" + cls.getName().replace('.', '/') + ".class"; + try { + InputStream classfile = cls.getResourceAsStream(classFilePath); + ClassReader cr = new ClassReader(Objects.requireNonNull(classfile, "Could not find class file for " + cls.getName())); + ClassVisitor cv = new HotSpotVMConfigVerifier(); + cr.accept(cv, 0); + return true; + } catch (IOException e) { + throw new JVMCIError(e); + } + } + + /** + * Source file context for error reporting. + */ + String sourceFile = null; + + /** + * Line number for error reporting. + */ + int lineNo = -1; + + private static Class resolve(String name) { + try { + return Class.forName(name.replace('/', '.')); + } catch (ClassNotFoundException e) { + throw new JVMCIError(e); + } + } + + HotSpotVMConfigVerifier() { + super(Opcodes.ASM5); + } + + @Override + public void visitSource(String source, String debug) { + this.sourceFile = source; + } + + void verify(boolean condition, String message) { + if (!condition) { + error(message); + } + } + + void error(String message) { + String errorMessage = format("%s:%d: %s is not allowed in the context of compilation replay. The unsafe access should be moved into the %s constructor and the result cached in a field", + sourceFile, lineNo, message, HotSpotVMConfig.class.getSimpleName()); + throw new JVMCIError(errorMessage); + + } + + @Override + public MethodVisitor visitMethod(int access, String name, String d, String signature, String[] exceptions) { + if (!Modifier.isStatic(access) && Modifier.isPublic(access) && !name.equals("")) { + return new MethodVisitor(Opcodes.ASM5) { + + @Override + public void visitLineNumber(int line, Label start) { + lineNo = line; + } + + private Executable resolveMethod(String owner, String methodName, String methodDesc) { + Class declaringClass = resolve(owner); + while (declaringClass != null) { + if (methodName.equals("")) { + for (Constructor c : declaringClass.getDeclaredConstructors()) { + if (methodDesc.equals(Type.getConstructorDescriptor(c))) { + return c; + } + } + } else { + Type[] argumentTypes = Type.getArgumentTypes(methodDesc); + for (Method m : declaringClass.getDeclaredMethods()) { + if (m.getName().equals(methodName)) { + if (Arrays.equals(argumentTypes, Type.getArgumentTypes(m))) { + if (Type.getReturnType(methodDesc).equals(Type.getReturnType(m))) { + return m; + } + } + } + } + } + declaringClass = declaringClass.getSuperclass(); + } + throw new NoSuchMethodError(owner + "." + methodName + methodDesc); + } + + /** + * Checks whether a given method is allowed to be called. + */ + private boolean checkInvokeTarget(Executable method) { + if (method.getDeclaringClass().equals(Unsafe.class)) { + return false; + } + return true; + } + + @Override + public void visitMethodInsn(int opcode, String owner, String methodName, String methodDesc, boolean itf) { + Executable callee = resolveMethod(owner, methodName, methodDesc); + verify(checkInvokeTarget(callee), "invocation of " + callee); + } + }; + } else { + return null; + } + } +} --- /dev/null 2015-09-16 15:20:23.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVMEventListener.java 2015-09-16 15:20:23.000000000 -0700 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.meta.*; + +public interface HotSpotVMEventListener { + + /** + * Notifies this client that the VM is shutting down. + */ + default void notifyShutdown() { + } + + /** + * Notify on successful install into the CodeCache. + * + * @param hotSpotCodeCacheProvider + * @param installedCode + * @param compResult + */ + default void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompilationResult compResult) { + } + + /** + * Perform any extra initialization required. + * + * @param runtime + */ + default void completeInitialization(HotSpotJVMCIRuntime runtime) { + } + + /** + * Create a custom {@link JVMCIMetaAccessContext} to be used for managing the lifetime of loaded + * metadata. It a custom one isn't created then the default implementation will be a single + * context with globally shared instances of {@link ResolvedJavaType} that are never released. + * + * @param hotSpotJVMCIRuntime + * @return a custom context or null + */ + default JVMCIMetaAccessContext createMetaAccessContext(HotSpotJVMCIRuntime hotSpotJVMCIRuntime) { + return null; + } +} --- /dev/null 2015-09-16 15:20:24.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVmSymbols.java 2015-09-16 15:20:24.000000000 -0700 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.internal.jvmci.hotspot.UnsafeAccess.UNSAFE; +import sun.misc.*; + +/** + * Class to access the C++ {@code vmSymbols} table. + */ +public final class HotSpotVmSymbols { + + /** + * Returns the symbol in the {@code vmSymbols} table at position {@code index} as {@link String} + * . + * + * @param index position in the symbol table + * @return the symbol at position id + */ + public static String symbolAt(int index) { + HotSpotJVMCIRuntimeProvider runtime = runtime(); + HotSpotVMConfig config = runtime.getConfig(); + assert config.vmSymbolsFirstSID <= index && index < config.vmSymbolsSIDLimit : "index " + index + " is out of bounds"; + assert config.symbolPointerSize == Unsafe.ADDRESS_SIZE : "the following address read is broken"; + return runtime.getCompilerToVM().getSymbol(UNSAFE.getAddress(config.vmSymbolsSymbols + index * config.symbolPointerSize)); + } +} --- /dev/null 2015-09-16 15:20:25.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/MetaspaceWrapperObject.java 2015-09-16 15:20:24.000000000 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +/** + * A tag interface indicating that this type is a wrapper around a HotSpot metaspace object. + * + * It would preferable if this were the base class containing the pointer but that would require + * mixins since most of the wrapper types have complex supertype hierarchies. + */ +public interface MetaspaceWrapperObject { + + long getMetaspacePointer(); +} --- /dev/null 2015-09-16 15:20:25.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/Stable.java 2015-09-16 15:20:25.000000000 -0700 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jvmci.hotspot; + +import java.lang.annotation.*; + +/** + * This annotation functions as an alias for the sun.invoke.Stable annotation within JVMCI code. It + * is specially recognized during class file parsing in the same way as that annotation. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Stable { +} --- /dev/null 2015-09-16 15:20:26.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/SuppressFBWarnings.java 2015-09-16 15:20:26.000000000 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +/** + * Used to suppress FindBugs warnings. + */ +public @interface SuppressFBWarnings { + /** + * The set of FindBugs warnings that are to be + * suppressed in annotated element. The value can be a bug category, kind or pattern. + */ + String[] value(); + + /** + * Reason why the warning is suppressed. + */ + String justification(); +} --- /dev/null 2015-09-16 15:20:27.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/UnsafeAccess.java 2015-09-16 15:20:27.000000000 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +/** + * Package private access to the {@link Unsafe} capability. + */ +class UnsafeAccess { + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} --- /dev/null 2015-09-16 15:20:28.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/events/EmptyEventProvider.java 2015-09-16 15:20:27.000000000 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot.events; + +import jdk.internal.jvmci.common.*; + +/** + * An empty implementation for {@link EventProvider}. This implementation is used when no logging is + * requested. + */ +public final class EmptyEventProvider implements EventProvider { + + public CompilationEvent newCompilationEvent() { + return new EmptyCompilationEvent(); + } + + public static class EmptyCompilationEvent implements CompilationEvent { + public void commit() { + throw JVMCIError.shouldNotReachHere(); + } + + public boolean shouldWrite() { + // Events of this class should never been written. + return false; + } + + public void begin() { + } + + public void end() { + } + + public void setMethod(String method) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setCompileId(int compileId) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setCompileLevel(int compileLevel) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setSucceeded(boolean succeeded) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setIsOsr(boolean isOsr) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setCodeSize(int codeSize) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setInlinedBytes(int inlinedBytes) { + throw JVMCIError.shouldNotReachHere(); + } + } + + public CompilerFailureEvent newCompilerFailureEvent() { + return new EmptyCompilerFailureEvent(); + } + + public static class EmptyCompilerFailureEvent implements CompilerFailureEvent { + public void commit() { + throw JVMCIError.shouldNotReachHere(); + } + + public boolean shouldWrite() { + // Events of this class should never been written. + return false; + } + + public void setCompileId(int compileId) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setMessage(String message) { + throw JVMCIError.shouldNotReachHere(); + } + } + +} --- /dev/null 2015-09-16 15:20:28.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/events/EventProvider.java 2015-09-16 15:20:28.000000000 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot.events; + +/** + * A provider that provides a specific implementation for events that can be logged in the compiler. + */ +public interface EventProvider { + + /** + * An instant event is an event that is not considered to have taken any time. + */ + interface InstantEvent { + /** + * Commits the event. + */ + void commit(); + + /** + * Determines if this particular event instance would be committed to the data stream right + * now if application called {@link #commit()}. This in turn depends on whether the event is + * enabled and possible other factors. + * + * @return if this event would be committed on a call to {@link #commit()}. + */ + boolean shouldWrite(); + } + + /** + * Timed events describe an operation that somehow consumes time. + */ + interface TimedEvent extends InstantEvent { + /** + * Starts the timing for this event. + */ + void begin(); + + /** + * Ends the timing period for this event. + */ + void end(); + } + + /** + * Creates a new {@link CompilationEvent}. + * + * @return a compilation event + */ + CompilationEvent newCompilationEvent(); + + /** + * A compilation event. + */ + interface CompilationEvent extends TimedEvent { + void setMethod(String method); + + void setCompileId(int compileId); + + void setCompileLevel(int compileLevel); + + void setSucceeded(boolean succeeded); + + void setIsOsr(boolean isOsr); + + void setCodeSize(int codeSize); + + void setInlinedBytes(int inlinedBytes); + } + + /** + * Creates a new {@link CompilerFailureEvent}. + * + * @return a compiler failure event + */ + CompilerFailureEvent newCompilerFailureEvent(); + + /** + * A compiler failure event. + */ + interface CompilerFailureEvent extends InstantEvent { + void setCompileId(int compileId); + + void setMessage(String message); + } +} --- /dev/null 2015-09-16 15:20:29.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/logging/package-info.java 2015-09-16 15:20:29.000000000 -0700 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * Logging framework for the HotSpot CRI implementation. + */ +package jdk.internal.jvmci.hotspot.logging; + --- /dev/null 2015-09-16 15:20:29.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspotvmconfig/src/jdk/internal/jvmci/hotspotvmconfig/HotSpotVMAddress.java 2015-09-16 15:20:29.000000000 -0700 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ address in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMAddress { + + /** + * Returns the name of the symbol this address is referring to. + * + * @return name of symbol of this address + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; + + /** + * List of operating systems where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostOSName()}. An empty list implies that the constant is required + * on all operating systems. + */ + @SuppressWarnings("javadoc") + String[] os() default {}; + +} --- /dev/null 2015-09-16 15:20:30.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspotvmconfig/src/jdk/internal/jvmci/hotspotvmconfig/HotSpotVMConstant.java 2015-09-16 15:20:30.000000000 -0700 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ constant in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMConstant { + + /** + * Returns the name of the constant. + * + * @return name of constant + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; +} --- /dev/null 2015-09-16 15:20:31.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspotvmconfig/src/jdk/internal/jvmci/hotspotvmconfig/HotSpotVMData.java 2015-09-16 15:20:30.000000000 -0700 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a entry in {@code gHotSpotVMData}. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMData { + + /** + * Returns the array index of this field. + * + * @return array index of field + */ + int index(); + +} --- /dev/null 2015-09-16 15:20:31.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspotvmconfig/src/jdk/internal/jvmci/hotspotvmconfig/HotSpotVMField.java 2015-09-16 15:20:31.000000000 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ field in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMField { + + /** + * Types of information this annotation can return. + */ + enum Type { + /** + * Returns the offset of this field within the type. Only valid for instance fields. + */ + OFFSET, + + /** + * Returns the absolute address of this field. Only valid for static fields. + */ + ADDRESS, + + /** + * Returns the value of this field. Only valid for static fields. + */ + VALUE; + } + + /** + * Specifies what type of information to return. + * + * @see Type + */ + Type get(); + + /** + * Returns the type name containing this field. + * + * @return name of containing type + */ + String type(); + + /** + * Returns the name of this field. + * + * @return name of field + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; +} --- /dev/null 2015-09-16 15:20:32.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspotvmconfig/src/jdk/internal/jvmci/hotspotvmconfig/HotSpotVMFlag.java 2015-09-16 15:20:32.000000000 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ flag in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMFlag { + + /** + * Returns the name of this flag. + * + * @return name of flag. + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; + + boolean optional() default false; +} --- /dev/null 2015-09-16 15:20:32.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspotvmconfig/src/jdk/internal/jvmci/hotspotvmconfig/HotSpotVMManual.java 2015-09-16 15:20:32.000000000 -0700 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Annotates a field in HotSpotVMConfig which is not read from the VM but is calculated manually. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMManual { + + /** + * Returns the name associated with that field. + * + * @return name associated with field + */ + String name(); + +} --- /dev/null 2015-09-16 15:20:33.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspotvmconfig/src/jdk/internal/jvmci/hotspotvmconfig/HotSpotVMType.java 2015-09-16 15:20:33.000000000 -0700 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ type in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMType { + + /** + * Types of information this annotation can return. + */ + enum Type { + /** + * Returns the size of the type (C++ {@code sizeof()}). + */ + SIZE; + } + + /** + * Specifies what type of information to return. + * + * @see Type + */ + Type get(); + + /** + * Returns the name of the type. + * + * @return name of type + */ + String name(); +} --- /dev/null 2015-09-16 15:20:34.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.inittimer/src/jdk/internal/jvmci/inittimer/InitTimer.java 2015-09-16 15:20:33.000000000 -0700 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.inittimer; + +/** + * A facility for timing a step in the runtime initialization sequence. This is independent from all + * other JVMCI code so as to not perturb the initialization sequence. It is enabled by setting the + * {@code "jvmci.inittimer"} system property to {@code "true"}. + */ +public final class InitTimer implements AutoCloseable { + final String name; + final long start; + + private InitTimer(String name) { + this.name = name; + this.start = System.currentTimeMillis(); + System.out.println("START: " + SPACES.substring(0, timerDepth * 2) + name); + assert Thread.currentThread() == initializingThread : Thread.currentThread() + " != " + initializingThread; + timerDepth++; + } + + @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "only the initializing thread accesses this field") + public void close() { + final long end = System.currentTimeMillis(); + timerDepth--; + System.out.println(" DONE: " + SPACES.substring(0, timerDepth * 2) + name + " [" + (end - start) + " ms]"); + } + + public static InitTimer timer(String name) { + return ENABLED ? new InitTimer(name) : null; + } + + public static InitTimer timer(String name, Object suffix) { + return ENABLED ? new InitTimer(name + suffix) : null; + } + + /** + * Specifies if initialization timing is enabled. + */ + private static final boolean ENABLED = Boolean.getBoolean("jvmci.inittimer") || Boolean.getBoolean("jvmci.runtime.TimeInit"); + + public static int timerDepth = 0; + public static final String SPACES = " "; + + /** + * Used to assert the invariant that all initialization happens on the same thread. + */ + public static final Thread initializingThread; + static { + if (ENABLED) { + initializingThread = Thread.currentThread(); + System.out.println("INITIALIZING THREAD: " + initializingThread); + } else { + initializingThread = null; + } + } +} --- /dev/null 2015-09-16 15:20:34.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.inittimer/src/jdk/internal/jvmci/inittimer/SuppressFBWarnings.java 2015-09-16 15:20:34.000000000 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.inittimer; + +/** + * Used to suppress FindBugs warnings. + */ +public @interface SuppressFBWarnings { + /** + * The set of FindBugs warnings that are to be + * suppressed in annotated element. The value can be a bug category, kind or pattern. + */ + String[] value(); + + /** + * Reason why the warning is suppressed. + */ + String justification(); +} --- /dev/null 2015-09-16 15:20:35.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/overview.html 2015-09-16 15:20:35.000000000 -0700 @@ -0,0 +1,38 @@ + + + + + + + + +The jdk.internal.jvmci.meta project provides an API to the runtime data structures +for various Java elements. Unlike standard Java reflection, it can model elements that are not yet loaded. +It can also expose profiling information collected by the runtime system. + + + --- /dev/null 2015-09-16 15:20:35.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/AbstractJavaProfile.java 2015-09-16 15:20:35.000000000 -0700 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * This object holds probability information for a set of items that were profiled at a specific + * BCI. The precision of the supplied values may vary, but a runtime that provides this information + * should be aware that it will be used to guide performance-critical decisions like speculative + * inlining, etc. + * + * @param a subclass of AbstractProfiledItem + * @param the class of the items that are profiled at the specific BCI and for which + * probabilities are stored. E.g., a ResolvedJavaType or a ResolvedJavaMethod. + */ +public abstract class AbstractJavaProfile, U> { + + private final double notRecordedProbability; + private final T[] pitems; + + public AbstractJavaProfile(double notRecordedProbability, T[] pitems) { + this.pitems = pitems; + assert !Double.isNaN(notRecordedProbability); + this.notRecordedProbability = notRecordedProbability; + assert isSorted(); + assert totalProbablility() >= 0 && totalProbablility() <= 1.0001 : totalProbablility() + " " + this; + } + + private double totalProbablility() { + double total = notRecordedProbability; + for (T item : pitems) { + total += item.probability; + } + return total; + } + + /** + * Determines if an array of profiled items are sorted in descending order of their + * probabilities. + */ + private boolean isSorted() { + for (int i = 1; i < pitems.length; i++) { + if (pitems[i - 1].getProbability() < pitems[i].getProbability()) { + return false; + } + } + return true; + } + + /** + * Returns the estimated probability of all types that could not be recorded due to profiling + * limitations. + * + * @return double value ≥ 0.0 and ≤ 1.0 + */ + public double getNotRecordedProbability() { + return notRecordedProbability; + } + + protected T[] getItems() { + return pitems; + } + + /** + * Searches for an entry of a given resolved Java type. + * + * @param type the type for which an entry should be searched + * @return the entry or null if no entry for this type can be found + */ + public T findEntry(ResolvedJavaType type) { + if (pitems != null) { + for (T pt : pitems) { + if (pt.getItem().equals(type)) { + return pt; + } + } + } + return null; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getName()); + builder.append("["); + if (pitems != null) { + for (T pt : pitems) { + builder.append(pt.toString()); + builder.append(", "); + } + } + builder.append(this.notRecordedProbability); + builder.append("]"); + return builder.toString(); + } + + public boolean isIncluded(U item) { + if (this.getNotRecordedProbability() > 0.0) { + return true; + } else { + for (int i = 0; i < getItems().length; i++) { + T pitem = getItems()[i]; + U curType = pitem.getItem(); + if (curType == item) { + return true; + } + } + } + return false; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof AbstractJavaProfile)) { + return false; + } + AbstractJavaProfile that = (AbstractJavaProfile) obj; + if (that.notRecordedProbability != notRecordedProbability) { + return false; + } + if (that.pitems.length != pitems.length) { + return false; + } + for (int i = 0; i < pitems.length; ++i) { + if (!pitems[i].equals(that.pitems[i])) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return (int) Double.doubleToLongBits(notRecordedProbability) + pitems.length * 13; + } +} --- /dev/null 2015-09-16 15:20:36.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/AbstractProfiledItem.java 2015-09-16 15:20:36.000000000 -0700 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * A profiled type that has a probability. Profiled types are naturally sorted in descending order + * of their probabilities. + */ +public abstract class AbstractProfiledItem implements Comparable> { + + protected final T item; + protected final double probability; + + public AbstractProfiledItem(T item, double probability) { + assert item != null; + assert probability >= 0.0D && probability <= 1.0D; + this.item = item; + this.probability = probability; + } + + protected T getItem() { + return item; + } + + /** + * Returns the estimated probability of {@link #getItem()}. + * + * @return double value ≥ 0.0 and ≤ 1.0 + */ + public double getProbability() { + return probability; + } + + @Override + public int compareTo(AbstractProfiledItem o) { + if (getProbability() > o.getProbability()) { + return -1; + } else if (getProbability() < o.getProbability()) { + return 1; + } + return 0; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(probability); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + item.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + AbstractProfiledItem other = (AbstractProfiledItem) obj; + if (Double.doubleToLongBits(probability) != Double.doubleToLongBits(other.probability)) { + return false; + } + return item.equals(other.item); + } + + @Override + public abstract String toString(); +} --- /dev/null 2015-09-16 15:20:37.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/AllocatableValue.java 2015-09-16 15:20:36.000000000 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Common base class for values that are stored in some location that's managed by the register + * allocator (e.g. register, stack slot). + */ +public abstract class AllocatableValue extends Value implements JavaValue { + + public static final AllocatableValue[] NONE = {}; + + public AllocatableValue(LIRKind lirKind) { + super(lirKind); + } +} --- /dev/null 2015-09-16 15:20:37.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/Assumptions.java 2015-09-16 15:20:37.000000000 -0700 @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.lang.invoke.*; +import java.util.*; + +/** + * Class for recording assumptions made during compilation. + */ +public final class Assumptions implements Iterable { + + /** + * Abstract base class for assumptions. An assumption assumes a property of the runtime that may + * be invalidated by subsequent execution (e.g., that a class has no subclasses implementing + * {@link NoFinalizableSubclass Object.finalize()}). + */ + public abstract static class Assumption { + } + + /** + * A class for providing information that is only valid in association with a set of + * {@link Assumption}s. + * + * @param + */ + public static class AssumptionResult { + Assumption[] assumptions; + final T result; + + private static final Assumption[] EMPTY = new Assumption[0]; + + public AssumptionResult(T result, Assumption... assumptions) { + this.result = result; + this.assumptions = assumptions; + } + + public AssumptionResult(T result) { + this(result, EMPTY); + } + + public T getResult() { + return result; + } + + public boolean isAssumptionFree() { + return assumptions.length == 0; + } + + public void add(AssumptionResult other) { + Assumption[] newAssumptions = Arrays.copyOf(this.assumptions, this.assumptions.length + other.assumptions.length); + System.arraycopy(other.assumptions, 0, newAssumptions, this.assumptions.length, other.assumptions.length); + this.assumptions = newAssumptions; + } + + public boolean canRecordTo(Assumptions target) { + /* + * We can use the result if it is either assumption free, or if we have a valid + * Assumptions object where we can record assumptions. + */ + return assumptions.length == 0 || target != null; + } + + public void recordTo(Assumptions target) { + assert canRecordTo(target); + + if (assumptions.length > 0) { + for (Assumption assumption : assumptions) { + target.record(assumption); + } + } + } + } + + /** + * An assumption that a given class has no subclasses implementing {@link Object#finalize()}). + */ + public static final class NoFinalizableSubclass extends Assumption { + + private ResolvedJavaType receiverType; + + public NoFinalizableSubclass(ResolvedJavaType receiverType) { + this.receiverType = receiverType; + } + + @Override + public int hashCode() { + return 31 + receiverType.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NoFinalizableSubclass) { + NoFinalizableSubclass other = (NoFinalizableSubclass) obj; + return other.receiverType.equals(receiverType); + } + return false; + } + + @Override + public String toString() { + return "NoFinalizableSubclass[receiverType=" + receiverType.toJavaName() + "]"; + } + + } + + /** + * An assumption that a given abstract or interface type has one direct concrete subtype. There + * is no requirement that the subtype is a leaf type. + */ + public static final class ConcreteSubtype extends Assumption { + + /** + * Type the assumption is made about. + */ + public final ResolvedJavaType context; + + /** + * Assumed concrete sub-type of the context type. + */ + public final ResolvedJavaType subtype; + + public ConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) { + this.context = context; + this.subtype = subtype; + assert context.isAbstract(); + assert subtype.isConcrete() || context.isInterface() : subtype.toString() + " : " + context.toString(); + assert !subtype.isArray() || subtype.getElementalType().isFinalFlagSet() : subtype.toString() + " : " + context.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + context.hashCode(); + result = prime * result + subtype.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConcreteSubtype) { + ConcreteSubtype other = (ConcreteSubtype) obj; + return other.context.equals(context) && other.subtype.equals(subtype); + } + return false; + } + + @Override + public String toString() { + return "ConcreteSubtype[context=" + context.toJavaName() + ", subtype=" + subtype.toJavaName() + "]"; + } + } + + /** + * An assumption that a given type has no subtypes. + */ + public static final class LeafType extends Assumption { + + /** + * Type the assumption is made about. + */ + public final ResolvedJavaType context; + + public LeafType(ResolvedJavaType context) { + this.context = context; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + context.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof LeafType) { + LeafType other = (LeafType) obj; + return other.context.equals(context); + } + return false; + } + + @Override + public String toString() { + return "LeafSubtype[context=" + context.toJavaName() + "]"; + } + } + + /** + * An assumption that a given virtual method has a given unique implementation. + */ + public static final class ConcreteMethod extends Assumption { + + /** + * A virtual (or interface) method whose unique implementation for the receiver type in + * {@link #context} is {@link #impl}. + */ + public final ResolvedJavaMethod method; + + /** + * A receiver type. + */ + public final ResolvedJavaType context; + + /** + * The unique implementation of {@link #method} for {@link #context}. + */ + public final ResolvedJavaMethod impl; + + public ConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { + this.method = method; + this.context = context; + this.impl = impl; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + method.hashCode(); + result = prime * result + context.hashCode(); + result = prime * result + impl.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConcreteMethod) { + ConcreteMethod other = (ConcreteMethod) obj; + return other.method.equals(method) && other.context.equals(context) && other.impl.equals(impl); + } + return false; + } + + @Override + public String toString() { + return "ConcreteMethod[method=" + method.format("%H.%n(%p)%r") + ", context=" + context.toJavaName() + ", impl=" + impl.format("%H.%n(%p)%r") + "]"; + } + } + + /** + * An assumption that a given call site's method handle did not change. + */ + public static final class CallSiteTargetValue extends Assumption { + + public final CallSite callSite; + public final MethodHandle methodHandle; + + public CallSiteTargetValue(CallSite callSite, MethodHandle methodHandle) { + this.callSite = callSite; + this.methodHandle = methodHandle; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + callSite.hashCode(); + result = prime * result + methodHandle.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CallSiteTargetValue) { + CallSiteTargetValue other = (CallSiteTargetValue) obj; + return callSite.equals(other.callSite) && methodHandle.equals(other.methodHandle); + } + return false; + } + + @Override + public String toString() { + return "CallSiteTargetValue[callSite=" + callSite + ", methodHandle=" + methodHandle + "]"; + } + } + + private final Set assumptions = new HashSet<>(); + + /** + * Returns whether any assumptions have been registered. + * + * @return {@code true} if at least one assumption has been registered, {@code false} otherwise. + */ + public boolean isEmpty() { + return assumptions.isEmpty(); + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Assumptions) { + Assumptions that = (Assumptions) obj; + if (!this.assumptions.equals(that.assumptions)) { + return false; + } + return true; + } + return false; + } + + @Override + public Iterator iterator() { + return assumptions.iterator(); + } + + /** + * Records an assumption that the specified type has no finalizable subclasses. + * + * @param receiverType the type that is assumed to have no finalizable subclasses + */ + public void recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) { + record(new NoFinalizableSubclass(receiverType)); + } + + /** + * Records that {@code subtype} is the only concrete subtype in the class hierarchy below + * {@code context}. + * + * @param context the root of the subtree of the class hierarchy that this assumptions is about + * @param subtype the one concrete subtype + */ + public void recordConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) { + record(new ConcreteSubtype(context, subtype)); + } + + /** + * Records that {@code impl} is the only possible concrete target for a virtual call to + * {@code method} with a receiver of type {@code context}. + * + * @param method a method that is the target of a virtual call + * @param context the receiver type of a call to {@code method} + * @param impl the concrete method that is the only possible target for the virtual call + */ + public void recordConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { + record(new ConcreteMethod(method, context, impl)); + } + + public void record(Assumption assumption) { + assumptions.add(assumption); + } + + /** + * Gets a copy of the assumptions recorded in this object as an array. + */ + public Assumption[] toArray() { + return assumptions.toArray(new Assumption[assumptions.size()]); + } + + /** + * Copies assumptions recorded by another {@link Assumptions} object into this object. + */ + public void record(Assumptions other) { + assert other != this; + assumptions.addAll(other.assumptions); + } + + @Override + public String toString() { + return "Assumptions[" + assumptions + "]"; + } +} --- /dev/null 2015-09-16 15:20:38.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/Constant.java 2015-09-16 15:20:38.000000000 -0700 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Represents a compile-time constant (boxed) value within the compiler. + */ +public interface Constant { + + boolean isDefaultForKind(); + + String toValueString(); +} --- /dev/null 2015-09-16 15:20:38.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/ConstantPool.java 2015-09-16 15:20:38.000000000 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2009, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Represents the runtime representation of the constant pool that is used by the compiler when + * parsing bytecode. Provides methods to look up a constant pool entry without performing + * resolution. They are used during compilation. + */ +public interface ConstantPool { + + /** + * Returns the number of entries the constant pool. + * + * @return number of entries in the constant pool + */ + int length(); + + /** + * Ensures that the type referenced by the specified constant pool entry is loaded and + * initialized. This can be used to compile time resolve a type. It works for field, method, or + * type constant pool entries. + * + * @param cpi the index of the constant pool entry that references the type + * @param opcode the opcode of the instruction that references the type + */ + void loadReferencedType(int cpi, int opcode); + + /** + * Looks up a reference to a field. If {@code opcode} is non-negative, then resolution checks + * specific to the bytecode it denotes are performed if the field is already resolved. Should + * any of these checks fail, an unresolved field reference is returned. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return a reference to the field at {@code cpi} in this pool + * @throws ClassFormatError if the entry at {@code cpi} is not a field + */ + JavaField lookupField(int cpi, int opcode); + + /** + * Looks up a reference to a method. If {@code opcode} is non-negative, then resolution checks + * specific to the bytecode it denotes are performed if the method is already resolved. Should + * any of these checks fail, an unresolved method reference is returned. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return a reference to the method at {@code cpi} in this pool + * @throws ClassFormatError if the entry at {@code cpi} is not a method + */ + JavaMethod lookupMethod(int cpi, int opcode); + + /** + * Looks up a reference to a type. If {@code opcode} is non-negative, then resolution checks + * specific to the bytecode it denotes are performed if the type is already resolved. Should any + * of these checks fail, an unresolved type reference is returned. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return a reference to the compiler interface type + */ + JavaType lookupType(int cpi, int opcode); + + /** + * Looks up an Utf8 string. + * + * @param cpi the constant pool index + * @return the Utf8 string at index {@code cpi} in this constant pool + */ + String lookupUtf8(int cpi); + + /** + * Looks up a method signature. + * + * @param cpi the constant pool index + * @return the method signature at index {@code cpi} in this constant pool + */ + Signature lookupSignature(int cpi); + + /** + * Looks up a constant at the specified index. + * + * @param cpi the constant pool index + * @return the {@code Constant} or {@code JavaType} instance representing the constant pool + * entry + */ + Object lookupConstant(int cpi); + + /** + * Looks up the appendix at the specified index. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return the appendix if it exists and is resolved or {@code null} + */ + JavaConstant lookupAppendix(int cpi, int opcode); +} --- /dev/null 2015-09-16 15:20:39.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/ConstantReflectionProvider.java 2015-09-16 15:20:39.000000000 -0700 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.lang.invoke.*; + +/** + * Reflection operations on values represented as {@linkplain JavaConstant constants}. All methods + * in this interface require the VM to access the actual object encapsulated in + * {@link JavaKind#Object object} constants. This access is not always possible, depending on kind + * of VM and the state that the VM is in. Therefore, all methods can return {@code null} at any + * time, to indicate that the result is not available at this point. The caller is responsible to + * check for {@code null} results and handle them properly, e.g., not perform an optimization. + */ +public interface ConstantReflectionProvider { + + /** + * Compares two constants for equality. The equality relationship is symmetric. Returns + * {@link Boolean#TRUE true} if the two constants represent the same run time value, + * {@link Boolean#FALSE false} if they are different. Returns {@code null} if the constants + * cannot be compared at this point. + */ + Boolean constantEquals(Constant x, Constant y); + + /** + * Returns the length of the array constant. Returns {@code null} if the constant is not an + * array, or if the array length is not available at this point. + */ + Integer readArrayLength(JavaConstant array); + + /** + * Reads a value from the given array at the given index. Returns {@code null} if the constant + * is not an array, if the index is out of bounds, or if the value is not available at this + * point. + */ + JavaConstant readArrayElement(JavaConstant array, int index); + + /** + * Reads a value from the given array at the given index if it is a stable array. Returns + * {@code null} if the constant is not a stable array, if it is a default value, if the index is + * out of bounds, or if the value is not available at this point. + */ + JavaConstant readConstantArrayElement(JavaConstant array, int index); + + /** + * Reads a value from the given array at the given offset if it is a stable array. The offset + * will be decoded relative to the platform addressing into an index into the array. Returns + * {@code null} if the constant is not a stable array, if it is a default value, if the offset + * is out of bounds, or if the value is not available at this point. + */ + JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset); + + /** + * Gets the constant value of this field. Note that a {@code static final} field may not be + * considered constant if its declaring class is not yet initialized or if it is a well known + * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}). + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @return the constant value of this field or {@code null} if this field is not considered + * constant by the runtime + */ + JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver); + + /** + * Gets the current value of this field for a given object, if available. + * + * There is no guarantee that the same value will be returned by this method for a field unless + * the field is considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant) + * constant} by the runtime. + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @return the value of this field or {@code null} if the value is not available (e.g., because + * the field holder is not yet initialized). + */ + JavaConstant readFieldValue(JavaField field, JavaConstant receiver); + + /** + * Gets the current value of this field for a given object, if available. Like + * {@link #readFieldValue(JavaField, JavaConstant)} but treats array fields as stable. + * + * There is no guarantee that the same value will be returned by this method for a field unless + * the field is considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant) + * constant} by the runtime. + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @param isDefaultStable if {@code true}, default values are considered stable + * @return the value of this field or {@code null} if the value is not available (e.g., because + * the field holder is not yet initialized). + */ + JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable); + + /** + * Converts the given {@link JavaKind#isPrimitive() primitive} constant to a boxed + * {@link JavaKind#Object object} constant, according to the Java boxing rules. Returns + * {@code null} if the source is is not a primitive constant, or the boxed value is not + * available at this point. + */ + JavaConstant boxPrimitive(JavaConstant source); + + /** + * Converts the given {@link JavaKind#Object object} constant to a + * {@link JavaKind#isPrimitive() primitive} constant, according to the Java unboxing rules. + * Returns {@code null} if the source is is not an object constant that can be unboxed, or the + * unboxed value is not available at this point. + */ + JavaConstant unboxPrimitive(JavaConstant source); + + /** + * Gets a string as a {@link JavaConstant}. + */ + JavaConstant forString(String value); + + /** + * Returns the {@link ResolvedJavaType} for a {@link Class} object (or any other object regarded + * as a class by the VM) encapsulated in the given constant. Returns {@code null} if the + * constant does not encapsulate a class, or if the type is not available at this point. + */ + ResolvedJavaType asJavaType(Constant constant); + + /** + * Check if the constant is embeddable in the code. + */ + boolean isEmbeddable(Constant constant); + + /** + * Gets access to the internals of {@link MethodHandle}. + */ + MethodHandleAccessProvider getMethodHandleAccess(); + + /** + * Gets raw memory access. + */ + MemoryAccessProvider getMemoryAccessProvider(); +} --- /dev/null 2015-09-16 15:20:40.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/DefaultProfilingInfo.java 2015-09-16 15:20:39.000000000 -0700 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * An implementation of {@link ProfilingInfo} that can used in the absence of real profile + * information. + */ +public final class DefaultProfilingInfo implements ProfilingInfo { + + private static final ProfilingInfo[] NO_PROFILING_INFO = new ProfilingInfo[]{new DefaultProfilingInfo(TriState.TRUE), new DefaultProfilingInfo(TriState.FALSE), + new DefaultProfilingInfo(TriState.UNKNOWN)}; + + private final TriState exceptionSeen; + + DefaultProfilingInfo(TriState exceptionSeen) { + this.exceptionSeen = exceptionSeen; + } + + @Override + public int getCodeSize() { + return 0; + } + + @Override + public JavaTypeProfile getTypeProfile(int bci) { + return null; + } + + @Override + public JavaMethodProfile getMethodProfile(int bci) { + return null; + } + + @Override + public double getBranchTakenProbability(int bci) { + return -1; + } + + @Override + public double[] getSwitchProbabilities(int bci) { + return null; + } + + @Override + public TriState getExceptionSeen(int bci) { + return exceptionSeen; + } + + @Override + public TriState getNullSeen(int bci) { + return TriState.UNKNOWN; + } + + @Override + public int getExecutionCount(int bci) { + return -1; + } + + public static ProfilingInfo get(TriState exceptionSeen) { + return NO_PROFILING_INFO[exceptionSeen.ordinal()]; + } + + @Override + public int getDeoptimizationCount(DeoptimizationReason reason) { + return 0; + } + + @Override + public boolean isMature() { + return false; + } + + @Override + public String toString() { + return "BaseProfilingInfo<" + this.toString(null, "; ") + ">"; + } + + public void setMature() { + // Do nothing + } + + public boolean setCompilerIRSize(Class irType, int nodeCount) { + return false; + } + + public int getCompilerIRSize(Class irType) { + return -1; + } +} --- /dev/null 2015-09-16 15:20:40.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/DeoptimizationAction.java 2015-09-16 15:20:40.000000000 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Specifies the action that should be taken by the runtime in case a certain deoptimization is + * triggered. + */ +public enum DeoptimizationAction { + /** + * Do not invalidate the machine code. This is typically used when deoptimizing at a point where + * it's highly likely nothing will change the likelihood of the deoptimization happening again. + * For example, a compiled array allocation where the size is negative. + */ + None(false), + + /** + * Do not invalidate the machine code, but schedule a recompilation if this deoptimization is + * triggered too often. + */ + RecompileIfTooManyDeopts(true), + + /** + * Invalidate the machine code and reset the profiling information. + */ + InvalidateReprofile(true), + + /** + * Invalidate the machine code and immediately schedule a recompilation. This is typically used + * when deoptimizing to resolve an unresolved symbol in which case extra profiling is not + * required to determine that the deoptimization will not re-occur. + */ + InvalidateRecompile(true), + + /** + * Invalidate the machine code and stop compiling the outermost method of this compilation. + */ + InvalidateStopCompiling(true); + + private final boolean invalidatesCompilation; + + private DeoptimizationAction(boolean invalidatesCompilation) { + this.invalidatesCompilation = invalidatesCompilation; + } + + public boolean doesInvalidateCompilation() { + return invalidatesCompilation; + } + +} --- /dev/null 2015-09-16 15:20:41.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/DeoptimizationReason.java 2015-09-16 15:20:41.000000000 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Enumeration of reasons for why a deoptimization is happening. + */ +public enum DeoptimizationReason { + None, + NullCheckException, + BoundsCheckException, + ClassCastException, + ArrayStoreException, + UnreachedCode, + TypeCheckedInliningViolated, + OptimizedTypeCheckViolated, + NotCompiledExceptionHandler, + Unresolved, + JavaSubroutineMismatch, + ArithmeticException, + RuntimeConstraint, + LoopLimitCheck, + Aliasing, + TransferToInterpreter, +} --- /dev/null 2015-09-16 15:20:41.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/ExceptionHandler.java 2015-09-16 15:20:41.000000000 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2009, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.util.*; + +/** + * Represents an exception handler within the bytecodes. + */ +public final class ExceptionHandler { + + private final int startBCI; + private final int endBCI; + private final int handlerBCI; + private final int catchTypeCPI; + private final JavaType catchType; + + /** + * Creates a new exception handler with the specified ranges. + * + * @param startBCI the start index of the protected range + * @param endBCI the end index of the protected range + * @param catchBCI the index of the handler + * @param catchTypeCPI the index of the throwable class in the constant pool + * @param catchType the type caught by this exception handler + */ + public ExceptionHandler(int startBCI, int endBCI, int catchBCI, int catchTypeCPI, JavaType catchType) { + this.startBCI = startBCI; + this.endBCI = endBCI; + this.handlerBCI = catchBCI; + this.catchTypeCPI = catchTypeCPI; + this.catchType = catchType; + } + + /** + * Returns the start bytecode index of the protected range of this handler. + */ + public int getStartBCI() { + return startBCI; + } + + /** + * Returns the end bytecode index of the protected range of this handler. + */ + public int getEndBCI() { + return endBCI; + } + + /** + * Returns the bytecode index of the handler block of this handler. + */ + public int getHandlerBCI() { + return handlerBCI; + } + + /** + * Returns the index into the constant pool representing the type of exception caught by this + * handler. + */ + public int catchTypeCPI() { + return catchTypeCPI; + } + + /** + * Checks whether this handler catches all exceptions. + * + * @return {@code true} if this handler catches all exceptions + */ + public boolean isCatchAll() { + return catchTypeCPI == 0; + } + + /** + * Returns the type of exception caught by this exception handler. + */ + public JavaType getCatchType() { + return catchType; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ExceptionHandler)) { + return false; + } + ExceptionHandler that = (ExceptionHandler) obj; + if (this.startBCI != that.startBCI || this.endBCI != that.endBCI || this.handlerBCI != that.handlerBCI || this.catchTypeCPI != that.catchTypeCPI) { + return false; + } + return Objects.equals(this.catchType, that.catchType); + } + + @Override + public String toString() { + return "ExceptionHandler"; + } + + @Override + public int hashCode() { + return catchTypeCPI ^ endBCI ^ handlerBCI; + } +} --- /dev/null 2015-09-16 15:20:42.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/InvokeTarget.java 2015-09-16 15:20:42.000000000 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013, 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Represents the resolved target of an invocation. + */ +public interface InvokeTarget { +} --- /dev/null 2015-09-16 15:20:43.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/JVMCIMetaAccessContext.java 2015-09-16 15:20:42.000000000 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * A context in which the results looking up the {@link ResolvedJavaType} for a {@link Class} are + * cached. + */ +public interface JVMCIMetaAccessContext { + + /** + * Gets the JVMCI mirror for a {@link Class} object. + * + * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} + */ + + ResolvedJavaType fromClass(Class clazz); +} --- /dev/null 2015-09-16 15:20:43.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/JavaConstant.java 2015-09-16 15:20:43.000000000 -0700 @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Represents a constant (boxed) value, such as an integer, floating point number, or object + * reference, within the compiler and across the compiler/runtime interface. Exports a set of + * {@code JavaConstant} instances that represent frequently used constant values, such as + * {@link #NULL_POINTER}. + */ +public interface JavaConstant extends Constant, JavaValue { + /* + * Using a larger cache for integers leads to only a slight increase in cache hit ratio which is + * not enough to justify the impact on startup time. + */ + JavaConstant NULL_POINTER = new NullConstant(); + PrimitiveConstant INT_MINUS_1 = new PrimitiveConstant(JavaKind.Int, -1); + PrimitiveConstant INT_0 = new PrimitiveConstant(JavaKind.Int, 0); + PrimitiveConstant INT_1 = new PrimitiveConstant(JavaKind.Int, 1); + PrimitiveConstant INT_2 = new PrimitiveConstant(JavaKind.Int, 2); + PrimitiveConstant LONG_0 = new PrimitiveConstant(JavaKind.Long, 0L); + PrimitiveConstant LONG_1 = new PrimitiveConstant(JavaKind.Long, 1L); + PrimitiveConstant FLOAT_0 = new PrimitiveConstant(JavaKind.Float, Float.floatToRawIntBits(0.0F)); + PrimitiveConstant FLOAT_1 = new PrimitiveConstant(JavaKind.Float, Float.floatToRawIntBits(1.0F)); + PrimitiveConstant DOUBLE_0 = new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(0.0D)); + PrimitiveConstant DOUBLE_1 = new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(1.0D)); + PrimitiveConstant TRUE = new PrimitiveConstant(JavaKind.Boolean, 1L); + PrimitiveConstant FALSE = new PrimitiveConstant(JavaKind.Boolean, 0L); + + /** + * Returns the Java kind of this constant. + */ + JavaKind getJavaKind(); + + /** + * Checks whether this constant is null. + * + * @return {@code true} if this constant is the null constant + */ + boolean isNull(); + + static boolean isNull(Constant c) { + if (c instanceof JavaConstant) { + return ((JavaConstant) c).isNull(); + } else { + return false; + } + } + + /** + * Checks whether this constant is non-null. + * + * @return {@code true} if this constant is a primitive, or an object constant that is not null + */ + default boolean isNonNull() { + return !isNull(); + } + + /** + * Checks whether this constant is the default value for its kind (null, 0, 0.0, false). + * + * @return {@code true} if this constant is the default value for its kind + */ + boolean isDefaultForKind(); + + /** + * Returns the value of this constant as a boxed Java value. + * + * @return the value of this constant + */ + Object asBoxedPrimitive(); + + /** + * Returns the primitive int value this constant represents. The constant must have a + * {@link JavaKind#getStackKind()} of {@link JavaKind#Int}. + * + * @return the constant value + */ + int asInt(); + + /** + * Returns the primitive boolean value this constant represents. The constant must have kind + * {@link JavaKind#Boolean}. + * + * @return the constant value + */ + boolean asBoolean(); + + /** + * Returns the primitive long value this constant represents. The constant must have kind + * {@link JavaKind#Long}, a {@link JavaKind#getStackKind()} of {@link JavaKind#Int}. + * + * @return the constant value + */ + long asLong(); + + /** + * Returns the primitive float value this constant represents. The constant must have kind + * {@link JavaKind#Float}. + * + * @return the constant value + */ + float asFloat(); + + /** + * Returns the primitive double value this constant represents. The constant must have kind + * {@link JavaKind#Double}. + * + * @return the constant value + */ + double asDouble(); + + default String toValueString() { + if (getJavaKind() == JavaKind.Illegal) { + return "illegal"; + } else { + return getJavaKind().format(asBoxedPrimitive()); + } + } + + static String toString(JavaConstant constant) { + if (constant.getJavaKind() == JavaKind.Illegal) { + return "illegal"; + } else { + return constant.getJavaKind().getJavaName() + "[" + constant.toValueString() + "]"; + } + } + + /** + * Creates a boxed double constant. + * + * @param d the double value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forDouble(double d) { + if (Double.compare(0.0D, d) == 0) { + return DOUBLE_0; + } + if (Double.compare(d, 1.0D) == 0) { + return DOUBLE_1; + } + return new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(d)); + } + + /** + * Creates a boxed float constant. + * + * @param f the float value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forFloat(float f) { + if (Float.compare(f, 0.0F) == 0) { + return FLOAT_0; + } + if (Float.compare(f, 1.0F) == 0) { + return FLOAT_1; + } + return new PrimitiveConstant(JavaKind.Float, Float.floatToRawIntBits(f)); + } + + /** + * Creates a boxed long constant. + * + * @param i the long value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forLong(long i) { + if (i == 0) { + return LONG_0; + } else if (i == 1) { + return LONG_1; + } else { + return new PrimitiveConstant(JavaKind.Long, i); + } + } + + /** + * Creates a boxed integer constant. + * + * @param i the integer value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forInt(int i) { + switch (i) { + case -1: + return INT_MINUS_1; + case 0: + return INT_0; + case 1: + return INT_1; + case 2: + return INT_2; + default: + return new PrimitiveConstant(JavaKind.Int, i); + } + } + + /** + * Creates a boxed byte constant. + * + * @param i the byte value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forByte(byte i) { + return new PrimitiveConstant(JavaKind.Byte, i); + } + + /** + * Creates a boxed boolean constant. + * + * @param i the boolean value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forBoolean(boolean i) { + return i ? TRUE : FALSE; + } + + /** + * Creates a boxed char constant. + * + * @param i the char value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forChar(char i) { + return new PrimitiveConstant(JavaKind.Char, i); + } + + /** + * Creates a boxed short constant. + * + * @param i the short value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forShort(short i) { + return new PrimitiveConstant(JavaKind.Short, i); + } + + /** + * Creates a {@link JavaConstant} from a primitive integer of a certain kind. + */ + static PrimitiveConstant forIntegerKind(JavaKind kind, long i) { + switch (kind) { + case Boolean: + return forBoolean(i != 0); + case Byte: + return forByte((byte) i); + case Short: + return forShort((short) i); + case Char: + return forChar((char) i); + case Int: + return forInt((int) i); + case Long: + return forLong(i); + default: + throw new IllegalArgumentException("not an integer kind: " + kind); + } + } + + /** + * Creates a {@link JavaConstant} from a primitive integer of a certain width. + */ + static PrimitiveConstant forPrimitiveInt(int bits, long i) { + assert bits <= 64; + switch (bits) { + case 1: + return forBoolean(i != 0); + case 8: + return forByte((byte) i); + case 16: + return forShort((short) i); + case 32: + return forInt((int) i); + case 64: + return forLong(i); + default: + throw new IllegalArgumentException("unsupported integer width: " + bits); + } + } + + /** + * Creates a boxed constant for the given boxed primitive value. + * + * @param value the Java boxed value + * @return the primitive constant holding the {@code value} + */ + static PrimitiveConstant forBoxedPrimitive(Object value) { + if (value instanceof Boolean) { + return forBoolean((Boolean) value); + } else if (value instanceof Byte) { + return forByte((Byte) value); + } else if (value instanceof Character) { + return forChar((Character) value); + } else if (value instanceof Short) { + return forShort((Short) value); + } else if (value instanceof Integer) { + return forInt((Integer) value); + } else if (value instanceof Long) { + return forLong((Long) value); + } else if (value instanceof Float) { + return forFloat((Float) value); + } else if (value instanceof Double) { + return forDouble((Double) value); + } else { + return null; + } + } + + static PrimitiveConstant forIllegal() { + return new PrimitiveConstant(JavaKind.Illegal, 0); + } + + /** + * Returns a constant with the default value for the given kind. + */ + static JavaConstant defaultForKind(JavaKind kind) { + switch (kind) { + case Boolean: + return FALSE; + case Byte: + return forByte((byte) 0); + case Char: + return forChar((char) 0); + case Short: + return forShort((short) 0); + case Int: + return INT_0; + case Double: + return DOUBLE_0; + case Float: + return FLOAT_0; + case Long: + return LONG_0; + case Object: + return NULL_POINTER; + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Returns the zero value for a given numeric kind. + */ + static JavaConstant zero(JavaKind kind) { + switch (kind) { + case Boolean: + return FALSE; + case Byte: + return forByte((byte) 0); + case Char: + return forChar((char) 0); + case Double: + return DOUBLE_0; + case Float: + return FLOAT_0; + case Int: + return INT_0; + case Long: + return LONG_0; + case Short: + return forShort((short) 0); + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Returns the one value for a given numeric kind. + */ + static JavaConstant one(JavaKind kind) { + switch (kind) { + case Boolean: + return TRUE; + case Byte: + return forByte((byte) 1); + case Char: + return forChar((char) 1); + case Double: + return DOUBLE_1; + case Float: + return FLOAT_1; + case Int: + return INT_1; + case Long: + return LONG_1; + case Short: + return forShort((short) 1); + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Adds two numeric constants. + */ + static JavaConstant add(JavaConstant x, JavaConstant y) { + assert x.getJavaKind() == y.getJavaKind(); + switch (x.getJavaKind()) { + case Byte: + return forByte((byte) (x.asInt() + y.asInt())); + case Char: + return forChar((char) (x.asInt() + y.asInt())); + case Double: + return forDouble(x.asDouble() + y.asDouble()); + case Float: + return forFloat(x.asFloat() + y.asFloat()); + case Int: + return forInt(x.asInt() + y.asInt()); + case Long: + return forLong(x.asLong() + y.asLong()); + case Short: + return forShort((short) (x.asInt() + y.asInt())); + default: + throw new IllegalArgumentException(x.getJavaKind().toString()); + } + } + + /** + * Multiplies two numeric constants. + */ + static PrimitiveConstant mul(JavaConstant x, JavaConstant y) { + assert x.getJavaKind() == y.getJavaKind(); + switch (x.getJavaKind()) { + case Byte: + return forByte((byte) (x.asInt() * y.asInt())); + case Char: + return forChar((char) (x.asInt() * y.asInt())); + case Double: + return forDouble(x.asDouble() * y.asDouble()); + case Float: + return forFloat(x.asFloat() * y.asFloat()); + case Int: + return forInt(x.asInt() * y.asInt()); + case Long: + return forLong(x.asLong() * y.asLong()); + case Short: + return forShort((short) (x.asInt() * y.asInt())); + default: + throw new IllegalArgumentException(x.getJavaKind().toString()); + } + } +} --- /dev/null 2015-09-16 15:20:44.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/JavaField.java 2015-09-16 15:20:44.000000000 -0700 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.util.*; + +/** + * Represents a reference to a Java field, either resolved or unresolved fields. Fields, like + * methods and types, are resolved through {@link ConstantPool constant pools}. + */ +public interface JavaField extends TrustedInterface { + + /** + * Returns the name of this field. + */ + String getName(); + + /** + * Returns a {@link JavaType} object that identifies the declared type for this field. + */ + JavaType getType(); + + /** + * Returns the kind of this field. This is the same as calling {@link #getType}. + * {@link JavaType#getJavaKind getJavaKind}. + */ + default JavaKind getJavaKind() { + return getType().getJavaKind(); + } + + /** + * Returns the {@link JavaType} object representing the class or interface that declares this + * field. + */ + JavaType getDeclaringClass(); + + /** + * Gets a string for this field formatted according to a given format specification. A format + * specification is composed of characters that are to be copied verbatim to the result and + * specifiers that denote an attribute of this field that is to be copied to the result. A + * specifier is a single character preceded by a '%' character. The accepted specifiers and the + * field attributes they denote are described below: + * + *
+     *     Specifier | Description                                          | Example(s)
+     *     ----------+------------------------------------------------------------------------------------------
+     *     'T'       | Qualified type                                       | "int" "java.lang.String"
+     *     't'       | Unqualified type                                     | "int" "String"
+     *     'H'       | Qualified holder                                     | "java.util.Map.Entry"
+     *     'h'       | Unqualified holder                                   | "Entry"
+     *     'n'       | Field name                                           | "age"
+     *     'f'       | Indicator if field is unresolved, static or instance | "unresolved" "static" "instance"
+     *     '%'       | A '%' character                                      | "%"
+     * 
+ * + * @param format a format specification + * @return the result of formatting this field according to {@code format} + * @throws IllegalFormatException if an illegal specifier is encountered in {@code format} + */ + @SuppressWarnings("fallthrough") + default String format(String format) throws IllegalFormatException { + StringBuilder sb = new StringBuilder(); + int index = 0; + JavaType type = getType(); + while (index < format.length()) { + char ch = format.charAt(index++); + if (ch == '%') { + if (index >= format.length()) { + throw new UnknownFormatConversionException("An unquoted '%' character cannot terminate a field format specification"); + } + char specifier = format.charAt(index++); + switch (specifier) { + case 'T': + case 't': { + sb.append(type.toJavaName(specifier == 'T')); + break; + } + case 'H': + case 'h': { + sb.append(getDeclaringClass().toJavaName(specifier == 'H')); + break; + } + case 'n': { + sb.append(getName()); + break; + } + case 'f': { + sb.append(!(this instanceof ResolvedJavaField) ? "unresolved" : ((ResolvedJavaField) this).isStatic() ? "static" : "instance"); + break; + } + case '%': { + sb.append('%'); + break; + } + default: { + throw new UnknownFormatConversionException(String.valueOf(specifier)); + } + } + } else { + sb.append(ch); + } + } + return sb.toString(); + } +} --- /dev/null 2015-09-16 15:20:44.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/JavaKind.java 2015-09-16 15:20:44.000000000 -0700 @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.lang.reflect.*; + +//JaCoCo Exclude + +/** + * Denotes the basic kinds of types in CRI, including the all the Java primitive types, for example, + * {@link JavaKind#Int} for {@code int} and {@link JavaKind#Object} for all object types. A kind has + * a single character short name, a Java name, and a set of flags further describing its behavior. + */ +public enum JavaKind implements PlatformKind { + /** The primitive boolean kind, represented as an int on the stack. */ + Boolean('z', "boolean", 1, true, java.lang.Boolean.TYPE, java.lang.Boolean.class), + + /** The primitive byte kind, represented as an int on the stack. */ + Byte('b', "byte", 1, true, java.lang.Byte.TYPE, java.lang.Byte.class), + + /** The primitive short kind, represented as an int on the stack. */ + Short('s', "short", 1, true, java.lang.Short.TYPE, java.lang.Short.class), + + /** The primitive char kind, represented as an int on the stack. */ + Char('c', "char", 1, true, java.lang.Character.TYPE, java.lang.Character.class), + + /** The primitive int kind, represented as an int on the stack. */ + Int('i', "int", 1, true, java.lang.Integer.TYPE, java.lang.Integer.class), + + /** The primitive float kind. */ + Float('f', "float", 1, false, java.lang.Float.TYPE, java.lang.Float.class), + + /** The primitive long kind. */ + Long('j', "long", 2, false, java.lang.Long.TYPE, java.lang.Long.class), + + /** The primitive double kind. */ + Double('d', "double", 2, false, java.lang.Double.TYPE, java.lang.Double.class), + + /** The Object kind, also used for arrays. */ + Object('a', "Object", 1, false, null, null), + + /** The void float kind. */ + Void('v', "void", 0, false, java.lang.Void.TYPE, java.lang.Void.class), + + /** The non-type. */ + Illegal('-', "illegal", 0, false, null, null); + + private final char typeChar; + private final String javaName; + private final boolean isStackInt; + private final Class primitiveJavaClass; + private final Class boxedJavaClass; + private final EnumKey key = new EnumKey<>(this); + private final int slotCount; + + private JavaKind(char typeChar, String javaName, int slotCount, boolean isStackInt, Class primitiveJavaClass, Class boxedJavaClass) { + this.typeChar = typeChar; + this.javaName = javaName; + this.slotCount = slotCount; + this.isStackInt = isStackInt; + this.primitiveJavaClass = primitiveJavaClass; + this.boxedJavaClass = boxedJavaClass; + assert primitiveJavaClass == null || javaName.equals(primitiveJavaClass.getName()); + } + + /** + * Returns the number of stack slots occupied by this kind according to the Java bytecodes + * specification. + */ + public int getSlotCount() { + return this.slotCount; + } + + /** + * Returns whether this kind occupied two stack slots. + */ + public boolean needsTwoSlots() { + return this.slotCount == 2; + } + + /** + * Returns the name of the kind as a single character. + */ + public char getTypeChar() { + return typeChar; + } + + /** + * Returns the name of this kind which will also be it Java programming language name if it is + * {@linkplain #isPrimitive() primitive} or {@code void}. + */ + public String getJavaName() { + return javaName; + } + + public Key getKey() { + return key; + } + + /** + * Checks whether this type is a Java primitive type. + * + * @return {@code true} if this is {@link #Boolean}, {@link #Byte}, {@link #Char}, + * {@link #Short}, {@link #Int}, {@link #Long}, {@link #Float}, {@link #Double}, or + * {@link #Void}. + */ + public boolean isPrimitive() { + return primitiveJavaClass != null; + } + + /** + * Returns the kind that represents this kind when on the Java operand stack. + * + * @return the kind used on the operand stack + */ + public JavaKind getStackKind() { + if (isStackInt) { + return Int; + } + return this; + } + + /** + * Checks whether this type is a Java primitive type representing an integer number. + * + * @return {@code true} if the stack kind is {@link #Int} or {@link #Long}. + */ + public boolean isNumericInteger() { + return isStackInt || this == JavaKind.Long; + } + + /** + * Checks whether this type is a Java primitive type representing an unsigned number. + * + * @return {@code true} if the kind is {@link #Boolean} or {@link #Char}. + */ + public boolean isUnsigned() { + return this == JavaKind.Boolean || this == JavaKind.Char; + } + + /** + * Checks whether this type is a Java primitive type representing a floating point number. + * + * @return {@code true} if this is {@link #Float} or {@link #Double}. + */ + public boolean isNumericFloat() { + return this == JavaKind.Float || this == JavaKind.Double; + } + + /** + * Checks whether this represent an Object of some sort. + * + * @return {@code true} if this is {@link #Object}. + */ + public boolean isObject() { + return this == JavaKind.Object; + } + + /** + * Returns the kind corresponding to the Java type string. + * + * @param typeString the Java type string + * @return the kind + */ + public static JavaKind fromTypeString(String typeString) { + assert typeString.length() > 0; + final char first = typeString.charAt(0); + if (first == '[' || first == 'L') { + return JavaKind.Object; + } + return JavaKind.fromPrimitiveOrVoidTypeChar(first); + } + + /** + * Returns the kind of a word given the size of a word in bytes. + * + * @param wordSizeInBytes the size of a word in bytes + * @return the kind representing a word value + */ + public static JavaKind fromWordSize(int wordSizeInBytes) { + if (wordSizeInBytes == 8) { + return JavaKind.Long; + } else { + assert wordSizeInBytes == 4 : "Unsupported word size!"; + return JavaKind.Int; + } + } + + /** + * Returns the kind from the character describing a primitive or void. + * + * @param ch the character + * @return the kind + */ + public static JavaKind fromPrimitiveOrVoidTypeChar(char ch) { + switch (ch) { + case 'Z': + return Boolean; + case 'C': + return Char; + case 'F': + return Float; + case 'D': + return Double; + case 'B': + return Byte; + case 'S': + return Short; + case 'I': + return Int; + case 'J': + return Long; + case 'V': + return Void; + } + throw new IllegalArgumentException("unknown primitive or void type character: " + ch); + } + + /** + * Returns the Kind representing the given Java class. + * + * @param klass the class + * @return the kind + */ + public static JavaKind fromJavaClass(Class klass) { + if (klass == Boolean.primitiveJavaClass) { + return Boolean; + } else if (klass == Byte.primitiveJavaClass) { + return Byte; + } else if (klass == Short.primitiveJavaClass) { + return Short; + } else if (klass == Char.primitiveJavaClass) { + return Char; + } else if (klass == Int.primitiveJavaClass) { + return Int; + } else if (klass == Long.primitiveJavaClass) { + return Long; + } else if (klass == Float.primitiveJavaClass) { + return Float; + } else if (klass == Double.primitiveJavaClass) { + return Double; + } else if (klass == Void.primitiveJavaClass) { + return Void; + } else { + return Object; + } + } + + /** + * Returns the Java class representing this kind. + * + * @return the Java class + */ + public Class toJavaClass() { + return primitiveJavaClass; + } + + /** + * Returns the Java class for instances of boxed values of this kind. + * + * @return the Java class + */ + public Class toBoxedJavaClass() { + return boxedJavaClass; + } + + /** + * Converts this value type to a string. + */ + @Override + public String toString() { + return javaName; + } + + /** + * Marker interface for types that should be {@linkplain JavaKind#format(Object) formatted} with + * their {@link Object#toString()} value. Calling {@link Object#toString()} on other objects + * poses a security risk because it can potentially call user code. + */ + public interface FormatWithToString { + } + + /** + * Classes for which invoking {@link Object#toString()} does not run user code. + */ + private static boolean isToStringSafe(Class c) { + return c == Boolean.class || c == Byte.class || c == Character.class || c == Short.class || c == Integer.class || c == Float.class || c == Long.class || c == Double.class; + } + + /** + * Gets a formatted string for a given value of this kind. + * + * @param value a value of this kind + * @return a formatted string for {@code value} based on this kind + */ + public String format(Object value) { + if (isPrimitive()) { + assert isToStringSafe(value.getClass()); + return value.toString(); + } else { + if (value == null) { + return "null"; + } else { + if (value instanceof String) { + String s = (String) value; + if (s.length() > 50) { + return "String:\"" + s.substring(0, 30) + "...\""; + } else { + return "String:\"" + s + '"'; + } + } else if (value instanceof JavaType) { + return "JavaType:" + ((JavaType) value).toJavaName(); + } else if (value instanceof Enum) { + return MetaUtil.getSimpleName(value.getClass(), true) + ":" + ((Enum) value).name(); + } else if (value instanceof FormatWithToString) { + return MetaUtil.getSimpleName(value.getClass(), true) + ":" + String.valueOf(value); + } else if (value instanceof Class) { + return "Class:" + ((Class) value).getName(); + } else if (isToStringSafe(value.getClass())) { + return value.toString(); + } else if (value.getClass().isArray()) { + return formatArray(value); + } else { + return MetaUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value); + } + } + } + } + + private static final int MAX_FORMAT_ARRAY_LENGTH = 5; + + private static String formatArray(Object array) { + Class componentType = array.getClass().getComponentType(); + assert componentType != null; + int arrayLength = Array.getLength(array); + StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{"); + int length = Math.min(MAX_FORMAT_ARRAY_LENGTH, arrayLength); + boolean primitive = componentType.isPrimitive(); + for (int i = 0; i < length; i++) { + if (primitive) { + buf.append(Array.get(array, i)); + } else { + Object o = ((Object[]) array)[i]; + buf.append(JavaKind.Object.format(o)); + } + if (i != length - 1) { + buf.append(", "); + } + } + if (arrayLength != length) { + buf.append(", ..."); + } + return buf.append('}').toString(); + } + + /** + * The minimum value that can be represented as a value of this kind. + * + * @return the minimum value + */ + public long getMinValue() { + switch (this) { + case Boolean: + return 0; + case Byte: + return java.lang.Byte.MIN_VALUE; + case Char: + return java.lang.Character.MIN_VALUE; + case Short: + return java.lang.Short.MIN_VALUE; + case Int: + return java.lang.Integer.MIN_VALUE; + case Long: + return java.lang.Long.MIN_VALUE; + default: + throw new IllegalArgumentException("illegal call to minValue on " + this); + } + } + + /** + * The maximum value that can be represented as a value of this kind. + * + * @return the maximum value + */ + public long getMaxValue() { + switch (this) { + case Boolean: + return 1; + case Byte: + return java.lang.Byte.MAX_VALUE; + case Char: + return java.lang.Character.MAX_VALUE; + case Short: + return java.lang.Short.MAX_VALUE; + case Int: + return java.lang.Integer.MAX_VALUE; + case Long: + return java.lang.Long.MAX_VALUE; + default: + throw new IllegalArgumentException("illegal call to maxValue on " + this); + } + } + + /** + * Number of bytes that are necessary to represent a value of this kind. + * + * @return the number of bytes + */ + public int getByteCount() { + if (this == Boolean) { + return 1; + } else { + return getBitCount() >> 3; + } + } + + /** + * Number of bits that are necessary to represent a value of this kind. + * + * @return the number of bits + */ + public int getBitCount() { + switch (this) { + case Boolean: + return 1; + case Byte: + return 8; + case Char: + case Short: + return 16; + case Float: + return 32; + case Int: + return 32; + case Double: + return 64; + case Long: + return 64; + default: + throw new IllegalArgumentException("illegal call to bits on " + this); + } + } + + public JavaConstant getDefaultValue() { + switch (this) { + case Boolean: + return JavaConstant.FALSE; + case Int: + return JavaConstant.INT_0; + case Long: + return JavaConstant.LONG_0; + case Float: + return JavaConstant.FLOAT_0; + case Double: + return JavaConstant.DOUBLE_0; + case Object: + return JavaConstant.NULL_POINTER; + case Byte: + case Char: + case Short: + return new PrimitiveConstant(this, 0); + default: + throw new IllegalArgumentException("illegal call to getDefaultValue on " + this); + } + } + + @Override + public int getSizeInBytes() { + return getByteCount(); + } + + @Override + public int getVectorLength() { + return 1; + } +} --- /dev/null 2015-09-16 15:20:45.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/JavaMethod.java 2015-09-16 15:20:45.000000000 -0700 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2009, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.util.*; + +/** + * Represents a reference to a Java method, either resolved or unresolved. Methods, like fields and + * types, are resolved through {@link ConstantPool constant pools}. + */ +public interface JavaMethod extends TrustedInterface { + + /** + * Returns the name of this method. + */ + String getName(); + + /** + * Returns the {@link JavaType} object representing the class or interface that declares this + * method. + */ + JavaType getDeclaringClass(); + + /** + * Returns the signature of this method. + */ + Signature getSignature(); + + /** + * Gets a string for this method formatted according to a given format specification. A format + * specification is composed of characters that are to be copied verbatim to the result and + * specifiers that denote an attribute of this method that is to be copied to the result. A + * specifier is a single character preceded by a '%' character. The accepted specifiers and the + * method attributes they denote are described below: + * + *
+     *     Specifier | Description                                          | Example(s)
+     *     ----------+------------------------------------------------------------------------------------------
+     *     'R'       | Qualified return type                                | "int" "java.lang.String"
+     *     'r'       | Unqualified return type                              | "int" "String"
+     *     'H'       | Qualified holder                                     | "java.util.Map.Entry"
+     *     'h'       | Unqualified holder                                   | "Entry"
+     *     'n'       | Method name                                          | "add"
+     *     'P'       | Qualified parameter types, separated by ', '         | "int, java.lang.String"
+     *     'p'       | Unqualified parameter types, separated by ', '       | "int, String"
+     *     'f'       | Indicator if method is unresolved, static or virtual | "unresolved" "static" "virtual"
+     *     '%'       | A '%' character                                      | "%"
+     * 
+ * + * @param format a format specification + * @return the result of formatting this method according to {@code format} + * @throws IllegalFormatException if an illegal specifier is encountered in {@code format} + */ + @SuppressWarnings("fallthrough") + default String format(String format) throws IllegalFormatException { + StringBuilder sb = new StringBuilder(); + int index = 0; + Signature sig = null; + while (index < format.length()) { + char ch = format.charAt(index++); + if (ch == '%') { + if (index >= format.length()) { + throw new UnknownFormatConversionException("An unquoted '%' character cannot terminate a method format specification"); + } + char specifier = format.charAt(index++); + switch (specifier) { + case 'R': + case 'r': { + if (sig == null) { + sig = getSignature(); + } + sb.append(sig.getReturnType(null).toJavaName(specifier == 'R')); + break; + } + case 'H': + case 'h': { + sb.append(getDeclaringClass().toJavaName(specifier == 'H')); + break; + } + case 'n': { + sb.append(getName()); + break; + } + case 'P': + case 'p': { + if (sig == null) { + sig = getSignature(); + } + for (int i = 0; i < sig.getParameterCount(false); i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(sig.getParameterType(i, null).toJavaName(specifier == 'P')); + } + break; + } + case 'f': { + sb.append(!(this instanceof ResolvedJavaMethod) ? "unresolved" : ((ResolvedJavaMethod) this).isStatic() ? "static" : "virtual"); + break; + } + case '%': { + sb.append('%'); + break; + } + default: { + throw new UnknownFormatConversionException(String.valueOf(specifier)); + } + } + } else { + sb.append(ch); + } + } + return sb.toString(); + } +} --- /dev/null 2015-09-16 15:20:46.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/JavaMethodProfile.java 2015-09-16 15:20:45.000000000 -0700 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import jdk.internal.jvmci.meta.JavaMethodProfile.*; + +/** + * This profile object represents the method profile at a specific BCI. The precision of the + * supplied values may vary, but a runtime that provides this information should be aware that it + * will be used to guide performance-critical decisions like speculative inlining, etc. + */ +public final class JavaMethodProfile extends AbstractJavaProfile { + + public JavaMethodProfile(double notRecordedProbability, ProfiledMethod[] pitems) { + super(notRecordedProbability, pitems); + } + + public ProfiledMethod[] getMethods() { + return super.getItems(); + } + + public static class ProfiledMethod extends AbstractProfiledItem { + + public ProfiledMethod(ResolvedJavaMethod method, double probability) { + super(method, probability); + } + + /** + * Returns the type for this profile entry. + */ + public ResolvedJavaMethod getMethod() { + return getItem(); + } + + @Override + public String toString() { + return "{" + item.getName() + ", " + probability + "}"; + } + } +} --- /dev/null 2015-09-16 15:20:46.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/JavaType.java 2015-09-16 15:20:46.000000000 -0700 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import static jdk.internal.jvmci.meta.MetaUtil.*; + +/** + * Represents a resolved or unresolved type. Types include primitives, objects, {@code void}, and + * arrays thereof. + */ +public interface JavaType extends TrustedInterface { + + /** + * Returns the name of this type in internal form. The following are examples of strings + * returned by this method: + * + *
+     *     "Ljava/lang/Object;"
+     *     "I"
+     *     "[[B"
+     * 
+ */ + String getName(); + + /** + * Returns an unqualified name of this type. + * + *
+     *     "Object"
+     *     "Integer"
+     * 
+ */ + default String getUnqualifiedName() { + String name = getName(); + if (name.indexOf('/') != -1) { + name = name.substring(name.lastIndexOf('/') + 1); + } + if (name.endsWith(";")) { + name = name.substring(0, name.length() - 1); + } + return name; + } + + /** + * For array types, gets the type of the components, or {@code null} if this is not an array + * type. This method is analogous to {@link Class#getComponentType()}. + */ + JavaType getComponentType(); + + /** + * Gets the elemental type for this given type. The elemental type is the corresponding zero + * dimensional type of an array type. For example, the elemental type of {@code int[][][]} is + * {@code int}. A non-array type is its own elemental type. + */ + default JavaType getElementalType() { + JavaType t = this; + while (t.getComponentType() != null) { + t = t.getComponentType(); + } + return t; + } + + /** + * Gets the array class type representing an array with elements of this type. + */ + JavaType getArrayClass(); + + /** + * Gets the {@link JavaKind} of this type. + */ + JavaKind getJavaKind(); + + /** + * Resolves this type to a {@link ResolvedJavaType}. + * + * @param accessingClass the context of resolution (must not be null) + * @return the resolved Java type + * @throws LinkageError if the resolution failed + * @throws NullPointerException if {@code accessingClass} is {@code null} + */ + ResolvedJavaType resolve(ResolvedJavaType accessingClass); + + /** + * Gets the Java programming language name for this type. The following are examples of strings + * returned by this method: + * + *
+     *      java.lang.Object
+     *      int
+     *      boolean[][]
+     * 
+ * + * @return the Java name corresponding to this type + */ + default String toJavaName() { + return internalNameToJava(getName(), true, false); + } + + /** + * Gets the Java programming language name for this type. The following are examples of strings + * returned by this method: + * + *
+     *     qualified == true:
+     *         java.lang.Object
+     *         int
+     *         boolean[][]
+     *     qualified == false:
+     *         Object
+     *         int
+     *         boolean[][]
+     * 
+ * + * @param qualified specifies if the package prefix of this type should be included in the + * returned name + * @return the Java name corresponding to this type + */ + default String toJavaName(boolean qualified) { + JavaKind kind = getJavaKind(); + if (kind == JavaKind.Object) { + return internalNameToJava(getName(), qualified, false); + } + return getJavaKind().getJavaName(); + } + + /** + * Returns this type's name in the same format as {@link Class#getName()}. + */ + default String toClassName() { + return internalNameToJava(getName(), true, true); + } +} --- /dev/null 2015-09-16 15:20:47.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/JavaTypeProfile.java 2015-09-16 15:20:47.000000000 -0700 @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2011, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.util.*; + +import jdk.internal.jvmci.meta.JavaTypeProfile.*; + +/** + * This profile object represents the type profile at a specific BCI. The precision of the supplied + * values may vary, but a runtime that provides this information should be aware that it will be + * used to guide performance-critical decisions like speculative inlining, etc. + */ +public final class JavaTypeProfile extends AbstractJavaProfile { + + private static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0]; + + private final TriState nullSeen; + + public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType[] pitems) { + super(notRecordedProbability, pitems); + this.nullSeen = nullSeen; + } + + /** + * Returns whether a null value was at the type check. + */ + public TriState getNullSeen() { + return nullSeen; + } + + /** + * A list of types for which the runtime has recorded probability information. Note that this + * includes both positive and negative types where a positive type is a subtype of the checked + * type and a negative type is not. + */ + public ProfiledType[] getTypes() { + return getItems(); + } + + public JavaTypeProfile restrict(JavaTypeProfile otherProfile) { + if (otherProfile.getNotRecordedProbability() > 0.0) { + // Not useful for restricting since there is an unknown set of types occurring. + return this; + } + + if (this.getNotRecordedProbability() > 0.0) { + // We are unrestricted, so the other profile is always a better estimate. + return otherProfile; + } + + ArrayList result = new ArrayList<>(); + for (int i = 0; i < getItems().length; i++) { + ProfiledType ptype = getItems()[i]; + ResolvedJavaType type = ptype.getItem(); + if (otherProfile.isIncluded(type)) { + result.add(ptype); + } + } + + TriState newNullSeen = (otherProfile.getNullSeen() == TriState.FALSE) ? TriState.FALSE : getNullSeen(); + double newNotRecorded = getNotRecordedProbability(); + return createAdjustedProfile(result, newNullSeen, newNotRecorded); + } + + public JavaTypeProfile restrict(ResolvedJavaType declaredType, boolean nonNull) { + ArrayList result = new ArrayList<>(); + for (int i = 0; i < getItems().length; i++) { + ProfiledType ptype = getItems()[i]; + ResolvedJavaType type = ptype.getItem(); + if (declaredType.isAssignableFrom(type)) { + result.add(ptype); + } + } + + TriState newNullSeen = (nonNull) ? TriState.FALSE : getNullSeen(); + double newNotRecorded = this.getNotRecordedProbability(); + // Assume for the types not recorded, the incompatibility rate is the same. + if (getItems().length != 0) { + newNotRecorded *= ((double) result.size() / (double) getItems().length); + } + return createAdjustedProfile(result, newNullSeen, newNotRecorded); + } + + private JavaTypeProfile createAdjustedProfile(ArrayList result, TriState newNullSeen, double newNotRecorded) { + if (result.size() != this.getItems().length || newNotRecorded != getNotRecordedProbability() || newNullSeen != getNullSeen()) { + if (result.size() == 0) { + return new JavaTypeProfile(newNullSeen, 1.0, EMPTY_ARRAY); + } + double factor; + if (result.size() == this.getItems().length) { + /* List of types did not change, no need to recompute probabilities. */ + factor = 1.0; + } else { + double probabilitySum = 0.0; + for (int i = 0; i < result.size(); i++) { + probabilitySum += result.get(i).getProbability(); + } + probabilitySum += newNotRecorded; + + factor = 1.0 / probabilitySum; // Normalize to 1.0 + assert factor >= 1.0; + } + ProfiledType[] newResult = new ProfiledType[result.size()]; + for (int i = 0; i < newResult.length; ++i) { + ProfiledType curType = result.get(i); + newResult[i] = new ProfiledType(curType.getItem(), Math.min(1.0, curType.getProbability() * factor)); + } + double newNotRecordedTypeProbability = Math.min(1.0, newNotRecorded * factor); + return new JavaTypeProfile(newNullSeen, newNotRecordedTypeProbability, newResult); + } + return this; + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && nullSeen.equals(((JavaTypeProfile) other).nullSeen); + } + + @Override + public int hashCode() { + return nullSeen.hashCode() + super.hashCode(); + } + + public static class ProfiledType extends AbstractProfiledItem { + + public ProfiledType(ResolvedJavaType type, double probability) { + super(type, probability); + assert type.isArray() || type.isConcrete() : type; + } + + /** + * Returns the type for this profile entry. + */ + public ResolvedJavaType getType() { + return getItem(); + } + + @Override + public String toString() { + return String.format("%.6f#%s", probability, item); + } + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder("JavaTypeProfile", getNotRecordedProbability())).toString(); + } + + /** + * Returns {@code true} if all types seen at this location have been recorded in the profile. + */ + public boolean allTypesRecorded() { + return this.getNotRecordedProbability() == 0.0; + } + + /** + * Returns the single monormorphic type representing this profile or {@code null} if no such + * type exists. + */ + public ResolvedJavaType asSingleType() { + if (allTypesRecorded() && this.getTypes().length == 1) { + return getTypes()[0].getType(); + } + return null; + } +} --- /dev/null 2015-09-16 15:20:47.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/JavaValue.java 2015-09-16 15:20:47.000000000 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Marker interface for things that represent a Java value. + */ +public interface JavaValue { +} --- /dev/null 2015-09-16 15:20:48.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/LIRKind.java 2015-09-16 15:20:48.000000000 -0700 @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.util.*; + +/** + * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the + * low level representation of the value, and a {@link #referenceMask} that describes the location + * of object references in the value, and optionally a {@link #derivedReferenceBase}. + * + *

Constructing {@link LIRKind} instances

+ * + * During LIR generation, every new {@link Value} should get a {@link LIRKind} of the correct + * {@link PlatformKind} that also contains the correct reference information. {@linkplain LIRKind + * LIRKinds} should be created as follows: + * + *

+ * If the result value is created from one or more input values, the {@link LIRKind} should be + * created with {@link LIRKind#combine}(inputs). If the result has a different {@link PlatformKind} + * than the inputs, {@link LIRKind#combine}(inputs).{@link #changeType}(resultKind) should be used. + *

+ * If the result is an exact copy of one of the inputs, {@link Value#getLIRKind()} can be used. Note + * that this is only correct for move-like operations, like conditional move or compare-and-swap. + * For convert operations, {@link LIRKind#combine} should be used. + *

+ * If it is known that the result will be a reference (e.g. pointer arithmetic where the end result + * is a valid oop), {@link LIRKind#reference} should be used. + *

+ * If it is known that the result will neither be a reference nor be derived from a reference, + * {@link LIRKind#value} can be used. If the operation producing this value has inputs, this is very + * likely wrong, and {@link LIRKind#combine} should be used instead. + *

+ * If it is known that the result is derived from a reference in a way that the garbage collector + * can not track, {@link LIRKind#unknownReference} can be used. In most cases, + * {@link LIRKind#combine} should be used instead, since it is able to detect this automatically. + */ +public final class LIRKind { + + /** + * The non-type. This uses {@link #unknownReference}, so it can never be part of an oop map. + */ + public static final LIRKind Illegal = unknownReference(JavaKind.Illegal); + + private final PlatformKind platformKind; + private final int referenceMask; + + private AllocatableValue derivedReferenceBase; + + private static final int UNKNOWN_REFERENCE = -1; + + private LIRKind(PlatformKind platformKind, int referenceMask, AllocatableValue derivedReferenceBase) { + assert platformKind != JavaKind.Object : "Kind.Object shouldn't be used in the backend"; + this.platformKind = platformKind; + this.referenceMask = referenceMask; + this.derivedReferenceBase = derivedReferenceBase; + + assert derivedReferenceBase == null || !derivedReferenceBase.getLIRKind().isDerivedReference() : "derived reference can't have another derived reference as base"; + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a primitive value. Should + * be only used when it's guaranteed that the value is not even indirectly derived from a + * reference. Otherwise, {@link #combine(Value...)} should be used instead. + */ + public static LIRKind value(PlatformKind platformKind) { + return new LIRKind(platformKind, 0, null); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a single tracked oop + * reference. + */ + public static LIRKind reference(PlatformKind platformKind) { + return derivedReference(platformKind, null); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a derived reference. + */ + public static LIRKind derivedReference(PlatformKind platformKind, AllocatableValue base) { + int length = platformKind.getVectorLength(); + assert 0 < length && length < 32 : "vector of " + length + " references not supported"; + return new LIRKind(platformKind, (1 << length) - 1, base); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a value that is derived + * from a reference in a non-linear way. Values of this {@link LIRKind} can not be live at + * safepoints. In most cases, this should not be called directly. {@link #combine} should be + * used instead to automatically propagate this information. + */ + public static LIRKind unknownReference(PlatformKind platformKind) { + return new LIRKind(platformKind, UNKNOWN_REFERENCE, null); + } + + /** + * Create a derived reference. + * + * @param base An {@link AllocatableValue} containing the base pointer of the derived reference. + */ + public LIRKind makeDerivedReference(AllocatableValue base) { + assert !isUnknownReference() && derivedReferenceBase == null; + if (Value.ILLEGAL.equals(base)) { + return makeUnknownReference(); + } else { + if (isValue()) { + return derivedReference(platformKind, base); + } else { + return new LIRKind(platformKind, referenceMask, base); + } + } + } + + /** + * Derive a new type from inputs. The result will have the {@link PlatformKind} of one of the + * inputs. If all inputs are values, the result is a value. Otherwise, the result is an unknown + * reference. + * + * This method should be used to construct the result {@link LIRKind} of any operation that + * modifies values (e.g. arithmetics). + */ + public static LIRKind combine(Value... inputs) { + assert inputs.length > 0; + for (Value input : inputs) { + LIRKind kind = input.getLIRKind(); + if (kind.isUnknownReference()) { + return kind; + } else if (!kind.isValue()) { + return kind.makeUnknownReference(); + } + } + + // all inputs are values, just return one of them + return inputs[0].getLIRKind(); + } + + /** + * Merge the types of the inputs. The result will have the {@link PlatformKind} of one of the + * inputs. If all inputs are values (references), the result is a value (reference). Otherwise, + * the result is an unknown reference. + * + * This method should be used to construct the result {@link LIRKind} of merge operation that + * does not modify values (e.g. phis). + */ + public static LIRKind merge(Value... inputs) { + assert inputs.length > 0; + ArrayList kinds = new ArrayList<>(inputs.length); + for (int i = 0; i < inputs.length; i++) { + kinds.add(inputs[i].getLIRKind()); + } + return merge(kinds); + } + + /** + * Helper method to construct derived reference kinds. Returns the base value of a reference or + * derived reference. For values it returns {@code null}, and for unknown references it returns + * {@link Value#ILLEGAL}. + */ + public static AllocatableValue derivedBaseFromValue(AllocatableValue value) { + LIRKind kind = value.getLIRKind(); + if (kind.isValue()) { + return null; + } else if (kind.isDerivedReference()) { + return kind.getDerivedReferenceBase(); + } else if (kind.isUnknownReference()) { + return Value.ILLEGAL; + } else { + // kind is a reference + return value; + } + } + + /** + * Helper method to construct derived reference kinds. If one of {@code base1} or {@code base2} + * are set, it creates a derived reference using it as the base. If both are set, the result is + * an unknown reference. + */ + public static LIRKind combineDerived(LIRKind kind, AllocatableValue base1, AllocatableValue base2) { + if (base1 == null && base2 == null) { + return kind; + } else if (base1 == null) { + return kind.makeDerivedReference(base2); + } else if (base2 == null) { + return kind.makeDerivedReference(base1); + } else { + return kind.makeUnknownReference(); + } + } + + /** + * @see #merge(Value...) + */ + public static LIRKind merge(Iterable kinds) { + LIRKind mergeKind = null; + + for (LIRKind kind : kinds) { + + if (kind.isUnknownReference()) { + /** + * Kind is an unknown reference, therefore the result can only be also an unknown + * reference. + */ + mergeKind = kind; + break; + } + if (mergeKind == null) { + mergeKind = kind; + continue; + } + + if (kind.isValue()) { + /* Kind is a value. */ + if (mergeKind.referenceMask != 0) { + /* + * Inputs consists of values and references. Make the result an unknown + * reference. + */ + mergeKind = mergeKind.makeUnknownReference(); + break; + } + /* Check that other inputs are also values. */ + } else { + /* Kind is a reference. */ + if (mergeKind.referenceMask != kind.referenceMask) { + /* + * Reference maps do not match so the result can only be an unknown reference. + */ + mergeKind = mergeKind.makeUnknownReference(); + break; + } + } + + } + assert mergeKind != null && verifyMerge(mergeKind, kinds); + + // all inputs are values or references, just return one of them + return mergeKind; + } + + private static boolean verifyMerge(LIRKind mergeKind, Iterable kinds) { + for (LIRKind kind : kinds) { + assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind); + } + return true; + } + + /** + * Create a new {@link LIRKind} with the same reference information and a new + * {@linkplain #getPlatformKind platform kind}. If the new kind is a longer vector than this, + * the new elements are marked as untracked values. + */ + public LIRKind changeType(PlatformKind newPlatformKind) { + if (newPlatformKind == platformKind) { + return this; + } else if (isUnknownReference()) { + return unknownReference(newPlatformKind); + } else if (referenceMask == 0) { + // value type + return LIRKind.value(newPlatformKind); + } else { + // reference type + int newLength = Math.min(32, newPlatformKind.getVectorLength()); + int newReferenceMask = referenceMask & (0xFFFFFFFF >>> (32 - newLength)); + assert newReferenceMask != UNKNOWN_REFERENCE; + return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase); + } + } + + /** + * Create a new {@link LIRKind} with a new {@linkplain #getPlatformKind platform kind}. If the + * new kind is longer than this, the reference positions are repeated to fill the vector. + */ + public LIRKind repeat(PlatformKind newPlatformKind) { + if (isUnknownReference()) { + return unknownReference(newPlatformKind); + } else if (referenceMask == 0) { + // value type + return LIRKind.value(newPlatformKind); + } else { + // reference type + int oldLength = platformKind.getVectorLength(); + int newLength = newPlatformKind.getVectorLength(); + assert oldLength <= newLength && newLength < 32 && (newLength % oldLength) == 0; + + // repeat reference mask to fill new kind + int newReferenceMask = 0; + for (int i = 0; i < newLength; i += platformKind.getVectorLength()) { + newReferenceMask |= referenceMask << i; + } + + assert newReferenceMask != UNKNOWN_REFERENCE; + return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase); + } + } + + /** + * Create a new {@link LIRKind} with the same type, but marked as containing an + * {@link LIRKind#unknownReference}. + */ + public LIRKind makeUnknownReference() { + return new LIRKind(platformKind, UNKNOWN_REFERENCE, null); + } + + /** + * Get the low level type that is used in code generation. + */ + public PlatformKind getPlatformKind() { + return platformKind; + } + + /** + * Check whether this value is a derived reference. + */ + public boolean isDerivedReference() { + return getDerivedReferenceBase() != null; + } + + /** + * Get the base value of a derived reference. + */ + public AllocatableValue getDerivedReferenceBase() { + return derivedReferenceBase; + } + + /** + * Change the base value of a derived reference. This must be called on derived references only. + */ + public void setDerivedReferenceBase(AllocatableValue derivedReferenceBase) { + assert isDerivedReference(); + this.derivedReferenceBase = derivedReferenceBase; + } + + /** + * Check whether this value is derived from a reference in a non-linear way. If this returns + * {@code true}, this value must not be live at safepoints. + */ + public boolean isUnknownReference() { + return referenceMask == UNKNOWN_REFERENCE; + } + + public int getReferenceCount() { + assert !isUnknownReference(); + return Integer.bitCount(referenceMask); + } + + /** + * Check whether the {@code idx}th part of this value is a reference that must be tracked at + * safepoints. + * + * @param idx The index into the vector if this is a vector kind. Must be 0 if this is a scalar + * kind. + */ + public boolean isReference(int idx) { + assert 0 <= idx && idx < platformKind.getVectorLength() : "invalid index " + idx + " in " + this; + return !isUnknownReference() && (referenceMask & 1 << idx) != 0; + } + + /** + * Check whether this kind is a value type that doesn't need to be tracked at safepoints. + */ + public boolean isValue() { + return referenceMask == 0; + } + + @Override + public String toString() { + if (isValue()) { + return platformKind.name(); + } else if (isUnknownReference()) { + return platformKind.name() + "[*]"; + } else { + StringBuilder ret = new StringBuilder(); + ret.append(platformKind.name()); + ret.append('['); + for (int i = 0; i < platformKind.getVectorLength(); i++) { + if (isReference(i)) { + ret.append('.'); + } else { + ret.append(' '); + } + } + ret.append(']'); + return ret.toString(); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((platformKind == null) ? 0 : platformKind.hashCode()); + result = prime * result + referenceMask; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof LIRKind)) { + return false; + } + + LIRKind other = (LIRKind) obj; + return platformKind == other.platformKind && referenceMask == other.referenceMask; + } + + public static boolean verifyMoveKinds(LIRKind dst, LIRKind src) { + if (src.equals(dst)) { + return true; + } + /* + * TODO(je,rs) What we actually want is toStackKind(src.getPlatformKind()).equals( + * dst.getPlatformKind()) but due to the handling of sub-integer at the current point + * (phi-)moves from e.g. integer to short can happen. Therefore we compare stack kinds. + */ + if (toStackKind(src.getPlatformKind()).equals(toStackKind(dst.getPlatformKind()))) { + return !src.isUnknownReference() || dst.isUnknownReference(); + } + return false; + } + + private static PlatformKind toStackKind(PlatformKind platformKind) { + if (platformKind instanceof JavaKind) { + return ((JavaKind) platformKind).getStackKind(); + } + return platformKind; + } +} --- /dev/null 2015-09-16 15:20:49.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/LineNumberTable.java 2015-09-16 15:20:48.000000000 -0700 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +public interface LineNumberTable { + + int[] getLineNumberEntries(); + + int[] getBciEntries(); + + int getLineNumber(int bci); +} --- /dev/null 2015-09-16 15:20:49.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/LineNumberTableImpl.java 2015-09-16 15:20:49.000000000 -0700 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +public class LineNumberTableImpl implements LineNumberTable { + + private final int[] lineNumbers; + private final int[] bci; + + public LineNumberTableImpl(int[] lineNumbers, int[] bci) { + this.lineNumbers = lineNumbers; + this.bci = bci; + } + + @Override + public int[] getLineNumberEntries() { + return lineNumbers; + } + + @Override + public int[] getBciEntries() { + return bci; + } + + @Override + public int getLineNumber(@SuppressWarnings("hiding") int bci) { + for (int i = 0; i < this.bci.length - 1; i++) { + if (this.bci[i] <= bci && bci < this.bci[i + 1]) { + return lineNumbers[i]; + } + } + return lineNumbers[lineNumbers.length - 1]; + } +} --- /dev/null 2015-09-16 15:20:50.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/Local.java 2015-09-16 15:20:50.000000000 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +public interface Local { + + int getStartBCI(); + + int getEndBCI(); + + int getSlot(); + + String getName(); + + JavaType getType(); +} --- /dev/null 2015-09-16 15:20:50.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/LocalImpl.java 2015-09-16 15:20:50.000000000 -0700 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +public class LocalImpl implements Local { + + private final String name; + private final int startBci; + private final int endBci; + private final int slot; + private final JavaType type; + + public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) { + this.name = name; + this.startBci = startBci; + this.endBci = endBci; + this.slot = slot; + this.type = type; + } + + @Override + public int getStartBCI() { + return startBci; + } + + @Override + public int getEndBCI() { + return endBci; + } + + @Override + public String getName() { + return name; + } + + @Override + public JavaType getType() { + return type; + } + + @Override + public int getSlot() { + return slot; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof LocalImpl)) { + return false; + } + LocalImpl that = (LocalImpl) obj; + return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public String toString() { + return "LocalImpl"; + } +} --- /dev/null 2015-09-16 15:20:51.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/LocalVariableTable.java 2015-09-16 15:20:51.000000000 -0700 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +public interface LocalVariableTable { + + Local[] getLocals(); + + Local[] getLocalsAt(int bci); + + Local getLocal(int slot, int bci); +} --- /dev/null 2015-09-16 15:20:52.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/LocalVariableTableImpl.java 2015-09-16 15:20:51.000000000 -0700 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.util.*; + +public class LocalVariableTableImpl implements LocalVariableTable { + + private final Local[] locals; + + public LocalVariableTableImpl(Local[] locals) { + this.locals = locals; + } + + @Override + public Local getLocal(int slot, int bci) { + Local result = null; + for (Local local : locals) { + if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) { + if (result == null) { + result = local; + } else { + throw new IllegalStateException("Locals overlap!"); + } + } + } + return result; + } + + @Override + public Local[] getLocals() { + return locals; + } + + @Override + public Local[] getLocalsAt(int bci) { + List result = new ArrayList<>(); + for (Local l : locals) { + if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) { + result.add(l); + } + } + return result.toArray(new Local[result.size()]); + } + +} --- /dev/null 2015-09-16 15:20:52.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/LocationIdentity.java 2015-09-16 15:20:52.000000000 -0700 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.util.*; + +// JaCoCo Exclude + +/** + * Marker interface for location identities. A different location identity of two memory accesses + * guarantees that the two accesses do not interfere. + * + * Clients of {@link LocationIdentity} must use {@link #equals(Object)}, not {@code ==}, when + * comparing two {@link LocationIdentity} values for equality. Likewise, they must not use + * {@link IdentityHashMap}s with {@link LocationIdentity} values as keys. + */ +public abstract class LocationIdentity { + + private static final class AnyLocationIdentity extends LocationIdentity { + @Override + public boolean isImmutable() { + return false; + } + + @Override + public String toString() { + return "ANY_LOCATION"; + } + } + + public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity(); + + public static LocationIdentity any() { + return ANY_LOCATION; + } + + /** + * Denotes a location is unchanging in all cases. Not that this is different than the Java + * notion of final which only requires definite assignment. + */ + public abstract boolean isImmutable(); + + public final boolean isMutable() { + return !isImmutable(); + } + + public final boolean isAny() { + return this == ANY_LOCATION; + } + + public final boolean isSingle() { + return this != ANY_LOCATION; + } + + public final boolean overlaps(LocationIdentity other) { + return isAny() || other.isAny() || this.equals(other); + } +} --- /dev/null 2015-09-16 15:20:53.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/MemoryAccessProvider.java 2015-09-16 15:20:53.000000000 -0700 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Provides memory access operations for the target VM. + */ +public interface MemoryAccessProvider { + + /** + * Reads a value of this kind using a base address and a displacement. No bounds checking or + * type checking is performed. Returns {@code null} if the value is not available at this point. + * + * @param base the base address from which the value is read. + * @param displacement the displacement within the object in bytes + * @return the read value encapsulated in a {@link JavaConstant} object, or {@code null} if the + * value cannot be read. + */ + JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant base, long displacement); + + /** + * Reads a primitive value using a base address and a displacement. + * + * @param kind the {@link JavaKind} of the returned {@link JavaConstant} object + * @param base the base address from which the value is read + * @param displacement the displacement within the object in bytes + * @param bits the number of bits to read from memory + * @return the read value encapsulated in a {@link JavaConstant} object of {@link JavaKind} kind + */ + JavaConstant readPrimitiveConstant(JavaKind kind, Constant base, long displacement, int bits); + + /** + * Reads a Java {@link Object} value using a base address and a displacement. + * + * @param base the base address from which the value is read + * @param displacement the displacement within the object in bytes + * @return the read value encapsulated in a {@link Constant} object + */ + JavaConstant readObjectConstant(Constant base, long displacement); +} --- /dev/null 2015-09-16 15:20:53.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/MetaAccessProvider.java 2015-09-16 15:20:53.000000000 -0700 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2012, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.lang.reflect.*; + +/** + * Provides access to the metadata of a class typically provided in a class file. + */ +public interface MetaAccessProvider { + + /** + * Returns the resolved Java type representing a given Java class. + * + * @param clazz the Java class object + * @return the resolved Java type object + */ + ResolvedJavaType lookupJavaType(Class clazz); + + /** + * Returns the resolved Java types representing some given Java classes. + * + * @param classes the Java class objects + * @return the resolved Java type objects + */ + default ResolvedJavaType[] lookupJavaTypes(Class[] classes) { + ResolvedJavaType[] result = new ResolvedJavaType[classes.length]; + for (int i = 0; i < result.length; i++) { + result[i] = lookupJavaType(classes[i]); + } + return result; + } + + /** + * Provides the {@link ResolvedJavaMethod} for a {@link Method} or {@link Constructor} obtained + * via reflection. + */ + ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod); + + /** + * Provides the {@link ResolvedJavaField} for a {@link Field} obtained via reflection. + */ + ResolvedJavaField lookupJavaField(Field reflectionField); + + /** + * Returns the resolved Java type of the given {@link JavaConstant} object. + * + * @return {@code null} if {@code constant.isNull() || !constant.kind.isObject()} + */ + ResolvedJavaType lookupJavaType(JavaConstant constant); + + /** + * Returns the number of bytes occupied by this constant value or constant object. + * + * @param constant the constant whose bytes should be measured + * @return the number of bytes occupied by this constant + */ + long getMemorySize(JavaConstant constant); + + /** + * Parses a method + * descriptor into a {@link Signature}. The behavior of this method is undefined if the + * method descriptor is not well formed. + */ + Signature parseMethodDescriptor(String methodDescriptor); + + /** + * Encodes a deoptimization action and a deoptimization reason in an integer value. + * + * @param debugId an integer that can be used to track the origin of a deoptimization at + * runtime. There is no guarantee that the runtime will use this value. The runtime + * may even keep fewer than 32 bits. + * + * @return the encoded value as an integer + */ + JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int debugId); + + DeoptimizationReason decodeDeoptReason(JavaConstant constant); + + DeoptimizationAction decodeDeoptAction(JavaConstant constant); + + int decodeDebugId(JavaConstant constant); +} --- /dev/null 2015-09-16 15:20:54.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/MetaUtil.java 2015-09-16 15:20:54.000000000 -0700 @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +/** + * Miscellaneous collection of utility methods used by {@code jdk.internal.jvmci.meta} and its + * clients. + */ +public class MetaUtil { + + private static class ClassInfo { + public long totalSize; + public long instanceCount; + + @Override + public String toString() { + return "totalSize=" + totalSize + ", instanceCount=" + instanceCount; + } + } + + /** + * Returns the number of bytes occupied by this constant value or constant object and + * recursively all values reachable from this value. + * + * @param constant the constant whose bytes should be measured + * @param printTopN print total size and instance count of the top n classes is desired + * @return the number of bytes occupied by this constant + */ + public static long getMemorySizeRecursive(MetaAccessProvider access, ConstantReflectionProvider constantReflection, JavaConstant constant, PrintStream out, int printTopN) { + Set marked = new HashSet<>(); + Deque stack = new ArrayDeque<>(); + if (constant.getJavaKind() == JavaKind.Object && constant.isNonNull()) { + marked.add(constant); + } + final HashMap histogram = new HashMap<>(); + stack.push(constant); + long sum = 0; + while (!stack.isEmpty()) { + JavaConstant c = stack.pop(); + long memorySize = access.getMemorySize(constant); + sum += memorySize; + if (c.getJavaKind() == JavaKind.Object && c.isNonNull()) { + ResolvedJavaType clazz = access.lookupJavaType(c); + if (!histogram.containsKey(clazz)) { + histogram.put(clazz, new ClassInfo()); + } + ClassInfo info = histogram.get(clazz); + info.instanceCount++; + info.totalSize += memorySize; + ResolvedJavaType type = access.lookupJavaType(c); + if (type.isArray()) { + if (!type.getComponentType().isPrimitive()) { + int length = constantReflection.readArrayLength(c); + for (int i = 0; i < length; i++) { + JavaConstant value = constantReflection.readArrayElement(c, i); + pushConstant(marked, stack, value); + } + } + } else { + ResolvedJavaField[] instanceFields = type.getInstanceFields(true); + for (ResolvedJavaField f : instanceFields) { + if (f.getJavaKind() == JavaKind.Object) { + JavaConstant value = constantReflection.readFieldValue(f, c); + pushConstant(marked, stack, value); + } + } + } + } + } + ArrayList clazzes = new ArrayList<>(); + clazzes.addAll(histogram.keySet()); + Collections.sort(clazzes, new Comparator() { + + @Override + public int compare(ResolvedJavaType o1, ResolvedJavaType o2) { + long l1 = histogram.get(o1).totalSize; + long l2 = histogram.get(o2).totalSize; + if (l1 > l2) { + return -1; + } else if (l1 == l2) { + return 0; + } else { + return 1; + } + } + }); + + int z = 0; + for (ResolvedJavaType c : clazzes) { + if (z > printTopN) { + break; + } + out.println("Class " + c + ", " + histogram.get(c)); + ++z; + } + + return sum; + } + + private static void pushConstant(Set marked, Deque stack, JavaConstant value) { + if (value.isNonNull()) { + if (!marked.contains(value)) { + marked.add(value); + stack.push(value); + } + } + } + + /** + * Calls {@link JavaType#resolve(ResolvedJavaType)} on an array of types. + */ + public static ResolvedJavaType[] resolveJavaTypes(JavaType[] types, ResolvedJavaType accessingClass) { + ResolvedJavaType[] result = new ResolvedJavaType[types.length]; + for (int i = 0; i < result.length; i++) { + result[i] = types[i].resolve(accessingClass); + } + return result; + } + + /** + * Extends the functionality of {@link Class#getSimpleName()} to include a non-empty string for + * anonymous and local classes. + * + * @param clazz the class for which the simple name is being requested + * @param withEnclosingClass specifies if the returned name should be qualified with the name(s) + * of the enclosing class/classes of {@code clazz} (if any). This option is ignored + * if {@code clazz} denotes an anonymous or local class. + * @return the simple name + */ + public static String getSimpleName(Class clazz, boolean withEnclosingClass) { + final String simpleName = clazz.getSimpleName(); + if (simpleName.length() != 0) { + if (withEnclosingClass) { + String prefix = ""; + Class enclosingClass = clazz; + while ((enclosingClass = enclosingClass.getEnclosingClass()) != null) { + prefix = enclosingClass.getSimpleName() + "." + prefix; + } + return prefix + simpleName; + } + return simpleName; + } + // Must be an anonymous or local class + final String name = clazz.getName(); + int index = name.indexOf('$'); + if (index == -1) { + return name; + } + index = name.lastIndexOf('.', index); + if (index == -1) { + return name; + } + return name.substring(index + 1); + } + + static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) { + switch (name.charAt(0)) { + case 'L': { + String result = name.substring(1, name.length() - 1).replace('/', '.'); + if (!qualified) { + final int lastDot = result.lastIndexOf('.'); + if (lastDot != -1) { + result = result.substring(lastDot + 1); + } + } + return result; + } + case '[': + return classForNameCompatible ? name.replace('/', '.') : internalNameToJava(name.substring(1), qualified, classForNameCompatible) + "[]"; + default: + if (name.length() != 1) { + throw new IllegalArgumentException("Illegal internal name: " + name); + } + return JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)).getJavaName(); + } + } + + /** + * Turns an class name in internal format into a resolved Java type. + */ + public static ResolvedJavaType classForName(String internal, MetaAccessProvider metaAccess, ClassLoader cl) { + JavaKind k = JavaKind.fromTypeString(internal); + try { + String n = internalNameToJava(internal, true, true); + return metaAccess.lookupJavaType(k.isPrimitive() ? k.toJavaClass() : Class.forName(n, true, cl)); + } catch (ClassNotFoundException cnfe) { + throw new IllegalArgumentException("could not instantiate class described by " + internal, cnfe); + } + } + + /** + * Convenient shortcut for calling + * {@link #appendLocation(StringBuilder, ResolvedJavaMethod, int)} without having to supply a + * {@link StringBuilder} instance and convert the result to a string. + */ + public static String toLocation(ResolvedJavaMethod method, int bci) { + return appendLocation(new StringBuilder(), method, bci).toString(); + } + + /** + * Appends a string representation of a location specified by a given method and bci to a given + * {@link StringBuilder}. If a stack trace element with a non-null file name and non-negative + * line number is {@linkplain ResolvedJavaMethod#asStackTraceElement(int) available} for the + * given method, then the string returned is the {@link StackTraceElement#toString()} value of + * the stack trace element, suffixed by the bci location. For example: + * + *

+     *     java.lang.String.valueOf(String.java:2930) [bci: 12]
+     * 
+ * + * Otherwise, the string returned is the value of applying {@link JavaMethod#format(String)} + * with the format string {@code "%H.%n(%p)"}, suffixed by the bci location. For example: + * + *
+     *     java.lang.String.valueOf(int) [bci: 12]
+     * 
+ * + * @param sb + * @param method + * @param bci + */ + public static StringBuilder appendLocation(StringBuilder sb, ResolvedJavaMethod method, int bci) { + if (method != null) { + StackTraceElement ste = method.asStackTraceElement(bci); + if (ste.getFileName() != null && ste.getLineNumber() > 0) { + sb.append(ste); + } else { + sb.append(method.format("%H.%n(%p)")); + } + } else { + sb.append("Null method"); + } + return sb.append(" [bci: ").append(bci).append(']'); + } + + static void appendProfile(StringBuilder buf, AbstractJavaProfile profile, int bci, String type, String sep) { + if (profile != null) { + AbstractProfiledItem[] pitems = profile.getItems(); + if (pitems != null) { + buf.append(String.format("%s@%d:", type, bci)); + for (int j = 0; j < pitems.length; j++) { + AbstractProfiledItem pitem = pitems[j]; + buf.append(String.format(" %.6f (%s)%s", pitem.getProbability(), pitem.getItem(), sep)); + } + if (profile.getNotRecordedProbability() != 0) { + buf.append(String.format(" %.6f %s", profile.getNotRecordedProbability(), type, sep)); + } else { + buf.append(String.format(" %s", type, sep)); + } + } + } + } + + /** + * Converts a Java source-language class name into the internal form. + * + * @param className the class name + * @return the internal name form of the class name + */ + public static String toInternalName(String className) { + if (className.startsWith("[")) { + /* Already in the correct array style. */ + return className.replace('.', '/'); + } + + StringBuilder result = new StringBuilder(); + String base = className; + while (base.endsWith("[]")) { + result.append("["); + base = base.substring(0, base.length() - 2); + } + + switch (base) { + case "boolean": + result.append("Z"); + break; + case "byte": + result.append("B"); + break; + case "short": + result.append("S"); + break; + case "char": + result.append("C"); + break; + case "int": + result.append("I"); + break; + case "float": + result.append("F"); + break; + case "long": + result.append("J"); + break; + case "double": + result.append("D"); + break; + case "void": + result.append("V"); + break; + default: + result.append("L").append(base.replace('.', '/')).append(";"); + break; + } + return result.toString(); + } + + /** + * Prepends the String {@code indentation} to every line in String {@code lines}, including a + * possibly non-empty line following the final newline. + */ + public static String indent(String lines, String indentation) { + if (lines.length() == 0) { + return lines; + } + final String newLine = "\n"; + if (lines.endsWith(newLine)) { + return indentation + (lines.substring(0, lines.length() - 1)).replace(newLine, newLine + indentation) + newLine; + } + return indentation + lines.replace(newLine, newLine + indentation); + } + + /** + * Gets a string representation of an object based soley on its class and its + * {@linkplain System#identityHashCode(Object) identity hash code}. This avoids and calls to + * virtual methods on the object such as {@link Object#hashCode()}. + */ + public static String identityHashCodeString(Object obj) { + if (obj == null) { + return "null"; + } + return obj.getClass().getName() + "@" + System.identityHashCode(obj); + } + + /** + * Used to lookup constants from {@link Modifier} that are not public (VARARGS, SYNTHETIC etc.). + */ + static int getNonPublicModifierStaticField(String name) { + try { + Field field = Modifier.class.getDeclaredField(name); + field.setAccessible(true); + return field.getInt(null); + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + throw new InternalError(e); + } + } +} --- /dev/null 2015-09-16 15:20:55.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/MethodHandleAccessProvider.java 2015-09-16 15:20:55.000000000 -0700 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.lang.invoke.*; + +/** + * Interface to access the internals of the {@link MethodHandle} implementation of the VM. An + * implementation of this interface is usually required to access non-public classes, methods, and + * fields of {@link MethodHandle}, i.e., data that is not standardized by the Java specification. + */ +public interface MethodHandleAccessProvider { + + /** + * Identification for methods defined on the class {@link MethodHandle} that are processed by + * the {@link MethodHandleAccessProvider}. + */ + public enum IntrinsicMethod { + /** The method {@code MethodHandle.invokeBasic}. */ + INVOKE_BASIC, + /** The method {@code MethodHandle.linkToStatic}. */ + LINK_TO_STATIC, + /** The method {@code MethodHandle.linkToSpecial}. */ + LINK_TO_SPECIAL, + /** The method {@code MethodHandle.linkToVirtual}. */ + LINK_TO_VIRTUAL, + /** The method {@code MethodHandle.linkToInterface}. */ + LINK_TO_INTERFACE + } + + /** + * Returns the method handle method intrinsic identifier for the provided method, or + * {@code null} if the method is not an intrinsic processed by this interface. + */ + IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method); + + /** + * Resolves the invocation target for an invocation of {@link IntrinsicMethod#INVOKE_BASIC + * MethodHandle.invokeBasic} with the given constant receiver {@link MethodHandle}. Returns + * {@code null} if the invocation target is not available at this time. + *

+ * The first invocations of a method handle can use an interpreter to lookup the actual invoked + * method; frequently executed method handles can use Java bytecode generation to avoid the + * interpreter overhead. If the parameter forceBytecodeGeneration is set to true, the VM should + * try to generate bytecodes before this method returns. + */ + ResolvedJavaMethod resolveInvokeBasicTarget(JavaConstant methodHandle, boolean forceBytecodeGeneration); + + /** + * Resolves the invocation target for an invocation of a {@code MethodHandle.linkTo*} method + * with the given constant member name. The member name is the last parameter of the + * {@code linkTo*} method. Returns {@code null} if the invocation target is not available at + * this time. + */ + ResolvedJavaMethod resolveLinkToTarget(JavaConstant memberName); +} --- /dev/null 2015-09-16 15:20:55.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/ModifiersProvider.java 2015-09-16 15:20:55.000000000 -0700 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import static java.lang.reflect.Modifier.*; + +import java.lang.reflect.*; + +/** + * A Java element (i.e., a class, interface, field or method) that is described by a set of Java + * language {@linkplain #getModifiers() modifiers}. + */ +public interface ModifiersProvider { + int BRIDGE = MetaUtil.getNonPublicModifierStaticField("BRIDGE"); + int VARARGS = MetaUtil.getNonPublicModifierStaticField("VARARGS"); + int SYNTHETIC = MetaUtil.getNonPublicModifierStaticField("SYNTHETIC"); + int ANNOTATION = MetaUtil.getNonPublicModifierStaticField("ANNOTATION"); + int ENUM = MetaUtil.getNonPublicModifierStaticField("ENUM"); + int MANDATED = MetaUtil.getNonPublicModifierStaticField("MANDATED"); + + /** + * Returns the Java Virtual Machine modifiers for this element. Note that this can differ from + * standard Java Reflection modifiers. For example at the JVM level, classes ( + * {@link ResolvedJavaType}) can not be private or protected. + */ + int getModifiers(); + + /** + * @see Modifier#isInterface(int) + */ + default boolean isInterface() { + return Modifier.isInterface(getModifiers()); + } + + /** + * @see Modifier#isSynchronized(int) + */ + default boolean isSynchronized() { + return Modifier.isSynchronized(getModifiers()); + } + + /** + * @see Modifier#isStatic(int) + */ + default boolean isStatic() { + return Modifier.isStatic(getModifiers()); + } + + /** + * The setting of the final modifier bit for types is somewhat confusing, so don't export + * isFinal by default. Subclasses like {@link ResolvedJavaField} and {@link ResolvedJavaMethod} + * can export it as isFinal, but {@link ResolvedJavaType} can provide a more sensible equivalent + * like {@link ResolvedJavaType#isLeaf}. + * + * @see Modifier#isFinal(int) + */ + default boolean isFinalFlagSet() { + return Modifier.isFinal(getModifiers()); + } + + /** + * @see Modifier#isPublic(int) + */ + default boolean isPublic() { + return Modifier.isPublic(getModifiers()); + } + + /** + * Determines if this element is neither {@linkplain #isPublic() public}, + * {@linkplain #isProtected() protected} nor {@linkplain #isPrivate() private}. + */ + default boolean isPackagePrivate() { + return ((PUBLIC | PROTECTED | PRIVATE) & getModifiers()) == 0; + } + + /** + * @see Modifier#isPrivate(int) + */ + default boolean isPrivate() { + return Modifier.isPrivate(getModifiers()); + } + + /** + * @see Modifier#isProtected(int) + */ + default boolean isProtected() { + return Modifier.isProtected(getModifiers()); + } + + /** + * @see Modifier#isTransient(int) + */ + default boolean isTransient() { + return Modifier.isTransient(getModifiers()); + } + + /** + * @see Modifier#isStrict(int) + */ + default boolean isStrict() { + return Modifier.isStrict(getModifiers()); + } + + /** + * @see Modifier#isVolatile(int) + */ + default boolean isVolatile() { + return Modifier.isVolatile(getModifiers()); + } + + /** + * @see Modifier#isNative(int) + */ + default boolean isNative() { + return Modifier.isNative(getModifiers()); + } + + /** + * @see Modifier#isAbstract(int) + */ + default boolean isAbstract() { + return Modifier.isAbstract(getModifiers()); + } + + /** + * Checks that the method is concrete and not abstract. + * + * @return whether the method is a concrete method + */ + default boolean isConcrete() { + return !isAbstract(); + } + + static int jvmClassModifiers() { + // no SUPER + return PUBLIC | FINAL | INTERFACE | ABSTRACT | ANNOTATION | ENUM | SYNTHETIC; + } + + static int jvmMethodModifiers() { + return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | SYNCHRONIZED | BRIDGE | VARARGS | NATIVE | ABSTRACT | STRICT | SYNTHETIC; + } + + static int jvmFieldModifiers() { + return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | VOLATILE | TRANSIENT | ENUM | SYNTHETIC; + } +} --- /dev/null 2015-09-16 15:20:56.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/NullConstant.java 2015-09-16 15:20:56.000000000 -0700 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * The implementation type of the {@link JavaConstant#NULL_POINTER null constant}. + */ +final class NullConstant implements JavaConstant { + + protected NullConstant() { + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public boolean isDefaultForKind() { + return true; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public String toString() { + return JavaConstant.toString(this); + } + + @Override + public String toValueString() { + return "null"; + } + + @Override + public int hashCode() { + return 13; + } + + @Override + public boolean equals(Object o) { + return o instanceof NullConstant; + } +} --- /dev/null 2015-09-16 15:20:57.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/PlatformKind.java 2015-09-16 15:20:56.000000000 -0700 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2013, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Represents a platform-specific low-level type for values. + */ +public interface PlatformKind { + + String name(); + + JavaConstant getDefaultValue(); + + public interface Key { + + } + + public class EnumKey> implements Key { + private final Enum e; + + public EnumKey(Enum e) { + this.e = e; + } + + @Override + public int hashCode() { + return e.ordinal() ^ e.name().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof EnumKey) { + EnumKey that = (EnumKey) obj; + return this.e == that.e; + } + return false; + } + } + + /** + * Gets a value associated with this object that can be used as a stable key in a map. The + * {@link Object#hashCode()} implementation of the returned value should be stable between VM + * executions. + */ + Key getKey(); + + /** + * Get the size in bytes of this {@link PlatformKind}. + */ + int getSizeInBytes(); + + /** + * Returns how many primitive values fit in this {@link PlatformKind}. For scalar types this is + * one, for SIMD types it may be higher. + */ + int getVectorLength(); + + /** + * Gets a single type char that identifies this type for use in debug output. + */ + char getTypeChar(); +} --- /dev/null 2015-09-16 15:20:57.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/PrimitiveConstant.java 2015-09-16 15:20:57.000000000 -0700 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.nio.*; + +/** + * Represents a primitive constant value, such as an integer or floating point number, within the + * compiler and across the compiler/runtime interface. + */ +public class PrimitiveConstant implements JavaConstant, SerializableConstant { + + private final JavaKind kind; + + /** + * The boxed primitive value as a {@code long}. For {@code float} and {@code double} values, + * this value is the result of {@link Float#floatToRawIntBits(float)} and + * {@link Double#doubleToRawLongBits(double)} respectively. + */ + private final long primitive; + + protected PrimitiveConstant(JavaKind kind, long primitive) { + this.primitive = primitive; + this.kind = kind; + + assert kind.isPrimitive() || kind == JavaKind.Illegal; + } + + @Override + public JavaKind getJavaKind() { + return kind; + } + + @Override + public boolean isNull() { + return false; + } + + @Override + public boolean isDefaultForKind() { + return primitive == 0; + } + + @Override + public boolean asBoolean() { + assert getJavaKind() == JavaKind.Boolean; + return primitive != 0L; + } + + @Override + public int asInt() { + assert getJavaKind().getStackKind() == JavaKind.Int : getJavaKind().getStackKind(); + return (int) primitive; + } + + @Override + public long asLong() { + assert getJavaKind().isNumericInteger(); + return primitive; + } + + @Override + public float asFloat() { + assert getJavaKind() == JavaKind.Float; + return Float.intBitsToFloat((int) primitive); + } + + @Override + public double asDouble() { + assert getJavaKind() == JavaKind.Double; + return Double.longBitsToDouble(primitive); + } + + @Override + public Object asBoxedPrimitive() { + switch (getJavaKind()) { + case Byte: + return Byte.valueOf((byte) primitive); + case Boolean: + return Boolean.valueOf(asBoolean()); + case Short: + return Short.valueOf((short) primitive); + case Char: + return Character.valueOf((char) primitive); + case Int: + return Integer.valueOf(asInt()); + case Long: + return Long.valueOf(asLong()); + case Float: + return Float.valueOf(asFloat()); + case Double: + return Double.valueOf(asDouble()); + default: + throw new IllegalArgumentException("unexpected kind " + getJavaKind()); + } + } + + @Override + public int getSerializedSize() { + return getJavaKind().getByteCount(); + } + + @Override + public void serialize(ByteBuffer buffer) { + switch (getJavaKind()) { + case Byte: + case Boolean: + buffer.put((byte) primitive); + break; + case Short: + buffer.putShort((short) primitive); + break; + case Char: + buffer.putChar((char) primitive); + break; + case Int: + buffer.putInt(asInt()); + break; + case Long: + buffer.putLong(asLong()); + break; + case Float: + buffer.putFloat(asFloat()); + break; + case Double: + buffer.putDouble(asDouble()); + break; + default: + throw new IllegalArgumentException("unexpected kind " + getJavaKind()); + } + } + + @Override + public int hashCode() { + return (int) (primitive ^ (primitive >>> 32)) * (getJavaKind().ordinal() + 31); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof PrimitiveConstant)) { + return false; + } + PrimitiveConstant other = (PrimitiveConstant) o; + return this.kind.equals(other.kind) && this.primitive == other.primitive; + } + + @Override + public String toString() { + if (getJavaKind() == JavaKind.Illegal) { + return "illegal"; + } else { + return getJavaKind().getJavaName() + "[" + asBoxedPrimitive() + "|0x" + Long.toHexString(primitive) + "]"; + } + } +} --- /dev/null 2015-09-16 15:20:58.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/ProfilingInfo.java 2015-09-16 15:20:58.000000000 -0700 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2012, 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Provides access to the profiling information of one specific method. Every accessor method + * returns the information that is available at the time of invocation. If a method is invoked + * multiple times, it may return significantly different results for every invocation as the + * profiling information may be changed by other Java threads at any time. + */ +public interface ProfilingInfo { + + /** + * Returns the length of the bytecodes associated with this profile. + */ + int getCodeSize(); + + /** + * Returns an estimate of how often the branch at the given byte code was taken. + * + * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or -1 if + * this information is not available. + */ + double getBranchTakenProbability(int bci); + + /** + * Returns an estimate of how often the switch cases are taken at the given BCI. The default + * case is stored as the last entry. + * + * @return A double value that contains the estimated probabilities, with 0.0 meaning never and + * 1.0 meaning always, or -1 if this information is not available. + */ + double[] getSwitchProbabilities(int bci); + + /** + * Returns the TypeProfile for the given BCI. + * + * @return Returns a JavaTypeProfile object, or null if not available. + */ + JavaTypeProfile getTypeProfile(int bci); + + /** + * Returns the MethodProfile for the given BCI. + * + * @return Returns a JavaMethodProfile object, or null if not available. + */ + JavaMethodProfile getMethodProfile(int bci); + + /** + * Returns information if the given BCI did ever throw an exception. + * + * @return {@link TriState#TRUE} if the instruction has thrown an exception at least once, + * {@link TriState#FALSE} if it never threw an exception, and {@link TriState#UNKNOWN} + * if this information was not recorded. + */ + TriState getExceptionSeen(int bci); + + /** + * Returns information if null was ever seen for the given BCI. This information is collected + * for the aastore, checkcast and instanceof bytecodes. + * + * @return {@link TriState#TRUE} if null was seen for the instruction, {@link TriState#FALSE} if + * null was NOT seen, and {@link TriState#UNKNOWN} if this information was not recorded. + */ + TriState getNullSeen(int bci); + + /** + * Returns an estimate how often the current BCI was executed. Avoid comparing execution counts + * to each other, as the returned value highly depends on the time of invocation. + * + * @return the estimated execution count or -1 if not available. + */ + int getExecutionCount(int bci); + + /** + * Returns how frequently a method was deoptimized for the given deoptimization reason. This + * only indicates how often the method did fall back to the interpreter for the execution and + * does not indicate how often it was recompiled. + * + * @param reason the reason for which the number of deoptimizations should be queried + * @return the number of times the compiled method deoptimized for the given reason. + */ + int getDeoptimizationCount(DeoptimizationReason reason); + + /** + * Records the size of the compiler intermediate representation (IR) associated with this + * method. + * + * @param irType the IR type for which the size is being recorded + * @param irSize the IR size to be recorded. The unit depends on the IR. + * @return whether recording this information for {@code irType} is supported + */ + boolean setCompilerIRSize(Class irType, int irSize); + + /** + * Gets the size of the compiler intermediate representation (IR) associated with this method + * last recorded by {@link #setCompilerIRSize(Class, int)}. + * + * @param irType the IR type for which the size is being requested + * @return the requested IR size or -1 if it is unavailable for {@code irType} + */ + int getCompilerIRSize(Class irType); + + /** + * Returns true if the profiling information can be assumed as sufficiently accurate. + * + * @return true if the profiling information was recorded often enough mature enough, false + * otherwise. + */ + boolean isMature(); + + /** + * Force data to be treated as mature if possible. + */ + void setMature(); + + /** + * Formats this profiling information to a string. + * + * @param method an optional method that augments the profile string returned + * @param sep the separator to use for each separate profile record + */ + default String toString(ResolvedJavaMethod method, String sep) { + StringBuilder buf = new StringBuilder(100); + if (method != null) { + buf.append(String.format("canBeStaticallyBound: %b%s", method.canBeStaticallyBound(), sep)); + } + for (int i = 0; i < getCodeSize(); i++) { + if (getExecutionCount(i) != -1) { + buf.append(String.format("executionCount@%d: %d%s", i, getExecutionCount(i), sep)); + } + + if (getBranchTakenProbability(i) != -1) { + buf.append(String.format("branchProbability@%d: %.6f%s", i, getBranchTakenProbability(i), sep)); + } + + double[] switchProbabilities = getSwitchProbabilities(i); + if (switchProbabilities != null) { + buf.append(String.format("switchProbabilities@%d:", i)); + for (int j = 0; j < switchProbabilities.length; j++) { + buf.append(String.format(" %.6f", switchProbabilities[j])); + } + buf.append(sep); + } + + if (getExceptionSeen(i) != TriState.UNKNOWN) { + buf.append(String.format("exceptionSeen@%d: %s%s", i, getExceptionSeen(i).name(), sep)); + } + + if (getNullSeen(i) != TriState.UNKNOWN) { + buf.append(String.format("nullSeen@%d: %s%s", i, getNullSeen(i).name(), sep)); + } + + JavaTypeProfile typeProfile = getTypeProfile(i); + MetaUtil.appendProfile(buf, typeProfile, i, "types", sep); + + JavaMethodProfile methodProfile = getMethodProfile(i); + MetaUtil.appendProfile(buf, methodProfile, i, "methods", sep); + } + + boolean firstDeoptReason = true; + for (DeoptimizationReason reason : DeoptimizationReason.values()) { + int count = getDeoptimizationCount(reason); + if (count > 0) { + if (firstDeoptReason) { + buf.append("deoptimization history").append(sep); + firstDeoptReason = false; + } + buf.append(String.format(" %s: %d%s", reason.name(), count, sep)); + } + } + if (buf.length() == 0) { + return ""; + } + String s = buf.toString(); + return s.substring(0, s.length() - sep.length()); + } + +} --- /dev/null 2015-09-16 15:20:58.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/RawConstant.java 2015-09-16 15:20:58.000000000 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +public class RawConstant extends PrimitiveConstant { + + public RawConstant(long rawValue) { + super(JavaKind.Int, rawValue); + } +} --- /dev/null 2015-09-16 15:20:59.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/ResolvedJavaField.java 2015-09-16 15:20:59.000000000 -0700 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.lang.annotation.*; +import java.lang.reflect.*; + +/** + * Represents a reference to a resolved Java field. Fields, like methods and types, are resolved + * through {@link ConstantPool constant pools}. + */ +public interface ResolvedJavaField extends JavaField, ModifiersProvider { + + /** + * {@inheritDoc} + *

+ * Only the {@linkplain Modifier#fieldModifiers() field flags} specified in the JVM + * specification will be included in the returned mask. + */ + int getModifiers(); + + default boolean isFinal() { + return ModifiersProvider.super.isFinalFlagSet(); + } + + /** + * Determines if this field was injected by the VM. Such a field, for example, is not derived + * from a class file. + */ + boolean isInternal(); + + /** + * Determines if this field is a synthetic field as defined by the Java Language Specification. + */ + boolean isSynthetic(); + + /** + * Returns the {@link ResolvedJavaType} object representing the class or interface that declares + * this field. + */ + ResolvedJavaType getDeclaringClass(); + + /** + * Returns all annotations of this field. If no annotations are present, an array of length 0 is + * returned. + */ + Annotation[] getAnnotations(); + + /** + * Returns the annotation for the specified type of this field, if such an annotation is + * present. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return this element's annotation for the specified annotation type if present on this field, + * else {@code null} + */ + T getAnnotation(Class annotationClass); + + /** + * Returns an object representing the unique location identity of this resolved Java field. + * + * @return the location identity of the field + */ + LocationIdentity getLocationIdentity(); +} --- /dev/null 2015-09-16 15:21:00.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/ResolvedJavaMethod.java 2015-09-16 15:20:59.000000000 -0700 @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2009, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.lang.annotation.*; +import java.lang.invoke.*; +import java.lang.reflect.*; +import java.util.*; + +/** + * Represents a resolved Java method. Methods, like fields and types, are resolved through + * {@link ConstantPool constant pools}. + */ +public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersProvider { + + /** + * Returns the bytecode of this method, if the method has code. The returned byte array does not + * contain breakpoints or non-Java bytecodes. This may return null if the + * {@link #getDeclaringClass() holder} is not {@link ResolvedJavaType#isLinked() linked}. + * + * The contained constant pool indices may not be the ones found in the original class file but + * they can be used with the JVMCI API (e.g. methods in {@link ConstantPool}). + * + * @return the bytecode of the method, or {@code null} if {@code getCodeSize() == 0} or if the + * code is not ready. + */ + byte[] getCode(); + + /** + * Returns the size of the bytecode of this method, if the method has code. This is equivalent + * to {@link #getCode()}. {@code length} if the method has code. + * + * @return the size of the bytecode in bytes, or 0 if no bytecode is available + */ + int getCodeSize(); + + /** + * Returns the {@link ResolvedJavaType} object representing the class or interface that declares + * this method. + */ + ResolvedJavaType getDeclaringClass(); + + /** + * Returns the maximum number of locals used in this method's bytecodes. + */ + int getMaxLocals(); + + /** + * Returns the maximum number of stack slots used in this method's bytecodes. + */ + int getMaxStackSize(); + + /** + * {@inheritDoc} + *

+ * Only the {@linkplain Modifier#methodModifiers() method flags} specified in the JVM + * specification will be included in the returned mask. + */ + int getModifiers(); + + default boolean isFinal() { + return ModifiersProvider.super.isFinalFlagSet(); + } + + /** + * Determines if this method is a synthetic method as defined by the Java Language + * Specification. + */ + default boolean isSynthetic() { + return (SYNTHETIC & getModifiers()) == SYNTHETIC; + } + + /** + * Checks that the method is a varargs + * method. + * + * @return whether the method is a varargs method + */ + default boolean isVarArgs() { + return (VARARGS & getModifiers()) == VARARGS; + } + + /** + * Checks that the method is a bridge + * method. + * + * @return whether the method is a bridge method + */ + default boolean isBridge() { + return (BRIDGE & getModifiers()) == BRIDGE; + } + + /** + * Returns {@code true} if this method is a default method; returns {@code false} otherwise. + * + * A default method is a public non-abstract instance method, that is, a non-static method with + * a body, declared in an interface type. + * + * @return true if and only if this method is a default method as defined by the Java Language + * Specification. + */ + boolean isDefault(); + + /** + * Checks whether this method is a class initializer. + * + * @return {@code true} if the method is a class initializer + */ + boolean isClassInitializer(); + + /** + * Checks whether this method is a constructor. + * + * @return {@code true} if the method is a constructor + */ + boolean isConstructor(); + + /** + * Checks whether this method can be statically bound (usually, that means it is final or + * private or static, but not abstract, or the declaring class is final). + * + * @return {@code true} if this method can be statically bound + */ + boolean canBeStaticallyBound(); + + /** + * Returns the list of exception handlers for this method. + */ + ExceptionHandler[] getExceptionHandlers(); + + /** + * Returns a stack trace element for this method and a given bytecode index. + */ + StackTraceElement asStackTraceElement(int bci); + + /** + * Returns an object that provides access to the profiling information recorded for this method. + */ + default ProfilingInfo getProfilingInfo() { + return getProfilingInfo(true, true); + } + + /** + * Returns an object that provides access to the profiling information recorded for this method. + * + * @param includeNormal if true, + * {@linkplain ProfilingInfo#getDeoptimizationCount(DeoptimizationReason) + * deoptimization counts} will include deoptimization that happened during execution + * of standard non-osr methods. + * @param includeOSR if true, + * {@linkplain ProfilingInfo#getDeoptimizationCount(DeoptimizationReason) + * deoptimization counts} will include deoptimization that happened during execution + * of on-stack-replacement methods. + */ + ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR); + + /** + * Invalidates the profiling information and restarts profiling upon the next invocation. + */ + void reprofile(); + + /** + * Returns the constant pool of this method. + */ + ConstantPool getConstantPool(); + + /** + * Returns all annotations of this method. If no annotations are present, an array of length 0 + * is returned. + */ + Annotation[] getAnnotations(); + + /** + * Returns the annotation for the specified type of this method, if such an annotation is + * present. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return this element's annotation for the specified annotation type if present on this + * method, else {@code null} + */ + T getAnnotation(Class annotationClass); + + /** + * Returns an array of arrays that represent the annotations on the formal parameters, in + * declaration order, of this method. + * + * @see Method#getParameterAnnotations() + */ + Annotation[][] getParameterAnnotations(); + + /** + * Returns an array of {@link Type} objects that represent the formal parameter types, in + * declaration order, of this method. + * + * @see Method#getGenericParameterTypes() + */ + Type[] getGenericParameterTypes(); + + /** + * Returns {@code true} if this method is not excluded from inlining and has associated Java + * bytecodes (@see {@link ResolvedJavaMethod#hasBytecodes()}). + */ + boolean canBeInlined(); + + /** + * Returns {@code true} if the inlining of this method should be forced. + */ + boolean shouldBeInlined(); + + /** + * Returns the LineNumberTable of this method or null if this method does not have a line + * numbers table. + */ + LineNumberTable getLineNumberTable(); + + /** + * Returns the local variable table of this method or null if this method does not have a local + * variable table. + */ + LocalVariableTable getLocalVariableTable(); + + /** + * Invokes the underlying method represented by this object, on the specified object with the + * specified parameters. This method is similar to a reflective method invocation by + * {@link Method#invoke}. + * + * @param receiver The receiver for the invocation, or {@code null} if it is a static method. + * @param arguments The arguments for the invocation. + * @return The value returned by the method invocation, or {@code null} if the return type is + * {@code void}. + */ + JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments); + + /** + * Gets the encoding of (that is, a constant representing the value of) this method. + * + * @return a constant representing a reference to this method + */ + Constant getEncoding(); + + /** + * Checks if this method is present in the virtual table for subtypes of the specified + * {@linkplain ResolvedJavaType type}. + * + * @return true is this method is present in the virtual table for subtypes of this type. + */ + boolean isInVirtualMethodTable(ResolvedJavaType resolved); + + /** + * Gets the annotation of a particular type for a formal parameter of this method. + * + * @param annotationClass the Class object corresponding to the annotation type + * @param parameterIndex the index of a formal parameter of {@code method} + * @return the annotation of type {@code annotationClass} for the formal parameter present, else + * null + * @throws IndexOutOfBoundsException if {@code parameterIndex} does not denote a formal + * parameter + */ + default T getParameterAnnotation(Class annotationClass, int parameterIndex) { + if (parameterIndex >= 0) { + Annotation[][] parameterAnnotations = getParameterAnnotations(); + for (Annotation a : parameterAnnotations[parameterIndex]) { + if (a.annotationType() == annotationClass) { + return annotationClass.cast(a); + } + } + } + return null; + } + + default JavaType[] toParameterTypes() { + JavaType receiver = isStatic() || isConstructor() ? null : getDeclaringClass(); + return getSignature().toParameterTypes(receiver); + } + + /** + * Gets the annotations of a particular type for the formal parameters of this method. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return the annotation of type {@code annotationClass} (if any) for each formal parameter + * present + */ + @SuppressWarnings("unchecked") + default T[] getParameterAnnotations(Class annotationClass) { + Annotation[][] parameterAnnotations = getParameterAnnotations(); + T[] result = (T[]) Array.newInstance(annotationClass, parameterAnnotations.length); + for (int i = 0; i < parameterAnnotations.length; i++) { + for (Annotation a : parameterAnnotations[i]) { + if (a.annotationType() == annotationClass) { + result[i] = annotationClass.cast(a); + } + } + } + return result; + } + + /** + * Checks whether the method has bytecodes associated with it. Methods without bytecodes are + * either abstract or native methods. + * + * @return whether the definition of this method is Java bytecodes + */ + default boolean hasBytecodes() { + return isConcrete() && !isNative(); + } + + /** + * Checks whether the method has a receiver parameter - i.e., whether it is not static. + * + * @return whether the method has a receiver parameter + */ + default boolean hasReceiver() { + return !isStatic(); + } + + /** + * Determines if this method is {@link java.lang.Object#Object()}. + */ + default boolean isJavaLangObjectInit() { + return getDeclaringClass().isJavaLangObject() && getName().equals(""); + } + + SpeculationLog getSpeculationLog(); + + /** + * Determines if the method identified by its holder and name is a signature + * polymorphic method. + */ + static boolean isSignaturePolymorphic(JavaType holder, String name, MetaAccessProvider metaAccess) { + if (!holder.getName().equals("Ljava/lang/invoke/MethodHandle;")) { + return false; + } + ResolvedJavaType methodHandleType = metaAccess.lookupJavaType(MethodHandle.class); + Signature signature = metaAccess.parseMethodDescriptor("([Ljava/lang/Object;)Ljava/lang/Object;"); + ResolvedJavaMethod method = methodHandleType.findMethod(name, signature); + if (method == null) { + return false; + } + return method.isNative() && method.isVarArgs(); + } +} --- /dev/null 2015-09-16 15:21:00.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/ResolvedJavaType.java 2015-09-16 15:21:00.000000000 -0700 @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.lang.annotation.*; +import java.net.*; + +import jdk.internal.jvmci.meta.Assumptions.*; + +/** + * Represents a resolved Java type. Types include primitives, objects, {@code void}, and arrays + * thereof. Types, like fields and methods, are resolved through {@link ConstantPool constant pools} + * . + */ +public interface ResolvedJavaType extends JavaType, ModifiersProvider { + /** + * Gets the runtime representation of the Java class object of this type. + */ + JavaConstant getJavaClass(); + + /** + * Gets the runtime representation of the "hub" of this type--that is, the closest part of the + * type representation which is typically stored in the object header. + */ + Constant getObjectHub(); + + /** + * Checks whether this type has a finalizer method. + * + * @return {@code true} if this class has a finalizer + */ + boolean hasFinalizer(); + + /** + * Checks whether this type has any finalizable subclasses so far. Any decisions based on this + * information require the registration of a dependency, since this information may change. + * + * @return {@code true} if this class has any subclasses with finalizers + */ + AssumptionResult hasFinalizableSubclass(); + + /** + * Checks whether this type is an interface. + * + * @return {@code true} if this type is an interface + */ + boolean isInterface(); + + /** + * Checks whether this type is an instance class. + * + * @return {@code true} if this type is an instance class + */ + boolean isInstanceClass(); + + /** + * Checks whether this type is an array class. + * + * @return {@code true} if this type is an array class + */ + boolean isArray(); + + /** + * Checks whether this type is primitive. + * + * @return {@code true} if this type is primitive + */ + boolean isPrimitive(); + + /** + * {@inheritDoc} + *

+ * Only the flags specified in the JVM specification will be included in the returned mask. This + * method is identical to {@link Class#getModifiers()} in terms of the value return for this + * type. + */ + int getModifiers(); + + /* + * The setting of the final bit for types is a bit confusing since arrays are marked as final. + * This method provides a semantically equivalent test that appropriate for types. + */ + default boolean isLeaf() { + return getElementalType().isFinalFlagSet(); + } + + /** + * Checks whether this type is initialized. If a type is initialized it implies that it was + * {@link #isLinked() linked} and that the static initializer has run. + * + * @return {@code true} if this type is initialized + */ + boolean isInitialized(); + + /** + * Initializes this type. + */ + void initialize(); + + /** + * Checks whether this type is linked and verified. When a type is linked the static initializer + * has not necessarily run. An {@link #isInitialized() initialized} type is always linked. + * + * @return {@code true} if this type is linked + */ + boolean isLinked(); + + /** + * Determines if this type is either the same as, or is a superclass or superinterface of, the + * type represented by the specified parameter. This method is identical to + * {@link Class#isAssignableFrom(Class)} in terms of the value return for this type. + */ + boolean isAssignableFrom(ResolvedJavaType other); + + /** + * Returns true if this type is exactly the type {@link java.lang.Object}. + */ + default boolean isJavaLangObject() { + // Removed assertion due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=434442 + return getSuperclass() == null && !isInterface() && getJavaKind() == JavaKind.Object; + } + + /** + * Checks whether the specified object is an instance of this type. + * + * @param obj the object to test + * @return {@code true} if the object is an instance of this type + */ + boolean isInstance(JavaConstant obj); + + /** + * Returns this type if it is an exact type otherwise returns null. This type is exact if it is + * void, primitive, final, or an array of a final or primitive type. + * + * @return this type if it is exact; {@code null} otherwise + */ + ResolvedJavaType asExactType(); + + /** + * Gets the super class of this type. If this type represents either the {@code Object} class, + * an interface, a primitive type, or void, then null is returned. If this object represents an + * array class then the type object representing the {@code Object} class is returned. + */ + ResolvedJavaType getSuperclass(); + + /** + * Gets the interfaces implemented or extended by this type. This method is analogous to + * {@link Class#getInterfaces()} and as such, only returns the interfaces directly implemented + * or extended by this type. + */ + ResolvedJavaType[] getInterfaces(); + + /** + * Gets the single implementor of this type. Calling this method on a non-interface type causes + * an exception. + *

+ * If the compiler uses the result of this method for its compilation, the usage must be guarded + * because the verifier can not guarantee that the assigned type really implements this + * interface. Additionally, class loading can invalidate the result of this method. + * + * @return {@code null} if there is no implementor, the implementor if there is only one, or + * {@code this} if there are more than one. + */ + ResolvedJavaType getSingleImplementor(); + + /** + * Walks the class hierarchy upwards and returns the least common class that is a superclass of + * both the current and the given type. + * + * @return the least common type that is a super type of both the current and the given type, or + * {@code null} if primitive types are involved. + */ + ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType); + + /** + * Attempts to get a leaf concrete subclass of this type. + *

+ * For an {@linkplain #isArray() array} type A, the leaf concrete subclass is A if the + * {@linkplain #getElementalType() elemental} type of A is final (which includes primitive + * types). Otherwise {@code null} is returned for A. + *

+ * For a non-array type T, the result is the leaf concrete type in the current hierarchy of T. + *

+ * A runtime may decide not to manage or walk a large hierarchy and so the result is + * conservative. That is, a non-null result is guaranteed to be the leaf concrete class in T's + * hierarchy at the current point in time but a null result does not necessarily imply + * that there is no leaf concrete class in T's hierarchy. + *

+ * If the compiler uses the result of this method for its compilation, it must register the + * {@link AssumptionResult} in its {@link Assumptions} because dynamic class loading can + * invalidate the result of this method. + * + * @return an {@link AssumptionResult} containing the leaf concrete subclass for this type as + * described above + */ + AssumptionResult findLeafConcreteSubtype(); + + ResolvedJavaType getComponentType(); + + default ResolvedJavaType getElementalType() { + ResolvedJavaType t = this; + while (t.isArray()) { + t = t.getComponentType(); + } + return t; + } + + ResolvedJavaType getArrayClass(); + + /** + * Resolves the method implementation for virtual dispatches on objects of this dynamic type. + * This resolution process only searches "up" the class hierarchy of this type. + * + * @param method the method to select the implementation of + * @param callerType the caller or context type used to perform access checks + * @return the link-time resolved method (might be abstract) or {@code null} if it can not be + * linked + */ + ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType); + + /** + * Resolves the method implementation for virtual dispatches on objects of this dynamic type. + * This resolution process only searches "up" the class hierarchy of this type. A broader search + * that also walks "down" the hierarchy is implemented by + * {@link #findUniqueConcreteMethod(ResolvedJavaMethod)}. + * + * @param method the method to select the implementation of + * @param callerType the caller or context type used to perform access checks + * @return the concrete method that would be selected at runtime, or {@code null} if there is no + * concrete implementation of {@code method} in this type or any of its superclasses + */ + ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType); + + /** + * Given a {@link ResolvedJavaMethod} A, returns a concrete {@link ResolvedJavaMethod} B that is + * the only possible unique target for a virtual call on A(). Returns {@code null} if either no + * such concrete method or more than one such method exists. Returns the method A if A is a + * concrete method that is not overridden. + *

+ * If the compiler uses the result of this method for its compilation, it must register an + * assumption because dynamic class loading can invalidate the result of this method. + * + * @param method the method A for which a unique concrete target is searched + * @return the unique concrete target or {@code null} if no such target exists or assumptions + * are not supported by this runtime + */ + AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method); + + /** + * Returns the instance fields of this class, including + * {@linkplain ResolvedJavaField#isInternal() internal} fields. A zero-length array is returned + * for array and primitive types. The order of fields returned by this method is stable. That + * is, for a single JVM execution the same order is returned each time this method is called. It + * is also the "natural" order, which means that the JVM would expect the fields in this order + * if no specific order is given. + * + * @param includeSuperclasses if true, then instance fields for the complete hierarchy of this + * type are included in the result + * @return an array of instance fields + */ + ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses); + + /** + * Returns the static fields of this class, including + * {@linkplain ResolvedJavaField#isInternal() internal} fields. A zero-length array is returned + * for array and primitive types. The order of fields returned by this method is stable. That + * is, for a single JVM execution the same order is returned each time this method is called. + */ + ResolvedJavaField[] getStaticFields(); + + /** + * Returns all annotations of this class. If no annotations are present, an array of length 0 is + * returned. + */ + Annotation[] getAnnotations(); + + /** + * Returns the annotation for the specified type of this class, if such an annotation is + * present. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return this element's annotation for the specified annotation type if present on this class, + * else {@code null} + */ + T getAnnotation(Class annotationClass); + + /** + * Returns the instance field of this class (or one of its super classes) at the given offset, + * or {@code null} if there is no such field. + * + * @param offset the offset of the field to look for + * @return the field with the given offset, or {@code null} if there is no such field. + */ + ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedKind); + + /** + * Returns name of source file of this type. + */ + String getSourceFileName(); + + /** + * Returns the class file path - if available - of this type, or {@code null}. + */ + URL getClassFilePath(); + + /** + * Returns {@code true} if the type is a local type. + */ + boolean isLocal(); + + /** + * Returns {@code true} if the type is a member type. + */ + boolean isMember(); + + /** + * Returns the enclosing type of this type, if it exists, or {@code null}. + */ + ResolvedJavaType getEnclosingType(); + + /** + * Returns an array reflecting all the constructors declared by this type. This method is + * similar to {@link Class#getDeclaredConstructors()} in terms of returned constructors. + */ + ResolvedJavaMethod[] getDeclaredConstructors(); + + /** + * Returns an array reflecting all the methods declared by this type. This method is similar to + * {@link Class#getDeclaredMethods()} in terms of returned methods. + */ + ResolvedJavaMethod[] getDeclaredMethods(); + + /** + * Returns the {@code } method for this class if there is one. + */ + ResolvedJavaMethod getClassInitializer(); + + /** + * Returns true if this type represents an interface and it should be trusted even in places + * where the JVM verifier would not give any guarantees other than {@link Object}. + */ + boolean isTrustedInterfaceType(); + + default ResolvedJavaMethod findMethod(String name, Signature signature) { + for (ResolvedJavaMethod method : getDeclaredMethods()) { + if (method.getName().equals(name) && method.getSignature().equals(signature)) { + return method; + } + } + return null; + } +} --- /dev/null 2015-09-16 15:21:01.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/SerializableConstant.java 2015-09-16 15:21:01.000000000 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.nio.*; + +/** + * Represents a compile-time constant that can be converted to a byte array. + */ +public interface SerializableConstant extends Constant { + + /** + * Return the size in bytes of the serialized representation of this constant. + */ + int getSerializedSize(); + + /** + * Serialize the constant into the ByteBuffer. There must be at least + * {@link #getSerializedSize()} bytes available capacity in the buffer. + */ + void serialize(ByteBuffer buffer); +} --- /dev/null 2015-09-16 15:21:01.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/Signature.java 2015-09-16 15:21:01.000000000 -0700 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Represents a method signature provided by the runtime. + * + * @see Method + * Descriptors + */ +public interface Signature { + + /** + * Returns the number of parameters in this signature, adding 1 for a receiver if requested. + * + * @param receiver true if 1 is to be added to the result for a receiver + * @return the number of parameters; + 1 iff {@code receiver == true} + */ + int getParameterCount(boolean receiver); + + /** + * Gets the parameter type at the specified position. + * + * @param index the index into the parameters, with {@code 0} indicating the first parameter + * @param accessingClass the context of the type lookup. If non-null, its class loader is used + * for resolving the type. If {@code null}, then the type returned is either + * unresolved or a resolved type whose resolution is context free (e.g., a primitive + * type or a type in a java.* package). + * @return the {@code index}'th parameter type + * @throws LinkageError if {@code accessingClass != null} and resolution fails + * + */ + JavaType getParameterType(int index, ResolvedJavaType accessingClass); + + /** + * Gets the parameter kind at the specified position. This is the same as calling + * {@link #getParameterType}. {@link JavaType#getJavaKind getJavaKind}. + * + * @param index the index into the parameters, with {@code 0} indicating the first parameter + * @return the kind of the parameter at the specified position + */ + default JavaKind getParameterKind(int index) { + return getParameterType(index, null).getJavaKind(); + } + + /** + * Gets the return type of this signature. + * + * @param accessingClass the context of the type lookup. If non-null, its class loader is used + * for resolving the type. If {@code null}, then the type returned is either + * unresolved or a resolved type whose resolution is context free (e.g., a primitive + * type or a type in a java.* package). + * @return the return type + * @throws LinkageError if {@code accessingClass != null} and resolution fails + */ + JavaType getReturnType(ResolvedJavaType accessingClass); + + /** + * Gets the return kind of this signature. This is the same as calling {@link #getReturnType}. + * {@link JavaType#getJavaKind getJavaKind}. + */ + default JavaKind getReturnKind() { + return getReturnType(null).getJavaKind(); + } + + /** + * Gets the method + * descriptor corresponding to this signature. For example: + * + *

+     * (ILjava/lang/String;D)V
+     * 
+ * + * @return the signature as a string + */ + default String toMethodDescriptor() { + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < getParameterCount(false); ++i) { + sb.append(getParameterType(i, null).getName()); + } + sb.append(')').append(getReturnType(null).getName()); + return sb.toString(); + } + + default JavaType[] toParameterTypes(JavaType receiverType) { + int args = getParameterCount(false); + JavaType[] result; + int i = 0; + if (receiverType != null) { + result = new JavaType[args + 1]; + result[0] = receiverType; + i = 1; + } else { + result = new JavaType[args]; + } + for (int j = 0; j < args; j++) { + result[i + j] = getParameterType(j, null); + } + return result; + } + + default JavaKind[] toParameterKinds(boolean receiver) { + int args = getParameterCount(false); + JavaKind[] result; + int i = 0; + if (receiver) { + result = new JavaKind[args + 1]; + result[0] = JavaKind.Object; + i = 1; + } else { + result = new JavaKind[args]; + } + for (int j = 0; j < args; j++) { + result[i + j] = getParameterKind(j); + } + return result; + } +} --- /dev/null 2015-09-16 15:21:02.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/SpeculationLog.java 2015-09-16 15:21:02.000000000 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +import java.util.*; +import java.util.concurrent.*; + +/** + * Manages a list of unique deoptimization reasons. + * + */ +public abstract class SpeculationLog { + private volatile Object lastFailed; + private volatile Collection speculations; + private Set failedSpeculations; + + public synchronized void collectFailedSpeculations() { + if (lastFailed != null) { + if (failedSpeculations == null) { + failedSpeculations = new HashSet<>(2); + } + failedSpeculations.add(lastFailed); + lastFailed = null; + speculations = null; + } + } + + public boolean maySpeculate(Object reason) { + if (failedSpeculations != null && failedSpeculations.contains(reason)) { + return false; + } + return true; + } + + protected void addSpeculation(Object reason) { + assert maySpeculate(reason); + if (speculations == null) { + synchronized (this) { + if (speculations == null) { + speculations = new ConcurrentLinkedQueue<>(); + } + } + } + speculations.add(reason); + } + + public abstract JavaConstant speculate(Object reason); +} --- /dev/null 2015-09-16 15:21:03.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/TriState.java 2015-09-16 15:21:02.000000000 -0700 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Represents a logic value that can be either {@link #TRUE}, {@link #FALSE}, or {@link #UNKNOWN}. + */ +public enum TriState { + TRUE, + FALSE, + UNKNOWN; + + public static TriState get(boolean value) { + return value ? TRUE : FALSE; + } + + /** + * This is optimistic about {@link #UNKNOWN} (it prefers known values over {@link #UNKNOWN}) and + * pesimistic about known (it perfers {@link #TRUE} over {@link #FALSE}). + */ + public static TriState merge(TriState a, TriState b) { + if (a == TRUE || b == TRUE) { + return TRUE; + } + if (a == FALSE || b == FALSE) { + return FALSE; + } + assert a == UNKNOWN && b == UNKNOWN; + return UNKNOWN; + } + + public boolean isTrue() { + return this == TRUE; + } + + public boolean isFalse() { + return this == FALSE; + } + + public boolean isUnknown() { + return this == UNKNOWN; + } + + public boolean isKnown() { + return this != UNKNOWN; + } + + public boolean toBoolean() { + if (isTrue()) { + return true; + } else if (isFalse()) { + return false; + } else { + throw new IllegalStateException("Cannot convert to boolean, TriState is in an unknown state"); + } + } +} --- /dev/null 2015-09-16 15:21:03.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/TrustedInterface.java 2015-09-16 15:21:03.000000000 -0700 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Interfaces extending this interface should be trusted by the compiler. See + * {@link ResolvedJavaType#isTrustedInterfaceType()}. + * + */ +public interface TrustedInterface { + +} --- /dev/null 2015-09-16 15:21:04.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/VMConstant.java 2015-09-16 15:21:04.000000000 -0700 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +public interface VMConstant extends Constant { +} --- /dev/null 2015-09-16 15:21:04.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/Value.java 2015-09-16 15:21:04.000000000 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.meta; + +/** + * Abstract base class for values. + */ +public abstract class Value { + + public static final Value[] NO_VALUES = new Value[0]; + + public static final AllocatableValue ILLEGAL = new IllegalValue(); + + private static final class IllegalValue extends AllocatableValue { + private IllegalValue() { + super(LIRKind.Illegal); + } + + @Override + public String toString() { + return "-"; + } + + @Override + public boolean equals(Object other) { + // Due to de-serialization this object may exist multiple times. So we compare classes + // instead of the individual objects. (This anonymous class has always the same meaning) + return other instanceof IllegalValue; + } + } + + private final LIRKind lirKind; + + /** + * Initializes a new value of the specified kind. + * + * @param lirKind the kind + */ + protected Value(LIRKind lirKind) { + this.lirKind = lirKind; + } + + /** + * Returns a String representation of the kind, which should be the end of all + * {@link #toString()} implementation of subclasses. + */ + protected final String getKindSuffix() { + return "|" + getPlatformKind().getTypeChar(); + } + + public final LIRKind getLIRKind() { + return lirKind; + } + + /** + * Returns the platform specific kind used to store this value. + */ + public final PlatformKind getPlatformKind() { + return lirKind.getPlatformKind(); + } + + @Override + public int hashCode() { + return 41 + lirKind.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Value) { + Value that = (Value) obj; + return lirKind.equals(that.lirKind); + } + return false; + } + + /** + * Checks if this value is identical to {@code other}. + * + * Warning: Use with caution! Usually equivalence {@link #equals(Object)} is sufficient and + * should be used. + */ + public final boolean identityEquals(Value other) { + return this == other; + } +} --- /dev/null 2015-09-16 15:21:05.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/package-info.java 2015-09-16 15:21:05.000000000 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2009, 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Package that defines the interface between a runtime and a Java application that wants to access meta information. The runtime + * provides an implementation of the {@link jdk.internal.jvmci.meta.MetaAccessProvider} interface. + */ +package jdk.internal.jvmci.meta; + --- /dev/null 2015-09-16 15:21:06.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options.processor/src/META-INF/services/javax.annotation.processing.Processor 2015-09-16 15:21:05.000000000 -0700 @@ -0,0 +1 @@ +jdk.internal.jvmci.options.processor.OptionProcessor --- /dev/null 2015-09-16 15:21:06.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options.processor/src/jdk/internal/jvmci/options/processor/OptionProcessor.java 2015-09-16 15:21:06.000000000 -0700 @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options.processor; + +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import javax.tools.Diagnostic.Kind; +import javax.tools.*; + +import jdk.internal.jvmci.options.*; + +/** + * Processes static fields annotated with {@link Option}. An {@link OptionDescriptors} + * implementation is generated for each top level class containing at least one such field. The name + * of the generated class for top level class {@code com.foo.Bar} is + * {@code com.foo.Bar_OptionDescriptors}. + */ +@SupportedAnnotationTypes({"jdk.internal.jvmci.options.Option"}) +public class OptionProcessor extends AbstractProcessor { + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + private final Set processed = new HashSet<>(); + + private void processElement(Element element, OptionsInfo info) { + + if (!element.getModifiers().contains(Modifier.STATIC)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element); + return; + } + + Option annotation = element.getAnnotation(Option.class); + assert annotation != null; + assert element instanceof VariableElement; + assert element.getKind() == ElementKind.FIELD; + VariableElement field = (VariableElement) element; + String fieldName = field.getSimpleName().toString(); + + Elements elements = processingEnv.getElementUtils(); + Types types = processingEnv.getTypeUtils(); + + TypeMirror fieldType = field.asType(); + if (fieldType.getKind() != TypeKind.DECLARED) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + OptionValue.class.getName(), element); + return; + } + DeclaredType declaredFieldType = (DeclaredType) fieldType; + + TypeMirror optionValueType = elements.getTypeElement(OptionValue.class.getName()).asType(); + if (!types.isSubtype(fieldType, types.erasure(optionValueType))) { + String msg = String.format("Option field type %s is not a subclass of %s", fieldType, optionValueType); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); + return; + } + + if (!field.getModifiers().contains(Modifier.STATIC)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element); + return; + } + + String help = annotation.help(); + if (help.length() != 0) { + char firstChar = help.charAt(0); + if (!Character.isUpperCase(firstChar)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with upper case letter", element); + return; + } + } + + String optionName = annotation.name(); + if (optionName.equals("")) { + optionName = fieldName; + } + + DeclaredType declaredOptionValueType = declaredFieldType; + while (!types.isSameType(types.erasure(declaredOptionValueType), types.erasure(optionValueType))) { + List directSupertypes = types.directSupertypes(declaredFieldType); + assert !directSupertypes.isEmpty(); + declaredOptionValueType = (DeclaredType) directSupertypes.get(0); + } + + assert !declaredOptionValueType.getTypeArguments().isEmpty(); + String optionType = declaredOptionValueType.getTypeArguments().get(0).toString(); + if (optionType.startsWith("java.lang.")) { + optionType = optionType.substring("java.lang.".length()); + } + + Element enclosing = element.getEnclosingElement(); + String declaringClass = ""; + String separator = ""; + Set originatingElementsList = info.originatingElements; + originatingElementsList.add(field); + while (enclosing != null) { + if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { + if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { + String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); + return; + } + originatingElementsList.add(enclosing); + declaringClass = enclosing.getSimpleName() + separator + declaringClass; + separator = "."; + } else { + assert enclosing.getKind() == ElementKind.PACKAGE; + } + enclosing = enclosing.getEnclosingElement(); + } + + info.options.add(new OptionInfo(optionName, help, optionType, declaringClass, field)); + } + + private void createFiles(OptionsInfo info) { + String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); + Name topDeclaringClass = info.topDeclaringType.getSimpleName(); + Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]); + + createOptionsDescriptorsFile(info, pkg, topDeclaringClass, originatingElements); + } + + private void createOptionsDescriptorsFile(OptionsInfo info, String pkg, Name topDeclaringClass, Element[] originatingElements) { + String optionsClassName = topDeclaringClass + "_" + OptionDescriptors.class.getSimpleName(); + + Filer filer = processingEnv.getFiler(); + try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) { + + out.println("// CheckStyle: stop header check"); + out.println("// CheckStyle: stop line length check"); + out.println("// GENERATED CONTENT - DO NOT EDIT"); + out.println("// Source: " + topDeclaringClass + ".java"); + out.println("package " + pkg + ";"); + out.println(""); + out.println("import java.util.*;"); + out.println("import " + OptionDescriptors.class.getPackage().getName() + ".*;"); + out.println(""); + out.println("public class " + optionsClassName + " implements " + OptionDescriptors.class.getSimpleName() + " {"); + + String desc = OptionDescriptor.class.getSimpleName(); + + boolean needPrivateFieldAccessor = false; + int i = 0; + Collections.sort(info.options); + + out.println(" @Override"); + out.println(" public OptionDescriptor get(String value) {"); + out.println(" // CheckStyle: stop line length check"); + if (info.options.size() == 1) { + out.println(" if (value.equals(\"" + info.options.get(0).name + "\")) {"); + } else { + out.println(" switch (value) {"); + } + for (OptionInfo option : info.options) { + String name = option.name; + String optionValue; + if (option.field.getModifiers().contains(Modifier.PRIVATE)) { + needPrivateFieldAccessor = true; + optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; + } else { + optionValue = option.declaringClass + "." + option.field.getSimpleName(); + } + String type = option.type; + String help = option.help; + String declaringClass = option.declaringClass; + Name fieldName = option.field.getSimpleName(); + if (info.options.size() == 1) { + out.printf(" return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionValue); + } else { + out.printf(" case \"" + name + "\": return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionValue); + } + } + out.println(" }"); + out.println(" // CheckStyle: resume line length check"); + out.println(" return null;"); + out.println(" }"); + out.println(); + out.println(" @Override"); + out.println(" public Iterator<" + desc + "> iterator() {"); + out.println(" // CheckStyle: stop line length check"); + out.println(" List<" + desc + "> options = Arrays.asList("); + for (OptionInfo option : info.options) { + String optionValue; + if (option.field.getModifiers().contains(Modifier.PRIVATE)) { + needPrivateFieldAccessor = true; + optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; + } else { + optionValue = option.declaringClass + "." + option.field.getSimpleName(); + } + String name = option.name; + String type = option.type; + String help = option.help; + String declaringClass = option.declaringClass; + Name fieldName = option.field.getSimpleName(); + String comma = i == info.options.size() - 1 ? "" : ","; + out.printf(" %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s)%s\n", desc, name, type, help, declaringClass, fieldName, optionValue, comma); + i++; + } + out.println(" );"); + out.println(" // CheckStyle: resume line length check"); + out.println(" return options.iterator();"); + out.println(" }"); + if (needPrivateFieldAccessor) { + out.println(" private static " + OptionValue.class.getSimpleName() + " field(Class declaringClass, String fieldName) {"); + out.println(" try {"); + out.println(" java.lang.reflect.Field field = declaringClass.getDeclaredField(fieldName);"); + out.println(" field.setAccessible(true);"); + out.println(" return (" + OptionValue.class.getSimpleName() + ") field.get(null);"); + out.println(" } catch (Exception e) {"); + out.println(" throw (InternalError) new InternalError().initCause(e);"); + out.println(" }"); + out.println(" }"); + } + out.println("}"); + } + + try { + createOptionsFile(pkg, topDeclaringClass.toString(), originatingElements); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType); + } + } + + private void createOptionsFile(String pkg, String relativeName, Element... originatingElements) throws IOException { + String filename = "META-INF/jvmci.options/" + pkg + "." + relativeName; + FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, originatingElements); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8")); + writer.close(); + } + + protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) { + try { + // Ensure Unix line endings to comply with code style guide checked by Checkstyle + JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements); + return new PrintWriter(sourceFile.openWriter()) { + + @Override + public void println() { + print("\n"); + } + }; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + static class OptionInfo implements Comparable { + + final String name; + final String help; + final String type; + final String declaringClass; + final VariableElement field; + + public OptionInfo(String name, String help, String type, String declaringClass, VariableElement field) { + this.name = name; + this.help = help; + this.type = type; + this.declaringClass = declaringClass; + this.field = field; + } + + @Override + public int compareTo(OptionInfo other) { + return name.compareTo(other.name); + } + + @Override + public String toString() { + return declaringClass + "." + field; + } + } + + static class OptionsInfo { + + final Element topDeclaringType; + final List options = new ArrayList<>(); + final Set originatingElements = new HashSet<>(); + + public OptionsInfo(Element topDeclaringType) { + this.topDeclaringType = topDeclaringType; + } + } + + private static Element topDeclaringType(Element element) { + Element enclosing = element.getEnclosingElement(); + if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) { + assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE; + return element; + } + return topDeclaringType(enclosing); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return true; + } + + Map map = new HashMap<>(); + for (Element element : roundEnv.getElementsAnnotatedWith(Option.class)) { + if (!processed.contains(element)) { + processed.add(element); + Element topDeclaringType = topDeclaringType(element); + OptionsInfo options = map.get(topDeclaringType); + if (options == null) { + options = new OptionsInfo(topDeclaringType); + map.put(topDeclaringType, options); + } + processElement(element, options); + } + } + + boolean ok = true; + Map uniqueness = new HashMap<>(); + for (OptionsInfo info : map.values()) { + for (OptionInfo option : info.options) { + OptionInfo conflict = uniqueness.put(option.name, option); + if (conflict != null) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Duplicate option names for " + option + " and " + conflict, option.field); + ok = false; + } + } + } + + if (ok) { + for (OptionsInfo info : map.values()) { + createFiles(info); + } + } + + return true; + } +} --- /dev/null 2015-09-16 15:21:07.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/DerivedOptionValue.java 2015-09-16 15:21:07.000000000 -0700 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +import java.io.*; +import java.util.function.*; + +import jdk.internal.jvmci.options.OptionValue.*; + +/** + * A cached value that needs to be recomputed when an option changes. + */ +public class DerivedOptionValue { + + public interface OptionSupplier extends Supplier, Serializable { + } + + private final T initialValue; + private final OptionSupplier supplier; + + public DerivedOptionValue(OptionSupplier supplier) { + this.supplier = supplier; + assert OptionValue.getOverrideScope() == null : "derived option value should be initialized outside any override scope"; + this.initialValue = createValue(); + } + + public T getValue() { + OverrideScope overrideScope = OptionValue.getOverrideScope(); + if (overrideScope != null) { + return overrideScope.getDerived(this); + } else { + return initialValue; + } + } + + T createValue() { + return supplier.get(); + } +} --- /dev/null 2015-09-16 15:21:07.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/JVMCIJarsOptionDescriptorsProvider.java 2015-09-16 15:21:07.000000000 -0700 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +import java.io.*; +import java.util.*; +import java.util.jar.*; +import java.util.zip.*; + +import jdk.internal.jvmci.options.OptionsParser.*; + +/** + * Access to the {@link OptionDescriptors} declared by + * {@code META-INF/services/jdk.internal.jvmci.options.OptionDescriptors} files in + * {@code /lib/jvmci/*.jar}. + */ +class JVMCIJarsOptionDescriptorsProvider implements OptionDescriptorsProvider { + + static final String OptionDescriptorsServiceFile = "META-INF/services/" + OptionDescriptors.class.getName(); + + private final Iterator jars; + private final List optionsDescriptorsList; + + JVMCIJarsOptionDescriptorsProvider() { + List jarsList = findJVMCIJars(); + this.jars = jarsList.iterator(); + this.optionsDescriptorsList = new ArrayList<>(jarsList.size() * 3); + } + + /** + * Finds the list of JVMCI jars. + */ + private static List findJVMCIJars() { + File javaHome = new File(System.getProperty("java.home")); + File lib = new File(javaHome, "lib"); + File jvmci = new File(lib, "jvmci"); + if (!jvmci.exists()) { + throw new InternalError(jvmci + " does not exist"); + } + + List jarFiles = new ArrayList<>(); + for (String fileName : jvmci.list()) { + if (fileName.endsWith(".jar")) { + File file = new File(jvmci, fileName); + if (file.isDirectory()) { + continue; + } + jarFiles.add(file); + } + } + return jarFiles; + } + + public OptionDescriptor get(String name) { + // Look up loaded option descriptors first + for (OptionDescriptors optionDescriptors : optionsDescriptorsList) { + OptionDescriptor desc = optionDescriptors.get(name); + if (desc != null) { + return desc; + } + } + while (jars.hasNext()) { + File path = jars.next(); + try (JarFile jar = new JarFile(path)) { + ZipEntry entry = jar.getEntry(OptionDescriptorsServiceFile); + if (entry != null) { + BufferedReader br = new BufferedReader(new InputStreamReader(jar.getInputStream(entry))); + String line = null; + OptionDescriptor desc = null; + while ((line = br.readLine()) != null) { + OptionDescriptors options; + try { + options = (OptionDescriptors) Class.forName(line).newInstance(); + optionsDescriptorsList.add(options); + if (desc == null) { + desc = options.get(name); + } + } catch (Exception e) { + throw new InternalError("Error instantiating class " + line + " read from " + path, e); + } + } + if (desc != null) { + return desc; + } + } + } catch (IOException e) { + throw new InternalError("Error reading " + path, e); + } + } + return null; + } +} --- /dev/null 2015-09-16 15:21:08.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/NestedBooleanOptionValue.java 2015-09-16 15:21:08.000000000 -0700 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +/** + * A nested Boolean {@link OptionValue} that can be overridden by a {@link #masterOption master + * option}. + *

+ *

  • If the option is present on the command line the specified value is used. + *
  • Otherwise {@link #getValue()} depends on the {@link #masterOption} and evaluates as follows: + *
      + *
    • If {@link #masterOption} is set, this value equals to {@link #initialValue}. + *
    • Otherwise, if {@link #masterOption} is {@code false}, this option is {@code false}. + */ +public class NestedBooleanOptionValue extends OptionValue { + private final OptionValue masterOption; + private final Boolean initialValue; + + public NestedBooleanOptionValue(OptionValue masterOption, Boolean initialValue) { + super(null); + this.masterOption = masterOption; + this.initialValue = initialValue; + } + + public OptionValue getMasterOption() { + return masterOption; + } + + @Override + public Boolean getValue() { + Boolean v = super.getValue(); + if (v == null) { + return initialValue && masterOption.getValue(); + } + return v; + } + +} --- /dev/null 2015-09-16 15:21:09.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/Option.java 2015-09-16 15:21:08.000000000 -0700 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +import java.lang.annotation.*; + +/** + * Describes the attributes of an option whose {@link OptionValue value} is in a static field + * annotated by this annotation type. + * + * @see OptionDescriptor + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.FIELD) +public @interface Option { + + /** + * Gets a help message for the option. New lines can be embedded in the message with + * {@code "%n"}. + */ + String help(); + + /** + * The name of the option. By default, the name of the annotated field should be used. + */ + String name() default ""; + + /** + * Specifies the type of the option. + */ + OptionType type() default OptionType.Debug; +} --- /dev/null 2015-09-16 15:21:09.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/OptionDescriptor.java 2015-09-16 15:21:09.000000000 -0700 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +/** + * Describes the attributes of a static field {@linkplain Option option} and provides access to its + * {@linkplain OptionValue value}. + */ +public final class OptionDescriptor { + + protected final String name; + protected final Class type; + protected final String help; + protected final OptionValue option; + protected final Class declaringClass; + protected final String fieldName; + + public static OptionDescriptor create(String name, Class type, String help, Class declaringClass, String fieldName, OptionValue option) { + OptionDescriptor result = option.getDescriptor(); + if (result == null) { + result = new OptionDescriptor(name, type, help, declaringClass, fieldName, option); + option.setDescriptor(result); + } + assert result.name.equals(name) && result.type == type && result.declaringClass == declaringClass && result.fieldName.equals(fieldName) && result.option == option; + return result; + } + + private OptionDescriptor(String name, Class type, String help, Class declaringClass, String fieldName, OptionValue option) { + this.name = name; + this.type = type; + this.help = help; + this.option = option; + this.declaringClass = declaringClass; + this.fieldName = fieldName; + assert !type.isPrimitive() : "must used boxed type instead of " + type; + } + + /** + * Gets the type of values stored in the option. This will be the boxed type for a primitive + * option. + */ + public Class getType() { + return type; + } + + /** + * Gets a descriptive help message for the option. + */ + public String getHelp() { + return help; + } + + /** + * Gets the name of the option. It's up to the client of this object how to use the name to get + * a user specified value for the option from the environment. + */ + public String getName() { + return name; + } + + /** + * Gets the boxed option value. + */ + public OptionValue getOptionValue() { + return option; + } + + public Class getDeclaringClass() { + return declaringClass; + } + + public String getFieldName() { + return fieldName; + } + + /** + * Gets a description of the location where this option is stored. + */ + public String getLocation() { + return getDeclaringClass().getName() + "." + getFieldName(); + } +} --- /dev/null 2015-09-16 15:21:10.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/OptionDescriptors.java 2015-09-16 15:21:10.000000000 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +/** + * An interface to a set of {@link OptionDescriptor}s. + */ +public interface OptionDescriptors extends Iterable { + /** + * Gets the {@link OptionDescriptor} matching a given option name or {@code null} if this option + * descriptor set doesn't contain a matching option. + */ + OptionDescriptor get(String value); +} --- /dev/null 2015-09-16 15:21:10.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/OptionType.java 2015-09-16 15:21:10.000000000 -0700 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +/** + * Classifies JVMCI options in several categories depending on who this option is relevant for. + * + */ +public enum OptionType { + /** + * An option common for users to apply. + */ + User, + + /** + * An option only relevant in corner cases and for fine-tuning. + */ + Expert, + + /** + * An option only relevant when debugging the compiler. + */ + Debug +} --- /dev/null 2015-09-16 15:21:11.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/OptionValue.java 2015-09-16 15:21:11.000000000 -0700 @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +import java.io.*; +import java.util.*; +import java.util.Map.Entry; + +/** + * An option value. + */ +public class OptionValue { + /** + * Temporarily changes the value for an option. The {@linkplain OptionValue#getValue() value} of + * {@code option} is set to {@code value} until {@link OverrideScope#close()} is called on the + * object returned by this method. + *

      + * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be + * used: + * + *

      +     * try (OverrideScope s = OptionValue.override(myOption, myValue) {
      +     *     // code that depends on myOption == myValue
      +     * }
      +     * 
      + */ + public static OverrideScope override(OptionValue option, Object value) { + OverrideScope current = getOverrideScope(); + if (current == null) { + if (!value.equals(option.getValue())) { + return new SingleOverrideScope(option, value); + } + Map, Object> overrides = Collections.emptyMap(); + return new MultipleOverridesScope(current, overrides); + } + return new MultipleOverridesScope(current, option, value); + } + + /** + * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue() + * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value} + * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by + * this method. + *

      + * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be + * used: + * + *

      +     * Map<OptionValue, Object> overrides = new HashMap<>();
      +     * overrides.put(myOption1, myValue1);
      +     * overrides.put(myOption2, myValue2);
      +     * try (OverrideScope s = OptionValue.override(overrides) {
      +     *     // code that depends on myOption == myValue
      +     * }
      +     * 
      + */ + public static OverrideScope override(Map, Object> overrides) { + OverrideScope current = getOverrideScope(); + if (current == null && overrides.size() == 1) { + Entry, Object> single = overrides.entrySet().iterator().next(); + OptionValue option = single.getKey(); + Object overrideValue = single.getValue(); + if (!overrideValue.equals(option.getValue())) { + return new SingleOverrideScope(option, overrideValue); + } + } + return new MultipleOverridesScope(current, overrides); + } + + /** + * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue() + * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value} + * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by + * this method. + *

      + * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be + * used: + * + *

      +     * try (OverrideScope s = OptionValue.override(myOption1, myValue1, myOption2, myValue2) {
      +     *     // code that depends on myOption == myValue
      +     * }
      +     * 
      + * + * @param overrides overrides in the form {@code [option1, override1, option2, override2, ...]} + */ + public static OverrideScope override(Object... overrides) { + OverrideScope current = getOverrideScope(); + if (current == null && overrides.length == 2) { + OptionValue option = (OptionValue) overrides[0]; + Object overrideValue = overrides[1]; + if (!overrideValue.equals(option.getValue())) { + return new SingleOverrideScope(option, overrideValue); + } + } + Map, Object> map = Collections.emptyMap(); + for (int i = 0; i < overrides.length; i += 2) { + OptionValue option = (OptionValue) overrides[i]; + Object overrideValue = overrides[i + 1]; + if (!overrideValue.equals(option.getValue())) { + if (map.isEmpty()) { + map = new HashMap<>(); + } + map.put(option, overrideValue); + } + } + return new MultipleOverridesScope(current, map); + } + + private static final ThreadLocal overrideScopeTL = new ThreadLocal<>(); + + protected static OverrideScope getOverrideScope() { + return overrideScopeTL.get(); + } + + protected static void setOverrideScope(OverrideScope overrideScope) { + overrideScopeTL.set(overrideScope); + } + + private T defaultValue; + + /** + * The raw option value. + */ + protected T value; + + private OptionDescriptor descriptor; + + private long reads; + private OptionValue next; + private static OptionValue head; + + private static final boolean ShowReadsHistogram = Boolean.getBoolean("jvmci.showOptionValueReadsHistogram"); + + private static void addToHistogram(OptionValue option) { + if (ShowReadsHistogram) { + synchronized (OptionValue.class) { + option.next = head; + head = option; + } + } + } + + @SuppressWarnings("unchecked") + public OptionValue(T value) { + this.defaultValue = value; + this.value = (T) DEFAULT; + addToHistogram(this); + } + + private static final Object DEFAULT = "DEFAULT"; + private static final Object UNINITIALIZED = "UNINITIALIZED"; + + /** + * Creates an uninitialized option value for a subclass that initializes itself + * {@link #defaultValue() lazily}. + */ + @SuppressWarnings("unchecked") + protected OptionValue() { + this.defaultValue = (T) UNINITIALIZED; + this.value = (T) DEFAULT; + addToHistogram(this); + } + + /** + * Lazy initialization of default value. + */ + protected T defaultValue() { + throw new InternalError("Option without a default value value must override defaultValue()"); + } + + /** + * Sets the descriptor for this option. + */ + public void setDescriptor(OptionDescriptor descriptor) { + assert this.descriptor == null : "Overwriting existing descriptor"; + this.descriptor = descriptor; + } + + /** + * Returns the descriptor for this option, if it has been set by + * {@link #setDescriptor(OptionDescriptor)}. + */ + public OptionDescriptor getDescriptor() { + return descriptor; + } + + /** + * Gets the name of this option. The name for an option value with a null + * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is the value of + * {@link Object#toString()}. + */ + public String getName() { + return descriptor == null ? super.toString() : (descriptor.getDeclaringClass().getName() + "." + descriptor.getName()); + } + + @Override + public String toString() { + return getName() + "=" + getValue(); + } + + /** + * The initial value specified in source code. The returned value is not affected by calls to + * {@link #setValue(Object)} or registering {@link OverrideScope}s. Therefore, it is also not + * affected by options set on the command line. + */ + public T getDefaultValue() { + if (defaultValue == UNINITIALIZED) { + defaultValue = defaultValue(); + } + return defaultValue; + } + + /** + * Returns true if the option has the same value that was set in the source code. + */ + public boolean hasDefaultValue() { + if (!(this instanceof StableOptionValue)) { + getValue(); // ensure initialized + } + return value == DEFAULT || Objects.equals(value, getDefaultValue()); + } + + /** + * Gets the value of this option. + */ + public T getValue() { + if (ShowReadsHistogram) { + reads++; + } + if (!(this instanceof StableOptionValue)) { + OverrideScope overrideScope = getOverrideScope(); + if (overrideScope != null) { + T override = overrideScope.getOverride(this); + if (override != null) { + return override; + } + } + } + if (value != DEFAULT) { + return value; + } else { + return getDefaultValue(); + } + } + + /** + * Gets the values of this option including overridden values. + * + * @param c the collection to which the values are added. If null, one is allocated. + * @return the collection to which the values were added in order from most overridden to + * current value + */ + @SuppressWarnings("unchecked") + public Collection getValues(Collection c) { + Collection values = c == null ? new ArrayList<>() : c; + if (!(this instanceof StableOptionValue)) { + OverrideScope overrideScope = getOverrideScope(); + if (overrideScope != null) { + overrideScope.getOverrides(this, (Collection) values); + } + } + if (value != DEFAULT) { + values.add(value); + } else { + values.add(getDefaultValue()); + } + return values; + } + + /** + * Sets the value of this option. + */ + @SuppressWarnings("unchecked") + public void setValue(Object v) { + this.value = (T) v; + } + + /** + * An object whose {@link #close()} method reverts the option value overriding initiated by + * {@link OptionValue#override(OptionValue, Object)} or {@link OptionValue#override(Map)}. + */ + public abstract static class OverrideScope implements AutoCloseable { + + private Map, Object> derivedCache = null; + + public T getDerived(DerivedOptionValue key) { + if (derivedCache == null) { + derivedCache = new HashMap<>(); + } + @SuppressWarnings("unchecked") + T ret = (T) derivedCache.get(key); + if (ret == null) { + ret = key.createValue(); + derivedCache.put(key, ret); + } + return ret; + } + + abstract void addToInherited(Map, Object> inherited); + + abstract T getOverride(OptionValue option); + + abstract void getOverrides(OptionValue option, Collection c); + + public abstract void close(); + } + + static class SingleOverrideScope extends OverrideScope { + + private final OptionValue option; + private final Object value; + + public SingleOverrideScope(OptionValue option, Object value) { + if (option instanceof StableOptionValue) { + throw new IllegalArgumentException("Cannot override stable option " + option); + } + this.option = option; + this.value = value; + setOverrideScope(this); + } + + @Override + void addToInherited(Map, Object> inherited) { + inherited.put(option, value); + } + + @SuppressWarnings("unchecked") + @Override + T getOverride(OptionValue key) { + if (key == this.option) { + return (T) value; + } + return null; + } + + @Override + void getOverrides(OptionValue key, Collection c) { + if (key == this.option) { + c.add(value); + } + } + + @Override + public void close() { + setOverrideScope(null); + } + } + + static class MultipleOverridesScope extends OverrideScope { + final OverrideScope parent; + final Map, Object> overrides; + + public MultipleOverridesScope(OverrideScope parent, OptionValue option, Object value) { + this.parent = parent; + this.overrides = new HashMap<>(); + if (parent != null) { + parent.addToInherited(overrides); + } + if (option instanceof StableOptionValue) { + throw new IllegalArgumentException("Cannot override stable option " + option); + } + if (!value.equals(option.getValue())) { + this.overrides.put(option, value); + } + if (!overrides.isEmpty()) { + setOverrideScope(this); + } + } + + MultipleOverridesScope(OverrideScope parent, Map, Object> overrides) { + this.parent = parent; + if (overrides.isEmpty() && parent == null) { + this.overrides = Collections.emptyMap(); + return; + } + this.overrides = new HashMap<>(); + if (parent != null) { + parent.addToInherited(this.overrides); + } + for (Map.Entry, Object> e : overrides.entrySet()) { + OptionValue option = e.getKey(); + if (option instanceof StableOptionValue) { + throw new IllegalArgumentException("Cannot override stable option " + option); + } + if (!e.getValue().equals(option.getValue())) { + this.overrides.put(option, e.getValue()); + } + } + if (!this.overrides.isEmpty()) { + setOverrideScope(this); + } + } + + @Override + void addToInherited(Map, Object> inherited) { + if (parent != null) { + parent.addToInherited(inherited); + } + inherited.putAll(overrides); + } + + @SuppressWarnings("unchecked") + @Override + T getOverride(OptionValue option) { + return (T) overrides.get(option); + } + + @Override + void getOverrides(OptionValue option, Collection c) { + Object v = overrides.get(option); + if (v != null) { + c.add(v); + } + if (parent != null) { + parent.getOverrides(option, c); + } + } + + @Override + public void close() { + if (!overrides.isEmpty()) { + setOverrideScope(parent); + } + } + } + + static { + if (ShowReadsHistogram) { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + ArrayList> options = new ArrayList<>(); + for (OptionValue option = head; option != null; option = option.next) { + options.add(option); + } + Collections.sort(options, new Comparator>() { + + public int compare(OptionValue o1, OptionValue o2) { + if (o1.reads < o2.reads) { + return -1; + } else if (o1.reads > o2.reads) { + return 1; + } else { + return o1.getName().compareTo(o2.getName()); + } + } + }); + PrintStream out = System.out; + out.println("=== OptionValue reads histogram ==="); + for (OptionValue option : options) { + out.println(option.reads + "\t" + option); + } + } + }); + } + } +} --- /dev/null 2015-09-16 15:21:12.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/OptionsLoader.java 2015-09-16 15:21:11.000000000 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +import java.util.*; + +/** + * Helper class used to load option descriptors. Only to be used in the slow-path. + */ +public class OptionsLoader { + public static final SortedMap options = new TreeMap<>(); + + /** + * Initializes {@link #options} from {@link Options} services. + */ + static { + for (OptionDescriptors opts : ServiceLoader.load(OptionDescriptors.class, OptionsLoader.class.getClassLoader())) { + for (OptionDescriptor desc : opts) { + String name = desc.getName(); + OptionDescriptor existing = options.put(name, desc); + assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation(); + } + } + } +} --- /dev/null 2015-09-16 15:21:12.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/OptionsParser.java 2015-09-16 15:21:12.000000000 -0700 @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +import static jdk.internal.jvmci.inittimer.InitTimer.*; + +import java.io.*; +import java.util.*; + +import jdk.internal.jvmci.inittimer.*; + +/** + * This class contains methods for parsing JVMCI options and matching them against a set of + * {@link OptionDescriptors}. The {@link OptionDescriptors} are loaded from JVMCI jars, either + * {@linkplain JVMCIJarsOptionDescriptorsProvider directly} or via a {@link ServiceLoader}. + */ +public class OptionsParser { + + /** + * Character used to escape a space or a literal % in a JVMCI option value. + */ + private static final char ESCAPE = '%'; + + private static final OptionValue PrintFlags = new OptionValue<>(false); + + /** + * A service for looking up {@link OptionDescriptor}s. + */ + public interface OptionDescriptorsProvider { + /** + * Gets the {@link OptionDescriptor} matching a given option {@linkplain Option#name() name} + * or null if no option of that name is provided by this object. + */ + OptionDescriptor get(String name); + } + + public interface OptionConsumer { + void set(OptionDescriptor desc, Object value); + } + + /** + * Finds the index of the next character in {@code s} starting at {@code from} that is a + * {@linkplain #ESCAPE non-escaped} space iff {@code spaces == true}. + */ + private static int skip(String s, int from, boolean spaces) { + int len = s.length(); + int i = from; + while (i < len) { + char ch = s.charAt(i); + if (ch == ESCAPE) { + if (i == len - 1) { + throw new InternalError("Escape character " + ESCAPE + " cannot be at end of jvmci.options value: " + s); + } + ch = s.charAt(i + 1); + if (ch != ESCAPE && ch != ' ') { + throw new InternalError("Escape character " + ESCAPE + " must be followed by space or another " + ESCAPE + " character"); + } + if (spaces) { + return i; + } + i++; + } else if (ch == ' ' != spaces) { + return i; + } + i++; + } + return len; + } + + private static String unescape(String s) { + int esc = s.indexOf(ESCAPE); + if (esc == -1) { + return s; + } + StringBuilder sb = new StringBuilder(s.length()); + int start = 0; + do { + sb.append(s.substring(start, esc)); + char escaped = s.charAt(esc + 1); + if (escaped == ' ') { + sb.append(' '); + } else { + assert escaped == ESCAPE; + sb.append(ESCAPE); + } + start = esc + 2; + esc = s.indexOf(ESCAPE, start); + } while (esc != -1); + if (start < s.length()) { + sb.append(s.substring(start)); + } + return sb.toString(); + } + + /** + * Parses the options in {@code /lib/jvmci/options} if {@code parseOptionsFile == true} and + * the file exists followed by the {@linkplain #ESCAPE non-escaped} space separated JVMCI + * options in {@code options} if {@code options != null}. + * + * Called from VM. This method has an object return type to allow it to be called with a VM + * utility function used to call other static initialization methods. + * + * @param options {@linkplain #ESCAPE non-escaped} space separated set of JVMCI options to parse + * @param parseOptionsFile specifies whether to look for and parse + * {@code /lib/jvmci.options} + */ + @SuppressWarnings("try") + public static Boolean parseOptionsFromVM(String options, boolean parseOptionsFile) { + try (InitTimer t = timer("ParseOptions")) { + JVMCIJarsOptionDescriptorsProvider odp = new JVMCIJarsOptionDescriptorsProvider(); + + if (parseOptionsFile) { + File javaHome = new File(System.getProperty("java.home")); + File lib = new File(javaHome, "lib"); + File jvmci = new File(lib, "jvmci"); + File jvmciOptions = new File(jvmci, "options"); + if (jvmciOptions.exists()) { + try (BufferedReader br = new BufferedReader(new FileReader(jvmciOptions))) { + String option = null; + while ((option = br.readLine()) != null) { + option = option.trim(); + if (!option.isEmpty() && option.charAt(0) != '#') { + parseOption(option, null, odp); + } + } + } catch (IOException e) { + throw new InternalError("Error reading " + jvmciOptions, e); + } + } + } + + if (options != null) { + int index = skip(options, 0, true); + while (index < options.length()) { + int end = skip(options, index, false); + String option = unescape(options.substring(index, end)); + parseOption(option, null, odp); + index = skip(options, end, true); + } + } + } + return Boolean.TRUE; + } + + public static void parseOption(String option, OptionConsumer setter, OptionDescriptorsProvider odp) { + parseOption(OptionsLoader.options, option, setter, odp); + } + + /** + * Parses a given option value specification. + * + * @param option the specification of an option and its value + * @param setter the object to notify of the parsed option and value + * @throws IllegalArgumentException if there's a problem parsing {@code option} + */ + public static void parseOption(SortedMap options, String option, OptionConsumer setter, OptionDescriptorsProvider odp) { + if (option.length() == 0) { + return; + } + + Object value = null; + String optionName = null; + String valueString = null; + + char first = option.charAt(0); + if (first == '+' || first == '-') { + optionName = option.substring(1); + value = (first == '+'); + } else { + int index = option.indexOf('='); + if (index == -1) { + optionName = option; + valueString = null; + } else { + optionName = option.substring(0, index); + valueString = option.substring(index + 1); + } + } + + OptionDescriptor desc = odp == null ? options.get(optionName) : odp.get(optionName); + if (desc == null && value != null) { + int index = option.indexOf('='); + if (index != -1) { + optionName = option.substring(1, index); + desc = odp == null ? options.get(optionName) : odp.get(optionName); + } + if (desc == null && optionName.equals("PrintFlags")) { + desc = OptionDescriptor.create("PrintFlags", Boolean.class, "Prints all JVMCI flags and exits", OptionsParser.class, "PrintFlags", PrintFlags); + } + } + if (desc == null) { + List matches = fuzzyMatch(options, optionName); + Formatter msg = new Formatter(); + msg.format("Could not find option %s", optionName); + if (!matches.isEmpty()) { + msg.format("%nDid you mean one of the following?"); + for (OptionDescriptor match : matches) { + boolean isBoolean = match.getType() == Boolean.class; + msg.format("%n %s%s%s", isBoolean ? "(+/-)" : "", match.getName(), isBoolean ? "" : "="); + } + } + throw new IllegalArgumentException(msg.toString()); + } + + Class optionType = desc.getType(); + + if (value == null) { + if (optionType == Boolean.TYPE || optionType == Boolean.class) { + throw new IllegalArgumentException("Boolean option '" + optionName + "' must use +/- prefix"); + } + + if (valueString == null) { + throw new IllegalArgumentException("Missing value for non-boolean option '" + optionName + "' must use " + optionName + "= format"); + } + + if (optionType == Float.class) { + value = Float.parseFloat(valueString); + } else if (optionType == Double.class) { + value = Double.parseDouble(valueString); + } else if (optionType == Integer.class) { + value = Integer.valueOf((int) parseLong(valueString)); + } else if (optionType == Long.class) { + value = Long.valueOf(parseLong(valueString)); + } else if (optionType == String.class) { + value = valueString; + } else { + throw new IllegalArgumentException("Wrong value for option '" + optionName + "'"); + } + } else { + if (optionType != Boolean.class) { + throw new IllegalArgumentException("Non-boolean option '" + optionName + "' can not use +/- prefix. Use " + optionName + "= format"); + } + } + if (setter == null) { + desc.getOptionValue().setValue(value); + } else { + setter.set(desc, value); + } + + if (PrintFlags.getValue()) { + printFlags(options, "JVMCI", System.out); + System.exit(0); + } + } + + private static long parseLong(String v) { + String valueString = v.toLowerCase(); + long scale = 1; + if (valueString.endsWith("k")) { + scale = 1024L; + } else if (valueString.endsWith("m")) { + scale = 1024L * 1024L; + } else if (valueString.endsWith("g")) { + scale = 1024L * 1024L * 1024L; + } else if (valueString.endsWith("t")) { + scale = 1024L * 1024L * 1024L * 1024L; + } + + if (scale != 1) { + /* Remove trailing scale character. */ + valueString = valueString.substring(0, valueString.length() - 1); + } + + return Long.parseLong(valueString) * scale; + } + + /** + * Wraps some given text to one or more lines of a given maximum width. + * + * @param text text to wrap + * @param width maximum width of an output line, exception for words in {@code text} longer than + * this value + * @return {@code text} broken into lines + */ + private static List wrap(String text, int width) { + List lines = Collections.singletonList(text); + if (text.length() > width) { + String[] chunks = text.split("\\s+"); + lines = new ArrayList<>(); + StringBuilder line = new StringBuilder(); + for (String chunk : chunks) { + if (line.length() + chunk.length() > width) { + lines.add(line.toString()); + line.setLength(0); + } + if (line.length() != 0) { + line.append(' '); + } + String[] embeddedLines = chunk.split("%n", -2); + if (embeddedLines.length == 1) { + line.append(chunk); + } else { + for (int i = 0; i < embeddedLines.length; i++) { + line.append(embeddedLines[i]); + if (i < embeddedLines.length - 1) { + lines.add(line.toString()); + line.setLength(0); + } + } + } + } + if (line.length() != 0) { + lines.add(line.toString()); + } + } + return lines; + } + + public static void printFlags(SortedMap sortedOptions, String prefix, PrintStream out) { + out.println("[List of " + prefix + " options]"); + for (Map.Entry e : sortedOptions.entrySet()) { + e.getKey(); + OptionDescriptor desc = e.getValue(); + Object value = desc.getOptionValue().getValue(); + List helpLines = wrap(desc.getHelp(), 70); + out.println(String.format("%9s %-40s = %-14s %s", desc.getType().getSimpleName(), e.getKey(), value, helpLines.get(0))); + for (int i = 1; i < helpLines.size(); i++) { + out.println(String.format("%67s %s", " ", helpLines.get(i))); + } + } + } + + /** + * Compute string similarity based on Dice's coefficient. + * + * Ported from str_similar() in globals.cpp. + */ + static float stringSimiliarity(String str1, String str2) { + int hit = 0; + for (int i = 0; i < str1.length() - 1; ++i) { + for (int j = 0; j < str2.length() - 1; ++j) { + if ((str1.charAt(i) == str2.charAt(j)) && (str1.charAt(i + 1) == str2.charAt(j + 1))) { + ++hit; + break; + } + } + } + return 2.0f * hit / (str1.length() + str2.length()); + } + + private static final float FUZZY_MATCH_THRESHOLD = 0.7F; + + /** + * Returns the set of options that fuzzy match a given option name. + */ + private static List fuzzyMatch(SortedMap options, String optionName) { + List matches = new ArrayList<>(); + for (Map.Entry e : options.entrySet()) { + float score = stringSimiliarity(e.getKey(), optionName); + if (score >= FUZZY_MATCH_THRESHOLD) { + matches.add(e.getValue()); + } + } + return matches; + } +} --- /dev/null 2015-09-16 15:21:13.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.options/src/jdk/internal/jvmci/options/StableOptionValue.java 2015-09-16 15:21:13.000000000 -0700 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.options; + +/** + * An option that always returns the same {@linkplain #getValue() value}. + */ +public class StableOptionValue extends OptionValue { + + /** + * Creates a stable option value. + */ + public StableOptionValue(T value) { + super(value); + } + + /** + * Used to assert the invariant for stability. Without using locks, this check is not safe + * against races and so it's only an assertion. + */ + private boolean getValueCalled; + + /** + * Creates an uninitialized stable option value for a subclass that initializes itself + * {@link #defaultValue() lazily}. + */ + public StableOptionValue() { + } + + /** + * Gets the value of this option. + */ + @Override + public final T getValue() { + T result = super.getValue(); + assert initGetValueCalled(); + return result; + } + + private boolean initGetValueCalled() { + getValueCalled = true; + return true; + } + + /** + * {@inheritDoc} + *

      + * This must only be called if {@link #getValue()} has never been called. + */ + @Override + public final void setValue(Object v) { + assert !getValueCalled; + super.setValue(v); + } +} --- /dev/null 2015-09-16 15:21:13.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.runtime/src/jdk/internal/jvmci/runtime/JVMCI.java 2015-09-16 15:21:13.000000000 -0700 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.runtime; + +import java.util.*; + +public class JVMCI { + + private static final JVMCIRuntime runtime; + + private static native JVMCIRuntime initializeRuntime(); + + public static void initialize() { + // force static initializer + } + + /** + * Gets the singleton {@link JVMCIRuntime} instance available to the application. + * + * @throws UnsupportedOperationException if JVMCI is not supported + */ + public static JVMCIRuntime getRuntime() { + if (runtime == null) { + String javaHome = System.getProperty("java.home"); + String vmName = System.getProperty("java.vm.name"); + Formatter errorMessage = new Formatter(); + errorMessage.format("The VM does not support the JVMCI API.%n"); + errorMessage.format("Currently used Java home directory is %s.%n", javaHome); + errorMessage.format("Currently used VM configuration is: %s", vmName); + throw new UnsupportedOperationException(errorMessage.toString()); + } + return runtime; + } + + static { + JVMCIRuntime rt = null; + try { + rt = initializeRuntime(); + } catch (UnsatisfiedLinkError e) { + } + runtime = rt; + } +} --- /dev/null 2015-09-16 15:21:14.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.runtime/src/jdk/internal/jvmci/runtime/JVMCIBackend.java 2015-09-16 15:21:14.000000000 -0700 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.runtime; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.meta.*; + +/** + * A JVMCI backend encapsulates the capabilities needed by a Java based compiler for compiling and + * installing code for a single compute unit within a JVM. In a JVM with support for heterogeneous + * computing, more than one backend may be exposed. + */ +public class JVMCIBackend { + + private final MetaAccessProvider metaAccess; + private final CodeCacheProvider codeCache; + private final ConstantReflectionProvider constantReflection; + + public JVMCIBackend(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ConstantReflectionProvider constantReflection) { + this.metaAccess = metaAccess; + this.codeCache = codeCache; + this.constantReflection = constantReflection; + } + + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + public CodeCacheProvider getCodeCache() { + return codeCache; + } + + public ConstantReflectionProvider getConstantReflection() { + return constantReflection; + } + + public TargetDescription getTarget() { + return codeCache.getTarget(); + } +} --- /dev/null 2015-09-16 15:21:15.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.runtime/src/jdk/internal/jvmci/runtime/JVMCIRuntime.java 2015-09-16 15:21:14.000000000 -0700 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.runtime; + +import jdk.internal.jvmci.code.*; + +/** + * Interface for accessing the {@link JVMCI} APIs supported by the runtime. + */ +public interface JVMCIRuntime { + + /** + * Gets the host JVMCI backend. + */ + JVMCIBackend getHostJVMCIBackend(); + + /** + * Gets the backend for a given architecture. + * + * @param arch a specific architecture class + */ + JVMCIBackend getJVMCIBackend(Class arch); +} --- /dev/null 2015-09-16 15:21:15.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.service.processor/src/META-INF/services/javax.annotation.processing.Processor 2015-09-16 15:21:15.000000000 -0700 @@ -0,0 +1 @@ +jdk.internal.jvmci.service.processor.ServiceProviderProcessor --- /dev/null 2015-09-16 15:21:16.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.service.processor/src/jdk/internal/jvmci/service/processor/ServiceProviderProcessor.java 2015-09-16 15:21:16.000000000 -0700 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.service.processor; + +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.tools.Diagnostic.Kind; +import javax.tools.*; + +import jdk.internal.jvmci.service.*; + +@SupportedAnnotationTypes("jdk.internal.jvmci.service.ServiceProvider") +public class ServiceProviderProcessor extends AbstractProcessor { + + private final Set processed = new HashSet<>(); + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + private boolean verifyAnnotation(TypeMirror serviceInterface, TypeElement serviceProvider) { + if (!processingEnv.getTypeUtils().isSubtype(serviceProvider.asType(), serviceInterface)) { + String msg = String.format("Service provider class %s must implement service interface %s", serviceProvider.getSimpleName(), serviceInterface); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider); + return false; + } + + return true; + } + + private void processElement(TypeElement serviceProvider) { + if (processed.contains(serviceProvider)) { + return; + } + + processed.add(serviceProvider); + ServiceProvider annotation = serviceProvider.getAnnotation(ServiceProvider.class); + if (annotation != null) { + try { + annotation.value(); + } catch (MirroredTypeException ex) { + TypeMirror serviceInterface = ex.getTypeMirror(); + if (verifyAnnotation(serviceInterface, serviceProvider)) { + String interfaceName = ex.getTypeMirror().toString(); + createProviderFile(serviceProvider, interfaceName); + } + } + } + } + + private void createProviderFile(TypeElement serviceProvider, String interfaceName) { + if (serviceProvider.getNestingKind().isNested()) { + // This is a simplifying constraint that means we don't have to + // processed the qualified name to insert '$' characters at + // the relevant positions. + String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider); + return; + } + + String filename = "META-INF/jvmci.providers/" + serviceProvider.getQualifiedName(); + try { + FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, serviceProvider); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8")); + writer.println(interfaceName); + writer.close(); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), serviceProvider); + } + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return true; + } + + for (Element element : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) { + assert element.getKind().isClass(); + processElement((TypeElement) element); + } + + return true; + } +} --- /dev/null 2015-09-16 15:21:16.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.service/.checkstyle_checks.xml 2015-09-16 15:21:16.000000000 -0700 @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + --- /dev/null 2015-09-16 15:21:17.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.service/src/jdk/internal/jvmci/service/ServiceProvider.java 2015-09-16 15:21:17.000000000 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.service; + +import java.lang.annotation.*; + +/** + * Annotates a service provider than can be loaded via {@linkplain Services#load(Class)} or + * {@link Services#loadSingle(Class, boolean)}. + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface ServiceProvider { + + Class value(); +} --- /dev/null 2015-09-16 15:21:18.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.service/src/jdk/internal/jvmci/service/Services.java 2015-09-16 15:21:17.000000000 -0700 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.service; + +import java.util.*; + +/** + * A mechanism for accessing service providers via JVMCI. + */ +public final class Services { + + private Services() { + } + + /** + * Gets an {@link Iterable} of the JVMCI providers available for a given service. + */ + public static Iterable load(Class service) { + return ServiceLoader.load(service); + } + + /** + * Gets the JVMCI provider for a given service for which at most one provider must be available. + * + * @param service the service whose provider is being requested + * @param required specifies if an {@link InternalError} should be thrown if no provider of + * {@code service} is available + */ + public static S loadSingle(Class service, boolean required) { + Iterable providers = ServiceLoader.load(service); + S singleProvider = null; + try { + for (Iterator it = providers.iterator(); it.hasNext(); ) { + singleProvider = it.next(); + if (it.hasNext()) { + throw new InternalError(String.format("Multiple %s providers found", service.getName())); + } + } + } catch (ServiceConfigurationError e) { + // If the service is required we will bail out below. + } + if (singleProvider == null && required) { + String javaHome = System.getProperty("java.home"); + String vmName = System.getProperty("java.vm.name"); + Formatter errorMessage = new Formatter(); + errorMessage.format("The VM does not expose required service %s.%n", service.getName()); + errorMessage.format("Currently used Java home directory is %s.%n", javaHome); + errorMessage.format("Currently used VM configuration is: %s", vmName); + throw new UnsupportedOperationException(errorMessage.toString()); + } + return singleProvider; + } +} --- /dev/null 2015-09-16 15:21:18.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.sparc/src/jdk/internal/jvmci/sparc/SPARC.java 2015-09-16 15:21:18.000000000 -0700 @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2013, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.sparc; + +import static java.nio.ByteOrder.*; +import static jdk.internal.jvmci.code.MemoryBarriers.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.code.Register.RegisterCategory; +import jdk.internal.jvmci.meta.*; + +/** + * Represents the SPARC architecture. + */ +public class SPARC extends Architecture { + + public static final RegisterCategory CPU = new RegisterCategory("CPU"); + + // General purpose registers + public static final Register r0 = new Register(0, 0, "g0", CPU); + public static final Register r1 = new Register(1, 1, "g1", CPU); + public static final Register r2 = new Register(2, 2, "g2", CPU); + public static final Register r3 = new Register(3, 3, "g3", CPU); + public static final Register r4 = new Register(4, 4, "g4", CPU); + public static final Register r5 = new Register(5, 5, "g5", CPU); + public static final Register r6 = new Register(6, 6, "g6", CPU); + public static final Register r7 = new Register(7, 7, "g7", CPU); + + public static final Register r8 = new Register(8, 8, "o0", CPU); + public static final Register r9 = new Register(9, 9, "o1", CPU); + public static final Register r10 = new Register(10, 10, "o2", CPU); + public static final Register r11 = new Register(11, 11, "o3", CPU); + public static final Register r12 = new Register(12, 12, "o4", CPU); + public static final Register r13 = new Register(13, 13, "o5", CPU); + public static final Register r14 = new Register(14, 14, "o6", CPU); + public static final Register r15 = new Register(15, 15, "o7", CPU); + + public static final Register r16 = new Register(16, 16, "l0", CPU); + public static final Register r17 = new Register(17, 17, "l1", CPU); + public static final Register r18 = new Register(18, 18, "l2", CPU); + public static final Register r19 = new Register(19, 19, "l3", CPU); + public static final Register r20 = new Register(20, 20, "l4", CPU); + public static final Register r21 = new Register(21, 21, "l5", CPU); + public static final Register r22 = new Register(22, 22, "l6", CPU); + public static final Register r23 = new Register(23, 23, "l7", CPU); + + public static final Register r24 = new Register(24, 24, "i0", CPU); + public static final Register r25 = new Register(25, 25, "i1", CPU); + public static final Register r26 = new Register(26, 26, "i2", CPU); + public static final Register r27 = new Register(27, 27, "i3", CPU); + public static final Register r28 = new Register(28, 28, "i4", CPU); + public static final Register r29 = new Register(29, 29, "i5", CPU); + public static final Register r30 = new Register(30, 30, "i6", CPU); + public static final Register r31 = new Register(31, 31, "i7", CPU); + + public static final Register g0 = r0; + public static final Register g1 = r1; + public static final Register g2 = r2; + public static final Register g3 = r3; + public static final Register g4 = r4; + public static final Register g5 = r5; + public static final Register g6 = r6; + public static final Register g7 = r7; + + public static final Register o0 = r8; + public static final Register o1 = r9; + public static final Register o2 = r10; + public static final Register o3 = r11; + public static final Register o4 = r12; + public static final Register o5 = r13; + public static final Register o6 = r14; + public static final Register o7 = r15; + + public static final Register l0 = r16; + public static final Register l1 = r17; + public static final Register l2 = r18; + public static final Register l3 = r19; + public static final Register l4 = r20; + public static final Register l5 = r21; + public static final Register l6 = r22; + public static final Register l7 = r23; + + public static final Register i0 = r24; + public static final Register i1 = r25; + public static final Register i2 = r26; + public static final Register i3 = r27; + public static final Register i4 = r28; + public static final Register i5 = r29; + public static final Register i6 = r30; + public static final Register i7 = r31; + + public static final Register sp = o6; + public static final Register fp = i6; + + // @formatter:off + public static final Register[] cpuRegisters = { + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15, + r16, r17, r18, r19, r20, r21, r22, r23, + r24, r25, r26, r27, r28, r29, r30, r31 + }; + // @formatter:on + + public static final RegisterCategory FPUs = new RegisterCategory("FPUs", cpuRegisters.length); + public static final RegisterCategory FPUd = new RegisterCategory("FPUd", cpuRegisters.length + 32); + + // Floating point registers + public static final Register f0 = new Register(32, 0, "f0", FPUs); + public static final Register f1 = new Register(33, 1, "f1", FPUs); + public static final Register f2 = new Register(34, 2, "f2", FPUs); + public static final Register f3 = new Register(35, 3, "f3", FPUs); + public static final Register f4 = new Register(36, 4, "f4", FPUs); + public static final Register f5 = new Register(37, 5, "f5", FPUs); + public static final Register f6 = new Register(38, 6, "f6", FPUs); + public static final Register f7 = new Register(39, 7, "f7", FPUs); + + public static final Register f8 = new Register(40, 8, "f8", FPUs); + public static final Register f9 = new Register(41, 9, "f9", FPUs); + public static final Register f10 = new Register(42, 10, "f10", FPUs); + public static final Register f11 = new Register(43, 11, "f11", FPUs); + public static final Register f12 = new Register(44, 12, "f12", FPUs); + public static final Register f13 = new Register(45, 13, "f13", FPUs); + public static final Register f14 = new Register(46, 14, "f14", FPUs); + public static final Register f15 = new Register(47, 15, "f15", FPUs); + + public static final Register f16 = new Register(48, 16, "f16", FPUs); + public static final Register f17 = new Register(49, 17, "f17", FPUs); + public static final Register f18 = new Register(50, 18, "f18", FPUs); + public static final Register f19 = new Register(51, 19, "f19", FPUs); + public static final Register f20 = new Register(52, 20, "f20", FPUs); + public static final Register f21 = new Register(53, 21, "f21", FPUs); + public static final Register f22 = new Register(54, 22, "f22", FPUs); + public static final Register f23 = new Register(55, 23, "f23", FPUs); + + public static final Register f24 = new Register(56, 24, "f24", FPUs); + public static final Register f25 = new Register(57, 25, "f25", FPUs); + public static final Register f26 = new Register(58, 26, "f26", FPUs); + public static final Register f27 = new Register(59, 27, "f27", FPUs); + public static final Register f28 = new Register(60, 28, "f28", FPUs); + public static final Register f29 = new Register(61, 29, "f29", FPUs); + public static final Register f30 = new Register(62, 30, "f30", FPUs); + public static final Register f31 = new Register(63, 31, "f31", FPUs); + + public static final Register d0 = new Register(32, getDoubleEncoding(0), "d0", FPUs); + public static final Register d2 = new Register(34, getDoubleEncoding(2), "d2", FPUs); + public static final Register d4 = new Register(36, getDoubleEncoding(4), "d4", FPUs); + public static final Register d6 = new Register(38, getDoubleEncoding(6), "d6", FPUs); + public static final Register d8 = new Register(40, getDoubleEncoding(8), "d8", FPUs); + public static final Register d10 = new Register(42, getDoubleEncoding(10), "d10", FPUs); + public static final Register d12 = new Register(44, getDoubleEncoding(12), "d12", FPUs); + public static final Register d14 = new Register(46, getDoubleEncoding(14), "d14", FPUs); + + public static final Register d16 = new Register(48, getDoubleEncoding(16), "d16", FPUs); + public static final Register d18 = new Register(50, getDoubleEncoding(18), "d18", FPUs); + public static final Register d20 = new Register(52, getDoubleEncoding(20), "d20", FPUs); + public static final Register d22 = new Register(54, getDoubleEncoding(22), "d22", FPUs); + public static final Register d24 = new Register(56, getDoubleEncoding(24), "d24", FPUs); + public static final Register d26 = new Register(58, getDoubleEncoding(26), "d26", FPUs); + public static final Register d28 = new Register(60, getDoubleEncoding(28), "d28", FPUs); + public static final Register d30 = new Register(62, getDoubleEncoding(28), "d28", FPUs); + + public static final Register d32 = new Register(64, getDoubleEncoding(32), "d32", FPUd); + public static final Register d34 = new Register(65, getDoubleEncoding(34), "d34", FPUd); + public static final Register d36 = new Register(66, getDoubleEncoding(36), "d36", FPUd); + public static final Register d38 = new Register(67, getDoubleEncoding(38), "d38", FPUd); + public static final Register d40 = new Register(68, getDoubleEncoding(40), "d40", FPUd); + public static final Register d42 = new Register(69, getDoubleEncoding(42), "d42", FPUd); + public static final Register d44 = new Register(70, getDoubleEncoding(44), "d44", FPUd); + public static final Register d46 = new Register(71, getDoubleEncoding(46), "d46", FPUd); + + public static final Register d48 = new Register(72, getDoubleEncoding(48), "d48", FPUd); + public static final Register d50 = new Register(73, getDoubleEncoding(50), "d50", FPUd); + public static final Register d52 = new Register(74, getDoubleEncoding(52), "d52", FPUd); + public static final Register d54 = new Register(75, getDoubleEncoding(54), "d54", FPUd); + public static final Register d56 = new Register(76, getDoubleEncoding(56), "d56", FPUd); + public static final Register d58 = new Register(77, getDoubleEncoding(58), "d58", FPUd); + public static final Register d60 = new Register(78, getDoubleEncoding(60), "d60", FPUd); + public static final Register d62 = new Register(79, getDoubleEncoding(62), "d62", FPUd); + + // @formatter:off + public static final Register[] fpuRegisters = { + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + + // @formatter:off + public static final Register[] allRegisters = { + // CPU + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15, + r16, r17, r18, r19, r20, r21, r22, r23, + r24, r25, r26, r27, r28, r29, r30, r31, + // FPU + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + + /** + * Stack bias for stack and frame pointer loads. + */ + public static final int STACK_BIAS = 0x7ff; + /** + * In fact there are 64 single floating point registers, 32 of them could be accessed. TODO: + * Improve handling of these float registers + */ + public static final int FLOAT_REGISTER_COUNT = 64; + + /** + * Alignment for valid memory access. + */ + public static final int MEMORY_ACCESS_ALIGN = 4; + + public static final int INSTRUCTION_SIZE = 4; + + /** + * Size to keep free for flushing the register-window to stack. + */ + public static final int REGISTER_SAFE_AREA_SIZE = 128; + + public final Set features; + + public SPARC(Set features) { + super("SPARC", JavaKind.Long, BIG_ENDIAN, false, allRegisters, LOAD_LOAD | LOAD_STORE | STORE_STORE, 1, r31.encoding + FLOAT_REGISTER_COUNT + 1, 8); + this.features = features; + } + + @Override + public boolean canStoreValue(RegisterCategory category, PlatformKind lirKind) { + if (!(lirKind instanceof JavaKind)) { + return false; + } + + JavaKind kind = (JavaKind) lirKind; + if (category.equals(CPU)) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + return true; + } + } else if (category.equals(FPUs) && kind.equals(JavaKind.Float)) { + return true; + } else if (category.equals(FPUd) && kind.equals(JavaKind.Double)) { + return true; + } + return false; + } + + @Override + public PlatformKind getLargestStorableKind(RegisterCategory category) { + if (category.equals(CPU)) { + return JavaKind.Long; + } else if (category.equals(FPUd)) { + return JavaKind.Double; + } else if (category.equals(FPUs)) { + return JavaKind.Float; + } else { + return JavaKind.Illegal; + } + } + + @Override + public PlatformKind getPlatformKind(JavaKind javaKind) { + if (javaKind.isObject()) { + return JavaKind.Long; + } else { + return javaKind; + } + } + + public static int spillSlotSize(TargetDescription td, PlatformKind kind) { + return Math.max(td.getSizeInBytes(kind), MEMORY_ACCESS_ALIGN); + } + + public static int getDoubleEncoding(int reg) { + assert reg < 64 && ((reg & 1) == 0); + // ignore v8 assertion for now + return (reg & 0x1e) | ((reg & 0x20) >> 5); + } + + public static boolean isCPURegister(Register r) { + return r.getRegisterCategory().equals(CPU); + } + + public static boolean isCPURegister(Register... regs) { + for (Register reg : regs) { + if (!isCPURegister(reg)) { + return false; + } + } + return true; + } + + public static boolean isGlobalRegister(Register r) { + return isCPURegister(r) && g0.number <= r.number && r.number <= g7.number; + } + + public static boolean isSingleFloatRegister(Register r) { + return r.name.startsWith("f"); + } + + public static boolean isDoubleFloatRegister(Register r) { + return r.name.startsWith("d"); + } + + public Set getFeatures() { + return features; + } + + public boolean hasFeature(CPUFeature feature) { + return features.contains(feature); + } + + public enum CPUFeature { + VIS1, + VIS2, + VIS3, + CBCOND, + BLOCK_ZEROING + } +} --- /dev/null 2015-09-16 15:21:19.000000000 -0700 +++ new/src/os/aix/vm/vmStructs_aix.hpp 2015-09-16 15:21:19.000000000 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_AIX_VM_VMSTRUCTS_AIX_HPP +#define OS_AIX_VM_VMSTRUCTS_AIX_HPP + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) + +#endif // OS_AIX_VM_VMSTRUCTS_AIX_HPP --- /dev/null 2015-09-16 15:21:19.000000000 -0700 +++ new/src/os/bsd/vm/vmStructs_bsd.hpp 2015-09-16 15:21:19.000000000 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_BSD_VM_VMSTRUCTS_BSD_HPP +#define OS_BSD_VM_VMSTRUCTS_BSD_HPP + +#include + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ + declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) + +#endif // OS_BSD_VM_VMSTRUCTS_BSD_HPP --- /dev/null 2015-09-16 15:21:20.000000000 -0700 +++ new/src/os/linux/vm/vmStructs_linux.hpp 2015-09-16 15:21:20.000000000 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_LINUX_VM_VMSTRUCTS_LINUX_HPP +#define OS_LINUX_VM_VMSTRUCTS_LINUX_HPP + +#include + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ + declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) + +#endif // OS_LINUX_VM_VMSTRUCTS_LINUX_HPP --- /dev/null 2015-09-16 15:21:21.000000000 -0700 +++ new/src/os/solaris/vm/vmStructs_solaris.hpp 2015-09-16 15:21:20.000000000 -0700 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_SOLARIS_VM_VMSTRUCTS_SOLARIS_HPP +#define OS_SOLARIS_VM_VMSTRUCTS_SOLARIS_HPP + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + declare_unsigned_integer_type(OSThread::thread_id_t) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) + +#endif // OS_SOLARIS_VM_VMSTRUCTS_SOLARIS_HPP --- /dev/null 2015-09-16 15:21:21.000000000 -0700 +++ new/src/os/windows/vm/vmStructs_windows.hpp 2015-09-16 15:21:21.000000000 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_WINDOWS_VM_VMSTRUCTS_WINDOWS_HPP +#define OS_WINDOWS_VM_VMSTRUCTS_WINDOWS_HPP + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) + +#endif // OS_WINDOWS_VM_VMSTRUCTS_WINDOWS_HPP --- /dev/null 2015-09-16 15:21:22.000000000 -0700 +++ new/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp 2015-09-16 15:21:22.000000000 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" +#include "runtime/arguments.hpp" +#include "runtime/globals.hpp" +#include "utilities/defaultStream.hpp" + +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose) { + if (!EnableJVMCI) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); + } + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose) { + if (!EnableJVMCI) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); + } + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} --- /dev/null 2015-09-16 15:21:23.000000000 -0700 +++ new/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp 2015-09-16 15:21:22.000000000 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP +#define SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP + +#include "runtime/globals.hpp" +#include "utilities/globalDefinitions.hpp" + +/* + * Here we have JVMCI arguments constraints functions, which are called automatically + * whenever flag's value changes. If the constraint fails the function should return + * an appropriate error value. + */ + +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose); +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose); + +#endif /* SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP */ --- /dev/null 2015-09-16 15:21:23.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciCodeInstaller.cpp 2015-09-16 15:21:23.000000000 -0700 @@ -0,0 +1,1029 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "code/compiledIC.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/disassembler.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "asm/register.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/vmreg.hpp" + +#ifdef TARGET_ARCH_x86 +# include "vmreg_x86.inline.hpp" +#endif +#ifdef TARGET_ARCH_sparc +# include "vmreg_sparc.inline.hpp" +#endif +#ifdef TARGET_ARCH_zero +# include "vmreg_zero.inline.hpp" +#endif +#ifdef TARGET_ARCH_arm +# include "vmreg_arm.inline.hpp" +#endif +#ifdef TARGET_ARCH_ppc +# include "vmreg_ppc.inline.hpp" +#endif + + +// frequently used constants +// Allocate them with new so they are never destroyed (otherwise, a +// forced exit could destroy these objects while they are still in +// use). +ConstantOopWriteValue* CodeInstaller::_oop_null_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantOopWriteValue(NULL); +ConstantIntValue* CodeInstaller::_int_m1_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(-1); +ConstantIntValue* CodeInstaller::_int_0_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(0); +ConstantIntValue* CodeInstaller::_int_1_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(1); +ConstantIntValue* CodeInstaller::_int_2_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(2); +LocationValue* CodeInstaller::_illegal_value = new (ResourceObj::C_HEAP, mtCompiler) LocationValue(Location()); + +Method* getMethodFromHotSpotMethod(oop hotspot_method) { + assert(hotspot_method != NULL && hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass()), "sanity"); + return CompilerToVM::asMethod(hotspot_method); +} + +VMReg getVMRegFromLocation(oop location, int total_frame_size) { + oop reg = code_Location::reg(location); + jint offset = code_Location::offset(location); + + if (reg != NULL) { + // register + jint number = code_Register::number(reg); + VMReg vmReg = CodeInstaller::get_hotspot_reg(number); + assert(offset % 4 == 0, "must be aligned"); + return vmReg->next(offset / 4); + } else { + // stack slot + assert(offset % 4 == 0, "must be aligned"); + return VMRegImpl::stack2reg(offset / 4); + } +} + +// creates a HotSpot oop map out of the byte arrays provided by DebugInfo +OopMap* CodeInstaller::create_oop_map(oop debug_info) { + oop reference_map = DebugInfo::referenceMap(debug_info); + if (HotSpotReferenceMap::maxRegisterSize(reference_map) > 16) { + _has_wide_vector = true; + } + OopMap* map = new OopMap(_total_frame_size, _parameter_count); + objArrayOop objects = HotSpotReferenceMap::objects(reference_map); + objArrayOop derivedBase = HotSpotReferenceMap::derivedBase(reference_map); + typeArrayOop sizeInBytes = HotSpotReferenceMap::sizeInBytes(reference_map); + for (int i = 0; i < objects->length(); i++) { + oop location = objects->obj_at(i); + oop baseLocation = derivedBase->obj_at(i); + int bytes = sizeInBytes->int_at(i); + + VMReg vmReg = getVMRegFromLocation(location, _total_frame_size); + if (baseLocation != NULL) { + // derived oop + assert(bytes == 8, "derived oop can't be compressed"); + VMReg baseReg = getVMRegFromLocation(baseLocation, _total_frame_size); + map->set_derived_oop(vmReg, baseReg); + } else if (bytes == 8) { + // wide oop + map->set_oop(vmReg); + } else { + // narrow oop + assert(bytes == 4, "wrong size"); + map->set_narrowoop(vmReg); + } + } + + oop callee_save_info = (oop) DebugInfo::calleeSaveInfo(debug_info); + if (callee_save_info != NULL) { + objArrayOop registers = RegisterSaveLayout::registers(callee_save_info); + typeArrayOop slots = RegisterSaveLayout::slots(callee_save_info); + for (jint i = 0; i < slots->length(); i++) { + oop jvmci_reg = registers->obj_at(i); + jint jvmci_reg_number = code_Register::number(jvmci_reg); + VMReg hotspot_reg = CodeInstaller::get_hotspot_reg(jvmci_reg_number); + // HotSpot stack slots are 4 bytes + jint jvmci_slot = slots->int_at(i); + jint hotspot_slot = jvmci_slot * VMRegImpl::slots_per_word; + VMReg hotspot_slot_as_reg = VMRegImpl::stack2reg(hotspot_slot); + map->set_callee_saved(hotspot_slot_as_reg, hotspot_reg); +#ifdef _LP64 + // (copied from generate_oop_map() in c1_Runtime1_x86.cpp) + VMReg hotspot_slot_hi_as_reg = VMRegImpl::stack2reg(hotspot_slot + 1); + map->set_callee_saved(hotspot_slot_hi_as_reg, hotspot_reg->next()); +#endif + } + } + return map; +} + +static void record_metadata_reference(oop obj, jlong prim, jboolean compressed, OopRecorder* oop_recorder) { + if (obj->is_a(HotSpotResolvedObjectTypeImpl::klass())) { + Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(obj)); + if (compressed) { + assert(Klass::decode_klass((narrowKlass) prim) == klass, err_msg("%s @ " INTPTR_FORMAT " != " PTR64_FORMAT, klass->name()->as_C_string(), p2i(klass), prim)); + } else { + assert((Klass*) prim == klass, err_msg("%s @ " INTPTR_FORMAT " != " PTR64_FORMAT, klass->name()->as_C_string(), p2i(klass), prim)); + } + int index = oop_recorder->find_index(klass); + TRACE_jvmci_3("metadata[%d of %d] = %s", index, oop_recorder->metadata_count(), klass->name()->as_C_string()); + } else if (obj->is_a(HotSpotResolvedJavaMethodImpl::klass())) { + Method* method = (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(obj); + assert(!compressed, err_msg("unexpected compressed method pointer %s @ " INTPTR_FORMAT " = " PTR64_FORMAT, method->name()->as_C_string(), p2i(method), prim)); + int index = oop_recorder->find_index(method); + TRACE_jvmci_3("metadata[%d of %d] = %s", index, oop_recorder->metadata_count(), method->name()->as_C_string()); + } else { + assert(java_lang_String::is_instance(obj), + err_msg("unexpected metadata reference (%s) for constant " JLONG_FORMAT " (" PTR64_FORMAT ")", obj->klass()->name()->as_C_string(), prim, prim)); + } +} + +// Records any Metadata values embedded in a Constant (e.g., the value returned by HotSpotResolvedObjectTypeImpl.klass()). +static void record_metadata_in_constant(oop constant, OopRecorder* oop_recorder) { + if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { + oop obj = HotSpotMetaspaceConstantImpl::metaspaceObject(constant); + jlong prim = HotSpotMetaspaceConstantImpl::primitive(constant); + assert(obj != NULL, "must have an object"); + assert(prim != 0, "must have a primitive value"); + + record_metadata_reference(obj, prim, false, oop_recorder); + } +} + +static void record_metadata_in_patch(Handle& constant, OopRecorder* oop_recorder) { + record_metadata_reference(HotSpotMetaspaceConstantImpl::metaspaceObject(constant), HotSpotMetaspaceConstantImpl::primitive(constant), HotSpotMetaspaceConstantImpl::compressed(constant), oop_recorder); +} + +Location::Type CodeInstaller::get_oop_type(oop value) { + oop lirKind = Value::lirKind(value); + oop platformKind = LIRKind::platformKind(lirKind); + assert(LIRKind::referenceMask(lirKind) == 1, "unexpected referenceMask"); + + if (platformKind == word_kind()) { + return Location::oop; + } else { + return Location::narrowoop; + } +} + +ScopeValue* CodeInstaller::get_scope_value(oop value, BasicType type, GrowableArray* objects, ScopeValue* &second) { + second = NULL; + if (value == Value::ILLEGAL()) { + assert(type == T_ILLEGAL, "expected legal value"); + return _illegal_value; + } else if (value->is_a(RegisterValue::klass())) { + oop reg = RegisterValue::reg(value); + jint number = code_Register::number(reg); + VMReg hotspotRegister = get_hotspot_reg(number); + if (is_general_purpose_reg(hotspotRegister)) { + Location::Type locationType; + if (type == T_OBJECT) { + locationType = get_oop_type(value); + } else if (type == T_LONG) { + locationType = Location::lng; + } else { + assert(type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN, "unexpected type in cpu register"); + locationType = Location::int_in_long; + } + ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, hotspotRegister)); + if (type == T_LONG) { + second = value; + } + return value; + } else { + assert(type == T_FLOAT || type == T_DOUBLE, "only float and double expected in xmm register"); + Location::Type locationType; + if (type == T_FLOAT) { + // this seems weird, but the same value is used in c1_LinearScan + locationType = Location::normal; + } else { + locationType = Location::dbl; + } + ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, hotspotRegister)); + if (type == T_DOUBLE) { + second = value; + } + return value; + } + } else if (value->is_a(StackSlot::klass())) { + jint offset = StackSlot::offset(value); + if (StackSlot::addFrameSize(value)) { + offset += _total_frame_size; + } + + Location::Type locationType; + if (type == T_OBJECT) { + locationType = get_oop_type(value); + } else if (type == T_LONG) { + locationType = Location::lng; + } else if (type == T_DOUBLE) { + locationType = Location::dbl; + } else { + assert(type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN, "unexpected type in stack slot"); + locationType = Location::normal; + } + ScopeValue* value = new LocationValue(Location::new_stk_loc(locationType, offset)); + if (type == T_DOUBLE || type == T_LONG) { + second = value; + } + return value; + } else if (value->is_a(JavaConstant::klass())) { + record_metadata_in_constant(value, _oop_recorder); + if (value->is_a(PrimitiveConstant::klass())) { + if (value->is_a(RawConstant::klass())) { + jlong prim = PrimitiveConstant::primitive(value); + return new ConstantLongValue(prim); + } else { + assert(type == JVMCIRuntime::kindToBasicType(JavaKind::typeChar(PrimitiveConstant::kind(value))), "primitive constant type doesn't match"); + if (type == T_INT || type == T_FLOAT) { + jint prim = (jint)PrimitiveConstant::primitive(value); + switch (prim) { + case -1: return _int_m1_scope_value; + case 0: return _int_0_scope_value; + case 1: return _int_1_scope_value; + case 2: return _int_2_scope_value; + default: return new ConstantIntValue(prim); + } + } else { + assert(type == T_LONG || type == T_DOUBLE, "unexpected primitive constant type"); + jlong prim = PrimitiveConstant::primitive(value); + second = _int_1_scope_value; + return new ConstantLongValue(prim); + } + } + } else { + assert(type == T_OBJECT, "unexpected object constant"); + if (value->is_a(NullConstant::klass()) || value->is_a(HotSpotCompressedNullConstant::klass())) { + return _oop_null_scope_value; + } else { + assert(value->is_a(HotSpotObjectConstantImpl::klass()), "unexpected constant type"); + oop obj = HotSpotObjectConstantImpl::object(value); + assert(obj != NULL, "null value must be in NullConstant"); + return new ConstantOopWriteValue(JNIHandles::make_local(obj)); + } + } + } else if (value->is_a(VirtualObject::klass())) { + assert(type == T_OBJECT, "unexpected virtual object"); + int id = VirtualObject::id(value); + ScopeValue* object = objects->at(id); + assert(object != NULL, "missing value"); + return object; + } else { + value->klass()->print(); + value->print(); + } + ShouldNotReachHere(); + return NULL; +} + +void CodeInstaller::record_object_value(ObjectValue* sv, oop value, GrowableArray* objects) { + oop type = VirtualObject::type(value); + int id = VirtualObject::id(value); + oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type); + Klass* klass = java_lang_Class::as_Klass(javaMirror); + bool isLongArray = klass == Universe::longArrayKlassObj(); + + objArrayOop values = VirtualObject::values(value); + objArrayOop slotKinds = VirtualObject::slotKinds(value); + for (jint i = 0; i < values->length(); i++) { + ScopeValue* cur_second = NULL; + oop object = values->obj_at(i); + oop kind = slotKinds->obj_at(i); + BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); + ScopeValue* value = get_scope_value(object, type, objects, cur_second); + + if (isLongArray && cur_second == NULL) { + // we're trying to put ints into a long array... this isn't really valid, but it's used for some optimizations. + // add an int 0 constant + cur_second = _int_0_scope_value; + } + + if (cur_second != NULL) { + sv->field_values()->append(cur_second); + } + assert(value != NULL, "missing value"); + sv->field_values()->append(value); + } +} + +MonitorValue* CodeInstaller::get_monitor_value(oop value, GrowableArray* objects) { + guarantee(value->is_a(StackLockValue::klass()), "Monitors must be of type StackLockValue"); + + ScopeValue* second = NULL; + ScopeValue* owner_value = get_scope_value(StackLockValue::owner(value), T_OBJECT, objects, second); + assert(second == NULL, "monitor cannot occupy two stack slots"); + + ScopeValue* lock_data_value = get_scope_value(StackLockValue::slot(value), T_LONG, objects, second); + assert(second == lock_data_value, "monitor is LONG value that occupies two stack slots"); + assert(lock_data_value->is_location(), "invalid monitor location"); + Location lock_data_loc = ((LocationValue*)lock_data_value)->location(); + + bool eliminated = false; + if (StackLockValue::eliminated(value)) { + eliminated = true; + } + + return new MonitorValue(owner_value, lock_data_loc, eliminated); +} + +void CodeInstaller::initialize_dependencies(oop compiled_code, OopRecorder* recorder) { + JavaThread* thread = JavaThread::current(); + CompilerThread* compilerThread = thread->is_Compiler_thread() ? thread->as_CompilerThread() : NULL; + _oop_recorder = recorder; + _dependencies = new Dependencies(&_arena, _oop_recorder, compilerThread != NULL ? compilerThread->log() : NULL); + objArrayHandle assumptions = HotSpotCompiledCode::assumptions(compiled_code); + if (!assumptions.is_null()) { + int length = assumptions->length(); + for (int i = 0; i < length; ++i) { + Handle assumption = assumptions->obj_at(i); + if (!assumption.is_null()) { + if (assumption->klass() == Assumptions_NoFinalizableSubclass::klass()) { + assumption_NoFinalizableSubclass(assumption); + } else if (assumption->klass() == Assumptions_ConcreteSubtype::klass()) { + assumption_ConcreteSubtype(assumption); + } else if (assumption->klass() == Assumptions_LeafType::klass()) { + assumption_LeafType(assumption); + } else if (assumption->klass() == Assumptions_ConcreteMethod::klass()) { + assumption_ConcreteMethod(assumption); + } else if (assumption->klass() == Assumptions_CallSiteTargetValue::klass()) { + assumption_CallSiteTargetValue(assumption); + } else { + assumption->print(); + fatal("unexpected Assumption subclass"); + } + } + } + } + objArrayHandle methods = HotSpotCompiledCode::methods(compiled_code); + if (!methods.is_null()) { + int length = methods->length(); + for (int i = 0; i < length; ++i) { + Handle method_handle = methods->obj_at(i); + methodHandle method = getMethodFromHotSpotMethod(method_handle()); + + _dependencies->assert_evol_method(method()); + } + } +} + +RelocBuffer::~RelocBuffer() { + if (_buffer != NULL) { + FREE_C_HEAP_ARRAY(char, _buffer); + } +} + +address RelocBuffer::begin() const { + if (_buffer != NULL) { + return (address) _buffer; + } + return (address) _static_buffer; +} + +void RelocBuffer::set_size(size_t bytes) { + assert(bytes <= _size, "can't grow in size!"); + _size = bytes; +} + +void RelocBuffer::ensure_size(size_t bytes) { + assert(_buffer == NULL, "can only be used once"); + assert(_size == 0, "can only be used once"); + if (bytes >= RelocBuffer::stack_size) { + _buffer = NEW_C_HEAP_ARRAY(char, bytes, mtInternal); + } + _size = bytes; +} + +JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata) { + CodeBuffer buffer("JVMCI Compiler CodeBuffer for Metadata"); + jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); + initialize_dependencies(JNIHandles::resolve(compiled_code_obj), NULL); + + // Get instructions and constants CodeSections early because we need it. + _instructions = buffer.insts(); + _constants = buffer.consts(); + + initialize_fields(target(), JNIHandles::resolve(compiled_code_obj)); + if (!initialize_buffer(buffer)) { + return JVMCIEnv::code_too_large; + } + process_exception_handlers(); + + _debug_recorder->pcs_size(); // ehm, create the sentinel record + + assert(_debug_recorder->pcs_length() >= 2, "must be at least 2"); + + metadata.set_pc_desc(_debug_recorder->pcs(), _debug_recorder->pcs_length()); + metadata.set_scopes(_debug_recorder->stream()->buffer(), _debug_recorder->data_size()); + metadata.set_exception_table(&_exception_handler_table); + + RelocBuffer* reloc_buffer = metadata.get_reloc_buffer(); + + reloc_buffer->ensure_size(buffer.total_relocation_size()); + size_t size = (size_t) buffer.copy_relocations_to(reloc_buffer->begin(), (CodeBuffer::csize_t) reloc_buffer->size(), true); + reloc_buffer->set_size(size); + return JVMCIEnv::ok; +} + +// constructor used to create a method +JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log) { + CodeBuffer buffer("JVMCI Compiler CodeBuffer"); + jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); + OopRecorder* recorder = new OopRecorder(&_arena, true); + initialize_dependencies(JNIHandles::resolve(compiled_code_obj), recorder); + + // Get instructions and constants CodeSections early because we need it. + _instructions = buffer.insts(); + _constants = buffer.consts(); + + initialize_fields(target(), JNIHandles::resolve(compiled_code_obj)); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer); + if (result != JVMCIEnv::ok) { + return result; + } + process_exception_handlers(); + + int stack_slots = _total_frame_size / HeapWordSize; // conversion to words + + if (!compiled_code->is_a(HotSpotCompiledNmethod::klass())) { + oop stubName = HotSpotCompiledCode::name(compiled_code_obj); + char* name = strdup(java_lang_String::as_utf8_string(stubName)); + cb = RuntimeStub::new_runtime_stub(name, + &buffer, + CodeOffsets::frame_never_safe, + stack_slots, + _debug_recorder->_oopmaps, + false); + result = JVMCIEnv::ok; + } else { + nmethod* nm = NULL; + methodHandle method = getMethodFromHotSpotMethod(HotSpotCompiledNmethod::method(compiled_code)); + jint entry_bci = HotSpotCompiledNmethod::entryBCI(compiled_code); + jint id = HotSpotCompiledNmethod::id(compiled_code); + bool has_unsafe_access = HotSpotCompiledNmethod::hasUnsafeAccess(compiled_code) == JNI_TRUE; + JVMCIEnv* env = (JVMCIEnv*) (address) HotSpotCompiledNmethod::jvmciEnv(compiled_code); + if (id == -1) { + // Make sure a valid compile_id is associated with every compile + id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci); + } + result = JVMCIEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, + stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, + compiler, _debug_recorder, _dependencies, env, id, + has_unsafe_access, _has_wide_vector, installed_code, compiled_code, speculation_log); + cb = nm; + } + + if (cb != NULL) { + // Make sure the pre-calculated constants section size was correct. + guarantee((cb->code_begin() - cb->content_begin()) >= _constants_size, err_msg("%d < %d", (int)(cb->code_begin() - cb->content_begin()), _constants_size)); + } + return result; +} + +void CodeInstaller::initialize_fields(oop target, oop compiled_code) { + if (compiled_code->is_a(HotSpotCompiledNmethod::klass())) { + Handle hotspotJavaMethod = HotSpotCompiledNmethod::method(compiled_code); + methodHandle method = getMethodFromHotSpotMethod(hotspotJavaMethod()); + _parameter_count = method->size_of_parameters(); + TRACE_jvmci_2("installing code for %s", method->name_and_sig_as_C_string()); + } else { + // Must be a HotSpotCompiledRuntimeStub. + // Only used in OopMap constructor for non-product builds + _parameter_count = 0; + } + _sites_handle = JNIHandles::make_local(HotSpotCompiledCode::sites(compiled_code)); + _exception_handlers_handle = JNIHandles::make_local(HotSpotCompiledCode::exceptionHandlers(compiled_code)); + + _code_handle = JNIHandles::make_local(HotSpotCompiledCode::targetCode(compiled_code)); + _code_size = HotSpotCompiledCode::targetCodeSize(compiled_code); + _total_frame_size = HotSpotCompiledCode::totalFrameSize(compiled_code); + _custom_stack_area_offset = HotSpotCompiledCode::customStackAreaOffset(compiled_code); + + // Pre-calculate the constants section size. This is required for PC-relative addressing. + _data_section_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSection(compiled_code)); + guarantee(HotSpotCompiledCode::dataSectionAlignment(compiled_code) <= _constants->alignment(), "Alignment inside constants section is restricted by alignment of section begin"); + _constants_size = data_section()->length(); + + _data_section_patches_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSectionPatches(compiled_code)); + +#ifndef PRODUCT + _comments_handle = JNIHandles::make_local(HotSpotCompiledCode::comments(compiled_code)); +#endif + + _next_call_type = INVOKE_INVALID; + + _has_wide_vector = false; + + oop arch = TargetDescription::arch(target); + _word_kind_handle = JNIHandles::make_local(Architecture::wordKind(arch)); +} + +int CodeInstaller::estimate_stubs_size() { + // Return size for all stubs. + int static_call_stubs = 0; + objArrayOop sites = this->sites(); + for (int i = 0; i < sites->length(); i++) { + oop site = sites->obj_at(i); + if (site->is_a(CompilationResult_Mark::klass())) { + oop id_obj = CompilationResult_Mark::id(site); + if (id_obj != NULL) { + assert(java_lang_boxing_object::is_instance(id_obj, T_INT), "Integer id expected"); + jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT)); + if (id == INVOKESTATIC || id == INVOKESPECIAL) { + static_call_stubs++; + } + } + } + } + return static_call_stubs * CompiledStaticCall::to_interp_stub_size(); +} + +// perform data and call relocation on the CodeBuffer +JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer) { + objArrayHandle sites = this->sites(); + int locs_buffer_size = sites->length() * (relocInfo::length_limit + sizeof(relocInfo)); + + // Allocate enough space in the stub section for the static call + // stubs. Stubs have extra relocs but they are managed by the stub + // section itself so they don't need to be accounted for in the + // locs_buffer above. + int stubs_size = estimate_stubs_size(); + int total_size = round_to(_code_size, buffer.insts()->alignment()) + round_to(_constants_size, buffer.consts()->alignment()) + round_to(stubs_size, buffer.stubs()->alignment()); + + if (total_size > JVMCINMethodSizeLimit) { + return JVMCIEnv::code_too_large; + } + + buffer.initialize(total_size, locs_buffer_size); + if (buffer.blob() == NULL) { + return JVMCIEnv::cache_full; + } + buffer.initialize_stubs_size(stubs_size); + buffer.initialize_consts_size(_constants_size); + + _debug_recorder = new DebugInformationRecorder(_oop_recorder); + _debug_recorder->set_oopmaps(new OopMapSet()); + + buffer.initialize_oop_recorder(_oop_recorder); + + // copy the constant data into the newly created CodeBuffer + address end_data = _constants->start() + _constants_size; + memcpy(_constants->start(), data_section()->base(T_BYTE), _constants_size); + _constants->set_end(end_data); + + // copy the code into the newly created CodeBuffer + address end_pc = _instructions->start() + _code_size; + guarantee(_instructions->allocates2(end_pc), "initialize should have reserved enough space for all the code"); + memcpy(_instructions->start(), code()->base(T_BYTE), _code_size); + _instructions->set_end(end_pc); + + for (int i = 0; i < data_section_patches()->length(); i++) { + Handle patch = data_section_patches()->obj_at(i); + Handle reference = CompilationResult_DataPatch::reference(patch); + assert(reference->is_a(CompilationResult_ConstantReference::klass()), err_msg("patch in data section must be a ConstantReference")); + Handle constant = CompilationResult_ConstantReference::constant(reference); + if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { + record_metadata_in_patch(constant, _oop_recorder); + } else if (constant->is_a(HotSpotObjectConstantImpl::klass())) { + Handle obj = HotSpotObjectConstantImpl::object(constant); + jobject value = JNIHandles::make_local(obj()); + int oop_index = _oop_recorder->find_index(value); + + address dest = _constants->start() + CompilationResult_Site::pcOffset(patch); + if (HotSpotObjectConstantImpl::compressed(constant)) { +#ifdef _LP64 + _constants->relocate(dest, oop_Relocation::spec(oop_index), relocInfo::narrow_oop_in_const); +#else + fatal("unexpected compressed oop in 32-bit mode"); +#endif + } else { + _constants->relocate(dest, oop_Relocation::spec(oop_index)); + } + } else { + ShouldNotReachHere(); + } + } + jint last_pc_offset = -1; + for (int i = 0; i < sites->length(); i++) { + { + No_Safepoint_Verifier no_safepoint; + oop site = sites->obj_at(i); + jint pc_offset = CompilationResult_Site::pcOffset(site); + + if (site->is_a(CompilationResult_Call::klass())) { + TRACE_jvmci_4("call at %i", pc_offset); + site_Call(buffer, pc_offset, site); + } else if (site->is_a(CompilationResult_Infopoint::klass())) { + // three reasons for infopoints denote actual safepoints + oop reason = CompilationResult_Infopoint::reason(site); + if (InfopointReason::SAFEPOINT() == reason || InfopointReason::CALL() == reason || InfopointReason::IMPLICIT_EXCEPTION() == reason) { + TRACE_jvmci_4("safepoint at %i", pc_offset); + site_Safepoint(buffer, pc_offset, site); + } else { + // if the infopoint is not an actual safepoint, it must have one of the other reasons + // (safeguard against new safepoint types that require handling above) + assert(InfopointReason::METHOD_START() == reason || InfopointReason::METHOD_END() == reason || InfopointReason::LINE_NUMBER() == reason, ""); + site_Infopoint(buffer, pc_offset, site); + } + } else if (site->is_a(CompilationResult_DataPatch::klass())) { + TRACE_jvmci_4("datapatch at %i", pc_offset); + site_DataPatch(buffer, pc_offset, site); + } else if (site->is_a(CompilationResult_Mark::klass())) { + TRACE_jvmci_4("mark at %i", pc_offset); + site_Mark(buffer, pc_offset, site); + } else { + fatal("unexpected Site subclass"); + } + last_pc_offset = pc_offset; + } + if (CodeInstallSafepointChecks && SafepointSynchronize::do_call_back()) { + // this is a hacky way to force a safepoint check but nothing else was jumping out at me. + ThreadToNativeFromVM ttnfv(JavaThread::current()); + } + } + +#ifndef PRODUCT + if (comments() != NULL) { + No_Safepoint_Verifier no_safepoint; + for (int i = 0; i < comments()->length(); i++) { + oop comment = comments()->obj_at(i); + assert(comment->is_a(HotSpotCompiledCode_Comment::klass()), "cce"); + jint offset = HotSpotCompiledCode_Comment::pcOffset(comment); + char* text = java_lang_String::as_utf8_string(HotSpotCompiledCode_Comment::text(comment)); + buffer.block_comment(offset, text); + } + } +#endif + return JVMCIEnv::ok; +} + +void CodeInstaller::assumption_NoFinalizableSubclass(Handle assumption) { + Handle receiverType_handle = Assumptions_NoFinalizableSubclass::receiverType(assumption()); + Klass* receiverType = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(receiverType_handle)); + _dependencies->assert_has_no_finalizable_subclasses(receiverType); +} + +void CodeInstaller::assumption_ConcreteSubtype(Handle assumption) { + Handle context_handle = Assumptions_ConcreteSubtype::context(assumption()); + Handle subtype_handle = Assumptions_ConcreteSubtype::subtype(assumption()); + Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); + Klass* subtype = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(subtype_handle)); + + assert(context->is_abstract(), ""); + _dependencies->assert_abstract_with_unique_concrete_subtype(context, subtype); +} + +void CodeInstaller::assumption_LeafType(Handle assumption) { + Handle context_handle = Assumptions_LeafType::context(assumption()); + Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); + + _dependencies->assert_leaf_type(context); +} + +void CodeInstaller::assumption_ConcreteMethod(Handle assumption) { + Handle impl_handle = Assumptions_ConcreteMethod::impl(assumption()); + Handle context_handle = Assumptions_ConcreteMethod::context(assumption()); + + methodHandle impl = getMethodFromHotSpotMethod(impl_handle()); + Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); + + _dependencies->assert_unique_concrete_method(context, impl()); +} + +void CodeInstaller::assumption_CallSiteTargetValue(Handle assumption) { + Handle callSite = Assumptions_CallSiteTargetValue::callSite(assumption()); + Handle methodHandle = Assumptions_CallSiteTargetValue::methodHandle(assumption()); + + _dependencies->assert_call_site_target_value(callSite(), methodHandle()); +} + +void CodeInstaller::process_exception_handlers() { + if (exception_handlers() != NULL) { + objArrayOop handlers = exception_handlers(); + for (int i = 0; i < handlers->length(); i++) { + oop exc = handlers->obj_at(i); + jint pc_offset = CompilationResult_Site::pcOffset(exc); + jint handler_offset = CompilationResult_ExceptionHandler::handlerPos(exc); + + // Subtable header + _exception_handler_table.add_entry(HandlerTableEntry(1, pc_offset, 0)); + + // Subtable entry + _exception_handler_table.add_entry(HandlerTableEntry(-1, handler_offset, 0)); + } + } +} + +// If deoptimization happens, the interpreter should reexecute these bytecodes. +// This function mainly helps the compilers to set up the reexecute bit. +static bool bytecode_should_reexecute(Bytecodes::Code code) { + switch (code) { + case Bytecodes::_invokedynamic: + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + return false; + default: + return true; + } + return true; +} + +GrowableArray* CodeInstaller::record_virtual_objects(oop debug_info) { + objArrayOop virtualObjects = DebugInfo::virtualObjectMapping(debug_info); + if (virtualObjects == NULL) { + return NULL; + } + GrowableArray* objects = new GrowableArray(virtualObjects->length(), virtualObjects->length(), NULL); + // Create the unique ObjectValues + for (int i = 0; i < virtualObjects->length(); i++) { + oop value = virtualObjects->obj_at(i); + int id = VirtualObject::id(value); + oop type = VirtualObject::type(value); + oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type); + ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror))); + assert(objects->at(id) == NULL, "once"); + objects->at_put(id, sv); + } + // All the values which could be referenced by the VirtualObjects + // exist, so now describe all the VirtualObjects themselves. + for (int i = 0; i < virtualObjects->length(); i++) { + oop value = virtualObjects->obj_at(i); + int id = VirtualObject::id(value); + record_object_value(objects->at(id)->as_ObjectValue(), value, objects); + } + _debug_recorder->dump_object_pool(objects); + return objects; +} + +void CodeInstaller::record_scope(jint pc_offset, oop debug_info) { + oop position = DebugInfo::bytecodePosition(debug_info); + if (position == NULL) { + // Stubs do not record scope info, just oop maps + return; + } + + GrowableArray* objectMapping = record_virtual_objects(debug_info); + record_scope(pc_offset, position, objectMapping); +} + +void CodeInstaller::record_scope(jint pc_offset, oop position, GrowableArray* objects) { + oop frame = NULL; + if (position->is_a(BytecodeFrame::klass())) { + frame = position; + } + oop caller_frame = BytecodePosition::caller(position); + if (caller_frame != NULL) { + record_scope(pc_offset, caller_frame, objects); + } + + oop hotspot_method = BytecodePosition::method(position); + Method* method = getMethodFromHotSpotMethod(hotspot_method); + jint bci = BytecodePosition::bci(position); + if (bci == BytecodeFrame::BEFORE_BCI()) { + bci = SynchronizationEntryBCI; + } + + TRACE_jvmci_2("Recording scope pc_offset=%d bci=%d method=%s", pc_offset, bci, method->name_and_sig_as_C_string()); + + bool reexecute = false; + if (frame != NULL) { + if (bci == SynchronizationEntryBCI){ + reexecute = false; + } else { + Bytecodes::Code code = Bytecodes::java_code_at(method, method->bcp_from(bci)); + reexecute = bytecode_should_reexecute(code); + if (frame != NULL) { + reexecute = (BytecodeFrame::duringCall(frame) == JNI_FALSE); + } + } + } + + DebugToken* locals_token = NULL; + DebugToken* expressions_token = NULL; + DebugToken* monitors_token = NULL; + bool throw_exception = false; + + if (frame != NULL) { + jint local_count = BytecodeFrame::numLocals(frame); + jint expression_count = BytecodeFrame::numStack(frame); + jint monitor_count = BytecodeFrame::numLocks(frame); + objArrayOop values = BytecodeFrame::values(frame); + objArrayOop slotKinds = BytecodeFrame::slotKinds(frame); + + assert(local_count + expression_count + monitor_count == values->length(), "unexpected values length"); + assert(local_count + expression_count == slotKinds->length(), "unexpected slotKinds length"); + + GrowableArray* locals = local_count > 0 ? new GrowableArray (local_count) : NULL; + GrowableArray* expressions = expression_count > 0 ? new GrowableArray (expression_count) : NULL; + GrowableArray* monitors = monitor_count > 0 ? new GrowableArray (monitor_count) : NULL; + + TRACE_jvmci_2("Scope at bci %d with %d values", bci, values->length()); + TRACE_jvmci_2("%d locals %d expressions, %d monitors", local_count, expression_count, monitor_count); + + for (jint i = 0; i < values->length(); i++) { + ScopeValue* second = NULL; + oop value = values->obj_at(i); + if (i < local_count) { + oop kind = slotKinds->obj_at(i); + BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); + ScopeValue* first = get_scope_value(value, type, objects, second); + if (second != NULL) { + locals->append(second); + } + locals->append(first); + } else if (i < local_count + expression_count) { + oop kind = slotKinds->obj_at(i); + BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); + ScopeValue* first = get_scope_value(value, type, objects, second); + if (second != NULL) { + expressions->append(second); + } + expressions->append(first); + } else { + monitors->append(get_monitor_value(value, objects)); + } + if (second != NULL) { + i++; + assert(i < values->length(), "double-slot value not followed by Value.ILLEGAL"); + assert(values->obj_at(i) == Value::ILLEGAL(), "double-slot value not followed by Value.ILLEGAL"); + } + } + + locals_token = _debug_recorder->create_scope_values(locals); + expressions_token = _debug_recorder->create_scope_values(expressions); + monitors_token = _debug_recorder->create_monitor_values(monitors); + + throw_exception = BytecodeFrame::rethrowException(frame) == JNI_TRUE; + } + + _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, false, + locals_token, expressions_token, monitors_token); +} + +void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site) { + oop debug_info = CompilationResult_Infopoint::debugInfo(site); + assert(debug_info != NULL, "debug info expected"); + + // address instruction = _instructions->start() + pc_offset; + // jint next_pc_offset = Assembler::locate_next_instruction(instruction) - _instructions->start(); + _debug_recorder->add_safepoint(pc_offset, create_oop_map(debug_info)); + record_scope(pc_offset, debug_info); + _debug_recorder->end_safepoint(pc_offset); +} + +void CodeInstaller::site_Infopoint(CodeBuffer& buffer, jint pc_offset, oop site) { + oop debug_info = CompilationResult_Infopoint::debugInfo(site); + assert(debug_info != NULL, "debug info expected"); + + _debug_recorder->add_non_safepoint(pc_offset); + record_scope(pc_offset, debug_info); + _debug_recorder->end_non_safepoint(pc_offset); +} + +void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, oop site) { + oop target = CompilationResult_Call::target(site); + InstanceKlass* target_klass = InstanceKlass::cast(target->klass()); + + oop hotspot_method = NULL; // JavaMethod + oop foreign_call = NULL; + + if (target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallTarget_klass())) { + foreign_call = target; + } else { + hotspot_method = target; + } + + oop debug_info = CompilationResult_Call::debugInfo(site); + + assert(!!hotspot_method ^ !!foreign_call, "Call site needs exactly one type"); + + NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset); + jint next_pc_offset = CodeInstaller::pd_next_offset(inst, pc_offset, hotspot_method); + + if (debug_info != NULL) { + _debug_recorder->add_safepoint(next_pc_offset, create_oop_map(debug_info)); + record_scope(next_pc_offset, debug_info); + } + + if (foreign_call != NULL) { + jlong foreign_call_destination = HotSpotForeignCallTarget::address(foreign_call); + CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination); + } else { // method != NULL + assert(hotspot_method != NULL, "unexpected JavaMethod"); + assert(debug_info != NULL, "debug info expected"); + + TRACE_jvmci_3("method call"); + CodeInstaller::pd_relocate_JavaMethod(hotspot_method, pc_offset); + if (_next_call_type == INVOKESTATIC || _next_call_type == INVOKESPECIAL) { + // Need a static call stub for transitions from compiled to interpreted. + CompiledStaticCall::emit_to_interp_stub(buffer, _instructions->start() + pc_offset); + } + } + + _next_call_type = INVOKE_INVALID; + + if (debug_info != NULL) { + _debug_recorder->end_safepoint(next_pc_offset); + } +} + +void CodeInstaller::site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site) { + oop reference = CompilationResult_DataPatch::reference(site); + if (reference->is_a(CompilationResult_ConstantReference::klass())) { + Handle constant = CompilationResult_ConstantReference::constant(reference); + if (constant->is_a(HotSpotObjectConstantImpl::klass())) { + pd_patch_OopConstant(pc_offset, constant); + } else if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { + record_metadata_in_patch(constant, _oop_recorder); + } else if (constant->is_a(HotSpotSentinelConstant::klass())) { + fatal("sentinel constant unsupported"); + } else { + fatal("unknown constant type in data patch"); + } + } else if (reference->is_a(CompilationResult_DataSectionReference::klass())) { + int data_offset = CompilationResult_DataSectionReference::offset(reference); + assert(0 <= data_offset && data_offset < _constants_size, err_msg("data offset 0x%X points outside data section (size 0x%X)", data_offset, _constants_size)); + pd_patch_DataSectionReference(pc_offset, data_offset); + } else { + fatal("unknown data patch type"); + } +} + +void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, oop site) { + oop id_obj = CompilationResult_Mark::id(site); + + if (id_obj != NULL) { + assert(java_lang_boxing_object::is_instance(id_obj, T_INT), "Integer id expected"); + jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT)); + + address pc = _instructions->start() + pc_offset; + + switch (id) { + case UNVERIFIED_ENTRY: + _offsets.set_value(CodeOffsets::Entry, pc_offset); + break; + case VERIFIED_ENTRY: + _offsets.set_value(CodeOffsets::Verified_Entry, pc_offset); + break; + case OSR_ENTRY: + _offsets.set_value(CodeOffsets::OSR_Entry, pc_offset); + break; + case EXCEPTION_HANDLER_ENTRY: + _offsets.set_value(CodeOffsets::Exceptions, pc_offset); + break; + case DEOPT_HANDLER_ENTRY: + _offsets.set_value(CodeOffsets::Deopt, pc_offset); + break; + case INVOKEVIRTUAL: + case INVOKEINTERFACE: + case INLINE_INVOKE: + case INVOKESTATIC: + case INVOKESPECIAL: + _next_call_type = (MarkId) id; + _invoke_mark_pc = pc; + break; + case POLL_NEAR: + case POLL_FAR: + case POLL_RETURN_NEAR: + case POLL_RETURN_FAR: + pd_relocate_poll(pc, id); + break; + case CARD_TABLE_ADDRESS: + case HEAP_TOP_ADDRESS: + case HEAP_END_ADDRESS: + case NARROW_KLASS_BASE_ADDRESS: + case CRC_TABLE_ADDRESS: + break; + default: + ShouldNotReachHere(); + break; + } + } +} + --- /dev/null 2015-09-16 15:21:24.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciCodeInstaller.hpp 2015-09-16 15:21:24.000000000 -0700 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_CODE_INSTALLER_HPP +#define SHARE_VM_JVMCI_JVMCI_CODE_INSTALLER_HPP + +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "code/nativeInst.hpp" + +class RelocBuffer : public StackObj { + enum { stack_size = 1024 }; +public: + RelocBuffer() : _size(0), _buffer(0) {} + ~RelocBuffer(); + void ensure_size(size_t bytes); + void set_size(size_t bytes); + address begin() const; + size_t size() const { return _size; } +private: + size_t _size; + char _static_buffer[stack_size]; + char *_buffer; +}; + +class CodeMetadata { +public: + CodeMetadata() {} + + CodeBlob* get_code_blob() const { return _cb; } + + PcDesc* get_pc_desc() const { return _pc_desc; } + int get_nr_pc_desc() const { return _nr_pc_desc; } + + u_char* get_scopes_desc() const { return _scopes_desc; } + int get_scopes_size() const { return _nr_scopes_desc; } + + RelocBuffer* get_reloc_buffer() { return &_reloc_buffer; } + + ExceptionHandlerTable* get_exception_table() { return _exception_table; } + + void set_pc_desc(PcDesc* desc, int count) { + _pc_desc = desc; + _nr_pc_desc = count; + } + + void set_scopes(u_char* scopes, int size) { + _scopes_desc = scopes; + _nr_scopes_desc = size; + } + + void set_exception_table(ExceptionHandlerTable* table) { + _exception_table = table; + } + +private: + CodeBlob* _cb; + PcDesc* _pc_desc; + int _nr_pc_desc; + + u_char* _scopes_desc; + int _nr_scopes_desc; + + RelocBuffer _reloc_buffer; + ExceptionHandlerTable* _exception_table; +}; + +/* + * This class handles the conversion from a InstalledCode to a CodeBlob or an nmethod. + */ +class CodeInstaller : public StackObj { + friend class VMStructs; +private: + enum MarkId { + VERIFIED_ENTRY = 1, + UNVERIFIED_ENTRY = 2, + OSR_ENTRY = 3, + EXCEPTION_HANDLER_ENTRY = 4, + DEOPT_HANDLER_ENTRY = 5, + INVOKEINTERFACE = 6, + INVOKEVIRTUAL = 7, + INVOKESTATIC = 8, + INVOKESPECIAL = 9, + INLINE_INVOKE = 10, + POLL_NEAR = 11, + POLL_RETURN_NEAR = 12, + POLL_FAR = 13, + POLL_RETURN_FAR = 14, + CARD_TABLE_ADDRESS = 15, + HEAP_TOP_ADDRESS = 16, + HEAP_END_ADDRESS = 17, + NARROW_KLASS_BASE_ADDRESS = 18, + CRC_TABLE_ADDRESS = 19, + INVOKE_INVALID = -1 + }; + + Arena _arena; + + jobject _data_section_handle; + jobject _data_section_patches_handle; + jobject _sites_handle; + jobject _exception_handlers_handle; + CodeOffsets _offsets; + + jobject _code_handle; + jint _code_size; + jint _total_frame_size; + jint _custom_stack_area_offset; + jint _parameter_count; + jint _constants_size; +#ifndef PRODUCT + jobject _comments_handle; +#endif + + bool _has_wide_vector; + jobject _word_kind_handle; + + MarkId _next_call_type; + address _invoke_mark_pc; + + CodeSection* _instructions; + CodeSection* _constants; + + OopRecorder* _oop_recorder; + DebugInformationRecorder* _debug_recorder; + Dependencies* _dependencies; + ExceptionHandlerTable _exception_handler_table; + + static ConstantOopWriteValue* _oop_null_scope_value; + static ConstantIntValue* _int_m1_scope_value; + static ConstantIntValue* _int_0_scope_value; + static ConstantIntValue* _int_1_scope_value; + static ConstantIntValue* _int_2_scope_value; + static LocationValue* _illegal_value; + + jint pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method); + void pd_patch_OopConstant(int pc_offset, Handle& constant); + void pd_patch_DataSectionReference(int pc_offset, int data_offset); + void pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst); + void pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination); + void pd_relocate_JavaMethod(oop method, jint pc_offset); + void pd_relocate_poll(address pc, jint mark); + + objArrayOop sites() { return (objArrayOop) JNIHandles::resolve(_sites_handle); } + arrayOop code() { return (arrayOop) JNIHandles::resolve(_code_handle); } + arrayOop data_section() { return (arrayOop) JNIHandles::resolve(_data_section_handle); } + objArrayOop data_section_patches() { return (objArrayOop) JNIHandles::resolve(_data_section_patches_handle); } + objArrayOop exception_handlers() { return (objArrayOop) JNIHandles::resolve(_exception_handlers_handle); } +#ifndef PRODUCT + objArrayOop comments() { return (objArrayOop) JNIHandles::resolve(_comments_handle); } +#endif + + void record_resolved(oop obj); + + oop word_kind() { return (oop) JNIHandles::resolve(_word_kind_handle); } + +public: + CodeInstaller() : _arena(mtCompiler) {} + + JVMCIEnv::CodeInstallResult gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata); + JVMCIEnv::CodeInstallResult install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log); + + static address runtime_call_target_address(oop runtime_call); + static VMReg get_hotspot_reg(jint jvmciRegisterNumber); + static bool is_general_purpose_reg(VMReg hotspotRegister); + + const OopMapSet* oopMapSet() const { return _debug_recorder->_oopmaps; } + +protected: + Location::Type get_oop_type(oop value); + ScopeValue* get_scope_value(oop value, BasicType type, GrowableArray* objects, ScopeValue* &second); + MonitorValue* get_monitor_value(oop value, GrowableArray* objects); + + // extract the fields of the CompilationResult + void initialize_fields(oop target, oop target_method); + void initialize_dependencies(oop target_method, OopRecorder* oop_recorder); + + int estimate_stubs_size(); + + // perform data and call relocation on the CodeBuffer + JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer); + + void assumption_NoFinalizableSubclass(Handle assumption); + void assumption_ConcreteSubtype(Handle assumption); + void assumption_LeafType(Handle assumption); + void assumption_ConcreteMethod(Handle assumption); + void assumption_CallSiteTargetValue(Handle assumption); + + void site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site); + void site_Infopoint(CodeBuffer& buffer, jint pc_offset, oop site); + void site_Call(CodeBuffer& buffer, jint pc_offset, oop site); + void site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site); + void site_Mark(CodeBuffer& buffer, jint pc_offset, oop site); + + OopMap* create_oop_map(oop debug_info); + + void record_scope(jint pc_offset, oop debug_info); + void record_scope(jint pc_offset, oop code_pos, GrowableArray* objects); + void record_object_value(ObjectValue* sv, oop value, GrowableArray* objects); + + GrowableArray* record_virtual_objects(oop debug_info); + + void process_exception_handlers(); + int estimateStubSpace(int static_call_stubs); +}; + +/** + * Gets the Method metaspace object from a HotSpotResolvedJavaMethodImpl Java object. + */ +Method* getMethodFromHotSpotMethod(oop hotspot_method); + + + +#endif // SHARE_VM_JVMCI_JVMCI_CODE_INSTALLER_HPP --- /dev/null 2015-09-16 15:21:24.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciCompiler.cpp 2015-09-16 15:21:24.000000000 -0700 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/handles.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "runtime/compilationPolicy.hpp" +#include "runtime/globals_extension.hpp" + +JVMCICompiler* JVMCICompiler::_instance = NULL; +elapsedTimer JVMCICompiler::_codeInstallTimer; + +JVMCICompiler::JVMCICompiler() : AbstractCompiler(jvmci) { + _bootstrapping = false; + _methodsCompiled = 0; + assert(_instance == NULL, "only one instance allowed"); + _instance = this; +} + +// Initialization +void JVMCICompiler::initialize() { + if (!UseCompiler || !EnableJVMCI || !UseJVMCICompiler || !should_perform_init()) { + return; + } + + set_state(initialized); + + // JVMCI is considered as application code so we need to + // stop the VM deferring compilation now. + CompilationPolicy::completed_vm_startup(); +} + +void JVMCICompiler::bootstrap() { +#ifndef PRODUCT + // We turn off CompileTheWorld so that compilation requests are not + // ignored during bootstrap or that JVMCI can be compiled by C1/C2. + FlagSetting ctwOff(CompileTheWorld, false); +#endif + + JavaThread* THREAD = JavaThread::current(); + _bootstrapping = true; + ResourceMark rm; + HandleMark hm; + if (PrintBootstrap) { + tty->print("Bootstrapping JVMCI"); + } + jlong start = os::javaTimeMillis(); + + Array* objectMethods = InstanceKlass::cast(SystemDictionary::Object_klass())->methods(); + // Initialize compile queue with a selected set of methods. + int len = objectMethods->length(); + for (int i = 0; i < len; i++) { + methodHandle mh = objectMethods->at(i); + if (!mh->is_native() && !mh->is_static() && !mh->is_initializer()) { + ResourceMark rm; + int hot_count = 10; // TODO: what's the appropriate value? + CompileBroker::compile_method(mh, InvocationEntryBci, CompLevel_full_optimization, mh, hot_count, "bootstrap", THREAD); + } + } + + int qsize; + bool first_round = true; + int z = 0; + do { + // Loop until there is something in the queue. + do { + os::sleep(THREAD, 100, true); + qsize = CompileBroker::queue_size(CompLevel_full_optimization); + } while (first_round && qsize == 0); + first_round = false; + if (PrintBootstrap) { + while (z < (_methodsCompiled / 100)) { + ++z; + tty->print_raw("."); + } + } + } while (qsize != 0); + + if (PrintBootstrap) { + tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)", os::javaTimeMillis() - start, _methodsCompiled); + } + _bootstrapping = false; +} + +void JVMCICompiler::compile_method(methodHandle method, int entry_bci, JVMCIEnv* env) { + JVMCI_EXCEPTION_CONTEXT + + bool is_osr = entry_bci != InvocationEntryBci; + if (_bootstrapping && is_osr) { + // no OSR compilations during bootstrap - the compiler is just too slow at this point, + // and we know that there are no endless loops + return; + } + + HandleMark hm; + ResourceMark rm; + Handle receiver = JVMCIRuntime::get_HotSpotJVMCIRuntime(CHECK_ABORT); + + JavaValue method_result(T_OBJECT); + { + JavaCallArguments args; + args.push_long((jlong) (address) method()); + JavaCalls::call_static(&method_result, SystemDictionary::HotSpotResolvedJavaMethodImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::method_fromMetaspace_signature(), &args, CHECK_ABORT); + } + + JavaValue result(T_VOID); + JavaCallArguments args; + args.push_oop(receiver); + args.push_oop((oop)method_result.get_jobject()); + args.push_int(entry_bci); + args.push_long((jlong) (address) env); + args.push_int(env->task()->compile_id()); + JavaCalls::call_special(&result, receiver->klass(), vmSymbols::compileMethod_name(), vmSymbols::compileMethod_signature(), &args, CHECK_ABORT); + + _methodsCompiled++; +} + + +// Compilation entry point for methods +void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) { + ShouldNotReachHere(); +} + +// Print compilation timers and statistics +void JVMCICompiler::print_timers() { + print_compilation_timers(); +} + +// Print compilation timers and statistics +void JVMCICompiler::print_compilation_timers() { + TRACE_jvmci_1("JVMCICompiler::print_timers"); + tty->print_cr(" JVMCI code install time: %6.3f s", _codeInstallTimer.seconds()); +} --- /dev/null 2015-09-16 15:21:25.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciCompiler.hpp 2015-09-16 15:21:25.000000000 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_COMPILER_HPP +#define SHARE_VM_JVMCI_JVMCI_COMPILER_HPP + +#include "compiler/abstractCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "utilities/exceptions.hpp" + +class JVMCICompiler : public AbstractCompiler { +private: + bool _bootstrapping; + + /** + * Number of methods compiled by JVMCI. This is not synchronized + * so may not be 100% accurate. + */ + volatile int _methodsCompiled; + + static JVMCICompiler* _instance; + + static elapsedTimer _codeInstallTimer; + +public: + JVMCICompiler(); + + static JVMCICompiler* instance(TRAPS) { + if (!EnableJVMCI) { + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled") + } + return _instance; + } + + virtual const char* name() { return "JVMCI"; } + + virtual bool supports_native() { return true; } + virtual bool supports_osr () { return true; } + + bool is_jvmci() { return true; } + bool is_c1 () { return false; } + bool is_c2 () { return false; } + + bool needs_stubs () { return false; } + + // Initialization + virtual void initialize(); + + void bootstrap(); + + // Compilation entry point for methods + virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci); + + void compile_method(methodHandle target, int entry_bci, JVMCIEnv* env); + + // Print compilation timers and statistics + virtual void print_timers(); + + // Print compilation statistics + void reset_compilation_stats(); + + // Print compilation timers and statistics + static void print_compilation_timers(); + + static elapsedTimer* codeInstallTimer() { return &_codeInstallTimer; } +}; + +#endif // SHARE_VM_JVMCI_JVMCI_COMPILER_HPP --- /dev/null 2015-09-16 15:21:26.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciCompilerToVM.cpp 2015-09-16 15:21:25.000000000 -0700 @@ -0,0 +1,1351 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "code/codeCache.hpp" +#include "code/scopeDesc.hpp" +#include "interpreter/linkResolver.hpp" +#include "memory/oopFactory.hpp" +#include "oops/generateOopMap.hpp" +#include "oops/fieldStreams.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "runtime/fieldDescriptor.hpp" +#include "runtime/javaCalls.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "compiler/abstractCompiler.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/compilerOracle.hpp" +#include "compiler/disassembler.hpp" +#include "compiler/oopMap.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "gc/g1/heapRegion.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/deoptimization.hpp" +#include "runtime/vframe.hpp" +#include "runtime/vframe_hp.hpp" +#include "runtime/vmStructs.hpp" + + +// Entry to native method implementation that transitions current thread to '_thread_in_vm'. +#define C2V_VMENTRY(result_type, name, signature) \ + JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + TRACE_jvmci_1("CompilerToVM::" #name); \ + TRACE_CALL(result_type, jvmci_ ## name signature) \ + JVMCI_VM_ENTRY_MARK; \ + +#define C2V_END } + +oop CompilerToVM::get_jvmci_method(methodHandle method, TRAPS) { + if (method() != NULL) { + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_long((jlong) (address) method()); + JavaCalls::call_static(&result, SystemDictionary::HotSpotResolvedJavaMethodImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::method_fromMetaspace_signature(), &args, CHECK_NULL); + + return (oop)result.get_jobject(); + } + return NULL; +} + +oop CompilerToVM::get_jvmci_type(KlassHandle klass, TRAPS) { + if (klass() != NULL) { + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_oop(klass->java_mirror()); + JavaCalls::call_static(&result, SystemDictionary::HotSpotResolvedObjectTypeImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::klass_fromMetaspace_signature(), &args, CHECK_NULL); + + return (oop)result.get_jobject(); + } + return NULL; +} + +extern "C" { +extern VMStructEntry* gHotSpotVMStructs; +extern uint64_t gHotSpotVMStructEntryTypeNameOffset; +extern uint64_t gHotSpotVMStructEntryFieldNameOffset; +extern uint64_t gHotSpotVMStructEntryTypeStringOffset; +extern uint64_t gHotSpotVMStructEntryIsStaticOffset; +extern uint64_t gHotSpotVMStructEntryOffsetOffset; +extern uint64_t gHotSpotVMStructEntryAddressOffset; +extern uint64_t gHotSpotVMStructEntryArrayStride; + +extern VMTypeEntry* gHotSpotVMTypes; +extern uint64_t gHotSpotVMTypeEntryTypeNameOffset; +extern uint64_t gHotSpotVMTypeEntrySuperclassNameOffset; +extern uint64_t gHotSpotVMTypeEntryIsOopTypeOffset; +extern uint64_t gHotSpotVMTypeEntryIsIntegerTypeOffset; +extern uint64_t gHotSpotVMTypeEntryIsUnsignedOffset; +extern uint64_t gHotSpotVMTypeEntrySizeOffset; +extern uint64_t gHotSpotVMTypeEntryArrayStride; + +extern VMIntConstantEntry* gHotSpotVMIntConstants; +extern uint64_t gHotSpotVMIntConstantEntryNameOffset; +extern uint64_t gHotSpotVMIntConstantEntryValueOffset; +extern uint64_t gHotSpotVMIntConstantEntryArrayStride; + +extern VMLongConstantEntry* gHotSpotVMLongConstants; +extern uint64_t gHotSpotVMLongConstantEntryNameOffset; +extern uint64_t gHotSpotVMLongConstantEntryValueOffset; +extern uint64_t gHotSpotVMLongConstantEntryArrayStride; + +extern VMAddressEntry* gHotSpotVMAddresses; +extern uint64_t gHotSpotVMAddressEntryNameOffset; +extern uint64_t gHotSpotVMAddressEntryValueOffset; +extern uint64_t gHotSpotVMAddressEntryArrayStride; +} + +// FIXME This is only temporary until the GC code is changed. +bool CompilerToVM::_supports_inline_contig_alloc; +HeapWord** CompilerToVM::_heap_end_addr; +HeapWord** CompilerToVM::_heap_top_addr; + +/** + * We put all gHotSpotVM values in an array so we can read them easily from Java. + */ +static uintptr_t ciHotSpotVMData[28]; + +C2V_VMENTRY(jlong, initializeConfiguration, (JNIEnv *env, jobject)) + ciHotSpotVMData[0] = (uintptr_t) gHotSpotVMStructs; + ciHotSpotVMData[1] = gHotSpotVMStructEntryTypeNameOffset; + ciHotSpotVMData[2] = gHotSpotVMStructEntryFieldNameOffset; + ciHotSpotVMData[3] = gHotSpotVMStructEntryTypeStringOffset; + ciHotSpotVMData[4] = gHotSpotVMStructEntryIsStaticOffset; + ciHotSpotVMData[5] = gHotSpotVMStructEntryOffsetOffset; + ciHotSpotVMData[6] = gHotSpotVMStructEntryAddressOffset; + ciHotSpotVMData[7] = gHotSpotVMStructEntryArrayStride; + + ciHotSpotVMData[8] = (uintptr_t) gHotSpotVMTypes; + ciHotSpotVMData[9] = gHotSpotVMTypeEntryTypeNameOffset; + ciHotSpotVMData[10] = gHotSpotVMTypeEntrySuperclassNameOffset; + ciHotSpotVMData[11] = gHotSpotVMTypeEntryIsOopTypeOffset; + ciHotSpotVMData[12] = gHotSpotVMTypeEntryIsIntegerTypeOffset; + ciHotSpotVMData[13] = gHotSpotVMTypeEntryIsUnsignedOffset; + ciHotSpotVMData[14] = gHotSpotVMTypeEntrySizeOffset; + ciHotSpotVMData[15] = gHotSpotVMTypeEntryArrayStride; + + ciHotSpotVMData[16] = (uintptr_t) gHotSpotVMIntConstants; + ciHotSpotVMData[17] = gHotSpotVMIntConstantEntryNameOffset; + ciHotSpotVMData[18] = gHotSpotVMIntConstantEntryValueOffset; + ciHotSpotVMData[19] = gHotSpotVMIntConstantEntryArrayStride; + + ciHotSpotVMData[20] = (uintptr_t) gHotSpotVMLongConstants; + ciHotSpotVMData[21] = gHotSpotVMLongConstantEntryNameOffset; + ciHotSpotVMData[22] = gHotSpotVMLongConstantEntryValueOffset; + ciHotSpotVMData[23] = gHotSpotVMLongConstantEntryArrayStride; + + ciHotSpotVMData[24] = (uintptr_t) gHotSpotVMAddresses; + ciHotSpotVMData[25] = gHotSpotVMAddressEntryNameOffset; + ciHotSpotVMData[26] = gHotSpotVMAddressEntryValueOffset; + ciHotSpotVMData[27] = gHotSpotVMAddressEntryArrayStride; + + // FIXME This is only temporary until the GC code is changed. + CompilerToVM::_supports_inline_contig_alloc = Universe::heap()->supports_inline_contig_alloc(); + CompilerToVM::_heap_end_addr = CompilerToVM::_supports_inline_contig_alloc ? Universe::heap()->end_addr() : (HeapWord**) -1; + CompilerToVM::_heap_top_addr = CompilerToVM::_supports_inline_contig_alloc ? Universe::heap()->top_addr() : (HeapWord**) -1; + + return (jlong) (address) &ciHotSpotVMData; +C2V_END + +C2V_VMENTRY(jbyteArray, getBytecode, (JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + ResourceMark rm; + + int code_size = method->code_size(); + typeArrayOop reconstituted_code = oopFactory::new_byteArray(code_size, CHECK_NULL); + + guarantee(method->method_holder()->is_rewritten(), "Method's holder should be rewritten"); + // iterate over all bytecodes and replace non-Java bytecodes + + for (BytecodeStream s(method); s.next() != Bytecodes::_illegal; ) { + Bytecodes::Code code = s.code(); + Bytecodes::Code raw_code = s.raw_code(); + int bci = s.bci(); + int len = s.instruction_size(); + + // Restore original byte code. + reconstituted_code->byte_at_put(bci, (jbyte) (s.is_wide()? Bytecodes::_wide : code)); + if (len > 1) { + memcpy(reconstituted_code->byte_at_addr(bci + 1), s.bcp()+1, len-1); + } + + if (len > 1) { + // Restore the big-endian constant pool indexes. + // Cf. Rewriter::scan_method + switch (code) { + case Bytecodes::_getstatic: + case Bytecodes::_putstatic: + case Bytecodes::_getfield: + case Bytecodes::_putfield: + case Bytecodes::_invokevirtual: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokehandle: { + int cp_index = Bytes::get_native_u2((address) reconstituted_code->byte_at_addr(bci + 1)); + Bytes::put_Java_u2((address) reconstituted_code->byte_at_addr(bci + 1), (u2) cp_index); + break; + } + + case Bytecodes::_invokedynamic: + int cp_index = Bytes::get_native_u4((address) reconstituted_code->byte_at_addr(bci + 1)); + Bytes::put_Java_u4((address) reconstituted_code->byte_at_addr(bci + 1), (u4) cp_index); + break; + } + + // Not all ldc byte code are rewritten. + switch (raw_code) { + case Bytecodes::_fast_aldc: { + int cpc_index = reconstituted_code->byte_at(bci + 1) & 0xff; + int cp_index = method->constants()->object_to_cp_index(cpc_index); + assert(cp_index < method->constants()->length(), "sanity check"); + reconstituted_code->byte_at_put(bci + 1, (jbyte) cp_index); + break; + } + + case Bytecodes::_fast_aldc_w: { + int cpc_index = Bytes::get_native_u2((address) reconstituted_code->byte_at_addr(bci + 1)); + int cp_index = method->constants()->object_to_cp_index(cpc_index); + assert(cp_index < method->constants()->length(), "sanity check"); + Bytes::put_Java_u2((address) reconstituted_code->byte_at_addr(bci + 1), (u2) cp_index); + break; + } + } + } + } + + return (jbyteArray) JNIHandles::make_local(THREAD, reconstituted_code); +C2V_END + +C2V_VMENTRY(jint, getExceptionTableLength, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return method->exception_table_length(); +C2V_END + +C2V_VMENTRY(jlong, getExceptionTableStart, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + methodHandle method = CompilerToVM::asMethod(jvmci_method); + if (method->exception_table_length() == 0) { + return 0L; + } + return (jlong) (address) method->exception_table_start(); +C2V_END + +C2V_VMENTRY(jint, hasBalancedMonitors, (JNIEnv *, jobject, jobject jvmci_method)) + // Analyze the method to see if monitors are used properly. + methodHandle method(THREAD, CompilerToVM::asMethod(jvmci_method)); + { + EXCEPTION_MARK; + ResourceMark rm(THREAD); + GeneratePairingInfo gpi(method); + gpi.compute_map(CATCH); + if (!gpi.monitor_safe()) { + return false; + } + method->set_guaranteed_monitor_matching(); + } + return true; +C2V_END + +C2V_VMENTRY(jobject, getResolvedJavaMethodAtSlot, (JNIEnv *, jobject, jclass holder_handle, jint slot)) + oop java_class = JNIHandles::resolve(holder_handle); + Klass* holder = java_lang_Class::as_Klass(java_class); + methodHandle method = InstanceKlass::cast(holder)->method_with_idnum(slot); + oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +} + +C2V_VMENTRY(jobject, getResolvedJavaMethod, (JNIEnv *, jobject, jobject base, jlong offset)) + methodHandle method; + oop base_object = JNIHandles::resolve(base); + if (base_object == NULL) { + method = *((Method**)(offset)); + } else if (base_object->is_a(SystemDictionary::MemberName_klass())) { + method = (Method*) (intptr_t) base_object->long_field(offset); + } else if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + method = *((Method**)(HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object) + offset)); + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected type: %s", base_object->klass()->external_name())); + } + assert (method.is_null() || method->is_method(), "invalid read"); + oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +} + +C2V_VMENTRY(jobject, getConstantPool, (JNIEnv *, jobject, jobject base, jlong offset)) + constantPoolHandle cp; + oop base_object = JNIHandles::resolve(base); + jlong base_address = 0; + if (base_object != NULL) { + if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + base_address = HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotConstantPool_klass())) { + base_address = HotSpotConstantPool::metaspaceConstantPool(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { + base_address = (jlong) CompilerToVM::asKlass(base_object); + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected type: %s", base_object->klass()->external_name())); + } + } + cp = *((ConstantPool**) (intptr_t) (base_address + offset)); + if (!cp.is_null()) { + JavaValue method_result(T_OBJECT); + JavaCallArguments args; + args.push_long((jlong) (address) cp()); + JavaCalls::call_static(&method_result, SystemDictionary::HotSpotConstantPool_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::constantPool_fromMetaspace_signature(), &args, CHECK_NULL); + return JNIHandles::make_local(THREAD, (oop)method_result.get_jobject()); + } + return NULL; +} + +C2V_VMENTRY(jobject, getResolvedJavaType, (JNIEnv *, jobject, jobject base, jlong offset, jboolean compressed)) + KlassHandle klass; + oop base_object = JNIHandles::resolve(base); + jlong base_address = 0; + if (base_object != NULL && offset == oopDesc::klass_offset_in_bytes()) { + klass = base_object->klass(); + } else if (!compressed) { + if (base_object != NULL) { + if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + base_address = HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotConstantPool_klass())) { + base_address = HotSpotConstantPool::metaspaceConstantPool(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { + base_address = (jlong) CompilerToVM::asKlass(base_object); + } else if (base_object->is_a(SystemDictionary::Class_klass())) { + base_address = (jlong) (address) base_object; + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected arguments: %s " JLONG_FORMAT " %s", base_object->klass()->external_name(), offset, compressed ? "true" : "false")); + } + } + klass = *((Klass**) (intptr_t) (base_address + offset)); + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected arguments: %s " JLONG_FORMAT " %s", base_object->klass()->external_name(), offset, compressed ? "true" : "false")); + } + assert (klass.is_null() || klass->is_klass(), "invalid read"); + oop result = CompilerToVM::get_jvmci_type(klass, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +} + +C2V_VMENTRY(jobject, findUniqueConcreteMethod, (JNIEnv *, jobject, jobject jvmci_type, jobject jvmci_method)) + ResourceMark rm; + methodHandle method = CompilerToVM::asMethod(jvmci_method); + KlassHandle holder = CompilerToVM::asKlass(jvmci_type); + if (holder->is_interface()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Interface %s should be handled in Java code", holder->external_name())); + } + + methodHandle ucm; + { + MutexLocker locker(Compile_lock); + ucm = Dependencies::find_unique_concrete_method(holder(), method()); + } + oop result = CompilerToVM::get_jvmci_method(ucm, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jobject, getImplementor, (JNIEnv *, jobject, jobject jvmci_type)) + InstanceKlass* klass = (InstanceKlass*) CompilerToVM::asKlass(jvmci_type); + oop implementor = CompilerToVM::get_jvmci_type(klass->implementor(), CHECK_NULL); + return JNIHandles::make_local(THREAD, implementor); +C2V_END + +C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return method->is_ignored_by_security_stack_walk(); +C2V_END + +C2V_VMENTRY(jboolean, canInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return !method->is_not_compilable() && !CompilerOracle::should_not_inline(method) && !method->dont_inline(); +C2V_END + +C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return CompilerOracle::should_inline(method) || method->force_inline(); +C2V_END + +C2V_VMENTRY(jobject, lookupType, (JNIEnv*, jobject, jstring jname, jclass accessing_class, jboolean resolve)) + ResourceMark rm; + Handle name = JNIHandles::resolve(jname); + Symbol* class_name = java_lang_String::as_symbol(name, CHECK_0); + if (java_lang_String::length(name()) <= 1) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Primitive type %s should be handled in Java code", class_name->as_C_string())); + } + + Klass* resolved_klass = NULL; + Handle class_loader; + Handle protection_domain; + if (JNIHandles::resolve(accessing_class) == NULL) { + THROW_0(vmSymbols::java_lang_NullPointerException()); + } + Klass* accessing_klass = java_lang_Class::as_Klass(JNIHandles::resolve(accessing_class)); + class_loader = accessing_klass->class_loader(); + protection_domain = accessing_klass->protection_domain(); + + if (resolve) { + resolved_klass = SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, CHECK_0); + } else { + if (class_name->byte_at(0) == 'L' && + class_name->byte_at(class_name->utf8_length()-1) == ';') { + // This is a name from a signature. Strip off the trimmings. + // Call recursive to keep scope of strippedsym. + TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1, + class_name->utf8_length()-2, + CHECK_0); + resolved_klass = SystemDictionary::find(strippedsym, class_loader, protection_domain, CHECK_0); + } else if (FieldType::is_array(class_name)) { + FieldArrayInfo fd; + // dimension and object_key in FieldArrayInfo are assigned as a side-effect + // of this call + BasicType t = FieldType::get_array_info(class_name, fd, CHECK_0); + if (t == T_OBJECT) { + TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1+fd.dimension(), + class_name->utf8_length()-2-fd.dimension(), + CHECK_0); + // naked oop "k" is OK here -- we assign back into it + resolved_klass = SystemDictionary::find(strippedsym, + class_loader, + protection_domain, + CHECK_0); + if (resolved_klass != NULL) { + resolved_klass = resolved_klass->array_klass(fd.dimension(), CHECK_0); + } + } else { + resolved_klass = Universe::typeArrayKlassObj(t); + resolved_klass = TypeArrayKlass::cast(resolved_klass)->array_klass(fd.dimension(), CHECK_0); + } + } + } + Handle result = CompilerToVM::get_jvmci_type(resolved_klass, CHECK_NULL); + return JNIHandles::make_local(THREAD, result()); +C2V_END + +C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + oop result = cp->resolve_constant_at(index, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + return cp->name_and_type_ref_index_at(index); +C2V_END + +C2V_VMENTRY(jobject, lookupNameRefInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Handle sym = java_lang_String::create_from_symbol(cp->name_ref_at(index), CHECK_NULL); + return JNIHandles::make_local(THREAD, sym()); +C2V_END + +C2V_VMENTRY(jobject, lookupSignatureRefInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Handle sym = java_lang_String::create_from_symbol(cp->signature_ref_at(index), CHECK_NULL); + return JNIHandles::make_local(THREAD, sym()); +C2V_END + +C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + return cp->klass_ref_index_at(index); +C2V_END + +C2V_VMENTRY(jobject, resolveTypeInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Klass* resolved_klass = cp->klass_at(index, CHECK_NULL); + Handle klass = CompilerToVM::get_jvmci_type(resolved_klass, CHECK_NULL); + return JNIHandles::make_local(THREAD, klass()); +C2V_END + +C2V_VMENTRY(jobject, lookupKlassInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + KlassHandle loading_klass(cp->pool_holder()); + bool is_accessible = false; + KlassHandle klass = JVMCIEnv::get_klass_by_index(cp, index, is_accessible, loading_klass); + Symbol* symbol = NULL; + if (klass.is_null()) { + symbol = cp->klass_name_at(index); + } + Handle result; + if (!klass.is_null()) { + result = CompilerToVM::get_jvmci_type(klass, CHECK_NULL); + } else { + result = java_lang_String::create_from_symbol(symbol, CHECK_NULL); + } + return JNIHandles::make_local(THREAD, result()); +C2V_END + +C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, index); + return JNIHandles::make_local(THREAD, appendix_oop); +C2V_END + +C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + instanceKlassHandle pool_holder(cp->pool_holder()); + Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); + methodHandle method = JVMCIEnv::get_method_by_index(cp, index, bc, pool_holder); + oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + return cp->remap_instruction_operand_from_cache(index); +C2V_END + +C2V_VMENTRY(jobject, resolveFieldInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode, jlongArray info_handle)) + ResourceMark rm; + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF); + fieldDescriptor fd; + LinkInfo link_info(cp, index, CHECK_0); + LinkResolver::resolve_field(fd, link_info, Bytecodes::java_code(code), false, CHECK_0); + typeArrayOop info = (typeArrayOop) JNIHandles::resolve(info_handle); + assert(info != NULL && info->length() == 2, "must be"); + info->long_at_put(0, (jlong) fd.access_flags().as_int()); + info->long_at_put(1, (jlong) fd.offset()); + oop field_holder = CompilerToVM::get_jvmci_type(fd.field_holder(), CHECK_NULL); + return JNIHandles::make_local(THREAD, field_holder); +C2V_END + +C2V_VMENTRY(jint, getVtableIndexForInterface, (JNIEnv *, jobject, jobject jvmci_type, jobject jvmci_method)) + Klass* klass = CompilerToVM::asKlass(jvmci_type); + Method* method = CompilerToVM::asMethod(jvmci_method); + if (klass->is_interface()) { + ResourceMark rm; + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Interface %s should be handled in Java code", klass->external_name())); + } + return LinkResolver::vtable_index_of_interface_method(klass, method); +C2V_END + +C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_type, jobject jvmci_method, jobject caller_jvmci_type)) + Klass* recv_klass = CompilerToVM::asKlass(receiver_jvmci_type); + Klass* caller_klass = CompilerToVM::asKlass(caller_jvmci_type); + Method* method = CompilerToVM::asMethod(jvmci_method); + + if (recv_klass->oop_is_array() || (InstanceKlass::cast(recv_klass)->is_linked())) { + Klass* holder_klass = method->method_holder(); + Symbol* method_name = method->name(); + Symbol* method_signature = method->signature(); + + if (holder_klass->is_interface()) { + // do link-time resolution to check all access rules. + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); + methodHandle resolved_method = LinkResolver::linktime_resolve_interface_method_or_null(link_info); + if (resolved_method.is_null() || resolved_method->is_private()) { + return NULL; + } + assert(recv_klass->is_subtype_of(holder_klass), ""); + // do actual lookup + methodHandle sel_method = LinkResolver::lookup_instance_method_in_klasses(recv_klass, resolved_method->name(), resolved_method->signature(), CHECK_AND_CLEAR_0); + oop result = CompilerToVM::get_jvmci_method(sel_method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); + } else { + // do link-time resolution to check all access rules. + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); + methodHandle resolved_method = LinkResolver::linktime_resolve_virtual_method_or_null(link_info); + if (resolved_method.is_null()) { + return NULL; + } + // do actual lookup (see LinkResolver::runtime_resolve_virtual_method) + int vtable_index = Method::invalid_vtable_index; + Method* selected_method; + + if (resolved_method->method_holder()->is_interface()) { // miranda method + vtable_index = LinkResolver::vtable_index_of_interface_method(holder_klass, resolved_method); + assert(vtable_index >= 0 , "we should have valid vtable index at this point"); + + InstanceKlass* inst = InstanceKlass::cast(recv_klass); + selected_method = inst->method_at_vtable(vtable_index); + } else { + // at this point we are sure that resolved_method is virtual and not + // a miranda method; therefore, it must have a valid vtable index. + assert(!resolved_method->has_itable_index(), ""); + vtable_index = resolved_method->vtable_index(); + // We could get a negative vtable_index for final methods, + // because as an optimization they are they are never put in the vtable, + // unless they override an existing method. + // If we do get a negative, it means the resolved method is the the selected + // method, and it can never be changed by an override. + if (vtable_index == Method::nonvirtual_vtable_index) { + assert(resolved_method->can_be_statically_bound(), "cannot override this method"); + selected_method = resolved_method(); + } else { + // recv_klass might be an arrayKlassOop but all vtables start at + // the same place. The cast is to avoid virtual call and assertion. + InstanceKlass* inst = (InstanceKlass*)recv_klass; + selected_method = inst->method_at_vtable(vtable_index); + } + } + oop result = CompilerToVM::get_jvmci_method(selected_method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); + } + } + return NULL; +C2V_END + +C2V_VMENTRY(jboolean, hasFinalizableSubclass,(JNIEnv *, jobject, jobject jvmci_type)) + Klass* klass = CompilerToVM::asKlass(jvmci_type); + assert(klass != NULL, "method must not be called for primitive types"); + return Dependencies::find_finalizable_subclass(klass) != NULL; +C2V_END + +C2V_VMENTRY(jobject, getClassInitializer, (JNIEnv *, jobject, jobject jvmci_type)) + InstanceKlass* klass = (InstanceKlass*) CompilerToVM::asKlass(jvmci_type); + oop result = CompilerToVM::get_jvmci_method(klass->class_initializer(), CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv*, jobject, jlong addr)) + address target_addr = (address) addr; + if (target_addr != 0x0) { + int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int)); + int64_t off_high = (int64_t)target_addr - ((int64_t)CodeCache::high_bound() + sizeof(int)); + return MAX2(ABS(off_low), ABS(off_high)); + } + return -1; +C2V_END + +C2V_VMENTRY(void, doNotInlineOrCompile,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + method->set_not_c1_compilable(); + method->set_not_c2_compilable(); + method->set_dont_inline(true); +C2V_END + +C2V_VMENTRY(jint, installCode, (JNIEnv *jniEnv, jobject, jobject target, jobject compiled_code, jobject installed_code, jobject speculation_log)) + ResourceMark rm; + HandleMark hm; + Handle target_handle = JNIHandles::resolve(target); + Handle compiled_code_handle = JNIHandles::resolve(compiled_code); + CodeBlob* cb = NULL; + Handle installed_code_handle = JNIHandles::resolve(installed_code); + Handle speculation_log_handle = JNIHandles::resolve(speculation_log); + + JVMCICompiler* compiler = JVMCICompiler::instance(CHECK_JNI_ERR); + + TraceTime install_time("installCode", JVMCICompiler::codeInstallTimer()); + CodeInstaller installer; + JVMCIEnv::CodeInstallResult result = installer.install(compiler, target_handle, compiled_code_handle, cb, installed_code_handle, speculation_log_handle); + + if (PrintCodeCacheOnCompilation) { + stringStream s; + // Dump code cache into a buffer before locking the tty, + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + CodeCache::print_summary(&s, false); + } + ttyLocker ttyl; + tty->print_raw_cr(s.as_string()); + } + + if (result != JVMCIEnv::ok) { + assert(cb == NULL, "should be"); + } else { + if (!installed_code_handle.is_null()) { + assert(installed_code_handle->is_a(InstalledCode::klass()), "wrong type"); + InstalledCode::set_address(installed_code_handle, (jlong) cb); + InstalledCode::set_version(installed_code_handle, InstalledCode::version(installed_code_handle) + 1); + if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { + HotSpotInstalledCode::set_size(installed_code_handle, cb->size()); + HotSpotInstalledCode::set_codeStart(installed_code_handle, (jlong) cb->code_begin()); + HotSpotInstalledCode::set_codeSize(installed_code_handle, cb->code_size()); + } + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL && installed_code_handle->is_scavengable()) { + assert(nm->detect_scavenge_root_oops(), "nm should be scavengable if installed_code is scavengable"); + if (!UseG1GC) { + assert(nm->on_scavenge_root_list(), "nm should be on scavengable list"); + } + } + } + } + return result; +C2V_END + +C2V_VMENTRY(jint, getMetadata, (JNIEnv *jniEnv, jobject, jobject target, jobject compiled_code, jobject metadata)) + ResourceMark rm; + HandleMark hm; + + Handle target_handle = JNIHandles::resolve(target); + Handle compiled_code_handle = JNIHandles::resolve(compiled_code); + Handle metadata_handle = JNIHandles::resolve(metadata); + + HotSpotOopMap::klass()->initialize(thread); + + CodeMetadata code_metadata; + CodeBlob *cb = NULL; + CodeInstaller installer; + + JVMCIEnv::CodeInstallResult result = installer.gather_metadata(target_handle, compiled_code_handle, code_metadata); //cb, pc_descs, nr_pc_descs, scopes_descs, scopes_size, reloc_buffer); + if (result != JVMCIEnv::ok) { + return result; + } + + if (code_metadata.get_nr_pc_desc() > 0) { + typeArrayHandle pcArrayOop = oopFactory::new_byteArray(sizeof(PcDesc) * code_metadata.get_nr_pc_desc(), CHECK_(JVMCIEnv::cache_full)); + memcpy(pcArrayOop->byte_at_addr(0), code_metadata.get_pc_desc(), sizeof(PcDesc) * code_metadata.get_nr_pc_desc()); + HotSpotMetaData::set_pcDescBytes(metadata_handle, pcArrayOop()); + } + + if (code_metadata.get_scopes_size() > 0) { + typeArrayHandle scopesArrayOop = oopFactory::new_byteArray(code_metadata.get_scopes_size(), CHECK_(JVMCIEnv::cache_full)); + memcpy(scopesArrayOop->byte_at_addr(0), code_metadata.get_scopes_desc(), code_metadata.get_scopes_size()); + HotSpotMetaData::set_scopesDescBytes(metadata_handle, scopesArrayOop()); + } + + RelocBuffer* reloc_buffer = code_metadata.get_reloc_buffer(); + typeArrayHandle relocArrayOop = oopFactory::new_byteArray((int) reloc_buffer->size(), CHECK_(JVMCIEnv::cache_full)); + if (reloc_buffer->size() > 0) { + memcpy(relocArrayOop->byte_at_addr(0), reloc_buffer->begin(), reloc_buffer->size()); + } + HotSpotMetaData::set_relocBytes(metadata_handle, relocArrayOop()); + + const OopMapSet* oopMapSet = installer.oopMapSet(); + { + ResourceMark mark; + ImmutableOopMapBuilder builder(oopMapSet); + int oopmap_size = builder.heap_size(); + typeArrayHandle oopMapArrayHandle = oopFactory::new_byteArray(oopmap_size, CHECK_(JVMCIEnv::cache_full)); + builder.generate_into((address) oopMapArrayHandle->byte_at_addr(0)); + HotSpotMetaData::set_oopMaps(metadata_handle, oopMapArrayHandle()); + } + + HotSpotMetaData::set_metadata(metadata_handle, NULL); + + ExceptionHandlerTable* handler = code_metadata.get_exception_table(); + int table_size = handler->size_in_bytes(); + typeArrayHandle exceptionArrayOop = oopFactory::new_byteArray(table_size, CHECK_(JVMCIEnv::cache_full)); + + if (table_size > 0) { + handler->copy_bytes_to((address) exceptionArrayOop->byte_at_addr(0)); + } + HotSpotMetaData::set_exceptionBytes(metadata_handle, exceptionArrayOop()); + + return result; +C2V_END + +C2V_VMENTRY(void, notifyCompilationStatistics, (JNIEnv *jniEnv, jobject, jint id, jobject hotspot_method, jboolean osr, jint processedBytecodes, jlong time, jlong timeUnitsPerSecond, jobject installed_code)) + JVMCICompiler* compiler = JVMCICompiler::instance(CHECK); + CompilerStatistics* stats = compiler->stats(); + + elapsedTimer timer = elapsedTimer(time, timeUnitsPerSecond); + if (osr) { + stats->_osr.update(timer, processedBytecodes); + } else { + stats->_standard.update(timer, processedBytecodes); + } + Handle installed_code_handle = JNIHandles::resolve(installed_code); + if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { + stats->_nmethods_size += HotSpotInstalledCode::size(installed_code_handle); + stats->_nmethods_code_size += HotSpotInstalledCode::codeSize(installed_code_handle); + } + + if (CITimeEach) { + methodHandle method = CompilerToVM::asMethod(hotspot_method); + float bytes_per_sec = 1.0 * processedBytecodes / timer.seconds(); + tty->print_cr("%3d seconds: %f bytes/sec: %f (bytes %d)", + id, timer.seconds(), bytes_per_sec, processedBytecodes); + } +C2V_END + +C2V_VMENTRY(void, resetCompilationStatistics, (JNIEnv *jniEnv, jobject)) + JVMCICompiler* compiler = JVMCICompiler::instance(CHECK); + CompilerStatistics* stats = compiler->stats(); + stats->_standard.reset(); + stats->_osr.reset(); +C2V_END + +C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv *jniEnv, jobject, jlong codeBlob)) + ResourceMark rm; + HandleMark hm; + + CodeBlob* cb = (CodeBlob*) (address) codeBlob; + if (cb == NULL) { + return NULL; + } + + // We don't want the stringStream buffer to resize during disassembly as it + // uses scoped resource memory. If a nested function called during disassembly uses + // a ResourceMark and the buffer expands within the scope of the mark, + // the buffer becomes garbage when that scope is exited. Experience shows that + // the disassembled code is typically about 10x the code size so a fixed buffer + // sized to 20x code size plus a fixed amount for header info should be sufficient. + int bufferSize = cb->code_size() * 20 + 1024; + char* buffer = NEW_RESOURCE_ARRAY(char, bufferSize); + stringStream st(buffer, bufferSize); + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + if (!nm->is_alive()) { + return NULL; + } + Disassembler::decode(nm, &st); + } else { + Disassembler::decode(cb, &st); + } + if (st.size() <= 0) { + return NULL; + } + + Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); + return JNIHandles::make_local(THREAD, result()); +C2V_END + +C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv*, jobject, jobject jvmci_method, int bci)) + ResourceMark rm; + HandleMark hm; + + methodHandle method = CompilerToVM::asMethod(jvmci_method); + oop element = java_lang_StackTraceElement::create(method, bci, CHECK_NULL); + return JNIHandles::make_local(THREAD, element); +C2V_END + +C2V_VMENTRY(jobject, executeInstalledCode, (JNIEnv*, jobject, jobject args, jobject hotspotInstalledCode)) + ResourceMark rm; + HandleMark hm; + + jlong nmethodValue = InstalledCode::address(hotspotInstalledCode); + if (nmethodValue == 0L) { + THROW_NULL(vmSymbols::jdk_internal_jvmci_code_InvalidInstalledCodeException()); + } + nmethod* nm = (nmethod*) (address) nmethodValue; + methodHandle mh = nm->method(); + Symbol* signature = mh->signature(); + JavaCallArguments jca(mh->size_of_parameters()); + + JavaArgumentUnboxer jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static()); + JavaValue result(jap.get_ret_type()); + jca.set_alternative_target(nm); + JavaCalls::call(&result, mh, &jca, CHECK_NULL); + + if (jap.get_ret_type() == T_VOID) { + return NULL; + } else if (jap.get_ret_type() == T_OBJECT || jap.get_ret_type() == T_ARRAY) { + return JNIHandles::make_local(THREAD, (oop) result.get_jobject()); + } else { + jvalue *value = (jvalue *) result.get_value_addr(); + // Narrow the value down if required (Important on big endian machines) + switch (jap.get_ret_type()) { + case T_BOOLEAN: + value->z = (jboolean) value->i; + break; + case T_BYTE: + value->b = (jbyte) value->i; + break; + case T_CHAR: + value->c = (jchar) value->i; + break; + case T_SHORT: + value->s = (jshort) value->i; + break; + } + oop o = java_lang_boxing_object::create(jap.get_ret_type(), value, CHECK_NULL); + return JNIHandles::make_local(THREAD, o); + } +C2V_END + +C2V_VMENTRY(jlongArray, getLineNumberTable, (JNIEnv *, jobject, jobject jvmci_method)) + Method* method = CompilerToVM::asMethod(jvmci_method); + if (!method->has_linenumber_table()) { + return NULL; + } + u2 num_entries = 0; + CompressedLineNumberReadStream streamForSize(method->compressed_linenumber_table()); + while (streamForSize.read_pair()) { + num_entries++; + } + + CompressedLineNumberReadStream stream(method->compressed_linenumber_table()); + typeArrayOop result = oopFactory::new_longArray(2 * num_entries, CHECK_NULL); + + int i = 0; + jlong value; + while (stream.read_pair()) { + value = ((long) stream.bci()); + result->long_at_put(i, value); + value = ((long) stream.line()); + result->long_at_put(i + 1, value); + i += 2; + } + + return (jlongArray) JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jlong, getLocalVariableTableStart, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + Method* method = CompilerToVM::asMethod(jvmci_method); + if (!method->has_localvariable_table()) { + return 0; + } + return (jlong) (address) method->localvariable_table_start(); +C2V_END + +C2V_VMENTRY(jint, getLocalVariableTableLength, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + Method* method = CompilerToVM::asMethod(jvmci_method); + return method->localvariable_table_length(); +C2V_END + +C2V_VMENTRY(void, reprofile, (JNIEnv*, jobject, jobject jvmci_method)) + Method* method = CompilerToVM::asMethod(jvmci_method); + MethodCounters* mcs = method->method_counters(); + if (mcs != NULL) { + mcs->clear_counters(); + } + NOT_PRODUCT(method->set_compiled_invocation_count(0)); + + nmethod* code = method->code(); + if (code != NULL) { + code->make_not_entrant(); + } + + MethodData* method_data = method->method_data(); + if (method_data == NULL) { + ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); + method_data = MethodData::allocate(loader_data, method, CHECK); + method->set_method_data(method_data); + } else { + method_data->initialize(); + } +C2V_END + + +C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv*, jobject, jobject hotspotInstalledCode)) + jlong nativeMethod = InstalledCode::address(hotspotInstalledCode); + nmethod* m = (nmethod*)nativeMethod; + if (m != NULL && !m->is_not_entrant()) { + m->mark_for_deoptimization(); + VM_Deoptimize op; + VMThread::execute(&op); + } + InstalledCode::set_address(hotspotInstalledCode, 0); +C2V_END + +C2V_VMENTRY(jobject, readUncompressedOop, (JNIEnv*, jobject, jlong addr)) + oop ret = oopDesc::load_decode_heap_oop((oop*)(address)addr); + return JNIHandles::make_local(THREAD, ret); +C2V_END + +C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv*, jobject)) + typeArrayOop arrayOop = oopFactory::new_longArray(JVMCICounterSize, CHECK_NULL); + JavaThread::collect_counters(arrayOop); + return (jlongArray) JNIHandles::make_local(THREAD, arrayOop); +C2V_END + +C2V_VMENTRY(int, allocateCompileId, (JNIEnv*, jobject, jobject jvmci_method, int entry_bci)) + HandleMark hm; + ResourceMark rm; + Method* method = CompilerToVM::asMethod(jvmci_method); + return CompileBroker::assign_compile_id_unlocked(THREAD, method, entry_bci); +C2V_END + + +C2V_VMENTRY(jboolean, isMature, (JNIEnv*, jobject, jlong metaspace_method_data)) + MethodData* mdo = CompilerToVM::asMethodData(metaspace_method_data); + return mdo != NULL && mdo->is_mature(); +C2V_END + +C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv*, jobject, jobject jvmci_method, int entry_bci, int comp_level)) + Method* method = CompilerToVM::asMethod(jvmci_method); + return method->lookup_osr_nmethod_for(entry_bci, comp_level, true) != NULL; +C2V_END + +C2V_VMENTRY(jobject, getSymbol, (JNIEnv*, jobject, jlong symbol)) + Handle sym = java_lang_String::create_from_symbol((Symbol*)(address)symbol, CHECK_NULL); + return JNIHandles::make_local(THREAD, sym()); +C2V_END + +bool matches(jobjectArray methods, Method* method) { + objArrayOop methods_oop = (objArrayOop) JNIHandles::resolve(methods); + + for (int i = 0; i < methods_oop->length(); i++) { + if (CompilerToVM::asMethod(methods_oop->obj_at(i)) == method) { + return true; + } + } + return false; +} + +C2V_VMENTRY(jobject, getNextStackFrame, (JNIEnv*, jobject compilerToVM, jobject hs_frame, jobjectArray methods, jint initialSkip)) + ResourceMark rm; + + if (!thread->has_last_Java_frame()) return NULL; + Handle result = HotSpotStackFrameReference::klass()->allocate_instance(thread); + HotSpotStackFrameReference::klass()->initialize(thread); + + StackFrameStream fst(thread); + if (hs_frame != NULL) { + // look for the correct stack frame if one is given + intptr_t* stack_pointer = (intptr_t*) HotSpotStackFrameReference::stackPointer(hs_frame); + while (fst.current()->sp() != stack_pointer && !fst.is_done()) { + fst.next(); + } + if (fst.current()->sp() != stack_pointer) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "stack frame not found") + } + } + + int frame_number = 0; + vframe* vf = vframe::new_vframe(fst.current(), fst.register_map(), thread); + if (hs_frame != NULL) { + // look for the correct vframe within the stack frame if one is given + int last_frame_number = HotSpotStackFrameReference::frameNumber(hs_frame); + while (frame_number < last_frame_number) { + if (vf->is_top()) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "invalid frame number") + } + vf = vf->sender(); + frame_number ++; + } + // move one frame forward + if (vf->is_top()) { + if (fst.is_done()) { + return NULL; + } + fst.next(); + vf = vframe::new_vframe(fst.current(), fst.register_map(), thread); + frame_number = 0; + } else { + vf = vf->sender(); + frame_number++; + } + } + + while (true) { + // look for the given method + while (true) { + StackValueCollection* locals = NULL; + if (vf->is_compiled_frame()) { + // compiled method frame + compiledVFrame* cvf = compiledVFrame::cast(vf); + if (methods == NULL || matches(methods, cvf->method())) { + if (initialSkip > 0) { + initialSkip --; + } else { + GrowableArray* objects = cvf->scope()->objects(); + bool realloc_failures = false; + if (objects != NULL) { + realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), objects, THREAD); + Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects, realloc_failures); + + GrowableArray* local_values = cvf->scope()->locals(); + typeArrayHandle array = oopFactory::new_boolArray(local_values->length(), thread); + for (int i = 0; i < local_values->length(); i++) { + ScopeValue* value = local_values->at(i); + if (value->is_object()) { + array->bool_at_put(i, true); + } + } + HotSpotStackFrameReference::set_localIsVirtual(result, array()); + } else { + HotSpotStackFrameReference::set_localIsVirtual(result, NULL); + } + + locals = cvf->locals(); + HotSpotStackFrameReference::set_bci(result, cvf->bci()); + oop method = CompilerToVM::get_jvmci_method(cvf->method(), CHECK_NULL); + HotSpotStackFrameReference::set_method(result, method); + } + } + } else if (vf->is_interpreted_frame()) { + // interpreted method frame + interpretedVFrame* ivf = interpretedVFrame::cast(vf); + if (methods == NULL || matches(methods, ivf->method())) { + if (initialSkip > 0) { + initialSkip --; + } else { + locals = ivf->locals(); + HotSpotStackFrameReference::set_bci(result, ivf->bci()); + oop method = CompilerToVM::get_jvmci_method(ivf->method(), CHECK_NULL); + HotSpotStackFrameReference::set_method(result, method); + HotSpotStackFrameReference::set_localIsVirtual(result, NULL); + } + } + } + + // locals != NULL means that we found a matching frame and result is already partially initialized + if (locals != NULL) { + HotSpotStackFrameReference::set_compilerToVM(result, JNIHandles::resolve(compilerToVM)); + HotSpotStackFrameReference::set_stackPointer(result, (jlong) fst.current()->sp()); + HotSpotStackFrameReference::set_frameNumber(result, frame_number); + + // initialize the locals array + objArrayHandle array = oopFactory::new_objectArray(locals->size(), thread); + for (int i = 0; i < locals->size(); i++) { + StackValue* var = locals->at(i); + if (var->type() == T_OBJECT) { + array->obj_at_put(i, locals->at(i)->get_obj()()); + } + } + HotSpotStackFrameReference::set_locals(result, array()); + + return JNIHandles::make_local(thread, result()); + } + + if (vf->is_top()) { + break; + } + frame_number++; + vf = vf->sender(); + } // end of vframe loop + + if (fst.is_done()) { + break; + } + fst.next(); + vf = vframe::new_vframe(fst.current(), fst.register_map(), thread); + frame_number = 0; + } // end of frame loop + + // the end was reached without finding a matching method + return NULL; +C2V_END + +C2V_VMENTRY(void, resolveInvokeDynamicInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + CallInfo callInfo; + LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, Bytecodes::_invokedynamic, CHECK); + ConstantPoolCacheEntry* cp_cache_entry = cp->invokedynamic_cp_cache_entry_at(index); + cp_cache_entry->set_dynamic_call(cp, callInfo); +C2V_END + +C2V_VMENTRY(void, resolveInvokeHandleInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + CallInfo callInfo; + LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, Bytecodes::_invokehandle, CHECK); + ConstantPoolCacheEntry* cp_cache_entry = cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index)); + cp_cache_entry->set_method_handle(cp, callInfo); +C2V_END + +C2V_VMENTRY(jboolean, shouldDebugNonSafepoints, (JNIEnv*, jobject)) + //see compute_recording_non_safepoints in debugInfroRec.cpp + if (JvmtiExport::should_post_compiled_method_load() && FLAG_IS_DEFAULT(DebugNonSafepoints)) { + return true; + } + return DebugNonSafepoints; +C2V_END + +// public native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate); +C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame, bool invalidate)) + ResourceMark rm; + + if (hs_frame == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), "stack frame is null") + } + + HotSpotStackFrameReference::klass()->initialize(thread); + + // look for the given stack frame + StackFrameStream fst(thread); + intptr_t* stack_pointer = (intptr_t*) HotSpotStackFrameReference::stackPointer(hs_frame); + while (fst.current()->sp() != stack_pointer && !fst.is_done()) { + fst.next(); + } + if (fst.current()->sp() != stack_pointer) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "stack frame not found") + } + + if (invalidate) { + assert(fst.current()->cb()->is_nmethod(), "nmethod expected"); + ((nmethod*) fst.current()->cb())->make_not_entrant(); + } + Deoptimization::deoptimize(thread, *fst.current(), fst.register_map(), Deoptimization::Reason_none); + + vframe* vf = vframe::new_vframe(fst.current(), fst.register_map(), thread); + if (!vf->is_compiled_frame()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "compiled stack frame expected") + } + + GrowableArray* virtualFrames = new GrowableArray(10); + while (true) { + assert(vf->is_compiled_frame(), "Wrong frame type"); + virtualFrames->push(compiledVFrame::cast(vf)); + if (vf->is_top()) { + break; + } + vf = vf->sender(); + } + + int last_frame_number = HotSpotStackFrameReference::frameNumber(hs_frame); + if (last_frame_number >= virtualFrames->length()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "invalid frame number") + } + + // Reallocate the non-escaping objects and restore their fields. + assert (virtualFrames->at(last_frame_number)->scope() != NULL,"invalid scope"); + GrowableArray* objects = virtualFrames->at(last_frame_number)->scope()->objects(); + + if (objects == NULL) { + // no objects to materialize + return; + } + + bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), objects, THREAD); + Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects, realloc_failures); + + for (int frame_index = 0; frame_index < virtualFrames->length(); frame_index++) { + compiledVFrame* cvf = virtualFrames->at(frame_index); + + GrowableArray* scopeLocals = cvf->scope()->locals(); + StackValueCollection* locals = cvf->locals(); + + if (locals != NULL) { + for (int i2 = 0; i2 < locals->size(); i2++) { + StackValue* var = locals->at(i2); + if (var->type() == T_OBJECT && scopeLocals->at(i2)->is_object()) { + jvalue val; + val.l = (jobject) locals->at(i2)->get_obj()(); + cvf->update_local(T_OBJECT, i2, val); + } + } + } + } + + // all locals are materialized by now + HotSpotStackFrameReference::set_localIsVirtual(hs_frame, NULL); + + // update the locals array + objArrayHandle array = HotSpotStackFrameReference::locals(hs_frame); + StackValueCollection* locals = virtualFrames->at(last_frame_number)->locals(); + for (int i = 0; i < locals->size(); i++) { + StackValue* var = locals->at(i); + if (var->type() == T_OBJECT) { + array->obj_at_put(i, locals->at(i)->get_obj()()); + } + } +C2V_END + +C2V_VMENTRY(void, writeDebugOutput, (JNIEnv*, jobject, jbyteArray bytes, jint offset, jint length)) + while (length > 0) { + jbyte* start = ((typeArrayOop) JNIHandles::resolve(bytes))->byte_at_addr(offset); + tty->write((char*) start, MIN2(length, O_BUFLEN)); + length -= O_BUFLEN; + offset += O_BUFLEN; + } +C2V_END + +C2V_VMENTRY(void, flushDebugOutput, (JNIEnv*, jobject)) + tty->flush(); +C2V_END + + +#define CC (char*) /*cast a literal from (const char*)*/ +#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) + +#define SPECULATION_LOG "Ljdk/internal/jvmci/meta/SpeculationLog;" +#define STRING "Ljava/lang/String;" +#define OBJECT "Ljava/lang/Object;" +#define CLASS "Ljava/lang/Class;" +#define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" +#define INSTALLED_CODE "Ljdk/internal/jvmci/code/InstalledCode;" +#define TARGET_DESCRIPTION "Ljdk/internal/jvmci/code/TargetDescription;" +#define RESOLVED_METHOD "Ljdk/internal/jvmci/meta/ResolvedJavaMethod;" +#define HS_RESOLVED_METHOD "Ljdk/internal/jvmci/hotspot/HotSpotResolvedJavaMethodImpl;" +#define HS_RESOLVED_KLASS "Ljdk/internal/jvmci/hotspot/HotSpotResolvedObjectTypeImpl;" +#define HS_CONSTANT_POOL "Ljdk/internal/jvmci/hotspot/HotSpotConstantPool;" +#define HS_COMPILED_CODE "Ljdk/internal/jvmci/hotspot/HotSpotCompiledCode;" +#define HS_METADATA "Ljdk/internal/jvmci/hotspot/HotSpotMetaData;" +#define HS_STACK_FRAME_REF "Ljdk/internal/jvmci/hotspot/HotSpotStackFrameReference;" +#define METASPACE_METHOD_DATA "J" + +JNINativeMethod CompilerToVM::methods[] = { + {CC"getBytecode", CC"("HS_RESOLVED_METHOD")[B", FN_PTR(getBytecode)}, + {CC"getExceptionTableStart", CC"("HS_RESOLVED_METHOD")J", FN_PTR(getExceptionTableStart)}, + {CC"getExceptionTableLength", CC"("HS_RESOLVED_METHOD")I", FN_PTR(getExceptionTableLength)}, + {CC"hasBalancedMonitors", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(hasBalancedMonitors)}, + {CC"findUniqueConcreteMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD")"HS_RESOLVED_METHOD, FN_PTR(findUniqueConcreteMethod)}, + {CC"getImplementor", CC"("HS_RESOLVED_KLASS")"HS_RESOLVED_KLASS, FN_PTR(getImplementor)}, + {CC"getStackTraceElement", CC"("HS_RESOLVED_METHOD"I)"STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, + {CC"methodIsIgnoredBySecurityStackWalk", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, + {CC"doNotInlineOrCompile", CC"("HS_RESOLVED_METHOD")V", FN_PTR(doNotInlineOrCompile)}, + {CC"canInlineMethod", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(canInlineMethod)}, + {CC"shouldInlineMethod", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(shouldInlineMethod)}, + {CC"lookupType", CC"("STRING CLASS"Z)"HS_RESOLVED_KLASS, FN_PTR(lookupType)}, + {CC"lookupNameRefInPool", CC"("HS_CONSTANT_POOL"I)"STRING, FN_PTR(lookupNameRefInPool)}, + {CC"lookupNameAndTypeRefIndexInPool", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, + {CC"lookupSignatureRefInPool", CC"("HS_CONSTANT_POOL"I)"STRING, FN_PTR(lookupSignatureRefInPool)}, + {CC"lookupKlassRefIndexInPool", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(lookupKlassRefIndexInPool)}, + {CC"lookupKlassInPool", CC"("HS_CONSTANT_POOL"I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)}, + {CC"lookupAppendixInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(lookupAppendixInPool)}, + {CC"lookupMethodInPool", CC"("HS_CONSTANT_POOL"IB)"HS_RESOLVED_METHOD, FN_PTR(lookupMethodInPool)}, + {CC"constantPoolRemapInstructionOperandFromCache", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)}, + {CC"resolveConstantInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolveConstantInPool)}, + {CC"resolvePossiblyCachedConstantInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)}, + {CC"resolveTypeInPool", CC"("HS_CONSTANT_POOL"I)"HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)}, + {CC"resolveFieldInPool", CC"("HS_CONSTANT_POOL"IB[J)"HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)}, + {CC"resolveInvokeDynamicInPool", CC"("HS_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeDynamicInPool)}, + {CC"resolveInvokeHandleInPool", CC"("HS_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeHandleInPool)}, + {CC"resolveMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD HS_RESOLVED_KLASS")"HS_RESOLVED_METHOD, FN_PTR(resolveMethod)}, + {CC"getVtableIndexForInterface", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD")I", FN_PTR(getVtableIndexForInterface)}, + {CC"getClassInitializer", CC"("HS_RESOLVED_KLASS")"HS_RESOLVED_METHOD, FN_PTR(getClassInitializer)}, + {CC"hasFinalizableSubclass", CC"("HS_RESOLVED_KLASS")Z", FN_PTR(hasFinalizableSubclass)}, + {CC"getMaxCallTargetOffset", CC"(J)J", FN_PTR(getMaxCallTargetOffset)}, + {CC"getResolvedJavaMethodAtSlot", CC"("CLASS"I)"HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethodAtSlot)}, + {CC"getResolvedJavaMethod", CC"(Ljava/lang/Object;J)"HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethod)}, + {CC"getConstantPool", CC"(Ljava/lang/Object;J)"HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, + {CC"getResolvedJavaType", CC"(Ljava/lang/Object;JZ)"HS_RESOLVED_KLASS, FN_PTR(getResolvedJavaType)}, + {CC"initializeConfiguration", CC"()J", FN_PTR(initializeConfiguration)}, + {CC"installCode", CC"("TARGET_DESCRIPTION HS_COMPILED_CODE INSTALLED_CODE SPECULATION_LOG")I", FN_PTR(installCode)}, + {CC"getMetadata", CC"("TARGET_DESCRIPTION HS_COMPILED_CODE HS_METADATA")I", FN_PTR(getMetadata)}, + {CC"notifyCompilationStatistics", CC"(I"HS_RESOLVED_METHOD"ZIJJ"INSTALLED_CODE")V", FN_PTR(notifyCompilationStatistics)}, + {CC"resetCompilationStatistics", CC"()V", FN_PTR(resetCompilationStatistics)}, + {CC"disassembleCodeBlob", CC"(J)"STRING, FN_PTR(disassembleCodeBlob)}, + {CC"executeInstalledCode", CC"(["OBJECT INSTALLED_CODE")"OBJECT, FN_PTR(executeInstalledCode)}, + {CC"getLineNumberTable", CC"("HS_RESOLVED_METHOD")[J", FN_PTR(getLineNumberTable)}, + {CC"getLocalVariableTableStart", CC"("HS_RESOLVED_METHOD")J", FN_PTR(getLocalVariableTableStart)}, + {CC"getLocalVariableTableLength", CC"("HS_RESOLVED_METHOD")I", FN_PTR(getLocalVariableTableLength)}, + {CC"reprofile", CC"("HS_RESOLVED_METHOD")V", FN_PTR(reprofile)}, + {CC"invalidateInstalledCode", CC"("INSTALLED_CODE")V", FN_PTR(invalidateInstalledCode)}, + {CC"readUncompressedOop", CC"(J)"OBJECT, FN_PTR(readUncompressedOop)}, + {CC"collectCounters", CC"()[J", FN_PTR(collectCounters)}, + {CC"allocateCompileId", CC"("HS_RESOLVED_METHOD"I)I", FN_PTR(allocateCompileId)}, + {CC"isMature", CC"("METASPACE_METHOD_DATA")Z", FN_PTR(isMature)}, + {CC"hasCompiledCodeForOSR", CC"("HS_RESOLVED_METHOD"II)Z", FN_PTR(hasCompiledCodeForOSR)}, + {CC"getSymbol", CC"(J)"STRING, FN_PTR(getSymbol)}, + {CC"getNextStackFrame", CC"("HS_STACK_FRAME_REF "["HS_RESOLVED_METHOD"I)"HS_STACK_FRAME_REF, FN_PTR(getNextStackFrame)}, + {CC"materializeVirtualObjects", CC"("HS_STACK_FRAME_REF"Z)V", FN_PTR(materializeVirtualObjects)}, + {CC"shouldDebugNonSafepoints", CC"()Z", FN_PTR(shouldDebugNonSafepoints)}, + {CC"writeDebugOutput", CC"([BII)V", FN_PTR(writeDebugOutput)}, + {CC"flushDebugOutput", CC"()V", FN_PTR(flushDebugOutput)}, +}; + +int CompilerToVM::methods_count() { + return sizeof(methods) / sizeof(JNINativeMethod); +} + --- /dev/null 2015-09-16 15:21:27.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciCompilerToVM.hpp 2015-09-16 15:21:26.000000000 -0700 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2011, 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP +#define SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP + +#include "prims/jni.h" +#include "runtime/javaCalls.hpp" +#include "jvmci/jvmciJavaClasses.hpp" + +class CompilerToVM { +public: + /** + * Tag bits used by lookupKlassInPool to distinguish the types in Java. + */ + enum Tags { + KLASS_TAG = 0x0, + SYMBOL_TAG = 0x1 + }; + + // FIXME This is only temporary until the GC code is changed. + static bool _supports_inline_contig_alloc; + static HeapWord** _heap_end_addr; + static HeapWord** _heap_top_addr; + + static intptr_t tag_pointer(Klass* klass) { + return ((intptr_t) klass) | KLASS_TAG; + } + + static intptr_t tag_pointer(Symbol* symbol) { + return ((intptr_t) symbol) | SYMBOL_TAG; + } + + static JNINativeMethod methods[]; + static int methods_count(); + + static inline Method* asMethod(jobject jvmci_method) { + return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); + } + + static inline Method* asMethod(Handle jvmci_method) { + return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); + } + + static inline Method* asMethod(oop jvmci_method) { + return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); + } + + static inline ConstantPool* asConstantPool(jobject jvmci_constant_pool) { + return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); + } + + static inline ConstantPool* asConstantPool(Handle jvmci_constant_pool) { + return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); + } + + static inline ConstantPool* asConstantPool(oop jvmci_constant_pool) { + return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); + } + + static inline Klass* asKlass(jobject jvmci_type) { + return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); + } + + static inline Klass* asKlass(Handle jvmci_type) { + return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); + } + + static inline Klass* asKlass(oop jvmci_type) { + return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); + } + + static inline MethodData* asMethodData(jlong metaspaceMethodData) { + return (MethodData*) (address) metaspaceMethodData; + } + + static oop get_jvmci_method(methodHandle method, TRAPS); + + static oop get_jvmci_type(KlassHandle klass, TRAPS); +}; + +class JavaArgumentUnboxer : public SignatureIterator { + protected: + JavaCallArguments* _jca; + arrayOop _args; + int _index; + + oop next_arg(BasicType expectedType) { + assert(_index < _args->length(), "out of bounds"); + oop arg=((objArrayOop) (_args))->obj_at(_index++); + assert(expectedType == T_OBJECT || java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch"); + return arg; + } + + public: + JavaArgumentUnboxer(Symbol* signature, JavaCallArguments* jca, arrayOop args, bool is_static) : SignatureIterator(signature) { + this->_return_type = T_ILLEGAL; + _jca = jca; + _index = 0; + _args = args; + if (!is_static) { + _jca->push_oop(next_arg(T_OBJECT)); + } + iterate(); + assert(_index == args->length(), "arg count mismatch with signature"); + } + + inline void do_bool() { if (!is_return_type()) _jca->push_int(next_arg(T_BOOLEAN)->bool_field(java_lang_boxing_object::value_offset_in_bytes(T_BOOLEAN))); } + inline void do_char() { if (!is_return_type()) _jca->push_int(next_arg(T_CHAR)->char_field(java_lang_boxing_object::value_offset_in_bytes(T_CHAR))); } + inline void do_short() { if (!is_return_type()) _jca->push_int(next_arg(T_SHORT)->short_field(java_lang_boxing_object::value_offset_in_bytes(T_SHORT))); } + inline void do_byte() { if (!is_return_type()) _jca->push_int(next_arg(T_BYTE)->byte_field(java_lang_boxing_object::value_offset_in_bytes(T_BYTE))); } + inline void do_int() { if (!is_return_type()) _jca->push_int(next_arg(T_INT)->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT))); } + + inline void do_long() { if (!is_return_type()) _jca->push_long(next_arg(T_LONG)->long_field(java_lang_boxing_object::value_offset_in_bytes(T_LONG))); } + inline void do_float() { if (!is_return_type()) _jca->push_float(next_arg(T_FLOAT)->float_field(java_lang_boxing_object::value_offset_in_bytes(T_FLOAT))); } + inline void do_double() { if (!is_return_type()) _jca->push_double(next_arg(T_DOUBLE)->double_field(java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE))); } + + inline void do_object() { _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_object(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_array(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_void() { } +}; + +#endif // SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP --- /dev/null 2015-09-16 15:21:27.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciEnv.cpp 2015-09-16 15:21:27.000000000 -0700 @@ -0,0 +1,595 @@ +/* + * Copyright (c) 1999, 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "classfile/javaAssertions.hpp" +#include "classfile/systemDictionary.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/codeCache.hpp" +#include "code/scopeDesc.hpp" +#include "runtime/sweeper.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/compileLog.hpp" +#include "compiler/compilerOracle.hpp" +#include "interpreter/linkResolver.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/oopFactory.hpp" +#include "memory/universe.inline.hpp" +#include "oops/methodData.hpp" +#include "oops/objArrayKlass.hpp" +#include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "runtime/init.hpp" +#include "runtime/reflection.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/dtrace.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciJavaClasses.hpp" + +JVMCIEnv::JVMCIEnv(CompileTask* task, int system_dictionary_modification_counter) { + _task = task; + _system_dictionary_modification_counter = system_dictionary_modification_counter; + { + // Get Jvmti capabilities under lock to get consistent values. + MutexLocker mu(JvmtiThreadState_lock); + _jvmti_can_hotswap_or_post_breakpoint = JvmtiExport::can_hotswap_or_post_breakpoint(); + _jvmti_can_access_local_variables = JvmtiExport::can_access_local_variables(); + _jvmti_can_post_on_exceptions = JvmtiExport::can_post_on_exceptions(); + } +} + +// ------------------------------------------------------------------ +// Note: the logic of this method should mirror the logic of +// constantPoolOopDesc::verify_constant_pool_resolve. +bool JVMCIEnv::check_klass_accessibility(KlassHandle accessing_klass, KlassHandle resolved_klass) { + if (accessing_klass->oop_is_objArray()) { + accessing_klass = ObjArrayKlass::cast(accessing_klass())->bottom_klass(); + } + if (!accessing_klass->oop_is_instance()) { + return true; + } + + if (resolved_klass->oop_is_objArray()) { + // Find the element klass, if this is an array. + resolved_klass = ObjArrayKlass::cast(resolved_klass())->bottom_klass(); + } + if (resolved_klass->oop_is_instance()) { + return Reflection::verify_class_access(accessing_klass(), resolved_klass(), true); + } + return true; +} + +// ------------------------------------------------------------------ +KlassHandle JVMCIEnv::get_klass_by_name_impl(KlassHandle& accessing_klass, + constantPoolHandle& cpool, + Symbol* sym, + bool require_local) { + JVMCI_EXCEPTION_CONTEXT; + + // Now we need to check the SystemDictionary + if (sym->byte_at(0) == 'L' && + sym->byte_at(sym->utf8_length()-1) == ';') { + // This is a name from a signature. Strip off the trimmings. + // Call recursive to keep scope of strippedsym. + TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1, + sym->utf8_length()-2, + CHECK_(KlassHandle())); + return get_klass_by_name_impl(accessing_klass, cpool, strippedsym, require_local); + } + + Handle loader(THREAD, (oop)NULL); + Handle domain(THREAD, (oop)NULL); + if (!accessing_klass.is_null()) { + loader = Handle(THREAD, accessing_klass->class_loader()); + domain = Handle(THREAD, accessing_klass->protection_domain()); + } + + KlassHandle found_klass; + { + ttyUnlocker ttyul; // release tty lock to avoid ordering problems + MutexLocker ml(Compile_lock); + Klass* kls; + if (!require_local) { + kls = SystemDictionary::find_constrained_instance_or_array_klass(sym, loader, CHECK_(KlassHandle())); + } else { + kls = SystemDictionary::find_instance_or_array_klass(sym, loader, domain, CHECK_(KlassHandle())); + } + found_klass = KlassHandle(THREAD, kls); + } + + // If we fail to find an array klass, look again for its element type. + // The element type may be available either locally or via constraints. + // In either case, if we can find the element type in the system dictionary, + // we must build an array type around it. The CI requires array klasses + // to be loaded if their element klasses are loaded, except when memory + // is exhausted. + if (sym->byte_at(0) == '[' && + (sym->byte_at(1) == '[' || sym->byte_at(1) == 'L')) { + // We have an unloaded array. + // Build it on the fly if the element class exists. + TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1, + sym->utf8_length()-1, + CHECK_(KlassHandle())); + + // Get element Klass recursively. + KlassHandle elem_klass = + get_klass_by_name_impl(accessing_klass, + cpool, + elem_sym, + require_local); + if (!elem_klass.is_null()) { + // Now make an array for it + return elem_klass->array_klass(CHECK_(KlassHandle())); + } + } + + if (found_klass.is_null() && !cpool.is_null() && cpool->has_preresolution()) { + // Look inside the constant pool for pre-resolved class entries. + for (int i = cpool->length() - 1; i >= 1; i--) { + if (cpool->tag_at(i).is_klass()) { + Klass* kls = cpool->resolved_klass_at(i); + if (kls->name() == sym) { + return kls; + } + } + } + } + + return found_klass(); +} + +// ------------------------------------------------------------------ +KlassHandle JVMCIEnv::get_klass_by_name(KlassHandle& accessing_klass, + Symbol* klass_name, + bool require_local) { + ResourceMark rm; + constantPoolHandle cpool; + return get_klass_by_name_impl(accessing_klass, + cpool, + klass_name, + require_local); +} + +// ------------------------------------------------------------------ +// Implementation of get_klass_by_index. +KlassHandle JVMCIEnv::get_klass_by_index_impl(constantPoolHandle& cpool, + int index, + bool& is_accessible, + KlassHandle& accessor) { + JVMCI_EXCEPTION_CONTEXT; + KlassHandle klass (THREAD, ConstantPool::klass_at_if_loaded(cpool, index)); + Symbol* klass_name = NULL; + if (klass.is_null()) { + klass_name = cpool->klass_name_at(index); + } + + if (klass.is_null()) { + // Not found in constant pool. Use the name to do the lookup. + KlassHandle k = get_klass_by_name_impl(accessor, + cpool, + klass_name, + false); + // Calculate accessibility the hard way. + if (k.is_null()) { + is_accessible = false; + } else if (k->class_loader() != accessor->class_loader() && + get_klass_by_name_impl(accessor, cpool, k->name(), true).is_null()) { + // Loaded only remotely. Not linked yet. + is_accessible = false; + } else { + // Linked locally, and we must also check public/private, etc. + is_accessible = check_klass_accessibility(accessor, k); + } + if (!is_accessible) { + return KlassHandle(); + } + return k; + } + + // It is known to be accessible, since it was found in the constant pool. + is_accessible = true; + return klass; +} + +// ------------------------------------------------------------------ +// Get a klass from the constant pool. +KlassHandle JVMCIEnv::get_klass_by_index(constantPoolHandle& cpool, + int index, + bool& is_accessible, + KlassHandle& accessor) { + ResourceMark rm; + KlassHandle result = get_klass_by_index_impl(cpool, index, is_accessible, accessor); + return result; +} + +// ------------------------------------------------------------------ +// Implementation of get_field_by_index. +// +// Implementation note: the results of field lookups are cached +// in the accessor klass. +void JVMCIEnv::get_field_by_index_impl(instanceKlassHandle& klass, fieldDescriptor& field_desc, + int index) { + JVMCI_EXCEPTION_CONTEXT; + + assert(klass->is_linked(), "must be linked before using its constant-pool"); + + constantPoolHandle cpool(thread, klass->constants()); + + // Get the field's name, signature, and type. + Symbol* name = cpool->name_ref_at(index); + + int nt_index = cpool->name_and_type_ref_index_at(index); + int sig_index = cpool->signature_ref_index_at(nt_index); + Symbol* signature = cpool->symbol_at(sig_index); + + // Get the field's declared holder. + int holder_index = cpool->klass_ref_index_at(index); + bool holder_is_accessible; + KlassHandle declared_holder = get_klass_by_index(cpool, holder_index, + holder_is_accessible, + klass); + + // The declared holder of this field may not have been loaded. + // Bail out with partial field information. + if (!holder_is_accessible) { + return; + } + + + // Perform the field lookup. + Klass* canonical_holder = + InstanceKlass::cast(declared_holder())->find_field(name, signature, &field_desc); + if (canonical_holder == NULL) { + return; + } + + assert(canonical_holder == field_desc.field_holder(), "just checking"); +} + +// ------------------------------------------------------------------ +// Get a field by index from a klass's constant pool. +void JVMCIEnv::get_field_by_index(instanceKlassHandle& accessor, fieldDescriptor& fd, int index) { + ResourceMark rm; + return get_field_by_index_impl(accessor, fd, index); +} + +// ------------------------------------------------------------------ +// Perform an appropriate method lookup based on accessor, holder, +// name, signature, and bytecode. +methodHandle JVMCIEnv::lookup_method(instanceKlassHandle& h_accessor, + instanceKlassHandle& h_holder, + Symbol* name, + Symbol* sig, + Bytecodes::Code bc) { + JVMCI_EXCEPTION_CONTEXT; + LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); + methodHandle dest_method; + LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); + switch (bc) { + case Bytecodes::_invokestatic: + dest_method = + LinkResolver::resolve_static_call_or_null(link_info); + break; + case Bytecodes::_invokespecial: + dest_method = + LinkResolver::resolve_special_call_or_null(link_info); + break; + case Bytecodes::_invokeinterface: + dest_method = + LinkResolver::linktime_resolve_interface_method_or_null(link_info); + break; + case Bytecodes::_invokevirtual: + dest_method = + LinkResolver::linktime_resolve_virtual_method_or_null(link_info); + break; + default: ShouldNotReachHere(); + } + + return dest_method; +} + + +// ------------------------------------------------------------------ +methodHandle JVMCIEnv::get_method_by_index_impl(constantPoolHandle& cpool, + int index, Bytecodes::Code bc, + instanceKlassHandle& accessor) { + if (bc == Bytecodes::_invokedynamic) { + ConstantPoolCacheEntry* cpce = cpool->invokedynamic_cp_cache_entry_at(index); + bool is_resolved = !cpce->is_f1_null(); + if (is_resolved) { + // Get the invoker Method* from the constant pool. + // (The appendix argument, if any, will be noted in the method's signature.) + Method* adapter = cpce->f1_as_method(); + return methodHandle(adapter); + } + + return NULL; + } + + int holder_index = cpool->klass_ref_index_at(index); + bool holder_is_accessible; + KlassHandle holder = get_klass_by_index_impl(cpool, holder_index, holder_is_accessible, accessor); + + // Get the method's name and signature. + Symbol* name_sym = cpool->name_ref_at(index); + Symbol* sig_sym = cpool->signature_ref_at(index); + + if (cpool->has_preresolution() + || (holder() == SystemDictionary::MethodHandle_klass() && + MethodHandles::is_signature_polymorphic_name(holder(), name_sym))) { + // Short-circuit lookups for JSR 292-related call sites. + // That is, do not rely only on name-based lookups, because they may fail + // if the names are not resolvable in the boot class loader (7056328). + switch (bc) { + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + { + Method* m = ConstantPool::method_at_if_loaded(cpool, index); + if (m != NULL) { + return m; + } + } + break; + } + } + + if (holder_is_accessible) { // Our declared holder is loaded. + instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder); + methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc); + if (!m.is_null() && + (bc == Bytecodes::_invokestatic + ? InstanceKlass::cast(m->method_holder())->is_not_initialized() + : !InstanceKlass::cast(m->method_holder())->is_loaded())) { + m = NULL; + } + if (!m.is_null()) { + // We found the method. + return m; + } + } + + // Either the declared holder was not loaded, or the method could + // not be found. + + return NULL; +} + +// ------------------------------------------------------------------ +instanceKlassHandle JVMCIEnv::get_instance_klass_for_declared_method_holder(KlassHandle& method_holder) { + // For the case of .clone(), the method holder can be an ArrayKlass* + // instead of an InstanceKlass*. For that case simply pretend that the + // declared holder is Object.clone since that's where the call will bottom out. + if (method_holder->oop_is_instance()) { + return instanceKlassHandle(method_holder()); + } else if (method_holder->oop_is_array()) { + return instanceKlassHandle(SystemDictionary::Object_klass()); + } else { + ShouldNotReachHere(); + } + return NULL; +} + + +// ------------------------------------------------------------------ +methodHandle JVMCIEnv::get_method_by_index(constantPoolHandle& cpool, + int index, Bytecodes::Code bc, + instanceKlassHandle& accessor) { + ResourceMark rm; + return get_method_by_index_impl(cpool, index, bc, accessor); +} + +// ------------------------------------------------------------------ +// Check for changes to the system dictionary during compilation +// class loads, evolution, breakpoints +JVMCIEnv::CodeInstallResult JVMCIEnv::check_for_system_dictionary_modification(Dependencies* dependencies, Handle compiled_code, + JVMCIEnv* env, char** failure_detail) { + // If JVMTI capabilities were enabled during compile, the compilation is invalidated. + if (env != NULL) { + if (!env->_jvmti_can_hotswap_or_post_breakpoint && JvmtiExport::can_hotswap_or_post_breakpoint()) { + *failure_detail = (char*) "Hotswapping or breakpointing was enabled during compilation"; + return JVMCIEnv::dependencies_failed; + } + } + + // Dependencies must be checked when the system dictionary changes + // or if we don't know whether it has changed (i.e., env == NULL). + // In debug mode, always check dependencies. + bool counter_changed = env != NULL && env->_system_dictionary_modification_counter != SystemDictionary::number_of_modifications(); + bool verify_deps = env == NULL || trueInDebug || JavaAssertions::enabled(SystemDictionary::HotSpotInstalledCode_klass()->name()->as_C_string(), true); + if (!counter_changed && !verify_deps) { + return JVMCIEnv::ok; + } + + for (Dependencies::DepStream deps(dependencies); deps.next(); ) { + Klass* witness = deps.check_dependency(); + if (witness != NULL) { + // Use a fixed size buffer to prevent the string stream from + // resizing in the context of an inner resource mark. + char* buffer = NEW_RESOURCE_ARRAY(char, O_BUFLEN); + stringStream st(buffer, O_BUFLEN); + deps.print_dependency(witness, true, &st); + *failure_detail = st.as_string(); + if (env == NULL || counter_changed) { + return JVMCIEnv::dependencies_failed; + } else { + // The dependencies were invalid at the time of installation + // without any intervening modification of the system + // dictionary. That means they were invalidly constructed. + return JVMCIEnv::dependencies_invalid; + } + } + if (LogCompilation) { + deps.log_dependency(); + } + } + + return JVMCIEnv::ok; +} + +// ------------------------------------------------------------------ +JVMCIEnv::CodeInstallResult JVMCIEnv::register_method( + methodHandle& method, + nmethod*& nm, + int entry_bci, + CodeOffsets* offsets, + int orig_pc_offset, + CodeBuffer* code_buffer, + int frame_words, + OopMapSet* oop_map_set, + ExceptionHandlerTable* handler_table, + AbstractCompiler* compiler, + DebugInformationRecorder* debug_info, + Dependencies* dependencies, + JVMCIEnv* env, + int compile_id, + bool has_unsafe_access, + bool has_wide_vector, + Handle installed_code, + Handle compiled_code, + Handle speculation_log) { + JVMCI_EXCEPTION_CONTEXT; + nm = NULL; + int comp_level = CompLevel_full_optimization; + char* failure_detail = NULL; + JVMCIEnv::CodeInstallResult result; + { + // To prevent compile queue updates. + MutexLocker locker(MethodCompileQueue_lock, THREAD); + + // Prevent SystemDictionary::add_to_hierarchy from running + // and invalidating our dependencies until we install this method. + MutexLocker ml(Compile_lock); + + // Encode the dependencies now, so we can check them right away. + dependencies->encode_content_bytes(); + + // Check for {class loads, evolution, breakpoints} during compilation + result = check_for_system_dictionary_modification(dependencies, compiled_code, env, &failure_detail); + if (result != JVMCIEnv::ok) { + // While not a true deoptimization, it is a preemptive decompile. + MethodData* mdp = method()->method_data(); + if (mdp != NULL) { + mdp->inc_decompile_count(); + if (mdp->decompile_count() > (uint)PerMethodRecompilationCutoff) { + // TODO (chaeubl) enable this in the fastdebug build only once we are more stable + ResourceMark m; + tty->print_cr("WARN: endless recompilation of %s. Method was set to not compilable.", method()->name_and_sig_as_C_string()); + //ShouldNotReachHere(); + } + } + + // All buffers in the CodeBuffer are allocated in the CodeCache. + // If the code buffer is created on each compile attempt + // as in C2, then it must be freed. + //code_buffer->free_blob(); + } else { + ImplicitExceptionTable implicit_tbl; + nm = nmethod::new_nmethod(method, + compile_id, + entry_bci, + offsets, + orig_pc_offset, + debug_info, dependencies, code_buffer, + frame_words, oop_map_set, + handler_table, &implicit_tbl, + compiler, comp_level, installed_code, speculation_log); + + // Free codeBlobs + //code_buffer->free_blob(); + if (nm == NULL) { + // The CodeCache is full. Print out warning and disable compilation. + { + MutexUnlocker ml(Compile_lock); + MutexUnlocker locker(MethodCompileQueue_lock); + CompileBroker::handle_full_code_cache(CodeCache::get_code_blob_type(comp_level)); + } + } else { + nm->set_has_unsafe_access(has_unsafe_access); + nm->set_has_wide_vectors(has_wide_vector); + + // Record successful registration. + // (Put nm into the task handle *before* publishing to the Java heap.) + CompileTask* task = env == NULL ? NULL : env->task(); + if (task != NULL) task->set_code(nm); + + if (installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(installed_code())) { + if (entry_bci == InvocationEntryBci) { + if (TieredCompilation) { + // If there is an old version we're done with it + nmethod* old = method->code(); + if (TraceMethodReplacement && old != NULL) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + tty->print_cr("Replacing method %s", method_name); + } + if (old != NULL ) { + old->make_not_entrant(); + } + } + if (TraceNMethodInstalls) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + ttyLocker ttyl; + tty->print_cr("Installing method (%d) %s [entry point: %p]", + comp_level, + method_name, nm->entry_point()); + } + // Allow the code to be executed + method->set_code(method, nm); + } else { + if (TraceNMethodInstalls ) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + ttyLocker ttyl; + tty->print_cr("Installing osr method (%d) %s @ %d", + comp_level, + method_name, + entry_bci); + } + InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm); + } + } + } + result = nm != NULL ? JVMCIEnv::ok :JVMCIEnv::cache_full; + } + } + + // String creation must be done outside lock + if (failure_detail != NULL) { + // A failure to allocate the string is silently ignored. + Handle message = java_lang_String::create_from_str(failure_detail, THREAD); + HotSpotCompiledNmethod::set_installationFailureMessage(compiled_code, message()); + } + + // JVMTI -- compiled method notification (must be done outside lock) + if (nm != NULL) { + nm->post_compiled_method_load_event(); + } + + return result; +} + --- /dev/null 2015-09-16 15:21:28.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciEnv.hpp 2015-09-16 15:21:28.000000000 -0700 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1999, 2011, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_JVMCIENV_HPP +#define SHARE_VM_JVMCI_JVMCIENV_HPP + +#include "classfile/systemDictionary.hpp" +#include "code/debugInfoRec.hpp" +#include "code/dependencies.hpp" +#include "code/exceptionHandlerTable.hpp" +#include "compiler/oopMap.hpp" +#include "runtime/thread.hpp" + +class CompileTask; + +// Bring the JVMCI compiler thread into the VM state. +#define JVMCI_VM_ENTRY_MARK \ + JavaThread* thread = JavaThread::current(); \ + ThreadInVMfromNative __tiv(thread); \ + ResetNoHandleMark rnhm; \ + HandleMarkCleaner __hm(thread); \ + Thread* THREAD = thread; \ + debug_only(VMNativeEntryWrapper __vew;) + +#define JVMCI_EXCEPTION_CONTEXT \ + JavaThread* thread=JavaThread::current(); \ + Thread* THREAD = thread; + +// +// This class is the top level broker for requests from the compiler +// to the VM. +class JVMCIEnv : StackObj { + CI_PACKAGE_ACCESS_TO + + friend class CompileBroker; + friend class Dependencies; // for get_object, during logging + +public: + + enum CodeInstallResult { + ok, + dependencies_failed, + dependencies_invalid, + cache_full, + code_too_large + }; + + // Look up a klass by name from a particular class loader (the accessor's). + // If require_local, result must be defined in that class loader, or NULL. + // If !require_local, a result from remote class loader may be reported, + // if sufficient class loader constraints exist such that initiating + // a class loading request from the given loader is bound to return + // the class defined in the remote loader (or throw an error). + // + // Return an unloaded klass if !require_local and no class at all is found. + // + // The CI treats a klass as loaded if it is consistently defined in + // another loader, even if it hasn't yet been loaded in all loaders + // that could potentially see it via delegation. + static KlassHandle get_klass_by_name(KlassHandle& accessing_klass, + Symbol* klass_name, + bool require_local); + + // Constant pool access. + static KlassHandle get_klass_by_index(constantPoolHandle& cpool, + int klass_index, + bool& is_accessible, + KlassHandle& loading_klass); + static void get_field_by_index(instanceKlassHandle& loading_klass, fieldDescriptor& fd, + int field_index); + static methodHandle get_method_by_index(constantPoolHandle& cpool, + int method_index, Bytecodes::Code bc, + instanceKlassHandle& loading_klass); + + JVMCIEnv(CompileTask* task, int system_dictionary_modification_counter); + +private: + CompileTask* _task; + int _system_dictionary_modification_counter; + + // Cache JVMTI state + bool _jvmti_can_hotswap_or_post_breakpoint; + bool _jvmti_can_access_local_variables; + bool _jvmti_can_post_on_exceptions; + + // Implementation methods for loading and constant pool access. + static KlassHandle get_klass_by_name_impl(KlassHandle& accessing_klass, + constantPoolHandle& cpool, + Symbol* klass_name, + bool require_local); + static KlassHandle get_klass_by_index_impl(constantPoolHandle& cpool, + int klass_index, + bool& is_accessible, + KlassHandle& loading_klass); + static void get_field_by_index_impl(instanceKlassHandle& loading_klass, fieldDescriptor& fd, + int field_index); + static methodHandle get_method_by_index_impl(constantPoolHandle& cpool, + int method_index, Bytecodes::Code bc, + instanceKlassHandle& loading_klass); + + // Helper methods + static bool check_klass_accessibility(KlassHandle accessing_klass, KlassHandle resolved_klass); + static methodHandle lookup_method(instanceKlassHandle& accessor, + instanceKlassHandle& holder, + Symbol* name, + Symbol* sig, + Bytecodes::Code bc); + + private: + + // Is this thread currently in the VM state? + static bool is_in_vm(); + + // Helper routine for determining the validity of a compilation + // with respect to concurrent class loading. + static JVMCIEnv::CodeInstallResult check_for_system_dictionary_modification(Dependencies* target, Handle compiled_code, + JVMCIEnv* env, char** failure_detail); + +public: + CompileTask* task() { return _task; } + + // Register the result of a compilation. + static JVMCIEnv::CodeInstallResult register_method( + methodHandle& target, + nmethod*& nm, + int entry_bci, + CodeOffsets* offsets, + int orig_pc_offset, + CodeBuffer* code_buffer, + int frame_words, + OopMapSet* oop_map_set, + ExceptionHandlerTable* handler_table, + AbstractCompiler* compiler, + DebugInformationRecorder* debug_info, + Dependencies* dependencies, + JVMCIEnv* env, + int compile_id, + bool has_unsafe_access, + bool has_wide_vector, + Handle installed_code, + Handle compiled_code, + Handle speculation_log); + + // converts the Klass* representing the holder of a method into a + // InstanceKlass*. This is needed since the holder of a method in + // the bytecodes could be an array type. Basically this converts + // array types into java/lang/Object and other types stay as they are. + static instanceKlassHandle get_instance_klass_for_declared_method_holder(KlassHandle& klass); +}; + +#endif // SHARE_VM_JVMCI_JVMCIENV_HPP --- /dev/null 2015-09-16 15:21:28.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciJavaClasses.cpp 2015-09-16 15:21:28.000000000 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "runtime/jniHandles.hpp" +#include "classfile/symbolTable.hpp" +#include "memory/resourceArea.hpp" + +// This function is similar to javaClasses.cpp, it computes the field offset of a (static or instance) field. +// It looks up the name and signature symbols without creating new ones, all the symbols of these classes need to be already loaded. + +void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field) { + InstanceKlass* ik = InstanceKlass::cast(klass); + Symbol* name_symbol = SymbolTable::probe(name, (int)strlen(name)); + Symbol* signature_symbol = SymbolTable::probe(signature, (int)strlen(signature)); + if (name_symbol == NULL || signature_symbol == NULL) { +#ifndef PRODUCT + ik->print_on(tty); +#endif + fatal(err_msg("symbol with name %s and signature %s was not found in symbol table (klass=%s)", name, signature, klass->name()->as_C_string())); + } + + fieldDescriptor fd; + if (!ik->find_field(name_symbol, signature_symbol, &fd)) { + ResourceMark rm; + fatal(err_msg("Invalid layout of %s at %s", name_symbol->as_C_string(), ik->external_name())); + } + guarantee(fd.is_static() == static_field, "static/instance mismatch"); + dest_offset = fd.offset(); + assert(dest_offset != 0, "must be valid offset"); +} + +// This piece of macro magic creates the contents of the jvmci_compute_offsets method that initializes the field indices of all the access classes. + +#define START_CLASS(name) { Klass* k = SystemDictionary::name##_klass(); assert(k != NULL, "Could not find class " #name ""); + +#define END_CLASS } + +#define FIELD(klass, name, signature, static_field) compute_offset(klass::_##name##_offset, k, #name, signature, static_field); +#define CHAR_FIELD(klass, name) FIELD(klass, name, "C", false) +#define INT_FIELD(klass, name) FIELD(klass, name, "I", false) +#define BOOLEAN_FIELD(klass, name) FIELD(klass, name, "Z", false) +#define LONG_FIELD(klass, name) FIELD(klass, name, "J", false) +#define FLOAT_FIELD(klass, name) FIELD(klass, name, "F", false) +#define OOP_FIELD(klass, name, signature) FIELD(klass, name, signature, false) +#define STATIC_OOP_FIELD(klass, name, signature) FIELD(klass, name, signature, true) +#define STATIC_INT_FIELD(klass, name) FIELD(klass, name, "I", true) +#define STATIC_BOOLEAN_FIELD(klass, name) FIELD(klass, name, "Z", true) + + +void JVMCIJavaClasses::compute_offsets() { + COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, OOP_FIELD, OOP_FIELD, STATIC_OOP_FIELD, STATIC_OOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD) + guarantee(InstalledCode::_address_offset == sizeof(oopDesc), "codeBlob must be first field!"); +} + +#define EMPTY0 +#define EMPTY1(x) +#define EMPTY2(x,y) +#define FIELD2(klass, name) int klass::_##name##_offset = 0; +#define FIELD3(klass, name, sig) FIELD2(klass, name) + +COMPILER_CLASSES_DO(EMPTY1, EMPTY0, FIELD2, FIELD2, FIELD2, FIELD2, FIELD2, FIELD3, FIELD3, FIELD3, FIELD3, FIELD3, FIELD2, FIELD2) + + + + + --- /dev/null 2015-09-16 15:21:29.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciJavaClasses.hpp 2015-09-16 15:21:29.000000000 -0700 @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCIJAVACLASSES_HPP +#define SHARE_VM_JVMCI_JVMCIJAVACLASSES_HPP + +#include "classfile/systemDictionary.hpp" +#include "oops/instanceMirrorKlass.hpp" + +class JVMCIJavaClasses : AllStatic { + public: + static void compute_offsets(); +}; + +/* This macro defines the structure of the CompilationResult - classes. + * It will generate classes with accessors similar to javaClasses.hpp, but with specializations for oops, Handles and jni handles. + * + * The public interface of these classes will look like this: + + * class StackSlot : AllStatic { + * public: + * static Klass* klass(); + * static jint index(oop obj); + * static jint index(Handle obj); + * static jint index(jobject obj); + * static void set_index(oop obj, jint x); + * static void set_index(Handle obj, jint x); + * static void set_index(jobject obj, jint x); + * }; + * + */ + +#define COMPILER_CLASSES_DO(start_class, end_class, char_field, int_field, boolean_field, long_field, float_field, oop_field, typeArrayOop_field, objArrayOop_field, static_oop_field, static_objArrayOop_field, static_int_field, static_boolean_field) \ + start_class(Architecture) \ + oop_field(Architecture, wordKind, "Ljdk/internal/jvmci/meta/PlatformKind;") \ + end_class \ + start_class(TargetDescription) \ + oop_field(TargetDescription, arch, "Ljdk/internal/jvmci/code/Architecture;") \ + end_class \ + start_class(HotSpotResolvedObjectTypeImpl) \ + oop_field(HotSpotResolvedObjectTypeImpl, javaClass, "Ljava/lang/Class;") \ + end_class \ + start_class(HotSpotResolvedJavaMethodImpl) \ + long_field(HotSpotResolvedJavaMethodImpl, metaspaceMethod) \ + end_class \ + start_class(InstalledCode) \ + long_field(InstalledCode, address) \ + long_field(InstalledCode, version) \ + oop_field(InstalledCode, name, "Ljava/lang/String;") \ + end_class \ + start_class(HotSpotInstalledCode) \ + int_field(HotSpotInstalledCode, size) \ + long_field(HotSpotInstalledCode, codeStart) \ + int_field(HotSpotInstalledCode, codeSize) \ + end_class \ + start_class(HotSpotNmethod) \ + boolean_field(HotSpotNmethod, isDefault) \ + end_class \ + start_class(HotSpotCompiledCode) \ + oop_field(HotSpotCompiledCode, name, "Ljava/lang/String;") \ + objArrayOop_field(HotSpotCompiledCode, sites, "[Ljdk/internal/jvmci/code/CompilationResult$Site;") \ + objArrayOop_field(HotSpotCompiledCode, exceptionHandlers, "[Ljdk/internal/jvmci/code/CompilationResult$ExceptionHandler;") \ + objArrayOop_field(HotSpotCompiledCode, comments, "[Ljdk/internal/jvmci/hotspot/HotSpotCompiledCode$Comment;") \ + objArrayOop_field(HotSpotCompiledCode, assumptions, "[Ljdk/internal/jvmci/meta/Assumptions$Assumption;") \ + typeArrayOop_field(HotSpotCompiledCode, targetCode, "[B") \ + int_field(HotSpotCompiledCode, targetCodeSize) \ + typeArrayOop_field(HotSpotCompiledCode, dataSection, "[B") \ + int_field(HotSpotCompiledCode, dataSectionAlignment) \ + objArrayOop_field(HotSpotCompiledCode, dataSectionPatches, "[Ljdk/internal/jvmci/code/CompilationResult$DataPatch;") \ + boolean_field(HotSpotCompiledCode, isImmutablePIC) \ + int_field(HotSpotCompiledCode, totalFrameSize) \ + int_field(HotSpotCompiledCode, customStackAreaOffset) \ + objArrayOop_field(HotSpotCompiledCode, methods, "[Ljdk/internal/jvmci/meta/ResolvedJavaMethod;") \ + end_class \ + start_class(HotSpotCompiledCode_Comment) \ + oop_field(HotSpotCompiledCode_Comment, text, "Ljava/lang/String;") \ + int_field(HotSpotCompiledCode_Comment, pcOffset) \ + end_class \ + start_class(HotSpotCompiledNmethod) \ + oop_field(HotSpotCompiledNmethod, method, "Ljdk/internal/jvmci/hotspot/HotSpotResolvedJavaMethod;") \ + oop_field(HotSpotCompiledNmethod, installationFailureMessage, "Ljava/lang/String;") \ + int_field(HotSpotCompiledNmethod, entryBCI) \ + int_field(HotSpotCompiledNmethod, id) \ + long_field(HotSpotCompiledNmethod, jvmciEnv) \ + boolean_field(HotSpotCompiledNmethod, hasUnsafeAccess) \ + end_class \ + start_class(HotSpotJVMCIMetaAccessContext) \ + static_objArrayOop_field(HotSpotJVMCIMetaAccessContext, allContexts, "[Ljava/lang/ref/WeakReference;") \ + objArrayOop_field(HotSpotJVMCIMetaAccessContext, metadataRoots, "[Ljava/lang/Object;") \ + end_class \ + start_class(HotSpotForeignCallTarget) \ + long_field(HotSpotForeignCallTarget, address) \ + end_class \ + start_class(Assumptions_NoFinalizableSubclass) \ + oop_field(Assumptions_NoFinalizableSubclass, receiverType, "Ljdk/internal/jvmci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_ConcreteSubtype) \ + oop_field(Assumptions_ConcreteSubtype, context, "Ljdk/internal/jvmci/meta/ResolvedJavaType;") \ + oop_field(Assumptions_ConcreteSubtype, subtype, "Ljdk/internal/jvmci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_LeafType) \ + oop_field(Assumptions_LeafType, context, "Ljdk/internal/jvmci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_ConcreteMethod) \ + oop_field(Assumptions_ConcreteMethod, method, "Ljdk/internal/jvmci/meta/ResolvedJavaMethod;") \ + oop_field(Assumptions_ConcreteMethod, context, "Ljdk/internal/jvmci/meta/ResolvedJavaType;") \ + oop_field(Assumptions_ConcreteMethod, impl, "Ljdk/internal/jvmci/meta/ResolvedJavaMethod;") \ + end_class \ + start_class(Assumptions_CallSiteTargetValue) \ + oop_field(Assumptions_CallSiteTargetValue, callSite, "Ljava/lang/invoke/CallSite;") \ + oop_field(Assumptions_CallSiteTargetValue, methodHandle, "Ljava/lang/invoke/MethodHandle;") \ + end_class \ + start_class(CompilationResult_Site) \ + int_field(CompilationResult_Site, pcOffset) \ + end_class \ + start_class(CompilationResult_Call) \ + oop_field(CompilationResult_Call, target, "Ljdk/internal/jvmci/meta/InvokeTarget;") \ + oop_field(CompilationResult_Call, debugInfo, "Ljdk/internal/jvmci/code/DebugInfo;") \ + end_class \ + start_class(CompilationResult_DataPatch) \ + oop_field(CompilationResult_DataPatch, reference, "Ljdk/internal/jvmci/code/CompilationResult$Reference;") \ + end_class \ + start_class(CompilationResult_ConstantReference) \ + oop_field(CompilationResult_ConstantReference, constant, "Ljdk/internal/jvmci/meta/VMConstant;") \ + end_class \ + start_class(CompilationResult_DataSectionReference) \ + int_field(CompilationResult_DataSectionReference, offset) \ + end_class \ + start_class(InfopointReason) \ + static_oop_field(InfopointReason, UNKNOWN, "Ljdk/internal/jvmci/code/InfopointReason;") \ + static_oop_field(InfopointReason, SAFEPOINT, "Ljdk/internal/jvmci/code/InfopointReason;") \ + static_oop_field(InfopointReason, CALL, "Ljdk/internal/jvmci/code/InfopointReason;") \ + static_oop_field(InfopointReason, IMPLICIT_EXCEPTION, "Ljdk/internal/jvmci/code/InfopointReason;") \ + static_oop_field(InfopointReason, METHOD_START, "Ljdk/internal/jvmci/code/InfopointReason;") \ + static_oop_field(InfopointReason, METHOD_END, "Ljdk/internal/jvmci/code/InfopointReason;") \ + static_oop_field(InfopointReason, LINE_NUMBER, "Ljdk/internal/jvmci/code/InfopointReason;") \ + static_oop_field(InfopointReason, METASPACE_ACCESS, "Ljdk/internal/jvmci/code/InfopointReason;") \ + end_class \ + start_class(CompilationResult_Infopoint) \ + oop_field(CompilationResult_Infopoint, debugInfo, "Ljdk/internal/jvmci/code/DebugInfo;") \ + oop_field(CompilationResult_Infopoint, reason, "Ljdk/internal/jvmci/code/InfopointReason;") \ + end_class \ + start_class(CompilationResult_ExceptionHandler) \ + int_field(CompilationResult_ExceptionHandler, handlerPos) \ + end_class \ + start_class(CompilationResult_Mark) \ + oop_field(CompilationResult_Mark, id, "Ljava/lang/Object;") \ + end_class \ + start_class(DebugInfo) \ + oop_field(DebugInfo, bytecodePosition, "Ljdk/internal/jvmci/code/BytecodePosition;") \ + oop_field(DebugInfo, referenceMap, "Ljdk/internal/jvmci/code/ReferenceMap;") \ + oop_field(DebugInfo, calleeSaveInfo, "Ljdk/internal/jvmci/code/RegisterSaveLayout;") \ + objArrayOop_field(DebugInfo, virtualObjectMapping, "[Ljdk/internal/jvmci/code/VirtualObject;") \ + end_class \ + start_class(HotSpotReferenceMap) \ + objArrayOop_field(HotSpotReferenceMap, objects, "[Ljdk/internal/jvmci/code/Location;") \ + objArrayOop_field(HotSpotReferenceMap, derivedBase, "[Ljdk/internal/jvmci/code/Location;") \ + typeArrayOop_field(HotSpotReferenceMap, sizeInBytes, "[I") \ + int_field(HotSpotReferenceMap, maxRegisterSize) \ + end_class \ + start_class(RegisterSaveLayout) \ + objArrayOop_field(RegisterSaveLayout, registers, "[Ljdk/internal/jvmci/code/Register;") \ + typeArrayOop_field(RegisterSaveLayout, slots, "[I") \ + end_class \ + start_class(BytecodeFrame) \ + objArrayOop_field(BytecodeFrame, values, "[Ljdk/internal/jvmci/meta/JavaValue;") \ + objArrayOop_field(BytecodeFrame, slotKinds, "[Ljdk/internal/jvmci/meta/JavaKind;") \ + int_field(BytecodeFrame, numLocals) \ + int_field(BytecodeFrame, numStack) \ + int_field(BytecodeFrame, numLocks) \ + boolean_field(BytecodeFrame, rethrowException) \ + boolean_field(BytecodeFrame, duringCall) \ + static_int_field(BytecodeFrame, BEFORE_BCI) \ + end_class \ + start_class(BytecodePosition) \ + oop_field(BytecodePosition, caller, "Ljdk/internal/jvmci/code/BytecodePosition;") \ + oop_field(BytecodePosition, method, "Ljdk/internal/jvmci/meta/ResolvedJavaMethod;") \ + int_field(BytecodePosition, bci) \ + end_class \ + start_class(JavaConstant) \ + end_class \ + start_class(PrimitiveConstant) \ + oop_field(PrimitiveConstant, kind, "Ljdk/internal/jvmci/meta/JavaKind;") \ + long_field(PrimitiveConstant, primitive) \ + end_class \ + start_class(RawConstant) \ + long_field(RawConstant, primitive) \ + end_class \ + start_class(NullConstant) \ + end_class \ + start_class(HotSpotCompressedNullConstant) \ + end_class \ + start_class(HotSpotObjectConstantImpl) \ + oop_field(HotSpotObjectConstantImpl, object, "Ljava/lang/Object;") \ + boolean_field(HotSpotObjectConstantImpl, compressed) \ + end_class \ + start_class(HotSpotMetaspaceConstantImpl) \ + long_field(HotSpotMetaspaceConstantImpl, primitive) \ + oop_field(HotSpotMetaspaceConstantImpl, metaspaceObject, "Ljava/lang/Object;") \ + boolean_field(HotSpotMetaspaceConstantImpl, compressed) \ + end_class \ + start_class(HotSpotSentinelConstant) \ + end_class \ + start_class(JavaKind) \ + char_field(JavaKind, typeChar) \ + static_oop_field(JavaKind, Boolean, "Ljdk/internal/jvmci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Byte, "Ljdk/internal/jvmci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Char, "Ljdk/internal/jvmci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Short, "Ljdk/internal/jvmci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Int, "Ljdk/internal/jvmci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Long, "Ljdk/internal/jvmci/meta/JavaKind;"); \ + end_class \ + start_class(LIRKind) \ + oop_field(LIRKind, platformKind, "Ljdk/internal/jvmci/meta/PlatformKind;") \ + int_field(LIRKind, referenceMask) \ + end_class \ + start_class(Value) \ + oop_field(Value, lirKind, "Ljdk/internal/jvmci/meta/LIRKind;") \ + static_oop_field(Value, ILLEGAL, "Ljdk/internal/jvmci/meta/AllocatableValue;"); \ + end_class \ + start_class(RegisterValue) \ + oop_field(RegisterValue, reg, "Ljdk/internal/jvmci/code/Register;") \ + end_class \ + start_class(code_Location) \ + oop_field(code_Location, reg, "Ljdk/internal/jvmci/code/Register;") \ + int_field(code_Location, offset) \ + end_class \ + start_class(code_Register) \ + int_field(code_Register, number) \ + int_field(code_Register, encoding) \ + end_class \ + start_class(StackSlot) \ + int_field(StackSlot, offset) \ + boolean_field(StackSlot, addFrameSize) \ + end_class \ + start_class(VirtualObject) \ + int_field(VirtualObject, id) \ + oop_field(VirtualObject, type, "Ljdk/internal/jvmci/meta/ResolvedJavaType;") \ + objArrayOop_field(VirtualObject, values, "[Ljdk/internal/jvmci/meta/JavaValue;") \ + objArrayOop_field(VirtualObject, slotKinds, "[Ljdk/internal/jvmci/meta/JavaKind;") \ + end_class \ + start_class(StackLockValue) \ + oop_field(StackLockValue, owner, "Ljdk/internal/jvmci/meta/JavaValue;") \ + oop_field(StackLockValue, slot, "Ljdk/internal/jvmci/code/StackSlotValue;") \ + boolean_field(StackLockValue, eliminated) \ + end_class \ + start_class(SpeculationLog) \ + oop_field(SpeculationLog, lastFailed, "Ljava/lang/Object;") \ + end_class \ + start_class(HotSpotStackFrameReference) \ + oop_field(HotSpotStackFrameReference, compilerToVM, "Ljdk/internal/jvmci/hotspot/CompilerToVM;") \ + long_field(HotSpotStackFrameReference, stackPointer) \ + int_field(HotSpotStackFrameReference, frameNumber) \ + int_field(HotSpotStackFrameReference, bci) \ + oop_field(HotSpotStackFrameReference, method, "Ljdk/internal/jvmci/hotspot/HotSpotResolvedJavaMethod;") \ + objArrayOop_field(HotSpotStackFrameReference, locals, "[Ljava/lang/Object;") \ + typeArrayOop_field(HotSpotStackFrameReference, localIsVirtual, "[Z") \ + end_class \ + start_class(HotSpotMetaData) \ + typeArrayOop_field(HotSpotMetaData, pcDescBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, scopesDescBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, relocBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, exceptionBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, oopMaps, "[B") \ + objArrayOop_field(HotSpotMetaData, metadata, "[Ljava/lang/String;") \ + end_class \ + start_class(HotSpotOopMap) \ + int_field(HotSpotOopMap, offset) \ + int_field(HotSpotOopMap, count) \ + typeArrayOop_field(HotSpotOopMap, data, "[B") \ + end_class \ + start_class(HotSpotConstantPool) \ + long_field(HotSpotConstantPool, metaspaceConstantPool) \ + end_class \ + /* end*/ + + +#define START_CLASS(name) \ +class name : AllStatic { \ + private: \ + friend class JVMCICompiler; \ + static void check(oop obj, const char* field_name, int offset) { \ + assert(obj != NULL, err_msg("NULL field access of %s.%s", #name, field_name)); \ + assert(obj->is_a(SystemDictionary::name##_klass()), err_msg("wrong class, " #name " expected, found %s", obj->klass()->external_name())); \ + assert(offset != 0, "must be valid offset"); \ + } \ + static void compute_offsets(); \ + public: \ + static InstanceKlass* klass() { return SystemDictionary::name##_klass() == NULL ? NULL : InstanceKlass::cast(SystemDictionary::name##_klass()); } + +#define END_CLASS }; + +#define FIELD(name, type, accessor, cast) \ + static int _##name##_offset; \ + static type name(oop obj) { check(obj, #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ + static type name(Handle& obj) { check(obj(), #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ + static type name(jobject obj) { check(JNIHandles::resolve(obj), #name, _##name##_offset); return cast JNIHandles::resolve(obj)->accessor(_##name##_offset); } \ + static void set_##name(oop obj, type x) { check(obj, #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ + static void set_##name(Handle& obj, type x) { check(obj(), #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ + static void set_##name(jobject obj, type x) { check(JNIHandles::resolve(obj), #name, _##name##_offset); JNIHandles::resolve(obj)->accessor##_put(_##name##_offset, x); } + +#define EMPTY_CAST +#define CHAR_FIELD(klass, name) FIELD(name, jchar, char_field, EMPTY_CAST) +#define INT_FIELD(klass, name) FIELD(name, jint, int_field, EMPTY_CAST) +#define BOOLEAN_FIELD(klass, name) FIELD(name, jboolean, bool_field, EMPTY_CAST) +#define LONG_FIELD(klass, name) FIELD(name, jlong, long_field, EMPTY_CAST) +#define FLOAT_FIELD(klass, name) FIELD(name, jfloat, float_field, EMPTY_CAST) +#define OOP_FIELD(klass, name, signature) FIELD(name, oop, obj_field, EMPTY_CAST) +#define OBJARRAYOOP_FIELD(klass, name, signature) FIELD(name, objArrayOop, obj_field, (objArrayOop)) +#define TYPEARRAYOOP_FIELD(klass, name, signature) FIELD(name, typeArrayOop, obj_field, (typeArrayOop)) +#define STATIC_OOP_FIELD(klassName, name, signature) STATIC_OOPISH_FIELD(klassName, name, oop, signature) +#define STATIC_OBJARRAYOOP_FIELD(klassName, name, signature) STATIC_OOPISH_FIELD(klassName, name, objArrayOop, signature) +#define STATIC_OOPISH_FIELD(klassName, name, type, signature) \ + static int _##name##_offset; \ + static type name() { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + if (UseCompressedOops) { \ + return (type) oopDesc::load_decode_heap_oop((narrowOop *)addr); \ + } else { \ + return (type) oopDesc::load_decode_heap_oop((oop*)addr); \ + } \ + } \ + static void set_##name(type x) { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + assert(klassName::klass() != NULL, "Class not yet loaded: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + if (UseCompressedOops) { \ + oop_store((narrowOop *)addr, x); \ + } else { \ + oop_store((oop*)addr, x); \ + } \ + } +#define STATIC_PRIMITIVE_FIELD(klassName, name, jtypename) \ + static int _##name##_offset; \ + static jtypename name() { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + return *((jtypename *)addr); \ + } \ + static void set_##name(jtypename x) { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + *((jtypename *)addr) = x; \ + } + +#define STATIC_INT_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jint) +#define STATIC_BOOLEAN_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jboolean) + +COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, TYPEARRAYOOP_FIELD, OBJARRAYOOP_FIELD, STATIC_OOP_FIELD, STATIC_OBJARRAYOOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD) +#undef START_CLASS +#undef END_CLASS +#undef FIELD +#undef CHAR_FIELD +#undef INT_FIELD +#undef BOOLEAN_FIELD +#undef LONG_FIELD +#undef FLOAT_FIELD +#undef OOP_FIELD +#undef TYPEARRAYOOP_FIELD +#undef OBJARRAYOOP_FIELD +#undef STATIC_OOPISH_FIELD +#undef STATIC_OOP_FIELD +#undef STATIC_OBJARRAYOOP_FIELD +#undef STATIC_INT_FIELD +#undef STATIC_BOOLEAN_FIELD +#undef EMPTY_CAST + +void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field); + +#endif // SHARE_VM_JVMCI_JVMCIJAVACLASSES_HPP --- /dev/null 2015-09-16 15:21:30.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciRuntime.cpp 2015-09-16 15:21:30.000000000 -0700 @@ -0,0 +1,964 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "asm/codeBuffer.hpp" +#include "code/codeCache.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/disassembler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "prims/jvm.h" +#include "runtime/biasedLocking.hpp" +#include "runtime/interfaceSupport.hpp" +#include "runtime/reflection.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/debug.hpp" +#include "utilities/defaultStream.hpp" + +#if defined(_MSC_VER) +#define strtoll _strtoi64 +#endif + +jobject JVMCIRuntime::_HotSpotJVMCIRuntime_instance = NULL; +bool JVMCIRuntime::_HotSpotJVMCIRuntime_initialized = false; +const char* JVMCIRuntime::_compiler = NULL; +const char* JVMCIRuntime::_options = NULL; +bool JVMCIRuntime::_shutdown_called = false; + +void JVMCIRuntime::initialize_natives(JNIEnv *env, jclass c2vmClass) { +#ifdef _LP64 + uintptr_t heap_end = (uintptr_t) Universe::heap()->reserved_region().end(); + uintptr_t allocation_end = heap_end + ((uintptr_t)16) * 1024 * 1024 * 1024; + guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)"); +#else + fatal("check TLAB allocation code for address space conflicts"); +#endif + + JavaThread* THREAD = JavaThread::current(); + { + ThreadToNativeFromVM trans(THREAD); + + ResourceMark rm; + HandleMark hm; + + // Ensure _non_oop_bits is initialized + Universe::non_oop_word(); + + env->RegisterNatives(c2vmClass, CompilerToVM::methods, CompilerToVM::methods_count()); + } + if (HAS_PENDING_EXCEPTION) { + abort_on_pending_exception(PENDING_EXCEPTION, "Could not register natives"); + } +} + +BasicType JVMCIRuntime::kindToBasicType(jchar ch) { + switch(ch) { + case 'z': return T_BOOLEAN; + case 'b': return T_BYTE; + case 's': return T_SHORT; + case 'c': return T_CHAR; + case 'i': return T_INT; + case 'f': return T_FLOAT; + case 'j': return T_LONG; + case 'd': return T_DOUBLE; + case 'a': return T_OBJECT; + case '-': return T_ILLEGAL; + default: + fatal(err_msg("unexpected Kind: %c", ch)); + break; + } + return T_ILLEGAL; +} + +// Simple helper to see if the caller of a runtime stub which +// entered the VM has been deoptimized + +static bool caller_is_deopted() { + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, false); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + assert(caller_frame.is_compiled_frame(), "must be compiled"); + return caller_frame.is_deoptimized_frame(); +} + +// Stress deoptimization +static void deopt_caller() { + if ( !caller_is_deopted()) { + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, false); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); + assert(caller_is_deopted(), "Must be deoptimized"); + } +} + +JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance(JavaThread* thread, Klass* klass)) + JRT_BLOCK; + assert(klass->is_klass(), "not a class"); + instanceKlassHandle h(thread, klass); + h->check_valid_for_instantiation(true, CHECK); + // make sure klass is initialized + h->initialize(CHECK); + // allocate instance and return via TLS + oop obj = h->allocate_instance(CHECK); + thread->set_vm_result(obj); + JRT_BLOCK_END; + + if (ReduceInitialCardMarks) { + new_store_pre_barrier(thread); + } +JRT_END + +JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_klass, jint length)) + JRT_BLOCK; + // Note: no handle for klass needed since they are not used + // anymore after new_objArray() and no GC can happen before. + // (This may have to change if this code changes!) + assert(array_klass->is_klass(), "not a class"); + oop obj; + if (array_klass->oop_is_typeArray()) { + BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type(); + obj = oopFactory::new_typeArray(elt_type, length, CHECK); + } else { + Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); + obj = oopFactory::new_objArray(elem_klass, length, CHECK); + } + thread->set_vm_result(obj); + // This is pretty rare but this runtime patch is stressful to deoptimization + // if we deoptimize here so force a deopt to stress the path. + if (DeoptimizeALot) { + static int deopts = 0; + // Alternate between deoptimizing and raising an error (which will also cause a deopt) + if (deopts++ % 2 == 0) { + ResourceMark rm(THREAD); + THROW(vmSymbols::java_lang_OutOfMemoryError()); + } else { + deopt_caller(); + } + } + JRT_BLOCK_END; + + if (ReduceInitialCardMarks) { + new_store_pre_barrier(thread); + } +JRT_END + +void JVMCIRuntime::new_store_pre_barrier(JavaThread* thread) { + // After any safepoint, just before going back to compiled code, + // we inform the GC that we will be doing initializing writes to + // this object in the future without emitting card-marks, so + // GC may take any compensating steps. + // NOTE: Keep this code consistent with GraphKit::store_barrier. + + oop new_obj = thread->vm_result(); + if (new_obj == NULL) return; + + assert(Universe::heap()->can_elide_tlab_store_barriers(), + "compiler must check this first"); + // GC may decide to give back a safer copy of new_obj. + new_obj = Universe::heap()->new_store_pre_barrier(thread, new_obj); + thread->set_vm_result(new_obj); +} + +JRT_ENTRY(void, JVMCIRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims)) + assert(klass->is_klass(), "not a class"); + assert(rank >= 1, "rank must be nonzero"); + oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length)) + oop obj = Reflection::reflect_new_array(element_mirror, length, CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror)) + instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(type_mirror)); + + if (klass == NULL) { + ResourceMark rm(THREAD); + THROW(vmSymbols::java_lang_InstantiationException()); + } + + // Create new instance (the receiver) + klass->check_valid_for_instantiation(false, CHECK); + + // Make sure klass gets initialized + klass->initialize(CHECK); + + oop obj = klass->allocate_instance(CHECK); + thread->set_vm_result(obj); +JRT_END + +extern void vm_exit(int code); + +// Enter this method from compiled code handler below. This is where we transition +// to VM mode. This is done as a helper routine so that the method called directly +// from compiled code does not have to transition to VM. This allows the entry +// method to see if the nmethod that we have just looked up a handler for has +// been deoptimized while we were in the vm. This simplifies the assembly code +// cpu directories. +// +// We are entering here from exception stub (via the entry method below) +// If there is a compiled exception handler in this method, we will continue there; +// otherwise we will unwind the stack and continue at the caller of top frame method +// Note: we enter in Java using a special JRT wrapper. This wrapper allows us to +// control the area where we can allow a safepoint. After we exit the safepoint area we can +// check to see if the handler we are going to return is now in a nmethod that has +// been deoptimized. If that is the case we return the deopt blob +// unpack_with_exception entry instead. This makes life for the exception blob easier +// because making that same check and diverting is painful from assembly language. +JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, nmethod*& nm)) + // Reset method handle flag. + thread->set_is_method_handle_return(false); + + Handle exception(thread, ex); + nm = CodeCache::find_nmethod(pc); + assert(nm != NULL, "this is not a compiled method"); + // Adjust the pc as needed/ + if (nm->is_deopt_pc(pc)) { + RegisterMap map(thread, false); + frame exception_frame = thread->last_frame().sender(&map); + // if the frame isn't deopted then pc must not correspond to the caller of last_frame + assert(exception_frame.is_deoptimized_frame(), "must be deopted"); + pc = exception_frame.pc(); + } +#ifdef ASSERT + assert(exception.not_null(), "NULL exceptions should be handled by throw_exception"); + assert(exception->is_oop(), "just checking"); + // Check that exception is a subclass of Throwable, otherwise we have a VerifyError + if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { + if (ExitVMOnVerifyError) vm_exit(-1); + ShouldNotReachHere(); + } +#endif + + // Check the stack guard pages and reenable them if necessary and there is + // enough space on the stack to do so. Use fast exceptions only if the guard + // pages are enabled. + bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); + if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); + + if (JvmtiExport::can_post_on_exceptions()) { + // To ensure correct notification of exception catches and throws + // we have to deoptimize here. If we attempted to notify the + // catches and throws during this exception lookup it's possible + // we could deoptimize on the way out of the VM and end back in + // the interpreter at the throw site. This would result in double + // notifications since the interpreter would also notify about + // these same catches and throws as it unwound the frame. + + RegisterMap reg_map(thread); + frame stub_frame = thread->last_frame(); + frame caller_frame = stub_frame.sender(®_map); + + // We don't really want to deoptimize the nmethod itself since we + // can actually continue in the exception handler ourselves but I + // don't see an easy way to have the desired effect. + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); + assert(caller_is_deopted(), "Must be deoptimized"); + + return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + + // ExceptionCache is used only for exceptions at call sites and not for implicit exceptions + if (guard_pages_enabled) { + address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); + if (fast_continuation != NULL) { + // Set flag if return address is a method handle call site. + thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); + return fast_continuation; + } + } + + // If the stack guard pages are enabled, check whether there is a handler in + // the current method. Otherwise (guard pages disabled), force an unwind and + // skip the exception cache update (i.e., just leave continuation==NULL). + address continuation = NULL; + if (guard_pages_enabled) { + + // New exception handling mechanism can support inlined methods + // with exception handlers since the mappings are from PC to PC + + // debugging support + // tracing + if (TraceExceptions) { + ttyLocker ttyl; + ResourceMark rm; + tty->print_cr("Exception <%s> (" INTPTR_FORMAT ") thrown in compiled method <%s> at PC " INTPTR_FORMAT " for thread " INTPTR_FORMAT "", + exception->print_value_string(), p2i((address)exception()), nm->method()->print_value_string(), p2i(pc), p2i(thread)); + } + // for AbortVMOnException flag + NOT_PRODUCT(Exceptions::debug_check_abort(exception)); + + // Clear out the exception oop and pc since looking up an + // exception handler can cause class loading, which might throw an + // exception and those fields are expected to be clear during + // normal bytecode execution. + thread->clear_exception_oop_and_pc(); + + continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false); + // If an exception was thrown during exception dispatch, the exception oop may have changed + thread->set_exception_oop(exception()); + thread->set_exception_pc(pc); + + // the exception cache is used only by non-implicit exceptions + if (continuation != NULL && !SharedRuntime::deopt_blob()->contains(continuation)) { + nm->add_handler_for_exception_and_pc(exception, pc, continuation); + } + } + + // Set flag if return address is a method handle call site. + thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); + + if (TraceExceptions) { + ttyLocker ttyl; + ResourceMark rm; + tty->print_cr("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT " for exception thrown at PC " PTR_FORMAT, + p2i(thread), p2i(continuation), p2i(pc)); + } + + return continuation; +JRT_END + +// Enter this method from compiled code only if there is a Java exception handler +// in the method handling the exception. +// We are entering here from exception stub. We don't do a normal VM transition here. +// We do it in a helper. This is so we can check to see if the nmethod we have just +// searched for an exception handler has been deoptimized in the meantime. +address JVMCIRuntime::exception_handler_for_pc(JavaThread* thread) { + oop exception = thread->exception_oop(); + address pc = thread->exception_pc(); + // Still in Java mode + DEBUG_ONLY(ResetNoHandleMark rnhm); + nmethod* nm = NULL; + address continuation = NULL; + { + // Enter VM mode by calling the helper + ResetNoHandleMark rnhm; + continuation = exception_handler_for_pc_helper(thread, exception, pc, nm); + } + // Back in JAVA, use no oops DON'T safepoint + + // Now check to see if the compiled method we were called from is now deoptimized. + // If so we must return to the deopt blob and deoptimize the nmethod + if (nm != NULL && caller_is_deopted()) { + continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + + assert(continuation != NULL, "no handler found"); + return continuation; +} + +JRT_ENTRY(void, JVMCIRuntime::create_null_exception(JavaThread* thread)) + SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_NullPointerException()); + thread->set_vm_result(PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::create_out_of_bounds_exception(JavaThread* thread, jint index)) + char message[jintAsStringSize]; + sprintf(message, "%d", index); + SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message); + thread->set_vm_result(PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; +JRT_END + +JRT_ENTRY_NO_ASYNC(void, JVMCIRuntime::monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock)) + IF_TRACE_jvmci_3 { + char type[O_BUFLEN]; + obj->klass()->name()->as_C_string(type, O_BUFLEN); + markOop mark = obj->mark(); + TRACE_jvmci_3("%s: entered locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(mark), p2i(lock)); + tty->flush(); + } +#ifdef ASSERT + if (PrintBiasedLockingStatistics) { + Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); + } +#endif + Handle h_obj(thread, obj); + assert(h_obj()->is_oop(), "must be NULL or an object"); + if (UseBiasedLocking) { + // Retry fast entry if bias is revoked to avoid unnecessary inflation + ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); + } else { + if (JVMCIUseFastLocking) { + // When using fast locking, the compiled code has already tried the fast case + ObjectSynchronizer::slow_enter(h_obj, lock, THREAD); + } else { + ObjectSynchronizer::fast_enter(h_obj, lock, false, THREAD); + } + } + TRACE_jvmci_3("%s: exiting locking slow with obj=" INTPTR_FORMAT, thread->name(), p2i(obj)); +JRT_END + +JRT_LEAF(void, JVMCIRuntime::monitorexit(JavaThread* thread, oopDesc* obj, BasicLock* lock)) + assert(thread == JavaThread::current(), "threads must correspond"); + assert(thread->last_Java_sp(), "last_Java_sp must be set"); + // monitorexit is non-blocking (leaf routine) => no exceptions can be thrown + EXCEPTION_MARK; + +#ifdef DEBUG + if (!obj->is_oop()) { + ResetNoHandleMark rhm; + nmethod* method = thread->last_frame().cb()->as_nmethod_or_null(); + if (method != NULL) { + tty->print_cr("ERROR in monitorexit in method %s wrong obj " INTPTR_FORMAT, method->name(), p2i(obj)); + } + thread->print_stack_on(tty); + assert(false, "invalid lock object pointer dected"); + } +#endif + + if (JVMCIUseFastLocking) { + // When using fast locking, the compiled code has already tried the fast case + ObjectSynchronizer::slow_exit(obj, lock, THREAD); + } else { + ObjectSynchronizer::fast_exit(obj, lock, THREAD); + } + IF_TRACE_jvmci_3 { + char type[O_BUFLEN]; + obj->klass()->name()->as_C_string(type, O_BUFLEN); + TRACE_jvmci_3("%s: exited locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(obj->mark()), p2i(lock)); + tty->flush(); + } +JRT_END + +JRT_LEAF(void, JVMCIRuntime::log_object(JavaThread* thread, oopDesc* obj, jint flags)) + bool string = mask_bits_are_true(flags, LOG_OBJECT_STRING); + bool addr = mask_bits_are_true(flags, LOG_OBJECT_ADDRESS); + bool newline = mask_bits_are_true(flags, LOG_OBJECT_NEWLINE); + if (!string) { + if (!addr && obj->is_oop_or_null(true)) { + char buf[O_BUFLEN]; + tty->print("%s@" INTPTR_FORMAT, obj->klass()->name()->as_C_string(buf, O_BUFLEN), p2i(obj)); + } else { + tty->print(INTPTR_FORMAT, p2i(obj)); + } + } else { + ResourceMark rm; + assert(obj != NULL && java_lang_String::is_instance(obj), "must be"); + char *buf = java_lang_String::as_utf8_string(obj); + tty->print_raw(buf); + } + if (newline) { + tty->cr(); + } +JRT_END + +JRT_LEAF(void, JVMCIRuntime::write_barrier_pre(JavaThread* thread, oopDesc* obj)) + thread->satb_mark_queue().enqueue(obj); +JRT_END + +JRT_LEAF(void, JVMCIRuntime::write_barrier_post(JavaThread* thread, void* card_addr)) + thread->dirty_card_queue().enqueue(card_addr); +JRT_END + +JRT_LEAF(jboolean, JVMCIRuntime::validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child)) + bool ret = true; + if(!Universe::heap()->is_in_closed_subset(parent)) { + tty->print_cr("Parent Object " INTPTR_FORMAT " not in heap", p2i(parent)); + parent->print(); + ret=false; + } + if(!Universe::heap()->is_in_closed_subset(child)) { + tty->print_cr("Child Object " INTPTR_FORMAT " not in heap", p2i(child)); + child->print(); + ret=false; + } + return (jint)ret; +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::vm_error(JavaThread* thread, jlong where, jlong format, jlong value)) + ResourceMark rm; + const char *error_msg = where == 0L ? "" : (char*) (address) where; + char *detail_msg = NULL; + if (format != 0L) { + const char* buf = (char*) (address) format; + size_t detail_msg_length = strlen(buf) * 2; + detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length); + jio_snprintf(detail_msg, detail_msg_length, buf, value); + } + report_vm_error(__FILE__, __LINE__, error_msg, detail_msg); +JRT_END + +JRT_LEAF(oopDesc*, JVMCIRuntime::load_and_clear_exception(JavaThread* thread)) + oop exception = thread->exception_oop(); + assert(exception != NULL, "npe"); + thread->set_exception_oop(NULL); + thread->set_exception_pc(0); + return exception; +JRT_END + +PRAGMA_DIAG_PUSH +PRAGMA_FORMAT_NONLITERAL_IGNORED +JRT_LEAF(void, JVMCIRuntime::log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3)) + ResourceMark rm; + assert(format != NULL && java_lang_String::is_instance(format), "must be"); + char *buf = java_lang_String::as_utf8_string(format); + tty->print((const char*)buf, v1, v2, v3); +JRT_END +PRAGMA_DIAG_POP + +static void decipher(jlong v, bool ignoreZero) { + if (v != 0 || !ignoreZero) { + void* p = (void *)(address) v; + CodeBlob* cb = CodeCache::find_blob(p); + if (cb) { + if (cb->is_nmethod()) { + char buf[O_BUFLEN]; + tty->print("%s [" INTPTR_FORMAT "+" JLONG_FORMAT "]", cb->as_nmethod_or_null()->method()->name_and_sig_as_C_string(buf, O_BUFLEN), p2i(cb->code_begin()), (jlong)((address)v - cb->code_begin())); + return; + } + cb->print_value_on(tty); + return; + } + if (Universe::heap()->is_in(p)) { + oop obj = oop(p); + obj->print_value_on(tty); + return; + } + tty->print(INTPTR_FORMAT " [long: " JLONG_FORMAT ", double %lf, char %c]",p2i((void *)v), (jlong)v, (jdouble)v, (char)v); + } +} + +PRAGMA_DIAG_PUSH +PRAGMA_FORMAT_NONLITERAL_IGNORED +JRT_LEAF(void, JVMCIRuntime::vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3)) + ResourceMark rm; + const char *buf = (const char*) (address) format; + if (vmError) { + if (buf != NULL) { + fatal(err_msg(buf, v1, v2, v3)); + } else { + fatal(""); + } + } else if (buf != NULL) { + tty->print(buf, v1, v2, v3); + } else { + assert(v2 == 0, "v2 != 0"); + assert(v3 == 0, "v3 != 0"); + decipher(v1, false); + } +JRT_END +PRAGMA_DIAG_POP + +JRT_LEAF(void, JVMCIRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) + union { + jlong l; + jdouble d; + jfloat f; + } uu; + uu.l = value; + switch (typeChar) { + case 'z': tty->print(value == 0 ? "false" : "true"); break; + case 'b': tty->print("%d", (jbyte) value); break; + case 'c': tty->print("%c", (jchar) value); break; + case 's': tty->print("%d", (jshort) value); break; + case 'i': tty->print("%d", (jint) value); break; + case 'f': tty->print("%f", uu.f); break; + case 'j': tty->print(JLONG_FORMAT, value); break; + case 'd': tty->print("%lf", uu.d); break; + default: assert(false, "unknown typeChar"); break; + } + if (newline) { + tty->cr(); + } +JRT_END + +JRT_ENTRY(jint, JVMCIRuntime::identity_hash_code(JavaThread* thread, oopDesc* obj)) + return (jint) obj->identity_hash(); +JRT_END + +JRT_ENTRY(jboolean, JVMCIRuntime::thread_is_interrupted(JavaThread* thread, oopDesc* receiver, jboolean clear_interrupted)) + // Ensure that the C++ Thread and OSThread structures aren't freed before we operate. + // This locking requires thread_in_vm which is why this method cannot be JRT_LEAF. + Handle receiverHandle(thread, receiver); + MutexLockerEx ml(thread->threadObj() == (void*)receiver ? NULL : Threads_lock); + JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle()); + if (receiverThread == NULL) { + // The other thread may exit during this process, which is ok so return false. + return JNI_FALSE; + } else { + return (jint) Thread::is_interrupted(receiverThread, clear_interrupted != 0); + } +JRT_END + +JRT_ENTRY(jint, JVMCIRuntime::test_deoptimize_call_int(JavaThread* thread, int value)) + deopt_caller(); + return value; +JRT_END + +// private static JVMCIRuntime JVMCI.initializeRuntime() +JVM_ENTRY(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) + if (!EnableJVMCI) { + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled") + } + JVMCIRuntime::initialize_HotSpotJVMCIRuntime(CHECK_NULL); + jobject ret = JVMCIRuntime::get_HotSpotJVMCIRuntime_jobject(CHECK_NULL); + return ret; +JVM_END + +Handle JVMCIRuntime::callStatic(const char* className, const char* methodName, const char* signature, JavaCallArguments* args, TRAPS) { + guarantee(!_HotSpotJVMCIRuntime_initialized, "cannot reinitialize HotSpotJVMCIRuntime"); + + TempNewSymbol name = SymbolTable::new_symbol(className, CHECK_(Handle())); + KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, CHECK_(Handle())); + TempNewSymbol runtime = SymbolTable::new_symbol(methodName, CHECK_(Handle())); + TempNewSymbol sig = SymbolTable::new_symbol(signature, CHECK_(Handle())); + JavaValue result(T_OBJECT); + if (args == NULL) { + JavaCalls::call_static(&result, klass, runtime, sig, CHECK_(Handle())); + } else { + JavaCalls::call_static(&result, klass, runtime, sig, args, CHECK_(Handle())); + } + return Handle((oop)result.get_jobject()); +} + +static bool jvmci_options_file_exists() { + const char* home = Arguments::get_java_home(); + size_t path_len = strlen(home) + strlen("/lib/jvmci/options") + 1; + char path[JVM_MAXPATHLEN]; + char sep = os::file_separator()[0]; + jio_snprintf(path, JVM_MAXPATHLEN, "%s%clib%cjvmci%coptions", home, sep, sep, sep); + struct stat st; + return os::stat(path, &st) == 0; +} + +void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(TRAPS) { + if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) { +#ifdef ASSERT + // This should only be called in the context of the JVMCI class being initialized + TempNewSymbol name = SymbolTable::new_symbol("jdk/internal/jvmci/runtime/JVMCI", CHECK); + Klass* k = SystemDictionary::resolve_or_null(name, CHECK); + instanceKlassHandle klass = InstanceKlass::cast(k); + assert(klass->is_being_initialized() && klass->is_reentrant_initialization(THREAD), + "HotSpotJVMCIRuntime initialization should only be triggered through JVMCI initialization"); +#endif + + bool parseOptionsFile = jvmci_options_file_exists(); + if (_options != NULL || parseOptionsFile) { + JavaCallArguments args; + oop options = java_lang_String::create_oop_from_str(_options, CHECK); + args.push_oop(options); + args.push_int(parseOptionsFile); + callStatic("jdk/internal/jvmci/options/OptionsParser", + "parseOptionsFromVM", + "(Ljava/lang/String;Z)Ljava/lang/Boolean;", &args, CHECK); + } + + if (_compiler != NULL) { + JavaCallArguments args; + oop compiler = java_lang_String::create_oop_from_str(_compiler, CHECK); + args.push_oop(compiler); + callStatic("jdk/internal/jvmci/hotspot/HotSpotJVMCICompilerConfig", + "selectCompiler", + "(Ljava/lang/String;)Ljava/lang/Boolean;", &args, CHECK); + } + + Handle result = callStatic("jdk/internal/jvmci/hotspot/HotSpotJVMCIRuntime", + "runtime", + "()Ljdk/internal/jvmci/hotspot/HotSpotJVMCIRuntime;", NULL, CHECK); + _HotSpotJVMCIRuntime_initialized = true; + _HotSpotJVMCIRuntime_instance = JNIHandles::make_global(result()); + } +} + +void JVMCIRuntime::initialize_JVMCI(TRAPS) { + if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) { + callStatic("jdk/internal/jvmci/runtime/JVMCI", + "getRuntime", + "()Ljdk/internal/jvmci/runtime/JVMCIRuntime;", NULL, CHECK); + } + assert(_HotSpotJVMCIRuntime_initialized == true, "what?"); +} + +void JVMCIRuntime::metadata_do(void f(Metadata*)) { + // For simplicity, the existence of HotSpotJVMCIMetaAccessContext in + // the SystemDictionary well known classes should ensure the other + // classes have already been loaded, so make sure their order in the + // table enforces that. + assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_internal_jvmci_hotspot_HotSpotResolvedJavaMethodImpl) < + SystemDictionary::WK_KLASS_ENUM_NAME(jdk_internal_jvmci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); + assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_internal_jvmci_hotspot_HotSpotConstantPool) < + SystemDictionary::WK_KLASS_ENUM_NAME(jdk_internal_jvmci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); + assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_internal_jvmci_hotspot_HotSpotResolvedObjectTypeImpl) < + SystemDictionary::WK_KLASS_ENUM_NAME(jdk_internal_jvmci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); + + if (HotSpotJVMCIMetaAccessContext::klass() == NULL || + !HotSpotJVMCIMetaAccessContext::klass()->is_linked()) { + // Nothing could be registered yet + return; + } + + // WeakReference[] + objArrayOop allContexts = HotSpotJVMCIMetaAccessContext::allContexts(); + if (allContexts == NULL) { + return; + } + + // These must be loaded at this point but the linking state doesn't matter. + assert(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass() != NULL, "must be loaded"); + assert(SystemDictionary::HotSpotConstantPool_klass() != NULL, "must be loaded"); + assert(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass() != NULL, "must be loaded"); + + for (int i = 0; i < allContexts->length(); i++) { + oop ref = allContexts->obj_at(i); + if (ref != NULL) { + oop referent = java_lang_ref_Reference::referent(ref); + if (referent != NULL) { + // Chunked Object[] with last element pointing to next chunk + objArrayOop metadataRoots = HotSpotJVMCIMetaAccessContext::metadataRoots(referent); + while (metadataRoots != NULL) { + for (int typeIndex = 0; typeIndex < metadataRoots->length() - 1; typeIndex++) { + oop reference = metadataRoots->obj_at(typeIndex); + if (reference == NULL) { + continue; + } + oop metadataRoot = java_lang_ref_Reference::referent(reference); + if (metadataRoot == NULL) { + continue; + } + if (metadataRoot->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + Method* method = CompilerToVM::asMethod(metadataRoot); + f(method); + } else if (metadataRoot->is_a(SystemDictionary::HotSpotConstantPool_klass())) { + ConstantPool* constantPool = CompilerToVM::asConstantPool(metadataRoot); + f(constantPool); + } else if (metadataRoot->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { + Klass* klass = CompilerToVM::asKlass(metadataRoot); + f(klass); + } else { + metadataRoot->print(); + ShouldNotReachHere(); + } + } + metadataRoots = (objArrayOop)metadataRoots->obj_at(metadataRoots->length() - 1); + assert(metadataRoots == NULL || metadataRoots->is_objArray(), "wrong type"); + } + } + } + } +} + +// private static void CompilerToVM.init() +JVM_ENTRY(void, JVM_InitializeJVMCINatives(JNIEnv *env, jclass c2vmClass)) + JVMCIRuntime::initialize_natives(env, c2vmClass); +JVM_END + +/** + * Closure for parsing a line from a *.properties file in jre/lib/jvmci/properties. + * The line must match the regular expression "[^=]+=.*". That is one or more + * characters other than '=' followed by '=' followed by zero or more characters. + * Everything before the '=' is the property name and everything after '=' is the value. + * Lines that start with '#' are treated as comments and ignored. + * No special processing of whitespace or any escape characters is performed. + * The last definition of a property "wins" (i.e., it overrides all earlier + * definitions of the property). + */ +class JVMCIPropertiesFileClosure : public ParseClosure { + SystemProperty** _plist; +public: + JVMCIPropertiesFileClosure(SystemProperty** plist) : _plist(plist) {} + void do_line(char* line) { + if (line[0] == '#') { + // skip comment + return; + } + size_t len = strlen(line); + char* sep = strchr(line, '='); + if (sep == NULL) { + warn_and_abort("invalid format: could not find '=' character"); + return; + } + if (sep == line) { + warn_and_abort("invalid format: name cannot be empty"); + return; + } + *sep = '\0'; + const char* name = line; + char* value = sep + 1; + Arguments::PropertyList_unique_add(_plist, name, value); + } +}; + +void JVMCIRuntime::parse_properties(SystemProperty** plist) { + char jvmciDir[JVM_MAXPATHLEN]; + const char* fileSep = os::file_separator(); + jio_snprintf(jvmciDir, sizeof(jvmciDir), "%s%slib%sjvmci", + Arguments::get_java_home(), fileSep, fileSep, fileSep); + DIR* dir = os::opendir(jvmciDir); + if (dir != NULL) { + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(jvmciDir), mtInternal); + JVMCIPropertiesFileClosure closure(plist); + const unsigned suffix_len = (unsigned)strlen(".properties"); + while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL && !closure.is_aborted()) { + const char* name = entry->d_name; + if (strlen(name) > suffix_len && strcmp(name + strlen(name) - suffix_len, ".properties") == 0) { + char propertiesFilePath[JVM_MAXPATHLEN]; + jio_snprintf(propertiesFilePath, sizeof(propertiesFilePath), "%s%s%s",jvmciDir, fileSep, name); + JVMCIRuntime::parse_lines(propertiesFilePath, &closure, false); + } + } + FREE_C_HEAP_ARRAY(char, dbuf); + os::closedir(dir); + } +} + +#define CHECK_WARN_ABORT_(message) THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + warning(message); \ + char buf[512]; \ + jio_snprintf(buf, 512, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ + return; \ + } \ + (void)(0 + +void JVMCIRuntime::save_compiler(const char* compiler) { + assert(compiler != NULL, "npe"); + assert(_compiler == NULL, "cannot reassign JVMCI compiler"); + _compiler = compiler; +} + +void JVMCIRuntime::save_options(const char* options) { + assert(options != NULL, "npe"); + assert(_options == NULL, "cannot reassign JVMCI options"); + _options = options; +} + +void JVMCIRuntime::shutdown() { + if (_HotSpotJVMCIRuntime_instance != NULL) { + _shutdown_called = true; + JavaThread* THREAD = JavaThread::current(); + HandleMark hm(THREAD); + Handle receiver = get_HotSpotJVMCIRuntime(CHECK_ABORT); + JavaValue result(T_VOID); + JavaCallArguments args; + args.push_oop(receiver); + JavaCalls::call_special(&result, receiver->klass(), vmSymbols::shutdown_method_name(), vmSymbols::void_method_signature(), &args, CHECK_ABORT); + } +} + +void JVMCIRuntime::call_printStackTrace(Handle exception, Thread* thread) { + assert(exception->is_a(SystemDictionary::Throwable_klass()), "Throwable instance expected"); + JavaValue result(T_VOID); + JavaCalls::call_virtual(&result, + exception, + KlassHandle(thread, + SystemDictionary::Throwable_klass()), + vmSymbols::printStackTrace_name(), + vmSymbols::void_method_signature(), + thread); +} + +void JVMCIRuntime::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) { + Thread* THREAD = Thread::current(); + CLEAR_PENDING_EXCEPTION; + tty->print_raw_cr(message); + call_printStackTrace(exception, THREAD); + + // Give other aborting threads to also print their stack traces. + // This can be very useful when debugging class initialization + // failures. + os::sleep(THREAD, 200, false); + + vm_abort(dump_core); +} + +void JVMCIRuntime::parse_lines(char* path, ParseClosure* closure, bool warnStatFailure) { + struct stat st; + if (os::stat(path, &st) == 0 && (st.st_mode & S_IFREG) == S_IFREG) { // exists & is regular file + int file_handle = os::open(path, 0, 0); + if (file_handle != -1) { + char* buffer = NEW_C_HEAP_ARRAY(char, st.st_size + 1, mtInternal); + int num_read; + num_read = (int) os::read(file_handle, (char*) buffer, st.st_size); + if (num_read == -1) { + warning("Error reading file %s due to %s", path, strerror(errno)); + } else if (num_read != st.st_size) { + warning("Only read %d of " SIZE_FORMAT " bytes from %s", num_read, (size_t) st.st_size, path); + } + os::close(file_handle); + closure->set_filename(path); + if (num_read == st.st_size) { + buffer[num_read] = '\0'; + + char* line = buffer; + while (line - buffer < num_read && !closure->is_aborted()) { + // find line end (\r, \n or \r\n) + char* nextline = NULL; + char* cr = strchr(line, '\r'); + char* lf = strchr(line, '\n'); + if (cr != NULL && lf != NULL) { + char* min = MIN2(cr, lf); + *min = '\0'; + if (lf == cr + 1) { + nextline = lf + 1; + } else { + nextline = min + 1; + } + } else if (cr != NULL) { + *cr = '\0'; + nextline = cr + 1; + } else if (lf != NULL) { + *lf = '\0'; + nextline = lf + 1; + } + // trim left + while (*line == ' ' || *line == '\t') line++; + char* end = line + strlen(line); + // trim right + while (end > line && (*(end -1) == ' ' || *(end -1) == '\t')) end--; + *end = '\0'; + // skip comments and empty lines + if (*line != '#' && strlen(line) > 0) { + closure->parse_line(line); + } + if (nextline != NULL) { + line = nextline; + } else { + // File without newline at the end + break; + } + } + } + FREE_C_HEAP_ARRAY(char, buffer); + } else { + warning("Error opening file %s due to %s", path, strerror(errno)); + } + } else if (warnStatFailure) { + warning("Could not stat file %s due to %s", path, strerror(errno)); + } +} --- /dev/null 2015-09-16 15:21:30.000000000 -0700 +++ new/src/share/vm/jvmci/jvmciRuntime.hpp 2015-09-16 15:21:30.000000000 -0700 @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_RUNTIME_HPP +#define SHARE_VM_JVMCI_JVMCI_RUNTIME_HPP + +#include "interpreter/interpreter.hpp" +#include "memory/allocation.hpp" +#include "runtime/arguments.hpp" +#include "runtime/deoptimization.hpp" + +class ParseClosure : public StackObj { + int _lineNo; + char* _filename; + bool _abort; +protected: + void abort() { _abort = true; } + void warn_and_abort(const char* message) { + warn(message); + abort(); + } + void warn(const char* message) { + warning("Error at line %d while parsing %s: %s", _lineNo, _filename == NULL ? "?" : _filename, message); + } + public: + ParseClosure() : _lineNo(0), _filename(NULL), _abort(false) {} + void parse_line(char* line) { + _lineNo++; + do_line(line); + } + virtual void do_line(char* line) = 0; + int lineNo() { return _lineNo; } + bool is_aborted() { return _abort; } + void set_filename(char* path) {_filename = path; _lineNo = 0;} +}; + +#define CHECK_ABORT THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ + return; \ + } \ + (void)(0 + +#define CHECK_ABORT_(result) THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ + return result; \ + } \ + (void)(0 + +class JVMCIRuntime: public AllStatic { + private: + static jobject _HotSpotJVMCIRuntime_instance; + static bool _HotSpotJVMCIRuntime_initialized; + static const char* _compiler; + static const char* _options; + + static bool _shutdown_called; + + /** + * Instantiates a service object, calls its default constructor and returns it. + * + * @param name the name of a class implementing jdk.internal.jvmci.service.Service + */ + static Handle create_Service(const char* name, TRAPS); + + public: + + /** + * Parses *.properties files in jre/lib/jvmci/ and adds the properties to plist. + */ + static void parse_properties(SystemProperty** plist); + + /** + * Saves the value of the "jvmci.compiler" system property for processing + * when JVMCI is initialized. + */ + static void save_compiler(const char* compiler); + + /** + * Saves the value of the "jvmci.options" system property for processing + * when JVMCI is initialized. + */ + static void save_options(const char* options); + + static void initialize_natives(JNIEnv *env, jclass c2vmClass); + + static bool is_HotSpotJVMCIRuntime_initialized() { return _HotSpotJVMCIRuntime_initialized; } + + /** + * Gets the singleton HotSpotJVMCIRuntime instance, initializing it if necessary + */ + static Handle get_HotSpotJVMCIRuntime(TRAPS) { + initialize_JVMCI(CHECK_(Handle())); + return Handle(JNIHandles::resolve_non_null(_HotSpotJVMCIRuntime_instance)); + } + + static jobject get_HotSpotJVMCIRuntime_jobject(TRAPS) { + initialize_JVMCI(CHECK_NULL); + assert(_HotSpotJVMCIRuntime_initialized, "must be"); + return _HotSpotJVMCIRuntime_instance; + } + + static Handle callStatic(const char* className, const char* methodName, const char* returnType, JavaCallArguments* args, TRAPS); + + /** + * Trigger initialization of HotSpotJVMCIRuntime through JVMCI.getRuntime() + */ + static void initialize_JVMCI(TRAPS); + + /** + * Explicitly initialize HotSpotJVMCIRuntime itself + */ + static void initialize_HotSpotJVMCIRuntime(TRAPS); + + static void metadata_do(void f(Metadata*)); + + static void shutdown(); + + static bool shutdown_called() { + return _shutdown_called; + } + + static void parse_lines(char* path, ParseClosure* closure, bool warnStatFailure); + + /** + * Aborts the VM due to an unexpected exception. + */ + static void abort_on_pending_exception(Handle exception, const char* message, bool dump_core = false); + + /** + * Calls Throwable.printStackTrace() on a given exception. + */ + static void call_printStackTrace(Handle exception, Thread* thread); + + static BasicType kindToBasicType(jchar ch); + + // The following routines are all called from compiled JVMCI code + + static void new_instance(JavaThread* thread, Klass* klass); + static void new_array(JavaThread* thread, Klass* klass, jint length); + static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims); + static void dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length); + static void dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror); + static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupted); + static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3); + static jint identity_hash_code(JavaThread* thread, oopDesc* obj); + static address exception_handler_for_pc(JavaThread* thread); + static void monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void create_null_exception(JavaThread* thread); + static void create_out_of_bounds_exception(JavaThread* thread, jint index); + static void vm_error(JavaThread* thread, jlong where, jlong format, jlong value); + static oopDesc* load_and_clear_exception(JavaThread* thread); + static void log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3); + static void log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline); + // Note: Must be kept in sync with constants in jdk.internal.jvmci.replacements.Log + enum { + LOG_OBJECT_NEWLINE = 0x01, + LOG_OBJECT_STRING = 0x02, + LOG_OBJECT_ADDRESS = 0x04 + }; + static void log_object(JavaThread* thread, oopDesc* msg, jint flags); + static void write_barrier_pre(JavaThread* thread, oopDesc* obj); + static void write_barrier_post(JavaThread* thread, void* card); + static jboolean validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child); + static void new_store_pre_barrier(JavaThread* thread); + + // Test only function + static int test_deoptimize_call_int(JavaThread* thread, int value); +}; + +// Tracing macros. + +#define IF_TRACE_jvmci_1 if (!(JVMCITraceLevel >= 1)) ; else +#define IF_TRACE_jvmci_2 if (!(JVMCITraceLevel >= 2)) ; else +#define IF_TRACE_jvmci_3 if (!(JVMCITraceLevel >= 3)) ; else +#define IF_TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4)) ; else +#define IF_TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5)) ; else + +#define TRACE_jvmci_1 if (!(JVMCITraceLevel >= 1 && (tty->print("JVMCITrace-1: "), true))) ; else tty->print_cr +#define TRACE_jvmci_2 if (!(JVMCITraceLevel >= 2 && (tty->print(" JVMCITrace-2: "), true))) ; else tty->print_cr +#define TRACE_jvmci_3 if (!(JVMCITraceLevel >= 3 && (tty->print(" JVMCITrace-3: "), true))) ; else tty->print_cr +#define TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4 && (tty->print(" JVMCITrace-4: "), true))) ; else tty->print_cr +#define TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5 && (tty->print(" JVMCITrace-5: "), true))) ; else tty->print_cr + +#endif // SHARE_VM_JVMCI_JVMCI_RUNTIME_HPP --- /dev/null 2015-09-16 15:21:31.000000000 -0700 +++ new/src/share/vm/jvmci/jvmci_globals.cpp 2015-09-16 15:21:31.000000000 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2000, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "jvmci/jvmci_globals.hpp" + +JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ + MATERIALIZE_PD_DEVELOPER_FLAG, \ + MATERIALIZE_PRODUCT_FLAG, \ + MATERIALIZE_PD_PRODUCT_FLAG, \ + MATERIALIZE_DIAGNOSTIC_FLAG, \ + MATERIALIZE_EXPERIMENTAL_FLAG, \ + MATERIALIZE_NOTPRODUCT_FLAG, + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) --- /dev/null 2015-09-16 15:21:32.000000000 -0700 +++ new/src/share/vm/jvmci/jvmci_globals.hpp 2015-09-16 15:21:31.000000000 -0700 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2000, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_JVMCIGLOBALS_HPP +#define SHARE_VM_JVMCI_JVMCIGLOBALS_HPP + +#include "runtime/globals.hpp" + +// +// Defines all global flags used by the JVMCI compiler. Only flags that need +// to be accessible to the JVMCI C++ code should be defined here. All other +// JVMCI flags should be defined in JVMCIOptions.java. +// +#define JVMCI_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, range, constraint) \ + \ + experimental(bool, EnableJVMCI, false, \ + "Enable JVMCI") \ + \ + experimental(bool, UseJVMCICompiler, false, \ + "Use JVMCI as the default compiler") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, BootstrapJVMCI, false, \ + "Bootstrap JVMCI before running Java main method") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, PrintBootstrap, true, \ + "Print JVMCI bootstrap progress and summary") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCIThreads, 1, \ + "Force number of JVMCI compiler threads to use") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCIHostThreads, 1, \ + "Force number of compiler threads for JVMCI host compiler") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, CodeInstallSafepointChecks, true, \ + "Perform explicit safepoint checks while installing code") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + NOT_COMPILER2(product(intx, MaxVectorSize, 64, \ + "Max vector size in bytes, " \ + "actual size could be less depending on elements type")) \ + \ + NOT_COMPILER2(product(bool, ReduceInitialCardMarks, true, \ + "Defer write barriers of young objects")) \ + \ + experimental(intx, JVMCITraceLevel, 0, \ + "Trace level for JVMCI: " \ + "1 means emit a message for each CompilerToVM call," \ + "levels greater than 1 provide progressively greater detail") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCICounterSize, 0, \ + "Reserved size for benchmark counters") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, JVMCICountersExcludeCompiler, true, \ + "Exclude JVMCI compiler threads from benchmark counters") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + develop(bool, JVMCIUseFastLocking, true, \ + "Use fast inlined locking code") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCINMethodSizeLimit, (80*K)*wordSize, \ + "Maximum size of a compiled method.") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + develop(bool, TraceUncollectedSpeculations, false, \ + "Print message when a failed speculation was not collected") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + + +// Read default values for JVMCI globals + +JVMCI_FLAGS(DECLARE_DEVELOPER_FLAG, \ + DECLARE_PD_DEVELOPER_FLAG, \ + DECLARE_PRODUCT_FLAG, \ + DECLARE_PD_PRODUCT_FLAG, \ + DECLARE_DIAGNOSTIC_FLAG, \ + DECLARE_EXPERIMENTAL_FLAG, \ + DECLARE_NOTPRODUCT_FLAG, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + +#endif // SHARE_VM_JVMCI_JVMCIGLOBALS_HPP --- /dev/null 2015-09-16 15:21:32.000000000 -0700 +++ new/src/share/vm/jvmci/systemDictionary_jvmci.hpp 2015-09-16 15:21:32.000000000 -0700 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP +#define SHARE_VM_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP + +#if !INCLUDE_JVMCI +#define JVMCI_WK_KLASSES_DO(do_klass) +#else +#define JVMCI_WK_KLASSES_DO(do_klass) \ + /* JVMCI classes. These are loaded on-demand. */ \ + do_klass(HotSpotCompiledCode_klass, jdk_internal_jvmci_hotspot_HotSpotCompiledCode, Jvmci) \ + do_klass(HotSpotCompiledCode_Comment_klass, jdk_internal_jvmci_hotspot_HotSpotCompiledCode_Comment, Jvmci) \ + do_klass(HotSpotCompiledNmethod_klass, jdk_internal_jvmci_hotspot_HotSpotCompiledNmethod, Jvmci) \ + do_klass(HotSpotForeignCallTarget_klass, jdk_internal_jvmci_hotspot_HotSpotForeignCallTarget, Jvmci) \ + do_klass(HotSpotReferenceMap_klass, jdk_internal_jvmci_hotspot_HotSpotReferenceMap, Jvmci) \ + do_klass(HotSpotInstalledCode_klass, jdk_internal_jvmci_hotspot_HotSpotInstalledCode, Jvmci) \ + do_klass(HotSpotNmethod_klass, jdk_internal_jvmci_hotspot_HotSpotNmethod, Jvmci) \ + do_klass(HotSpotResolvedJavaMethodImpl_klass, jdk_internal_jvmci_hotspot_HotSpotResolvedJavaMethodImpl, Jvmci) \ + do_klass(HotSpotResolvedObjectTypeImpl_klass, jdk_internal_jvmci_hotspot_HotSpotResolvedObjectTypeImpl, Jvmci) \ + do_klass(HotSpotCompressedNullConstant_klass, jdk_internal_jvmci_hotspot_HotSpotCompressedNullConstant, Jvmci) \ + do_klass(HotSpotObjectConstantImpl_klass, jdk_internal_jvmci_hotspot_HotSpotObjectConstantImpl, Jvmci) \ + do_klass(HotSpotMetaspaceConstantImpl_klass, jdk_internal_jvmci_hotspot_HotSpotMetaspaceConstantImpl, Jvmci) \ + do_klass(HotSpotSentinelConstant_klass, jdk_internal_jvmci_hotspot_HotSpotSentinelConstant, Jvmci) \ + do_klass(HotSpotStackFrameReference_klass, jdk_internal_jvmci_hotspot_HotSpotStackFrameReference, Jvmci) \ + do_klass(HotSpotMetaData_klass, jdk_internal_jvmci_hotspot_HotSpotMetaData, Jvmci) \ + do_klass(HotSpotOopMap_klass, jdk_internal_jvmci_hotspot_HotSpotOopMap, Jvmci) \ + do_klass(HotSpotConstantPool_klass, jdk_internal_jvmci_hotspot_HotSpotConstantPool, Jvmci) \ + do_klass(HotSpotJVMCIMetaAccessContext_klass, jdk_internal_jvmci_hotspot_HotSpotJVMCIMetaAccessContext, Jvmci) \ + do_klass(Assumptions_ConcreteMethod_klass, jdk_internal_jvmci_meta_Assumptions_ConcreteMethod, Jvmci) \ + do_klass(Assumptions_NoFinalizableSubclass_klass, jdk_internal_jvmci_meta_Assumptions_NoFinalizableSubclass, Jvmci) \ + do_klass(Assumptions_ConcreteSubtype_klass, jdk_internal_jvmci_meta_Assumptions_ConcreteSubtype, Jvmci) \ + do_klass(Assumptions_LeafType_klass, jdk_internal_jvmci_meta_Assumptions_LeafType, Jvmci) \ + do_klass(Assumptions_CallSiteTargetValue_klass, jdk_internal_jvmci_meta_Assumptions_CallSiteTargetValue, Jvmci) \ + do_klass(Architecture_klass, jdk_internal_jvmci_code_Architecture, Jvmci) \ + do_klass(TargetDescription_klass, jdk_internal_jvmci_code_TargetDescription, Jvmci) \ + do_klass(BytecodePosition_klass, jdk_internal_jvmci_code_BytecodePosition, Jvmci) \ + do_klass(DebugInfo_klass, jdk_internal_jvmci_code_DebugInfo, Jvmci) \ + do_klass(RegisterSaveLayout_klass, jdk_internal_jvmci_code_RegisterSaveLayout, Jvmci) \ + do_klass(BytecodeFrame_klass, jdk_internal_jvmci_code_BytecodeFrame, Jvmci) \ + do_klass(CompilationResult_Call_klass, jdk_internal_jvmci_code_CompilationResult_Call, Jvmci) \ + do_klass(CompilationResult_ConstantReference_klass, jdk_internal_jvmci_code_CompilationResult_ConstantReference, Jvmci) \ + do_klass(CompilationResult_DataPatch_klass, jdk_internal_jvmci_code_CompilationResult_DataPatch, Jvmci) \ + do_klass(CompilationResult_DataSectionReference_klass, jdk_internal_jvmci_code_CompilationResult_DataSectionReference, Jvmci) \ + do_klass(CompilationResult_ExceptionHandler_klass, jdk_internal_jvmci_code_CompilationResult_ExceptionHandler, Jvmci) \ + do_klass(CompilationResult_Mark_klass, jdk_internal_jvmci_code_CompilationResult_Mark, Jvmci) \ + do_klass(CompilationResult_Infopoint_klass, jdk_internal_jvmci_code_CompilationResult_Infopoint, Jvmci) \ + do_klass(CompilationResult_Site_klass, jdk_internal_jvmci_code_CompilationResult_Site, Jvmci) \ + do_klass(InfopointReason_klass, jdk_internal_jvmci_code_InfopointReason, Jvmci) \ + do_klass(InstalledCode_klass, jdk_internal_jvmci_code_InstalledCode, Jvmci) \ + do_klass(code_Location_klass, jdk_internal_jvmci_code_Location, Jvmci) \ + do_klass(code_Register_klass, jdk_internal_jvmci_code_Register, Jvmci) \ + do_klass(RegisterValue_klass, jdk_internal_jvmci_code_RegisterValue, Jvmci) \ + do_klass(StackSlot_klass, jdk_internal_jvmci_code_StackSlot, Jvmci) \ + do_klass(StackLockValue_klass, jdk_internal_jvmci_code_StackLockValue, Jvmci) \ + do_klass(VirtualObject_klass, jdk_internal_jvmci_code_VirtualObject, Jvmci) \ + do_klass(SpeculationLog_klass, jdk_internal_jvmci_meta_SpeculationLog, Jvmci) \ + do_klass(JavaConstant_klass, jdk_internal_jvmci_meta_JavaConstant, Jvmci) \ + do_klass(PrimitiveConstant_klass, jdk_internal_jvmci_meta_PrimitiveConstant, Jvmci) \ + do_klass(RawConstant_klass, jdk_internal_jvmci_meta_RawConstant, Jvmci) \ + do_klass(NullConstant_klass, jdk_internal_jvmci_meta_NullConstant, Jvmci) \ + do_klass(ExceptionHandler_klass, jdk_internal_jvmci_meta_ExceptionHandler, Jvmci) \ + do_klass(JavaKind_klass, jdk_internal_jvmci_meta_JavaKind, Jvmci) \ + do_klass(LIRKind_klass, jdk_internal_jvmci_meta_LIRKind, Jvmci) \ + do_klass(Value_klass, jdk_internal_jvmci_meta_Value, Jvmci) +#endif + +#endif // SHARE_VM_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP + --- /dev/null 2015-09-16 15:21:33.000000000 -0700 +++ new/src/share/vm/jvmci/vmStructs_jvmci.hpp 2015-09-16 15:21:33.000000000 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2013, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP +#define SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP + +#include "compiler/abstractCompiler.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciRuntime.hpp" + +#define VM_STRUCTS_JVMCI(nonstatic_field, static_field) \ + nonstatic_field(JavaThread, _pending_deoptimization, int) \ + nonstatic_field(JavaThread, _pending_failed_speculation, oop) \ + nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \ + nonstatic_field(JavaThread, _jvmci_counters, jlong*) \ + nonstatic_field(MethodData, _jvmci_ir_size, int) \ + nonstatic_field(JVMCIEnv, _task, CompileTask*) \ + nonstatic_field(JVMCIEnv, _jvmti_can_hotswap_or_post_breakpoint, bool) \ + nonstatic_field(DeoptimizationBlob, _uncommon_trap_offset, int) \ + \ + static_field(CompilerToVM, _supports_inline_contig_alloc, bool) \ + static_field(CompilerToVM, _heap_end_addr, HeapWord**) \ + static_field(CompilerToVM, _heap_top_addr, HeapWord**) + +#define VM_TYPES_JVMCI(declare_type, declare_toplevel_type) \ + declare_toplevel_type(JVMCIEnv) \ + +#define VM_INT_CONSTANTS_JVMCI(declare_constant, declare_preprocessor_constant) \ + declare_constant(Deoptimization::Reason_unreached0) \ + declare_constant(Deoptimization::Reason_type_checked_inlining) \ + declare_constant(Deoptimization::Reason_optimized_type_check) \ + declare_constant(Deoptimization::Reason_aliasing) \ + declare_constant(Deoptimization::Reason_transfer_to_interpreter) \ + declare_constant(Deoptimization::Reason_not_compiled_exception_handler) \ + declare_constant(Deoptimization::Reason_unresolved) \ + declare_constant(Deoptimization::Reason_jsr_mismatch) \ + declare_constant(JVMCIEnv::ok) \ + declare_constant(JVMCIEnv::dependencies_failed) \ + declare_constant(JVMCIEnv::dependencies_invalid) \ + declare_constant(JVMCIEnv::cache_full) \ + declare_constant(JVMCIEnv::code_too_large) \ + \ + declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ + declare_preprocessor_constant("JVM_RECOGNIZED_FIELD_MODIFIERS", JVM_RECOGNIZED_FIELD_MODIFIERS) \ + \ + declare_constant(CompilerToVM::KLASS_TAG) \ + declare_constant(CompilerToVM::SYMBOL_TAG) \ + \ + declare_constant(CodeInstaller::VERIFIED_ENTRY) \ + declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ + declare_constant(CodeInstaller::OSR_ENTRY) \ + declare_constant(CodeInstaller::EXCEPTION_HANDLER_ENTRY) \ + declare_constant(CodeInstaller::DEOPT_HANDLER_ENTRY) \ + declare_constant(CodeInstaller::INVOKEINTERFACE) \ + declare_constant(CodeInstaller::INVOKEVIRTUAL) \ + declare_constant(CodeInstaller::INVOKESTATIC) \ + declare_constant(CodeInstaller::INVOKESPECIAL) \ + declare_constant(CodeInstaller::INLINE_INVOKE) \ + declare_constant(CodeInstaller::POLL_NEAR) \ + declare_constant(CodeInstaller::POLL_RETURN_NEAR) \ + declare_constant(CodeInstaller::POLL_FAR) \ + declare_constant(CodeInstaller::POLL_RETURN_FAR) \ + declare_constant(CodeInstaller::CARD_TABLE_ADDRESS) \ + declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \ + declare_constant(CodeInstaller::HEAP_END_ADDRESS) \ + declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \ + declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \ + declare_constant(CodeInstaller::INVOKE_INVALID) \ + \ + declare_constant(Method::invalid_vtable_index) \ + +#define VM_ADDRESSES_JVMCI(declare_address, declare_preprocessor_address, declare_function) \ + declare_function(JVMCIRuntime::new_instance) \ + declare_function(JVMCIRuntime::new_array) \ + declare_function(JVMCIRuntime::new_multi_array) \ + declare_function(JVMCIRuntime::dynamic_new_array) \ + declare_function(JVMCIRuntime::dynamic_new_instance) \ + \ + declare_function(JVMCIRuntime::thread_is_interrupted) \ + declare_function(JVMCIRuntime::vm_message) \ + declare_function(JVMCIRuntime::identity_hash_code) \ + declare_function(JVMCIRuntime::exception_handler_for_pc) \ + declare_function(JVMCIRuntime::monitorenter) \ + declare_function(JVMCIRuntime::monitorexit) \ + declare_function(JVMCIRuntime::create_null_exception) \ + declare_function(JVMCIRuntime::create_out_of_bounds_exception) \ + declare_function(JVMCIRuntime::log_primitive) \ + declare_function(JVMCIRuntime::log_object) \ + declare_function(JVMCIRuntime::log_printf) \ + declare_function(JVMCIRuntime::vm_error) \ + declare_function(JVMCIRuntime::load_and_clear_exception) \ + declare_function(JVMCIRuntime::write_barrier_pre) \ + declare_function(JVMCIRuntime::write_barrier_post) \ + declare_function(JVMCIRuntime::validate_object) \ + \ + declare_function(JVMCIRuntime::test_deoptimize_call_int) + +#endif // SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP --- /dev/null 2015-09-16 15:21:33.000000000 -0700 +++ new/src/share/vm/jvmci/vmSymbols_jvmci.hpp 2015-09-16 15:21:33.000000000 -0700 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_VMSYMBOLS_JVMCI_HPP +#define SHARE_VM_JVMCI_VMSYMBOLS_JVMCI_HPP + + +#if !INCLUDE_JVMCI +#define JVMCI_VM_SYMBOLS_DO(template, do_alias) +#else +#define JVMCI_VM_SYMBOLS_DO(template, do_alias) \ + template(jdk_internal_jvmci_hotspot_HotSpotCompiledCode, "jdk/internal/jvmci/hotspot/HotSpotCompiledCode") \ + template(jdk_internal_jvmci_hotspot_HotSpotCompiledCode_Comment, "jdk/internal/jvmci/hotspot/HotSpotCompiledCode$Comment") \ + template(jdk_internal_jvmci_hotspot_HotSpotCompiledNmethod, "jdk/internal/jvmci/hotspot/HotSpotCompiledNmethod") \ + template(jdk_internal_jvmci_hotspot_HotSpotForeignCallTarget, "jdk/internal/jvmci/hotspot/HotSpotForeignCallTarget") \ + template(jdk_internal_jvmci_hotspot_HotSpotReferenceMap, "jdk/internal/jvmci/hotspot/HotSpotReferenceMap") \ + template(jdk_internal_jvmci_hotspot_CompilerToVM, "jdk/internal/jvmci/hotspot/CompilerToVM") \ + template(jdk_internal_jvmci_hotspot_HotSpotInstalledCode, "jdk/internal/jvmci/hotspot/HotSpotInstalledCode") \ + template(jdk_internal_jvmci_hotspot_HotSpotNmethod, "jdk/internal/jvmci/hotspot/HotSpotNmethod") \ + template(jdk_internal_jvmci_hotspot_HotSpotResolvedJavaMethodImpl, "jdk/internal/jvmci/hotspot/HotSpotResolvedJavaMethodImpl") \ + template(jdk_internal_jvmci_hotspot_HotSpotResolvedObjectTypeImpl, "jdk/internal/jvmci/hotspot/HotSpotResolvedObjectTypeImpl") \ + template(jdk_internal_jvmci_hotspot_HotSpotCompressedNullConstant, "jdk/internal/jvmci/hotspot/HotSpotCompressedNullConstant") \ + template(jdk_internal_jvmci_hotspot_HotSpotObjectConstantImpl, "jdk/internal/jvmci/hotspot/HotSpotObjectConstantImpl") \ + template(jdk_internal_jvmci_hotspot_HotSpotMetaspaceConstantImpl, "jdk/internal/jvmci/hotspot/HotSpotMetaspaceConstantImpl") \ + template(jdk_internal_jvmci_hotspot_HotSpotSentinelConstant, "jdk/internal/jvmci/hotspot/HotSpotSentinelConstant") \ + template(jdk_internal_jvmci_hotspot_HotSpotStackFrameReference, "jdk/internal/jvmci/hotspot/HotSpotStackFrameReference") \ + template(jdk_internal_jvmci_hotspot_HotSpotMetaData, "jdk/internal/jvmci/hotspot/HotSpotMetaData") \ + template(jdk_internal_jvmci_hotspot_HotSpotOopMap, "jdk/internal/jvmci/hotspot/HotSpotOopMap") \ + template(jdk_internal_jvmci_hotspot_HotSpotConstantPool, "jdk/internal/jvmci/hotspot/HotSpotConstantPool") \ + template(jdk_internal_jvmci_hotspot_HotSpotJVMCIMetaAccessContext, "jdk/internal/jvmci/hotspot/HotSpotJVMCIMetaAccessContext") \ + template(jdk_internal_jvmci_meta_JavaConstant, "jdk/internal/jvmci/meta/JavaConstant") \ + template(jdk_internal_jvmci_meta_PrimitiveConstant, "jdk/internal/jvmci/meta/PrimitiveConstant") \ + template(jdk_internal_jvmci_meta_RawConstant, "jdk/internal/jvmci/meta/RawConstant") \ + template(jdk_internal_jvmci_meta_NullConstant, "jdk/internal/jvmci/meta/NullConstant") \ + template(jdk_internal_jvmci_meta_ExceptionHandler, "jdk/internal/jvmci/meta/ExceptionHandler") \ + template(jdk_internal_jvmci_meta_JavaKind, "jdk/internal/jvmci/meta/JavaKind") \ + template(jdk_internal_jvmci_meta_LIRKind, "jdk/internal/jvmci/meta/LIRKind") \ + template(jdk_internal_jvmci_meta_Value, "jdk/internal/jvmci/meta/Value") \ + template(jdk_internal_jvmci_meta_Assumptions_ConcreteSubtype, "jdk/internal/jvmci/meta/Assumptions$ConcreteSubtype") \ + template(jdk_internal_jvmci_meta_Assumptions_LeafType, "jdk/internal/jvmci/meta/Assumptions$LeafType") \ + template(jdk_internal_jvmci_meta_Assumptions_NoFinalizableSubclass, "jdk/internal/jvmci/meta/Assumptions$NoFinalizableSubclass") \ + template(jdk_internal_jvmci_meta_Assumptions_ConcreteMethod, "jdk/internal/jvmci/meta/Assumptions$ConcreteMethod") \ + template(jdk_internal_jvmci_meta_Assumptions_CallSiteTargetValue, "jdk/internal/jvmci/meta/Assumptions$CallSiteTargetValue") \ + template(jdk_internal_jvmci_meta_SpeculationLog, "jdk/internal/jvmci/meta/SpeculationLog") \ + template(jdk_internal_jvmci_code_Architecture, "jdk/internal/jvmci/code/Architecture") \ + template(jdk_internal_jvmci_code_TargetDescription, "jdk/internal/jvmci/code/TargetDescription") \ + template(jdk_internal_jvmci_code_CompilationResult_Call, "jdk/internal/jvmci/code/CompilationResult$Call") \ + template(jdk_internal_jvmci_code_CompilationResult_ConstantReference, "jdk/internal/jvmci/code/CompilationResult$ConstantReference") \ + template(jdk_internal_jvmci_code_CompilationResult_DataPatch, "jdk/internal/jvmci/code/CompilationResult$DataPatch") \ + template(jdk_internal_jvmci_code_CompilationResult_DataSectionReference, "jdk/internal/jvmci/code/CompilationResult$DataSectionReference") \ + template(jdk_internal_jvmci_code_CompilationResult_ExceptionHandler, "jdk/internal/jvmci/code/CompilationResult$ExceptionHandler") \ + template(jdk_internal_jvmci_code_CompilationResult_Mark, "jdk/internal/jvmci/code/CompilationResult$Mark") \ + template(jdk_internal_jvmci_code_CompilationResult_Infopoint, "jdk/internal/jvmci/code/CompilationResult$Infopoint") \ + template(jdk_internal_jvmci_code_CompilationResult_Site, "jdk/internal/jvmci/code/CompilationResult$Site") \ + template(jdk_internal_jvmci_code_InfopointReason, "jdk/internal/jvmci/code/InfopointReason") \ + template(jdk_internal_jvmci_code_InstalledCode, "jdk/internal/jvmci/code/InstalledCode") \ + template(jdk_internal_jvmci_code_BytecodeFrame, "jdk/internal/jvmci/code/BytecodeFrame") \ + template(jdk_internal_jvmci_code_BytecodePosition, "jdk/internal/jvmci/code/BytecodePosition") \ + template(jdk_internal_jvmci_code_DebugInfo, "jdk/internal/jvmci/code/DebugInfo") \ + template(jdk_internal_jvmci_code_Location, "jdk/internal/jvmci/code/Location") \ + template(jdk_internal_jvmci_code_Register, "jdk/internal/jvmci/code/Register") \ + template(jdk_internal_jvmci_code_RegisterValue, "jdk/internal/jvmci/code/RegisterValue") \ + template(jdk_internal_jvmci_code_StackSlot, "jdk/internal/jvmci/code/StackSlot") \ + template(jdk_internal_jvmci_code_StackLockValue, "jdk/internal/jvmci/code/StackLockValue") \ + template(jdk_internal_jvmci_code_VirtualObject, "jdk/internal/jvmci/code/VirtualObject") \ + template(jdk_internal_jvmci_code_RegisterSaveLayout, "jdk/internal/jvmci/code/RegisterSaveLayout") \ + template(jdk_internal_jvmci_code_InvalidInstalledCodeException, "jdk/internal/jvmci/code/InvalidInstalledCodeException") \ + template(compileMethod_name, "compileMethod") \ + template(compileMethod_signature, "(Ljdk/internal/jvmci/hotspot/HotSpotResolvedJavaMethod;IJI)V") \ + template(fromMetaspace_name, "fromMetaspace") \ + template(method_fromMetaspace_signature, "(J)Ljdk/internal/jvmci/hotspot/HotSpotResolvedJavaMethod;") \ + template(constantPool_fromMetaspace_signature, "(J)Ljdk/internal/jvmci/hotspot/HotSpotConstantPool;") \ + template(klass_fromMetaspace_signature, "(Ljava/lang/Class;)Ljdk/internal/jvmci/hotspot/HotSpotResolvedObjectTypeImpl;") \ + template(jdk_internal_jvmci_hotspot_Stable_signature, "Ljdk/internal/jvmci/hotspot/Stable;") +#endif + +#endif // SHARE_VM_JVMCI_VMSYMBOLS_JVMCI_HPP --- /dev/null 2015-09-16 15:21:34.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.options.test/src/jdk/internal/jvmci/options/test/NestedBooleanOptionValueTest.java 2015-09-16 15:21:34.000000000 -0700 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2013, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @run junit jdk.internal.jvmci.options.test.NestedBooleanOptionValueTest + */ + +package jdk.internal.jvmci.options.test; + +import static jdk.internal.jvmci.options.test.NestedBooleanOptionValueTest.Options.*; +import static org.junit.Assert.*; +import jdk.internal.jvmci.options.*; +import jdk.internal.jvmci.options.OptionValue.*; + +import org.junit.*; + +public class NestedBooleanOptionValueTest { + + public static class Options { + public static final OptionValue Master0 = new OptionValue<>(true); + public static final OptionValue NestedOption0 = new NestedBooleanOptionValue(Master0, true); + public static final OptionValue Master1 = new OptionValue<>(true); + public static final OptionValue NestedOption1 = new NestedBooleanOptionValue(Master1, true); + public static final OptionValue Master2 = new OptionValue<>(true); + public static final OptionValue NestedOption2 = new NestedBooleanOptionValue(Master2, false); + } + + static final OptionDescriptor master0 = OptionDescriptor.create("Master0", Boolean.class, "", Options.class, "Master0", Master0); + static final OptionDescriptor nestedOption0 = OptionDescriptor.create("NestedOption0", Boolean.class, "", Options.class, "NestedOption0", NestedOption0); + static final OptionDescriptor master1 = OptionDescriptor.create("Master1", Boolean.class, "", Options.class, "Master1", Master1); + static final OptionDescriptor nestedOption1 = OptionDescriptor.create("NestedOption1", Boolean.class, "", Options.class, "NestedOption1", NestedOption1); + static final OptionDescriptor master2 = OptionDescriptor.create("Master2", Boolean.class, "", Options.class, "Master2", Master2); + static final OptionDescriptor nestedOption2 = OptionDescriptor.create("NestedOption2", Boolean.class, "", Options.class, "NestedOption2", NestedOption2); + + @SuppressWarnings("try") + @Test + public void runOverrides() { + assertTrue(Master0.getValue()); + assertTrue(NestedOption0.getValue()); + try (OverrideScope s1 = OptionValue.override(Master0, false)) { + assertFalse(Master0.getValue()); + assertFalse(NestedOption0.getValue()); + try (OverrideScope s2 = OptionValue.override(NestedOption0, false)) { + assertFalse(NestedOption0.getValue()); + } + try (OverrideScope s2 = OptionValue.override(NestedOption0, true)) { + assertTrue(NestedOption0.getValue()); + } + } + assertTrue(Master0.getValue()); + try (OverrideScope s1 = OptionValue.override(NestedOption0, false)) { + assertFalse(NestedOption0.getValue()); + } + try (OverrideScope s1 = OptionValue.override(NestedOption0, true)) { + assertTrue(NestedOption0.getValue()); + } + } + + @Test + public void runDefaultTrue() { + Master1.setValue(true); + assertTrue(Master1.getValue()); + assertTrue(NestedOption1.getValue()); + // nested value unset + Master1.setValue(false); + assertFalse(Master1.getValue()); + assertFalse(NestedOption1.getValue()); + // set false + Master1.setValue(false); + NestedOption1.setValue(false); + assertFalse(Master1.getValue()); + assertFalse(NestedOption1.getValue()); + Master1.setValue(true); + assertTrue(Master1.getValue()); + assertFalse(NestedOption1.getValue()); + // set true + Master1.setValue(false); + NestedOption1.setValue(true); + assertFalse(Master1.getValue()); + assertTrue(NestedOption1.getValue()); + Master1.setValue(true); + assertTrue(Master1.getValue()); + assertTrue(NestedOption1.getValue()); + } + + @Test + public void runDefaultFalse() { + Master2.setValue(true); + assertTrue(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + // nested value unset + Master2.setValue(false); + assertFalse(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + // set false + Master2.setValue(false); + NestedOption2.setValue(false); + assertFalse(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + Master2.setValue(true); + assertTrue(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + // set true + Master2.setValue(false); + NestedOption2.setValue(true); + assertFalse(Master2.getValue()); + assertTrue(NestedOption2.getValue()); + Master2.setValue(true); + assertTrue(Master2.getValue()); + assertTrue(NestedOption2.getValue()); + } + +} --- /dev/null 2015-09-16 15:21:35.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.options.test/src/jdk/internal/jvmci/options/test/TestOptionValue.java 2015-09-16 15:21:35.000000000 -0700 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2013, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @run junit jdk.internal.jvmci.options.test.TestOptionValue + */ + +package jdk.internal.jvmci.options.test; + +import static jdk.internal.jvmci.options.test.TestOptionValue.Options.*; +import static org.junit.Assert.*; + +import java.util.*; + +import jdk.internal.jvmci.options.*; +import jdk.internal.jvmci.options.OptionValue.*; + +import org.junit.*; + +@SuppressWarnings("try") +public class TestOptionValue { + + public static class Options { + public static final OptionValue Stable = new StableOptionValue<>(true); + public static final OptionValue Mutable = new OptionValue<>("original"); + public static final OptionValue SecondMutable = new OptionValue<>("second"); + } + + static final OptionDescriptor stable = OptionDescriptor.create("Stable", Boolean.class, "", Options.class, "Stable", Stable); + static final OptionDescriptor mutable = OptionDescriptor.create("Mutable", String.class, "", Options.class, "Mutable", Mutable); + static final OptionDescriptor secondMutable = OptionDescriptor.create("SecondMutable", String.class, "", Options.class, "SecondMutable", SecondMutable); + + @Test + public void testMutable() { + assertEquals("original", Mutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals("override1", Mutable.getValue()); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals("override2", Mutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + try (OverrideScope s3 = OptionValue.override(Mutable, "override3")) { + assertEquals("override3", Mutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + } + assertEquals("original", Mutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "original")) { + assertEquals("original", Mutable.getValue()); + } + } + + @Test + public void testMultiple() { + assertEquals("original", Mutable.getValue()); + assertEquals("second", SecondMutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1", SecondMutable, "secondOverride1")) { + assertEquals("override1", Mutable.getValue()); + assertEquals("secondOverride1", SecondMutable.getValue()); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2", SecondMutable, "secondOverride2")) { + assertEquals("override2", Mutable.getValue()); + assertEquals("secondOverride2", SecondMutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + assertEquals("secondOverride1", SecondMutable.getValue()); + try (OverrideScope s3 = OptionValue.override(Mutable, "override3", SecondMutable, "secondOverride3")) { + assertEquals("override3", Mutable.getValue()); + assertEquals("secondOverride3", SecondMutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + assertEquals("secondOverride1", SecondMutable.getValue()); + } + assertEquals("original", Mutable.getValue()); + assertEquals("second", SecondMutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "original", SecondMutable, "second")) { + assertEquals("original", Mutable.getValue()); + assertEquals("second", SecondMutable.getValue()); + } + } + + @Test + public void testStable() { + assertTrue(Stable.getValue()); + try (OverrideScope s = OptionValue.override(Stable, false)) { + fail("cannot override stable option"); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void toStringTest() { + assertEquals("jdk.internal.jvmci.options.test.TestOptionValue$Options.Mutable=original", Mutable.toString()); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals("jdk.internal.jvmci.options.test.TestOptionValue$Options.Mutable=override1", Mutable.toString()); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals("jdk.internal.jvmci.options.test.TestOptionValue$Options.Mutable=override2", Mutable.toString()); + } + } + } + + @Test + public void getValuesTest() { + assertEquals(Arrays.asList("original"), Mutable.getValues(null)); + assertEquals(Arrays.asList(true), Stable.getValues(null)); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals(Arrays.asList("override1", "original"), Mutable.getValues(null)); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals(Arrays.asList("override2", "override1", "original"), Mutable.getValues(null)); + } + } + } +} --- /dev/null 2015-09-16 15:21:35.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/ConstantTest.java 2015-09-16 15:21:35.000000000 -0700 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile ConstantTest.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.ConstantTest + */ + +package jdk.internal.jvmci.runtime.test; + +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +public class ConstantTest extends FieldUniverse { + + @Test + public void testNegativeZero() { + Assert.assertTrue("Constant for 0.0f must be different from -0.0f", JavaConstant.FLOAT_0 != JavaConstant.forFloat(-0.0F)); + Assert.assertTrue("Constant for 0.0d must be different from -0.0d", JavaConstant.DOUBLE_0 != JavaConstant.forDouble(-0.0d)); + } + + @Test + public void testNullIsNull() { + Assert.assertTrue(JavaConstant.NULL_POINTER.isNull()); + } + + @Test + public void testOne() { + for (JavaKind kind : JavaKind.values()) { + if (kind.isNumericInteger() || kind.isNumericFloat()) { + Assert.assertTrue(JavaConstant.one(kind).getJavaKind() == kind); + } + } + Assert.assertEquals(1, JavaConstant.one(JavaKind.Int).asInt()); + Assert.assertEquals(1L, JavaConstant.one(JavaKind.Long).asLong()); + Assert.assertEquals(1, JavaConstant.one(JavaKind.Byte).asInt()); + Assert.assertEquals(1, JavaConstant.one(JavaKind.Short).asInt()); + Assert.assertEquals(1, JavaConstant.one(JavaKind.Char).asInt()); + Assert.assertTrue(1F == JavaConstant.one(JavaKind.Float).asFloat()); + Assert.assertTrue(1D == JavaConstant.one(JavaKind.Double).asDouble()); + } + + @Test(expected = IllegalArgumentException.class) + public void testIllegalOne() { + JavaConstant.one(JavaKind.Illegal); + } + + @Test(expected = IllegalArgumentException.class) + public void testVoidOne() { + JavaConstant.one(JavaKind.Void); + } +} --- /dev/null 2015-09-16 15:21:36.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/FieldUniverse.java 2015-09-16 15:21:36.000000000 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.runtime.test; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +/** + * Context for field related tests. + */ +public class FieldUniverse extends TypeUniverse { + + public static final Map fields = new HashMap<>(); + + { + for (Class c : classes) { + for (Field f : c.getDeclaredFields()) { + ResolvedJavaField field = metaAccess.lookupJavaField(f); + fields.put(f, field); + } + } + } +} --- /dev/null 2015-09-16 15:21:37.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/MethodUniverse.java 2015-09-16 15:21:36.000000000 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.runtime.test; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +/** + * Context for method related tests. + */ +public class MethodUniverse extends TypeUniverse { + + public static final Map methods = new HashMap<>(); + public static final Map, ResolvedJavaMethod> constructors = new HashMap<>(); + + { + for (Class c : classes) { + for (Method m : c.getDeclaredMethods()) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + methods.put(m, method); + } + for (Constructor m : c.getDeclaredConstructors()) { + constructors.put(m, metaAccess.lookupJavaMethod(m)); + } + } + } +} --- /dev/null 2015-09-16 15:21:37.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/NameAndSignature.java 2015-09-16 15:21:37.000000000 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2012, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.runtime.test; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.runtime.*; + +class NameAndSignature { + + public static final MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + + final String name; + final Class returnType; + final Class[] parameterTypes; + + public NameAndSignature(Method m) { + this.name = m.getName(); + this.returnType = m.getReturnType(); + this.parameterTypes = m.getParameterTypes(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NameAndSignature) { + NameAndSignature s = (NameAndSignature) obj; + return s.returnType == returnType && name.equals(s.name) && Arrays.equals(s.parameterTypes, parameterTypes); + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(name + "("); + String sep = ""; + for (Class p : parameterTypes) { + sb.append(sep); + sep = ", "; + sb.append(p.getName()); + } + return sb.append(')').append(returnType.getName()).toString(); + } + + public boolean signatureEquals(ResolvedJavaMethod m) { + Signature s = m.getSignature(); + ResolvedJavaType declaringClass = m.getDeclaringClass(); + if (!s.getReturnType(declaringClass).resolve(declaringClass).equals(metaAccess.lookupJavaType(returnType))) { + return false; + } + if (s.getParameterCount(false) != parameterTypes.length) { + return false; + } + for (int i = 0; i < parameterTypes.length; i++) { + if (!s.getParameterType(i, declaringClass).resolve(declaringClass).equals(metaAccess.lookupJavaType(parameterTypes[i]))) { + return false; + } + } + return true; + } +} --- /dev/null 2015-09-16 15:21:38.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/RedefineClassTest.java 2015-09-16 15:21:38.000000000 -0700 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2011, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile RedefineClassTest.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.RedefineClassTest + */ + +package jdk.internal.jvmci.runtime.test; + +import static org.junit.Assume.*; + +import java.io.*; +import java.lang.instrument.*; +import java.lang.management.*; +import java.lang.reflect.*; +import java.nio.file.*; +import java.security.*; +import java.util.*; +import java.util.jar.*; + +import javax.tools.*; + +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +/** + * Tests that {@link ResolvedJavaMethod}s are safe in the context of class redefinition being used + * to redefine the method to which they refer. + */ +public class RedefineClassTest extends TypeUniverse { + + static class Foo { + public static Object getName() { + return "foo"; + } + } + + @Test + public void test() throws Throwable { + + Method fooMethod = Foo.class.getDeclaredMethod("getName"); + + ResolvedJavaMethod foo1 = metaAccess.lookupJavaMethod(fooMethod); + ResolvedJavaMethod foo2 = metaAccess.lookupJavaMethod(fooMethod); + + String foo1Code = Arrays.toString(foo1.getCode()); + String foo2Code = Arrays.toString(foo2.getCode()); + + Assert.assertEquals("foo", Foo.getName()); + + redefineFoo(); + System.gc(); + + // Make sure the transformation happened + Assert.assertEquals("bar", Foo.getName()); + + Assert.assertEquals(foo1Code, Arrays.toString(foo1.getCode())); + Assert.assertEquals(foo2Code, Arrays.toString(foo1.getCode())); + } + + /** + * Adds the class file bytes for a given class to a JAR stream. + */ + static void add(JarOutputStream jar, Class c) throws IOException { + String name = c.getName(); + String classAsPath = name.replace('.', '/') + ".class"; + jar.putNextEntry(new JarEntry(classAsPath)); + + InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath); + + int nRead; + byte[] buf = new byte[1024]; + while ((nRead = stream.read(buf, 0, buf.length)) != -1) { + jar.write(buf, 0, nRead); + } + + jar.closeEntry(); + } + + protected void redefineFoo() throws Exception { + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + Attributes mainAttrs = manifest.getMainAttributes(); + mainAttrs.putValue("Agent-Class", FooAgent.class.getName()); + mainAttrs.putValue("Can-Redefine-Classes", "true"); + mainAttrs.putValue("Can-Retransform-Classes", "true"); + + Path jar = Files.createTempFile("myagent", ".jar"); + try { + JarOutputStream jarStream = new JarOutputStream(new FileOutputStream(jar.toFile()), manifest); + add(jarStream, FooAgent.class); + add(jarStream, FooTransformer.class); + jarStream.close(); + + loadAgent(jar); + } finally { + Files.deleteIfExists(jar); + } + } + + public static void loadAgent(Path agent) throws Exception { + String vmName = ManagementFactory.getRuntimeMXBean().getName(); + int p = vmName.indexOf('@'); + assumeTrue(p != -1); + String pid = vmName.substring(0, p); + ClassLoader cl = ToolProvider.getSystemToolClassLoader(); + Class c = Class.forName("com.sun.tools.attach.VirtualMachine", true, cl); + Method attach = c.getDeclaredMethod("attach", String.class); + Method loadAgent = c.getDeclaredMethod("loadAgent", String.class, String.class); + Method detach = c.getDeclaredMethod("detach"); + Object vm = attach.invoke(null, pid); + loadAgent.invoke(vm, agent.toString(), ""); + detach.invoke(vm); + } + + public static class FooAgent { + + public static void agentmain(@SuppressWarnings("unused") String args, Instrumentation inst) throws Exception { + if (inst.isRedefineClassesSupported() && inst.isRetransformClassesSupported()) { + inst.addTransformer(new FooTransformer(), true); + Class[] allClasses = inst.getAllLoadedClasses(); + for (int i = 0; i < allClasses.length; i++) { + Class c = allClasses[i]; + if (c == Foo.class) { + inst.retransformClasses(new Class[]{c}); + } + } + } + } + } + + /** + * This transformer replaces the first instance of the constant "foo" in the class file for + * {@link Foo} with "bar". + */ + static class FooTransformer implements ClassFileTransformer { + + @Override + public byte[] transform(ClassLoader cl, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + if (Foo.class.equals(classBeingRedefined)) { + String cf = new String(classfileBuffer); + int i = cf.indexOf("foo"); + Assert.assertTrue("cannot find \"foo\" constant in " + Foo.class.getSimpleName() + "'s class file", i > 0); + classfileBuffer[i] = 'b'; + classfileBuffer[i + 1] = 'a'; + classfileBuffer[i + 2] = 'r'; + } + return classfileBuffer; + } + } +} --- /dev/null 2015-09-16 15:21:39.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java 2015-09-16 15:21:38.000000000 -0700 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.ResolvedJavaTypeResolveConcreteMethodTest + */ + +package jdk.internal.jvmci.runtime.test; + +import static org.junit.Assert.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.runtime.*; + +import org.junit.*; + +public class ResolvedJavaTypeResolveConcreteMethodTest { + public final MetaAccessProvider metaAccess; + + public ResolvedJavaTypeResolveConcreteMethodTest() { + metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + } + + protected abstract static class A { + @SuppressWarnings("unused") + private void priv() { + } + + public void v1() { + } + + public void v2() { + } + + public abstract void abs(); + } + + protected static class B extends A implements I { + public void i() { + } + + @Override + public void v2() { + } + + @Override + public void abs() { + + } + } + + protected static class C extends B { + public void d() { + } + } + + protected abstract static class D extends A { + + } + + protected static class E extends D { + @Override + public void abs() { + } + } + + protected interface I { + void i(); + + default void d() { + } + } + + @Test + public void testDefaultMethod() { + ResolvedJavaType i = getType(I.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod di = getMethod(i, "d"); + ResolvedJavaMethod dc = getMethod(c, "d"); + + assertEquals(di, i.resolveConcreteMethod(di, c)); + assertEquals(di, b.resolveConcreteMethod(di, c)); + assertEquals(dc, c.resolveConcreteMethod(di, c)); + } + + @Test + public void testPrivateMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod priv = getMethod(a, "priv"); + + assertNull(a.resolveConcreteMethod(priv, c)); + assertNull(b.resolveConcreteMethod(priv, c)); + } + + @Test + public void testAbstractMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaType d = getType(D.class); + ResolvedJavaType e = getType(E.class); + ResolvedJavaMethod absa = getMethod(a, "abs"); + ResolvedJavaMethod absb = getMethod(b, "abs"); + ResolvedJavaMethod abse = getMethod(e, "abs"); + + assertNull(a.resolveConcreteMethod(absa, c)); + assertNull(d.resolveConcreteMethod(absa, c)); + + assertEquals(absb, b.resolveConcreteMethod(absa, c)); + assertEquals(absb, b.resolveConcreteMethod(absb, c)); + assertEquals(absb, c.resolveConcreteMethod(absa, c)); + assertEquals(absb, c.resolveConcreteMethod(absb, c)); + assertEquals(abse, e.resolveConcreteMethod(absa, c)); + assertNull(e.resolveConcreteMethod(absb, c)); + assertEquals(abse, e.resolveConcreteMethod(abse, c)); + } + + @Test + public void testVirtualMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod v1a = getMethod(a, "v1"); + ResolvedJavaMethod v2a = getMethod(a, "v2"); + ResolvedJavaMethod v2b = getMethod(b, "v2"); + + assertEquals(v1a, a.resolveConcreteMethod(v1a, c)); + assertEquals(v1a, b.resolveConcreteMethod(v1a, c)); + assertEquals(v1a, c.resolveConcreteMethod(v1a, c)); + assertEquals(v2a, a.resolveConcreteMethod(v2a, c)); + assertEquals(v2b, b.resolveConcreteMethod(v2a, c)); + assertEquals(v2b, b.resolveConcreteMethod(v2b, c)); + assertEquals(v2b, c.resolveConcreteMethod(v2a, c)); + assertEquals(v2b, c.resolveConcreteMethod(v2b, c)); + + } + + static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) { + for (ResolvedJavaMethod method : type.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + return method; + } + } + throw new IllegalArgumentException(); + } + + protected ResolvedJavaType getType(Class clazz) { + ResolvedJavaType type = metaAccess.lookupJavaType(clazz); + type.initialize(); + return type; + } +} --- /dev/null 2015-09-16 15:21:39.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/ResolvedJavaTypeResolveMethodTest.java 2015-09-16 15:21:39.000000000 -0700 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2014, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.ResolvedJavaTypeResolveMethodTest + */ + +package jdk.internal.jvmci.runtime.test; + +import static org.junit.Assert.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.runtime.*; + +import org.junit.*; + +public class ResolvedJavaTypeResolveMethodTest { + public final MetaAccessProvider metaAccess; + + public ResolvedJavaTypeResolveMethodTest() { + metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + } + + protected abstract static class A { + @SuppressWarnings("unused") + private void priv() { + } + + public void v1() { + } + + public void v2() { + } + + public abstract void abs(); + } + + protected static class B extends A implements I { + public void i() { + } + + @Override + public void v2() { + } + + @Override + public void abs() { + + } + } + + protected static class C extends B { + public void d() { + } + } + + protected abstract static class D extends A { + + } + + protected static class E extends D { + @Override + public void abs() { + } + } + + protected interface I { + void i(); + + default void d() { + } + } + + @Test + public void testDefaultMethod() { + ResolvedJavaType i = getType(I.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod di = getMethod(i, "d"); + ResolvedJavaMethod dc = getMethod(c, "d"); + + assertEquals(di, i.resolveMethod(di, c)); + assertEquals(di, b.resolveMethod(di, c)); + assertEquals(dc, c.resolveMethod(di, c)); + } + + @Test + public void testPrivateMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod priv = getMethod(a, "priv"); + + assertNull(a.resolveMethod(priv, c)); + assertNull(b.resolveMethod(priv, c)); + } + + @Test + public void testAbstractMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaType d = getType(D.class); + ResolvedJavaType e = getType(E.class); + ResolvedJavaMethod absa = getMethod(a, "abs"); + ResolvedJavaMethod absb = getMethod(b, "abs"); + ResolvedJavaMethod abse = getMethod(e, "abs"); + + assertEquals(absa, a.resolveMethod(absa, c)); + assertEquals(absa, d.resolveMethod(absa, c)); + + assertEquals(absb, b.resolveMethod(absa, c)); + assertEquals(absb, b.resolveMethod(absb, c)); + assertEquals(absb, c.resolveMethod(absa, c)); + assertEquals(absb, c.resolveMethod(absb, c)); + assertEquals(abse, e.resolveMethod(absa, c)); + assertNull(e.resolveMethod(absb, c)); + assertEquals(abse, e.resolveMethod(abse, c)); + } + + @Test + public void testVirtualMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod v1a = getMethod(a, "v1"); + ResolvedJavaMethod v2a = getMethod(a, "v2"); + ResolvedJavaMethod v2b = getMethod(b, "v2"); + + assertEquals(v1a, a.resolveMethod(v1a, c)); + assertEquals(v1a, b.resolveMethod(v1a, c)); + assertEquals(v1a, c.resolveMethod(v1a, c)); + assertEquals(v2a, a.resolveMethod(v2a, c)); + assertEquals(v2b, b.resolveMethod(v2a, c)); + assertEquals(v2b, b.resolveMethod(v2b, c)); + assertEquals(v2b, c.resolveMethod(v2a, c)); + assertEquals(v2b, c.resolveMethod(v2b, c)); + + } + + static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) { + for (ResolvedJavaMethod method : type.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + return method; + } + } + throw new IllegalArgumentException(); + } + + protected ResolvedJavaType getType(Class clazz) { + ResolvedJavaType type = metaAccess.lookupJavaType(clazz); + type.initialize(); + return type; + } +} --- /dev/null 2015-09-16 15:21:40.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/TestConstantReflectionProvider.java 2015-09-16 15:21:40.000000000 -0700 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile TestConstantReflectionProvider.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.TestConstantReflectionProvider + */ + +package jdk.internal.jvmci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link ConstantReflectionProvider}. It assumes an implementation of the interface that + * actually returns non-null results for access operations that are possible, i.e., the tests will + * fail for an implementation that spuriously returns null (which is allowed by the specification). + */ +public class TestConstantReflectionProvider extends TypeUniverse { + + @Test + public void constantEqualsTest() { + for (ConstantValue c1 : constants()) { + for (ConstantValue c2 : constants()) { + // test symmetry + assertEquals(constantReflection.constantEquals(c1.value, c2.value), constantReflection.constantEquals(c2.value, c1.value)); + if (c1.value.getJavaKind() != JavaKind.Object && c2.value.getJavaKind() != JavaKind.Object) { + assertEquals(c1.value.equals(c2.value), constantReflection.constantEquals(c2.value, c1.value)); + } + } + } + } + + @Test + public void readArrayLengthTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + Integer actual = constantReflection.readArrayLength(c); + if (c.getJavaKind() != JavaKind.Object || c.isNull() || !cv.boxed.getClass().isArray()) { + assertNull(actual); + } else { + assertNotNull(actual); + int actualInt = actual; + assertEquals(Array.getLength(cv.boxed), actualInt); + } + } + } + + static class PrimitiveConstants { + static final long LONG_CONST = 42; + static final int INT_CONST = 66; + static final byte BYTE_CONST = 123; + static final boolean BOOL_CONST = true; + } + + static class BoxedConstants { + static final Long LONG_CONST = 42L; + static final Integer INT_CONST = 66; + static final Byte BYTE_CONST = 123; + static final Boolean BOOL_CONST = true; + } + + @Test + public void boxTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + JavaConstant boxed = constantReflection.boxPrimitive(c); + if (boxed != null && c.getJavaKind().isPrimitive()) { + assertTrue(boxed.getJavaKind().isObject()); + assertFalse(boxed.isNull()); + } + } + + List primitiveConstants = readConstants(PrimitiveConstants.class); + List boxedConstants = readConstants(BoxedConstants.class); + for (int i = 0; i < primitiveConstants.size(); i++) { + ConstantValue prim = primitiveConstants.get(i); + ConstantValue box = boxedConstants.get(i); + assertEquals(box.value, constantReflection.boxPrimitive(prim.value)); + } + + assertNull(constantReflection.boxPrimitive(JavaConstant.NULL_POINTER)); + } + + @Test + public void unboxTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + JavaConstant unboxed = c.isNull() ? null : constantReflection.unboxPrimitive(c); + if (unboxed != null) { + assertFalse(unboxed.getJavaKind().isObject()); + } + } + List primitiveConstants = readConstants(PrimitiveConstants.class); + List boxedConstants = readConstants(BoxedConstants.class); + for (int i = 0; i < primitiveConstants.size(); i++) { + ConstantValue prim = primitiveConstants.get(i); + ConstantValue box = boxedConstants.get(i); + assert prim.getSimpleName().equals(box.getSimpleName()); + assertEquals(prim.value, constantReflection.unboxPrimitive(box.value)); + } + + assertNull(constantReflection.unboxPrimitive(JavaConstant.NULL_POINTER)); + } +} --- /dev/null 2015-09-16 15:21:40.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/TestJavaField.java 2015-09-16 15:21:40.000000000 -0700 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile TestJavaField.java FieldUniverse.java TypeUniverse.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.TestJavaField + */ + +package jdk.internal.jvmci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link JavaField}. + */ +public class TestJavaField extends FieldUniverse { + + @Test + public void getNameTest() { + for (Map.Entry e : fields.entrySet()) { + String expected = e.getKey().getName(); + String actual = e.getValue().getName(); + assertEquals(expected, actual); + } + } + + @Test + public void getTypeTest() { + for (Map.Entry e : fields.entrySet()) { + // Must resolve types first as a resolved types != unresolved types + ResolvedJavaField rf = e.getValue(); + JavaType expected = metaAccess.lookupJavaType(e.getKey().getType()).resolve(rf.getDeclaringClass()); + JavaType actual = rf.getType().resolve(rf.getDeclaringClass()); + assertEquals(expected, actual); + } + } + + @Test + public void getJavaKindTest() { + for (Map.Entry e : fields.entrySet()) { + JavaKind expected = metaAccess.lookupJavaType(e.getKey().getType()).getJavaKind(); + JavaKind actual = e.getValue().getJavaKind(); + assertEquals(expected, actual); + } + } + + @Test + public void getDeclaringClassTest() { + for (Map.Entry e : fields.entrySet()) { + Class expected = e.getKey().getDeclaringClass(); + ResolvedJavaType actual = e.getValue().getDeclaringClass(); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } +} --- /dev/null 2015-09-16 15:21:41.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/TestJavaMethod.java 2015-09-16 15:21:41.000000000 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile TestJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java NameAndSignature.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.TestJavaMethod + */ + +package jdk.internal.jvmci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link JavaMethod}. + */ +public class TestJavaMethod extends MethodUniverse { + + @Test + public void getNameTest() { + for (Map.Entry e : methods.entrySet()) { + String expected = e.getKey().getName(); + String actual = e.getValue().getName(); + assertEquals(expected, actual); + } + } + + @Test + public void getDeclaringClassTest() { + for (Map.Entry e : methods.entrySet()) { + Class expected = e.getKey().getDeclaringClass(); + ResolvedJavaType actual = e.getValue().getDeclaringClass(); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + + @Test + public void getSignatureTest() { + for (Map.Entry e : methods.entrySet()) { + assertTrue(new NameAndSignature(e.getKey()).signatureEquals(e.getValue())); + } + } +} --- /dev/null 2015-09-16 15:21:42.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/TestJavaType.java 2015-09-16 15:21:41.000000000 -0700 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile TestJavaType.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.TestJavaType + */ + +package jdk.internal.jvmci.runtime.test; + +import jdk.internal.jvmci.meta.*; +import static org.junit.Assert.*; + +import org.junit.*; + +/** + * Tests for {@link JavaType}. + */ +public class TestJavaType extends TypeUniverse { + + public TestJavaType() { + } + + @Test + public void getJavaKindTest() { + for (Class c : classes) { + JavaType type = metaAccess.lookupJavaType(c); + JavaKind expected = JavaKind.fromJavaClass(c); + JavaKind actual = type.getJavaKind(); + assertEquals(expected, actual); + } + } +} --- /dev/null 2015-09-16 15:21:42.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/TestMetaAccessProvider.java 2015-09-16 15:21:42.000000000 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile TestMetaAccessProvider.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.TestMetaAccessProvider + */ + +package jdk.internal.jvmci.runtime.test; + +import static jdk.internal.jvmci.meta.MetaUtil.*; +import static org.junit.Assert.*; + +import java.lang.reflect.*; + +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link MetaAccessProvider}. + */ +public class TestMetaAccessProvider extends TypeUniverse { + + @Test + public void lookupJavaTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertNotNull(c.toString(), type); + assertEquals(c.toString(), type.getName(), toInternalName(c.getName())); + assertEquals(c.toString(), type.getName(), toInternalName(type.toJavaName())); + assertEquals(c.toString(), c.getName(), type.toClassName()); + if (!type.isArray()) { + assertEquals(c.toString(), c.getName(), type.toJavaName()); + } + } + } + + @Test + public void lookupJavaMethodTest() { + for (Class c : classes) { + for (Method reflect : c.getDeclaredMethods()) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(reflect); + assertNotNull(method); + assertTrue(method.getDeclaringClass().equals(metaAccess.lookupJavaType(reflect.getDeclaringClass()))); + } + } + } + + @Test + public void lookupJavaFieldTest() { + for (Class c : classes) { + for (Field reflect : c.getDeclaredFields()) { + ResolvedJavaField field = metaAccess.lookupJavaField(reflect); + assertNotNull(field); + assertTrue(field.getDeclaringClass().equals(metaAccess.lookupJavaType(reflect.getDeclaringClass()))); + } + } + } + + @Test + public void lookupJavaTypeConstantTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + if (c.getJavaKind() == JavaKind.Object && !c.isNull()) { + Object o = cv.boxed; + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertNotNull(type); + assertTrue(type.equals(metaAccess.lookupJavaType(o.getClass()))); + } else { + assertEquals(metaAccess.lookupJavaType(c), null); + } + } + } +} --- /dev/null 2015-09-16 15:21:43.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/TestResolvedJavaField.java 2015-09-16 15:21:43.000000000 -0700 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile TestResolvedJavaField.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.TestResolvedJavaField + */ + +package jdk.internal.jvmci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link ResolvedJavaField}. + */ +public class TestResolvedJavaField extends FieldUniverse { + + public TestResolvedJavaField() { + } + + @Test + public void getModifiersTest() { + for (Map.Entry e : fields.entrySet()) { + int expected = e.getKey().getModifiers(); + int actual = e.getValue().getModifiers(); + assertEquals(expected, actual); + } + } + + @Test + public void isSyntheticTest() { + for (Map.Entry e : fields.entrySet()) { + boolean expected = e.getKey().isSynthetic(); + boolean actual = e.getValue().isSynthetic(); + assertEquals(expected, actual); + } + } + + @Test + public void getAnnotationsTest() { + for (Map.Entry e : fields.entrySet()) { + Annotation[] expected = e.getKey().getAnnotations(); + Annotation[] actual = e.getValue().getAnnotations(); + assertArrayEquals(expected, actual); + } + } + + @Test + public void getAnnotationTest() { + for (Map.Entry e : fields.entrySet()) { + for (Annotation expected : e.getKey().getAnnotations()) { + if (expected != null) { + Annotation actual = e.getValue().getAnnotation(expected.annotationType()); + assertEquals(expected, actual); + } + } + } + } + + @Test + public void getLocationIdentityTest() { + for (Map.Entry e : fields.entrySet()) { + LocationIdentity identity = e.getValue().getLocationIdentity(); + assertTrue(identity != null); + } + } + + static class ReadConstantValueTestConstants { + String stringField = "field"; + final String constantStringField = "constantField"; + + static final Object CONST1 = new ReadConstantValueTestConstants(); + static final Object CONST2 = null; + static final Object CONST3 = new String(); + } + + @Test + public void readConstantValueTest() throws NoSuchFieldException { + ResolvedJavaField field = metaAccess.lookupJavaField(ReadConstantValueTestConstants.class.getDeclaredField("stringField")); + List receiverConstants = readConstants(ReadConstantValueTestConstants.class); + for (ConstantValue receiver : receiverConstants) { + JavaConstant value = constantReflection.readConstantFieldValue(field, receiver.value); + assertNull(value); + } + + ResolvedJavaField constField = metaAccess.lookupJavaField(ReadConstantValueTestConstants.class.getDeclaredField("constantStringField")); + for (ConstantValue receiver : receiverConstants) { + JavaConstant value = constantReflection.readConstantFieldValue(constField, receiver.value); + if (value != null) { + Object expected = "constantField"; + String actual = ((ReadConstantValueTestConstants) receiver.boxed).constantStringField; + assertTrue(actual + " != " + expected, actual == expected); + } + } + } + + private Method findTestMethod(Method apiMethod) { + String testName = apiMethod.getName() + "Test"; + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { + return m; + } + } + return null; + } + + // @formatter:off + private static final String[] untestedApiMethods = { + "getDeclaringClass", + "isInternal", + "isFinal" + }; + // @formatter:on + + /** + * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written + * for them or are added to {@link #untestedApiMethods}. + */ + @Test + public void testCoverage() { + Set known = new HashSet<>(Arrays.asList(untestedApiMethods)); + for (Method m : ResolvedJavaField.class.getDeclaredMethods()) { + if (m.isSynthetic()) { + continue; + } + if (findTestMethod(m) == null) { + assertTrue("test missing for " + m, known.contains(m.getName())); + } else { + assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); + } + } + } +} --- /dev/null 2015-09-16 15:21:44.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/TestResolvedJavaMethod.java 2015-09-16 15:21:43.000000000 -0700 @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile TestResolvedJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.TestResolvedJavaMethod + */ + +package jdk.internal.jvmci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.annotation.*; +import java.lang.invoke.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link ResolvedJavaMethod}. + */ +public class TestResolvedJavaMethod extends MethodUniverse { + + public TestResolvedJavaMethod() { + } + + /** + * @see ResolvedJavaMethod#getCode() + */ + @Test + public void getCodeTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + byte[] code = m.getCode(); + if (code == null) { + assertTrue(m.getCodeSize() == 0); + } else { + if (m.isAbstract()) { + assertTrue(code.length == 0); + } else if (!m.isNative()) { + assertTrue(code.length > 0); + } + } + } + } + + /** + * @see ResolvedJavaMethod#getCodeSize() + */ + @Test + public void getCodeSizeTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + int codeSize = m.getCodeSize(); + if (m.isAbstract()) { + assertTrue(codeSize == 0); + } else if (!m.isNative()) { + assertTrue(codeSize > 0); + } + } + } + + @Test + public void getModifiersTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + int expected = e.getKey().getModifiers(); + int actual = m.getModifiers(); + assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + int expected = e.getKey().getModifiers(); + int actual = m.getModifiers(); + assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual); + } + } + + /** + * @see ResolvedJavaMethod#isClassInitializer() + */ + @Test + public void isClassInitializerTest() { + for (Map.Entry e : methods.entrySet()) { + // Class initializers are hidden from reflection + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isClassInitializer()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isClassInitializer()); + } + } + + @Test + public void isConstructorTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isConstructor()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.isConstructor()); + } + } + + @Test + public void isSyntheticTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isSynthetic(), m.isSynthetic()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isSynthetic(), m.isSynthetic()); + } + } + + @Test + public void isBridgeTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isBridge(), m.isBridge()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(false, m.isBridge()); + } + } + + @Test + public void isVarArgsTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isVarArgs(), m.isVarArgs()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isVarArgs(), m.isVarArgs()); + } + } + + @Test + public void isSynchronizedTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized()); + } + } + + @Test + public void canBeStaticallyBoundTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey())); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey())); + } + } + + private static boolean canBeStaticallyBound(Member method) { + int modifiers = method.getModifiers(); + return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(method.getDeclaringClass().getModifiers())) && + !Modifier.isAbstract(modifiers); + } + + private static String methodWithExceptionHandlers(String p1, Object o2) { + try { + return p1.substring(100) + o2.toString(); + } catch (IndexOutOfBoundsException e) { + e.printStackTrace(); + } catch (NullPointerException e) { + e.printStackTrace(); + } catch (RuntimeException e) { + e.printStackTrace(); + } + return null; + } + + @Test + public void getExceptionHandlersTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithExceptionHandlers", String.class, Object.class)); + ExceptionHandler[] handlers = method.getExceptionHandlers(); + assertNotNull(handlers); + assertEquals(handlers.length, 3); + handlers[0].getCatchType().equals(metaAccess.lookupJavaType(IndexOutOfBoundsException.class)); + handlers[1].getCatchType().equals(metaAccess.lookupJavaType(NullPointerException.class)); + handlers[2].getCatchType().equals(metaAccess.lookupJavaType(RuntimeException.class)); + } + + private static String nullPointerExceptionOnFirstLine(Object o, String ignored) { + return o.toString() + ignored; + } + + @Test + public void asStackTraceElementTest() throws NoSuchMethodException { + try { + nullPointerExceptionOnFirstLine(null, "ignored"); + Assert.fail("should not reach here"); + } catch (NullPointerException e) { + StackTraceElement expected = e.getStackTrace()[0]; + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); + StackTraceElement actual = method.asStackTraceElement(0); + assertEquals(expected, actual); + } + } + + @Test + public void getConstantPoolTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + ConstantPool cp = m.getConstantPool(); + assertTrue(cp.length() > 0); + } + } + + @Test(timeout = 1000L) + public void getAnnotationTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationTest")); + Test annotation = method.getAnnotation(Test.class); + assertNotNull(annotation); + assertEquals(1000L, annotation.timeout()); + } + + @Test(timeout = 1000L) + public void getAnnotationsTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationsTest")); + Annotation[] annotations = method.getAnnotations(); + assertNotNull(annotations); + assertEquals(1, annotations.length); + assertEquals(1000L, ((Test) annotations[0]).timeout()); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + @interface NonNull { + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + @interface Special { + } + + private static native void methodWithAnnotatedParameters(@NonNull HashMap p1, @Special @NonNull Class p2); + + @Test + public void getParameterAnnotationsTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + Annotation[][] annotations = method.getParameterAnnotations(); + assertEquals(2, annotations.length); + assertEquals(1, annotations[0].length); + assertEquals(NonNull.class, annotations[0][0].annotationType()); + assertEquals(2, annotations[1].length); + assertEquals(Special.class, annotations[1][0].annotationType()); + assertEquals(NonNull.class, annotations[1][1].annotationType()); + } + + @Test + public void getGenericParameterTypesTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + Type[] genericParameterTypes = method.getGenericParameterTypes(); + assertEquals(2, genericParameterTypes.length); + assertEquals("java.util.HashMap", genericParameterTypes[0].toString()); + assertEquals("java.lang.Class", genericParameterTypes[1].toString()); + } + + @Test + public void getMaxLocalsTest() throws NoSuchMethodException { + ResolvedJavaMethod method1 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + ResolvedJavaMethod method2 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); + assertEquals(0, method1.getMaxLocals()); + assertEquals(2, method2.getMaxLocals()); + + } + + @Test + public void getMaxStackSizeTest() throws NoSuchMethodException { + ResolvedJavaMethod method1 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + ResolvedJavaMethod method2 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); + assertEquals(0, method1.getMaxStackSize()); + // some versions of javac produce bytecode with a stacksize of 2 for this method + // JSR 292 also sometimes need one more stack slot + int method2StackSize = method2.getMaxStackSize(); + assertTrue(2 <= method2StackSize && method2StackSize <= 4); + } + + @Test + public void isDefaultTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isDefault(), m.isDefault()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isDefault()); + } + } + + @Test + public void hasReceiverTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasReceiver() != Modifier.isStatic(e.getKey().getModifiers())); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasReceiver()); + } + } + + @Test + public void hasBytecodesTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasBytecodes() == (m.isConcrete() && !m.isNative())); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasBytecodes()); + } + } + + @Test + public void isJavaLangObjectInitTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(Object.class.getConstructor()); + assertTrue(method.isJavaLangObjectInit()); + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isJavaLangObjectInit()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + Constructor key = e.getKey(); + if (key.getDeclaringClass() == Object.class && key.getParameters().length == 0) { + assertTrue(m.isJavaLangObjectInit()); + } else { + assertFalse(m.isJavaLangObjectInit()); + } + } + } + + @Test + public void isSignaturePolymorphicTest() { + ResolvedJavaType methodHandleType = metaAccess.lookupJavaType(MethodHandle.class); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeExact", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invoke", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeBasic", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToVirtual", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToStatic", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToSpecial", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToInterface", metaAccess)); + assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "type", metaAccess)); + assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(metaAccess.lookupJavaType(Object.class), "toString", metaAccess)); + } + + private Method findTestMethod(Method apiMethod) { + String testName = apiMethod.getName() + "Test"; + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { + return m; + } + } + return null; + } + + // @formatter:off + private static final String[] untestedApiMethods = { + "invoke", + "newInstance", + "getDeclaringClass", + "getEncoding", + "getProfilingInfo", + "reprofile", + "getCompilerStorage", + "canBeInlined", + "shouldBeInlined", + "getLineNumberTable", + "getLocalVariableTable", + "isInVirtualMethodTable", + "toParameterTypes", + "getParameterAnnotation", + "getSpeculationLog", + "isFinal", + "$jacocoInit" + }; + // @formatter:on + + /** + * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written + * for them or are added to {@link #untestedApiMethods}. + */ + @Test + public void testCoverage() { + Set known = new HashSet<>(Arrays.asList(untestedApiMethods)); + for (Method m : ResolvedJavaMethod.class.getDeclaredMethods()) { + if (Modifier.isStatic(m.getModifiers())) { + continue; + } + if (findTestMethod(m) == null) { + assertTrue("test missing for " + m, known.contains(m.getName())); + } else { + assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); + } + } + } +} --- /dev/null 2015-09-16 15:21:44.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/TestResolvedJavaType.java 2015-09-16 15:21:44.000000000 -0700 @@ -0,0 +1,946 @@ +/* + * Copyright (c) 2012, 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile TestResolvedJavaType.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.internal.jvmci.runtime.test.TestResolvedJavaType + */ + +package jdk.internal.jvmci.runtime.test; + +import static java.lang.reflect.Modifier.*; +import static org.junit.Assert.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.*; +import java.util.*; + +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.meta.Assumptions.*; + +import org.junit.*; + +import sun.reflect.ConstantPool; + +/** + * Tests for {@link ResolvedJavaType}. + */ +public class TestResolvedJavaType extends TypeUniverse { + + public TestResolvedJavaType() { + } + + @Test + public void findInstanceFieldWithOffsetTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Set reflectionFields = getInstanceFields(c, true); + for (Field f : reflectionFields) { + ResolvedJavaField rf = lookupField(type.getInstanceFields(true), f); + assertNotNull(rf); + long offset = isStatic(f.getModifiers()) ? unsafe.staticFieldOffset(f) : unsafe.objectFieldOffset(f); + ResolvedJavaField result = type.findInstanceFieldWithOffset(offset, rf.getJavaKind()); + assertNotNull(result); + assertTrue(fieldsEqual(f, result)); + } + } + } + + @Test + public void isInterfaceTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = c.isInterface(); + boolean actual = type.isInterface(); + assertEquals(expected, actual); + } + } + + @Test + public void isInstanceClassTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = !c.isArray() && !c.isPrimitive() && !c.isInterface(); + boolean actual = type.isInstanceClass(); + assertEquals(expected, actual); + } + } + + @Test + public void isArrayTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = c.isArray(); + boolean actual = type.isArray(); + assertEquals(expected, actual); + } + } + + @Test + public void getModifiersTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + int expected = c.getModifiers() & ModifiersProvider.jvmClassModifiers(); + int actual = type.getModifiers() & ModifiersProvider.jvmClassModifiers(); + Class elementalType = c; + while (elementalType.isArray()) { + elementalType = elementalType.getComponentType(); + } + if (elementalType.isMemberClass()) { + // member class get their modifiers from the inner-class attribute in the JVM and + // from the classfile header in jvmci + expected &= ~(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED); + actual &= ~(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED); + } + assertEquals(String.format("%s: 0x%x != 0x%x", type, expected, actual), expected, actual); + } + } + + @Test + public void isAssignableFromTest() { + Class[] all = classes.toArray(new Class[classes.size()]); + for (int i = 0; i < all.length; i++) { + Class c1 = all[i]; + for (int j = i; j < all.length; j++) { + Class c2 = all[j]; + ResolvedJavaType t1 = metaAccess.lookupJavaType(c1); + ResolvedJavaType t2 = metaAccess.lookupJavaType(c2); + boolean expected = c1.isAssignableFrom(c2); + boolean actual = t1.isAssignableFrom(t2); + assertEquals(expected, actual); + if (expected && t1 != t2) { + assertFalse(t2.isAssignableFrom(t1)); + } + } + } + } + + @Test + public void isInstanceTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + if (c.getJavaKind() == JavaKind.Object && !c.isNull()) { + ResolvedJavaType cType = metaAccess.lookupJavaType(c); + for (ResolvedJavaType t : javaTypes) { + if (t.isAssignableFrom(cType)) { + assertTrue(t.isInstance(c)); + } else { + assertFalse(t.isInstance(c)); + } + } + } + } + } + + private static Class asExactClass(Class c) { + if (c.isArray()) { + if (asExactClass(c.getComponentType()) != null) { + return c; + } + } else { + if (c.isPrimitive() || Modifier.isFinal(c.getModifiers())) { + return c; + } + } + return null; + } + + @Test + public void asExactTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + ResolvedJavaType exactType = type.asExactType(); + Class expected = asExactClass(c); + if (expected == null) { + assertTrue("exact(" + c.getName() + ") != null", exactType == null); + } else { + assertNotNull(exactType); + assertTrue(exactType.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + @Test + public void getSuperclassTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class expected = c.getSuperclass(); + ResolvedJavaType actual = type.getSuperclass(); + if (expected == null) { + assertTrue(actual == null); + } else { + assertNotNull(actual); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + @Test + public void getInterfacesTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class[] expected = c.getInterfaces(); + ResolvedJavaType[] actual = type.getInterfaces(); + assertEquals(expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + assertTrue(actual[i].equals(metaAccess.lookupJavaType(expected[i]))); + } + } + } + + public Class getSupertype(Class c) { + assert !c.isPrimitive(); + if (c.isArray()) { + Class componentType = c.getComponentType(); + if (componentType.isPrimitive() || componentType == Object.class) { + return Object.class; + } + return getArrayClass(getSupertype(componentType)); + } + if (c.isInterface()) { + return Object.class; + } + return c.getSuperclass(); + } + + public Class findLeastCommonAncestor(Class c1Initial, Class c2Initial) { + if (c1Initial.isPrimitive() || c2Initial.isPrimitive()) { + return null; + } else { + Class c1 = c1Initial; + Class c2 = c2Initial; + while (true) { + if (c1.isAssignableFrom(c2)) { + return c1; + } + if (c2.isAssignableFrom(c1)) { + return c2; + } + c1 = getSupertype(c1); + c2 = getSupertype(c2); + } + } + } + + @Test + public void findLeastCommonAncestorTest() { + Class[] all = classes.toArray(new Class[classes.size()]); + for (int i = 0; i < all.length; i++) { + Class c1 = all[i]; + for (int j = i; j < all.length; j++) { + Class c2 = all[j]; + ResolvedJavaType t1 = metaAccess.lookupJavaType(c1); + ResolvedJavaType t2 = metaAccess.lookupJavaType(c2); + Class expected = findLeastCommonAncestor(c1, c2); + ResolvedJavaType actual = t1.findLeastCommonAncestor(t2); + if (expected == null) { + assertTrue(actual == null); + } else { + assertNotNull(actual); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + } + + private static class Base { + } + + abstract static class Abstract1 extends Base { + } + + interface Interface1 { + } + + static class Concrete1 extends Abstract1 { + } + + static class Concrete2 extends Abstract1 implements Interface1 { + } + + static class Concrete3 extends Concrete2 { + } + + static final class Final1 extends Abstract1 { + } + + abstract static class Abstract4 extends Concrete3 { + } + + void checkConcreteSubtype(ResolvedJavaType type, ResolvedJavaType expected) { + AssumptionResult leafConcreteSubtype = type.findLeafConcreteSubtype(); + if (leafConcreteSubtype == null) { + // findLeafConcreteSubtype() is conservative + } else { + if (expected == null) { + assertNull(leafConcreteSubtype); + } else { + assertTrue(leafConcreteSubtype.getResult().equals(expected)); + } + } + + if (!type.isArray()) { + ResolvedJavaType arrayType = type.getArrayClass(); + AssumptionResult arraySubtype = arrayType.findLeafConcreteSubtype(); + if (arraySubtype != null) { + assertEquals(arraySubtype.getResult(), arrayType); + } else { + // findLeafConcreteSubtype() method is conservative + } + } + } + + @Test + public void findLeafConcreteSubtypeTest() { + ResolvedJavaType base = metaAccess.lookupJavaType(Base.class); + checkConcreteSubtype(base, base); + + ResolvedJavaType a1 = metaAccess.lookupJavaType(Abstract1.class); + ResolvedJavaType c1 = metaAccess.lookupJavaType(Concrete1.class); + + checkConcreteSubtype(base, null); + checkConcreteSubtype(a1, c1); + checkConcreteSubtype(c1, c1); + + ResolvedJavaType i1 = metaAccess.lookupJavaType(Interface1.class); + ResolvedJavaType c2 = metaAccess.lookupJavaType(Concrete2.class); + + checkConcreteSubtype(base, null); + checkConcreteSubtype(a1, null); + checkConcreteSubtype(c1, c1); + checkConcreteSubtype(i1, c2); + checkConcreteSubtype(c2, c2); + + ResolvedJavaType c3 = metaAccess.lookupJavaType(Concrete3.class); + checkConcreteSubtype(c2, null); + checkConcreteSubtype(c3, c3); + + ResolvedJavaType a4 = metaAccess.lookupJavaType(Abstract4.class); + checkConcreteSubtype(c3, null); + checkConcreteSubtype(a4, null); + + ResolvedJavaType a1a = metaAccess.lookupJavaType(Abstract1[].class); + checkConcreteSubtype(a1a, null); + ResolvedJavaType c1a = metaAccess.lookupJavaType(Concrete1[].class); + checkConcreteSubtype(c1a, null); + ResolvedJavaType f1a = metaAccess.lookupJavaType(Final1[].class); + checkConcreteSubtype(f1a, f1a); + + ResolvedJavaType obja = metaAccess.lookupJavaType(Object[].class); + checkConcreteSubtype(obja, null); + + ResolvedJavaType inta = metaAccess.lookupJavaType(int[].class); + checkConcreteSubtype(inta, inta); + } + + interface NoImplementor { + } + + interface SingleImplementorInterface { + } + + static class SingleConcreteImplementor implements SingleImplementorInterface { + } + + interface SingleAbstractImplementorInterface { + } + + abstract static class SingleAbstractImplementor implements SingleAbstractImplementorInterface { + } + + interface MultiImplementorInterface { + } + + static class ConcreteImplementor1 implements MultiImplementorInterface { + } + + static class ConcreteImplementor2 implements MultiImplementorInterface { + } + + interface MultipleAbstractImplementorInterface { + } + + abstract static class MultiAbstractImplementor1 implements MultipleAbstractImplementorInterface { + } + + abstract static class MultiAbstractImplementor2 implements MultipleAbstractImplementorInterface { + } + + interface SingleAbstractImplementorInterface2 { + } + + interface ExtendedSingleImplementorInterface { + } + + abstract static class SingleAbstractImplementor2 implements SingleAbstractImplementorInterface2 { + } + + static class ConcreteTransitiveImplementor1 extends SingleAbstractImplementor2 implements ExtendedSingleImplementorInterface { + } + + static class ConcreteTransitiveImplementor2 extends SingleAbstractImplementor2 implements ExtendedSingleImplementorInterface { + } + + @Test + public void getSingleImplementorTest() { + ResolvedJavaType iNi = metaAccess.lookupJavaType(NoImplementor.class); + assertNull(iNi.getSingleImplementor()); + + ResolvedJavaType iSi = metaAccess.lookupJavaType(SingleImplementorInterface.class); + ResolvedJavaType cSi = metaAccess.lookupJavaType(SingleConcreteImplementor.class); + assertEquals(cSi, iSi.getSingleImplementor()); + + ResolvedJavaType iSai = metaAccess.lookupJavaType(SingleAbstractImplementorInterface.class); + ResolvedJavaType aSai = metaAccess.lookupJavaType(SingleAbstractImplementor.class); + assertEquals(aSai, iSai.getSingleImplementor()); + + ResolvedJavaType iMi = metaAccess.lookupJavaType(MultiImplementorInterface.class); + metaAccess.lookupJavaType(ConcreteImplementor1.class); + metaAccess.lookupJavaType(ConcreteImplementor2.class); + assertEquals(iMi, iMi.getSingleImplementor()); + + ResolvedJavaType iMai = metaAccess.lookupJavaType(MultipleAbstractImplementorInterface.class); + metaAccess.lookupJavaType(MultiAbstractImplementor1.class); + metaAccess.lookupJavaType(MultiAbstractImplementor2.class); + assertEquals(iMai, iMai.getSingleImplementor()); + + ResolvedJavaType iSai2 = metaAccess.lookupJavaType(SingleAbstractImplementorInterface2.class); + ResolvedJavaType aSai2 = metaAccess.lookupJavaType(SingleAbstractImplementor2.class); + metaAccess.lookupJavaType(ConcreteTransitiveImplementor1.class); + metaAccess.lookupJavaType(ConcreteTransitiveImplementor2.class); + assertEquals(aSai2, iSai2.getSingleImplementor()); + } + + @Test(expected = JVMCIError.class) + public void getSingleImplementorTestClassReceiver() { + ResolvedJavaType base = metaAccess.lookupJavaType(Base.class); + base.getSingleImplementor(); + } + + @Test(expected = JVMCIError.class) + public void getSingleImplementorTestPrimitiveReceiver() { + ResolvedJavaType primitive = metaAccess.lookupJavaType(int.class); + primitive.getSingleImplementor(); + } + + @Test + public void getComponentTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class expected = c.getComponentType(); + ResolvedJavaType actual = type.getComponentType(); + if (expected == null) { + assertNull(actual); + } else { + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + @Test + public void getArrayClassTest() { + for (Class c : classes) { + if (c != void.class) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class expected = getArrayClass(c); + ResolvedJavaType actual = type.getArrayClass(); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + static class Declarations { + + final Method implementation; + final Set declarations; + + public Declarations(Method impl) { + this.implementation = impl; + declarations = new HashSet<>(); + } + } + + /** + * See Method + * overriding. + */ + static boolean isOverriderOf(Method impl, Method m) { + if (!isPrivate(m.getModifiers()) && !isFinal(m.getModifiers())) { + if (m.getName().equals(impl.getName())) { + if (m.getReturnType() == impl.getReturnType()) { + if (Arrays.equals(m.getParameterTypes(), impl.getParameterTypes())) { + if (isPublic(m.getModifiers()) || isProtected(m.getModifiers())) { + // m is public or protected + return isPublic(impl.getModifiers()) || isProtected(impl.getModifiers()); + } else { + // m is package-private + return impl.getDeclaringClass().getPackage() == m.getDeclaringClass().getPackage(); + } + } + } + } + } + return false; + } + + static final Map, VTable> vtables = new HashMap<>(); + + static class VTable { + + final Map methods = new HashMap<>(); + } + + static synchronized VTable getVTable(Class c) { + VTable vtable = vtables.get(c); + if (vtable == null) { + vtable = new VTable(); + if (c != Object.class) { + VTable superVtable = getVTable(c.getSuperclass()); + vtable.methods.putAll(superVtable.methods); + } + for (Method m : c.getDeclaredMethods()) { + if (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers())) { + if (isAbstract(m.getModifiers())) { + // A subclass makes a concrete method in a superclass abstract + vtable.methods.remove(new NameAndSignature(m)); + } else { + vtable.methods.put(new NameAndSignature(m), m); + } + } + } + vtables.put(c, vtable); + } + return vtable; + } + + static Set findDeclarations(Method impl, Class c) { + Set declarations = new HashSet<>(); + NameAndSignature implSig = new NameAndSignature(impl); + if (c != null) { + for (Method m : c.getDeclaredMethods()) { + if (new NameAndSignature(m).equals(implSig)) { + declarations.add(m); + break; + } + } + if (!c.isInterface()) { + declarations.addAll(findDeclarations(impl, c.getSuperclass())); + } + for (Class i : c.getInterfaces()) { + declarations.addAll(findDeclarations(impl, i)); + } + } + return declarations; + } + + private static void checkResolveMethod(ResolvedJavaType type, ResolvedJavaType context, ResolvedJavaMethod decl, ResolvedJavaMethod expected) { + ResolvedJavaMethod impl = type.resolveConcreteMethod(decl, context); + assertEquals(expected, impl); + } + + @Test + public void resolveMethodTest() { + ResolvedJavaType context = metaAccess.lookupJavaType(TestResolvedJavaType.class); + for (Class c : classes) { + if (c.isInterface() || c.isPrimitive()) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (Method m : c.getDeclaredMethods()) { + if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) { + ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m); + ResolvedJavaMethod impl = type.resolveMethod(resolved, context); + ResolvedJavaMethod expected = resolved.isDefault() || resolved.isAbstract() ? resolved : null; + assertEquals(m.toString(), expected, impl); + } else { + // As of JDK 8, interfaces can have static and private methods + } + } + } else { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + VTable vtable = getVTable(c); + for (Method impl : vtable.methods.values()) { + Set decls = findDeclarations(impl, c); + for (Method decl : decls) { + ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl); + if (m.isPublic()) { + ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl); + checkResolveMethod(type, context, m, i); + } + } + } + } + } + } + + @Test + public void resolveConcreteMethodTest() { + ResolvedJavaType context = metaAccess.lookupJavaType(TestResolvedJavaType.class); + for (Class c : classes) { + if (c.isInterface() || c.isPrimitive()) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (Method m : c.getDeclaredMethods()) { + if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) { + ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m); + ResolvedJavaMethod impl = type.resolveConcreteMethod(resolved, context); + ResolvedJavaMethod expected = resolved.isDefault() ? resolved : null; + assertEquals(m.toString(), expected, impl); + } else { + // As of JDK 8, interfaces can have static and private methods + } + } + } else { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + VTable vtable = getVTable(c); + for (Method impl : vtable.methods.values()) { + Set decls = findDeclarations(impl, c); + for (Method decl : decls) { + ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl); + if (m.isPublic()) { + ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl); + checkResolveMethod(type, context, m, i); + } + } + } + for (Method m : c.getDeclaredMethods()) { + ResolvedJavaMethod impl = type.resolveConcreteMethod(metaAccess.lookupJavaMethod(m), context); + ResolvedJavaMethod expected = isAbstract(m.getModifiers()) ? null : impl; + assertEquals(type + " " + m.toString(), expected, impl); + } + } + } + } + + @Test + public void findUniqueConcreteMethodTest() throws NoSuchMethodException { + ResolvedJavaMethod thisMethod = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("findUniqueConcreteMethodTest")); + ResolvedJavaMethod ucm = metaAccess.lookupJavaType(getClass()).findUniqueConcreteMethod(thisMethod).getResult(); + assertEquals(thisMethod, ucm); + } + + public static Set getInstanceFields(Class c, boolean includeSuperclasses) { + if (c.isArray() || c.isPrimitive() || c.isInterface()) { + return Collections.emptySet(); + } + Set result = new HashSet<>(); + for (Field f : c.getDeclaredFields()) { + if (!Modifier.isStatic(f.getModifiers())) { + result.add(f); + } + } + if (includeSuperclasses && c != Object.class) { + result.addAll(getInstanceFields(c.getSuperclass(), true)); + } + return result; + } + + public static Set getStaticFields(Class c) { + Set result = new HashSet<>(); + for (Field f : c.getDeclaredFields()) { + if (Modifier.isStatic(f.getModifiers())) { + result.add(f); + } + } + return result; + } + + public boolean fieldsEqual(Field f, ResolvedJavaField rjf) { + return rjf.getDeclaringClass().equals(metaAccess.lookupJavaType(f.getDeclaringClass())) && rjf.getName().equals(f.getName()) && + rjf.getType().resolve(rjf.getDeclaringClass()).equals(metaAccess.lookupJavaType(f.getType())); + } + + public ResolvedJavaField lookupField(ResolvedJavaField[] fields, Field key) { + for (ResolvedJavaField rf : fields) { + if (fieldsEqual(key, rf)) { + return rf; + } + } + return null; + } + + public Field lookupField(Set fields, ResolvedJavaField key) { + for (Field f : fields) { + if (fieldsEqual(f, key)) { + return f; + } + } + return null; + } + + private static boolean isHiddenFromReflection(ResolvedJavaField f) { + if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Throwable.class)) && f.getName().equals("backtrace")) { + return true; + } + if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(ConstantPool.class)) && f.getName().equals("constantPoolOop")) { + return true; + } + if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Class.class)) && f.getName().equals("classLoader")) { + return true; + } + return false; + } + + @Test + public void getInstanceFieldsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (boolean includeSuperclasses : new boolean[]{true, false}) { + Set expected = getInstanceFields(c, includeSuperclasses); + ResolvedJavaField[] actual = type.getInstanceFields(includeSuperclasses); + for (Field f : expected) { + assertNotNull(lookupField(actual, f)); + } + for (ResolvedJavaField rf : actual) { + if (!isHiddenFromReflection(rf)) { + assertEquals(rf.toString(), lookupField(expected, rf) != null, !rf.isInternal()); + } + } + + // Test stability of getInstanceFields + ResolvedJavaField[] actual2 = type.getInstanceFields(includeSuperclasses); + assertArrayEquals(actual, actual2); + } + } + } + + @Test + public void getStaticFieldsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Set expected = getStaticFields(c); + ResolvedJavaField[] actual = type.getStaticFields(); + for (Field f : expected) { + assertNotNull(lookupField(actual, f)); + } + for (ResolvedJavaField rf : actual) { + if (!isHiddenFromReflection(rf)) { + assertEquals(lookupField(expected, rf) != null, !rf.isInternal()); + } + } + + // Test stability of getStaticFields + ResolvedJavaField[] actual2 = type.getStaticFields(); + assertArrayEquals(actual, actual2); + } + } + + @Test + public void getDeclaredMethodsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Method[] raw = c.getDeclaredMethods(); + Set expected = new HashSet<>(); + for (Method m : raw) { + ResolvedJavaMethod resolvedMethod = metaAccess.lookupJavaMethod(m); + assertNotNull(resolvedMethod); + expected.add(resolvedMethod); + } + Set actual = new HashSet<>(Arrays.asList(type.getDeclaredMethods())); + assertEquals(expected, actual); + } + } + + static class A { + static String name = "foo"; + } + + static class B extends A { + } + + static class C { + } + + static class D { + void foo() { + // use of assertions causes the class to have a + assert getClass() != null; + } + } + + static class SubD extends D { + + } + + @Test + public void getClassInitializerTest() { + assertNotNull(metaAccess.lookupJavaType(A.class).getClassInitializer()); + assertNotNull(metaAccess.lookupJavaType(D.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(B.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(C.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(int.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(void.class).getClassInitializer()); + } + + @Test + public void getAnnotationsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertArrayEquals(c.getAnnotations(), type.getAnnotations()); + } + } + + @Test + public void getAnnotationTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (Annotation a : c.getAnnotations()) { + assertEquals(a, type.getAnnotation(a.annotationType())); + } + } + } + + @Test + public void memberClassesTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertEquals(c.isLocalClass(), type.isLocal()); + assertEquals(c.isMemberClass(), type.isMember()); + Class enclc = c.getEnclosingClass(); + ResolvedJavaType enclt = type.getEnclosingType(); + assertFalse(enclc == null ^ enclt == null); + if (enclc != null) { + assertEquals(enclt, metaAccess.lookupJavaType(enclc)); + } + } + } + + @Test + public void classFilePathTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + URL path = type.getClassFilePath(); + if (type.isPrimitive() || type.isArray()) { + assertEquals(null, path); + } else { + assertNotNull(path); + String pathString = path.getPath(); + if (type.isLocal() || type.isMember()) { + assertTrue(pathString.indexOf('$') > 0); + } + } + } + } + + @Test + public void isTrustedInterfaceTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + if (TrustedInterface.class.isAssignableFrom(c)) { + assertTrue(type.isTrustedInterfaceType()); + } + } + } + + @Test + public void isLeafTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + ResolvedJavaType arrayType = c != void.class ? metaAccess.lookupJavaType(getArrayClass(c)) : null; + if (c.isPrimitive()) { + assertTrue(type.isLeaf()); + assertTrue(arrayType == null || arrayType.isLeaf()); + } else { + assertTrue(c.toString(), type.isLeaf() == arrayType.isLeaf()); + if (!c.isArray()) { + assertTrue(c.toString(), type.isLeaf() == Modifier.isFinal(c.getModifiers())); + } + } + } + } + + @Test + public void findMethodTest() { + try { + ResolvedJavaMethod findFoo = metaAccess.lookupJavaType(D.class).findMethod("foo", metaAccess.parseMethodDescriptor("()V")); + ResolvedJavaMethod expectedFoo = metaAccess.lookupJavaMethod(D.class.getDeclaredMethod("foo")); + assertEquals(expectedFoo, findFoo); + + ResolvedJavaMethod wrongReturnTypeFoo = metaAccess.lookupJavaType(D.class).findMethod("foo", metaAccess.parseMethodDescriptor("()I")); + assertNull(wrongReturnTypeFoo); + + ResolvedJavaMethod wrongArgumentsFoo = metaAccess.lookupJavaType(D.class).findMethod("foo", metaAccess.parseMethodDescriptor("(I)V")); + assertNull(wrongArgumentsFoo); + + ResolvedJavaMethod wrongNameFoo = metaAccess.lookupJavaType(D.class).findMethod("bar", metaAccess.parseMethodDescriptor("()V")); + assertNull(wrongNameFoo); + + ResolvedJavaMethod wrongClassFoo = metaAccess.lookupJavaType(SubD.class).findMethod("foo", metaAccess.parseMethodDescriptor("()V")); + assertNull(wrongClassFoo); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException(e); + } + } + + private Method findTestMethod(Method apiMethod) { + String testName = apiMethod.getName() + "Test"; + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { + return m; + } + } + return null; + } + + // @formatter:off + private static final String[] untestedApiMethods = { + "initialize", + "isPrimitive", + "newArray", + "getDeclaredConstructors", + "isInitialized", + "isLinked", + "getJavaClass", + "getObjectHub", + "hasFinalizableSubclass", + "hasFinalizer", + "getSourceFileName", + "getClassFilePath", + "isLocal", + "isJavaLangObject", + "isMember", + "getElementalType", + "getEnclosingType", + "$jacocoInit", + "isCpiSet", + "getCorrespondingCpi", + "setCorrespondingCpi" + }; + // @formatter:on + + /** + * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written + * for them or are added to {@link #untestedApiMethods}. + */ + @Test + public void testCoverage() { + Set known = new HashSet<>(Arrays.asList(untestedApiMethods)); + for (Method m : ResolvedJavaType.class.getDeclaredMethods()) { + if (findTestMethod(m) == null) { + assertTrue("test missing for " + m, known.contains(m.getName())); + } else { + assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); + } + } + } +} --- /dev/null 2015-09-16 15:21:45.000000000 -0700 +++ new/test/compiler/jvmci/jdk.internal.jvmci.runtime.test/src/jdk/internal/jvmci/runtime/test/TypeUniverse.java 2015-09-16 15:21:45.000000000 -0700 @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2013, 2014, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.runtime.test; + +import static java.lang.reflect.Modifier.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.Queue; +import java.util.stream.*; + +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.runtime.*; + +import org.junit.*; + +import sun.misc.*; + +//JaCoCo Exclude + +/** + * Context for type related tests. + */ +public class TypeUniverse { + + public static final Unsafe unsafe; + public static final double JAVA_VERSION = Double.valueOf(System.getProperty("java.specification.version")); + + public static final MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + public static final ConstantReflectionProvider constantReflection = JVMCI.getRuntime().getHostJVMCIBackend().getConstantReflection(); + public static final Collection> classes = new HashSet<>(); + public static final Set javaTypes; + public static final Map, Class> arrayClasses = new HashMap<>(); + + private static List constants; + + public class InnerClass { + + } + + public static class InnerStaticClass { + + } + + public static final class InnerStaticFinalClass { + + } + + private class PrivateInnerClass { + + } + + protected class ProtectedInnerClass { + + } + + static { + Unsafe theUnsafe = null; + try { + theUnsafe = Unsafe.getUnsafe(); + } catch (Exception e) { + try { + Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeField.setAccessible(true); + theUnsafe = (Unsafe) theUnsafeField.get(null); + } catch (Exception e1) { + throw (InternalError) new InternalError("unable to initialize unsafe").initCause(e1); + } + } + unsafe = theUnsafe; + + Class[] initialClasses = {void.class, boolean.class, byte.class, short.class, char.class, int.class, float.class, long.class, double.class, Object.class, Class.class, boolean[].class, + byte[].class, short[].class, char[].class, int[].class, float[].class, long[].class, double[].class, Object[].class, Class[].class, List[].class, boolean[][].class, + byte[][].class, short[][].class, char[][].class, int[][].class, float[][].class, long[][].class, double[][].class, Object[][].class, Class[][].class, List[][].class, + ClassLoader.class, String.class, Serializable.class, Cloneable.class, Test.class, TestMetaAccessProvider.class, List.class, Collection.class, Map.class, Queue.class, + HashMap.class, LinkedHashMap.class, IdentityHashMap.class, AbstractCollection.class, AbstractList.class, ArrayList.class, TrustedInterface.class, InnerClass.class, + InnerStaticClass.class, InnerStaticFinalClass.class, PrivateInnerClass.class, ProtectedInnerClass.class}; + for (Class c : initialClasses) { + addClass(c); + } + + javaTypes = Collections.unmodifiableSet(classes.stream().map(c -> metaAccess.lookupJavaType(c)).collect(Collectors.toSet())); + } + + static class ConstantsUniverse { + static final Object[] ARRAYS = classes.stream().map(c -> c != void.class && !c.isArray() ? Array.newInstance(c, 42) : null).filter(o -> o != null).collect(Collectors.toList()).toArray(); + static final Object CONST1 = new ArrayList<>(); + static final Object CONST2 = new ArrayList<>(); + static final Object CONST3 = new IdentityHashMap<>(); + static final Object CONST4 = new LinkedHashMap<>(); + static final Object CONST5 = new TreeMap<>(); + static final Object CONST6 = new ArrayDeque<>(); + static final Object CONST7 = new LinkedList<>(); + static final Object CONST8 = "a string"; + static final Object CONST9 = 42; + static final Object CONST10 = String.class; + static final Object CONST11 = String[].class; + } + + public static List constants() { + if (constants == null) { + List res = readConstants(JavaConstant.class); + res.addAll(readConstants(ConstantsUniverse.class)); + constants = res; + } + return constants; + } + + public static class ConstantValue { + public final String name; + public final JavaConstant value; + public final Object boxed; + + public ConstantValue(String name, JavaConstant value, Object boxed) { + this.name = name; + this.value = value; + this.boxed = boxed; + } + + @Override + public String toString() { + return name + "=" + value; + } + + public String getSimpleName() { + return name.substring(name.lastIndexOf('.') + 1); + } + } + + /** + * Reads the value of all {@code static final} fields from a given class into an array of + * {@link ConstantValue}s. + */ + public static List readConstants(Class fromClass) { + try { + List res = new ArrayList<>(); + for (Field field : fromClass.getDeclaredFields()) { + if (isStatic(field.getModifiers()) && isFinal(field.getModifiers())) { + JavaField javaField = metaAccess.lookupJavaField(field); + Object boxed = field.get(null); + if (boxed instanceof JavaConstant) { + res.add(new ConstantValue(javaField.format("%H.%n"), (JavaConstant) boxed, boxed)); + } else { + JavaConstant value = constantReflection.readConstantFieldValue(javaField, null); + if (value != null) { + res.add(new ConstantValue(javaField.format("%H.%n"), value, boxed)); + if (boxed instanceof Object[]) { + Object[] arr = (Object[]) boxed; + for (int i = 0; i < arr.length; i++) { + JavaConstant element = constantReflection.readArrayElement(value, i); + if (element != null) { + res.add(new ConstantValue(javaField.format("%H.%n[" + i + "]"), element, arr[i])); + } + } + } + } + } + } + } + return res; + } catch (Exception e) { + throw new AssertionError(e); + } + } + + public synchronized Class getArrayClass(Class componentType) { + Class arrayClass = arrayClasses.get(componentType); + if (arrayClass == null) { + arrayClass = Array.newInstance(componentType, 0).getClass(); + arrayClasses.put(componentType, arrayClass); + } + return arrayClass; + } + + public static int dimensions(Class c) { + if (c.getComponentType() != null) { + return 1 + dimensions(c.getComponentType()); + } + return 0; + } + + private static void addClass(Class c) { + if (classes.add(c)) { + if (c.getSuperclass() != null) { + addClass(c.getSuperclass()); + } + for (Class sc : c.getInterfaces()) { + addClass(sc); + } + for (Class dc : c.getDeclaredClasses()) { + addClass(dc); + } + for (Method m : c.getDeclaredMethods()) { + addClass(m.getReturnType()); + for (Class p : m.getParameterTypes()) { + addClass(p); + } + } + + if (c != void.class && dimensions(c) < 2) { + Class arrayClass = Array.newInstance(c, 0).getClass(); + arrayClasses.put(c, arrayClass); + addClass(arrayClass); + } + } + } +}