Mercurial > hg > graal-compiler
comparison src/cpu/x86/vm/c1_Runtime1_x86.cpp @ 1429:abc670a709dc
* -XX:TraceC1X=0...5 controls the native c1x tracing
* -Dc1x.debug=true turns on the logging proxies and lots of log output on the java side
* provide more information about types to the compiler (type hierarchy, etc)
* provide exception handler tables to the compiler
* add exception handlers to the nmethod
* correct implementation of ExceptionObject
* exception handling/unwinding entry points
* modified versions of handle/unwind exception stubs using standard calling conventions
* exception throwing
* implicit null pointer exception, implicit div by 0 exception
* arraystore/classcast/arrayindex exceptions
* checkcast implementation
* newarray, anewarray, multinewarray implementation
* correct new instance initialization
* access to java class mirrors (for ldc)
* unresolved methods
* class resolving - class patching (asssembly prototype copying)
author | Lukas Stadler <lukas.stadler@oracle.com> |
---|---|
date | Tue, 31 Aug 2010 22:13:30 -0700 |
parents | 760213a60e8b |
children | 72cfb36c6bb2 |
comparison
equal
deleted
inserted
replaced
1428:695451afc619 | 1429:abc670a709dc |
---|---|
597 | 597 |
598 // target: the entry point of the method that creates and posts the exception oop | 598 // target: the entry point of the method that creates and posts the exception oop |
599 // has_argument: true if the exception needs an argument (passed on stack because registers must be preserved) | 599 // has_argument: true if the exception needs an argument (passed on stack because registers must be preserved) |
600 | 600 |
601 OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) { | 601 OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) { |
602 // preserve all registers | 602 OopMapSet* oop_maps = new OopMapSet(); |
603 int num_rt_args = has_argument ? 2 : 1; | 603 if (UseC1X) { |
604 OopMap* oop_map = save_live_registers(sasm, num_rt_args); | 604 // c1x passes the argument in r10 |
605 | 605 OopMap* oop_map = save_live_registers(sasm, 1); |
606 // now all registers are saved and can be used freely | 606 |
607 // verify that no old value is used accidentally | 607 // now all registers are saved and can be used freely |
608 __ invalidate_registers(true, true, true, true, true, true); | 608 // verify that no old value is used accidentally |
609 | 609 __ invalidate_registers(true, true, true, true, true, true); |
610 // registers used by this stub | 610 |
611 const Register temp_reg = rbx; | 611 // registers used by this stub |
612 | 612 const Register temp_reg = rbx; |
613 // load argument for exception that is passed as an argument into the stub | 613 |
614 if (has_argument) { | 614 // load argument for exception that is passed as an argument into the stub |
615 #ifdef _LP64 | 615 if (has_argument) { |
616 __ movptr(c_rarg1, Address(rbp, 2*BytesPerWord)); | 616 __ movptr(c_rarg1, r10); |
617 #else | 617 } |
618 __ movptr(temp_reg, Address(rbp, 2*BytesPerWord)); | 618 int call_offset = __ call_RT(noreg, noreg, target, has_argument ? 1 : 0); |
619 __ push(temp_reg); | 619 |
620 #endif // _LP64 | 620 oop_maps->add_gc_map(call_offset, oop_map); |
621 } else { | |
622 // preserve all registers | |
623 int num_rt_args = has_argument ? 2 : 1; | |
624 OopMap* oop_map = save_live_registers(sasm, num_rt_args); | |
625 | |
626 // now all registers are saved and can be used freely | |
627 // verify that no old value is used accidentally | |
628 __ invalidate_registers(true, true, true, true, true, true); | |
629 | |
630 // registers used by this stub | |
631 const Register temp_reg = rbx; | |
632 | |
633 // load argument for exception that is passed as an argument into the stub | |
634 if (has_argument) { | |
635 #ifdef _LP64 | |
636 __ movptr(c_rarg1, Address(rbp, 2*BytesPerWord)); | |
637 #else | |
638 __ movptr(temp_reg, Address(rbp, 2*BytesPerWord)); | |
639 __ push(temp_reg); | |
640 #endif // _LP64 | |
641 } | |
642 int call_offset = __ call_RT(noreg, noreg, target, num_rt_args - 1); | |
643 | |
644 oop_maps->add_gc_map(call_offset, oop_map); | |
621 } | 645 } |
622 int call_offset = __ call_RT(noreg, noreg, target, num_rt_args - 1); | |
623 | |
624 OopMapSet* oop_maps = new OopMapSet(); | |
625 oop_maps->add_gc_map(call_offset, oop_map); | |
626 | 646 |
627 __ stop("should not reach here"); | 647 __ stop("should not reach here"); |
628 | 648 |
629 return oop_maps; | 649 return oop_maps; |
630 } | 650 } |
713 | 733 |
714 // return to exception handler | 734 // return to exception handler |
715 __ leave(); | 735 __ leave(); |
716 __ ret(0); | 736 __ ret(0); |
717 | 737 |
738 } | |
739 | |
740 void Runtime1::c1x_generate_handle_exception(StubAssembler *sasm, OopMapSet* oop_maps, OopMap* oop_map) { | |
741 NOT_LP64(fatal("64 bit only")); | |
742 // incoming parameters | |
743 const Register exception_oop = j_rarg0; | |
744 // other registers used in this stub | |
745 const Register exception_pc = j_rarg1; | |
746 const Register thread = r15_thread; | |
747 | |
748 __ block_comment("c1x_generate_handle_exception"); | |
749 | |
750 // verify that rax, contains a valid exception | |
751 __ verify_not_null_oop(exception_oop); | |
752 | |
753 #ifdef ASSERT | |
754 // check that fields in JavaThread for exception oop and issuing pc are | |
755 // empty before writing to them | |
756 Label oop_empty; | |
757 __ cmpptr(Address(thread, JavaThread::exception_oop_offset()), (int32_t) NULL_WORD); | |
758 __ jcc(Assembler::equal, oop_empty); | |
759 __ stop("exception oop already set"); | |
760 __ bind(oop_empty); | |
761 | |
762 Label pc_empty; | |
763 __ cmpptr(Address(thread, JavaThread::exception_pc_offset()), 0); | |
764 __ jcc(Assembler::equal, pc_empty); | |
765 __ stop("exception pc already set"); | |
766 __ bind(pc_empty); | |
767 #endif | |
768 | |
769 // save exception oop and issuing pc into JavaThread | |
770 // (exception handler will load it from here) | |
771 __ movptr(Address(thread, JavaThread::exception_oop_offset()), exception_oop); | |
772 __ movptr(exception_pc, Address(rbp, 1*BytesPerWord)); | |
773 __ movptr(Address(thread, JavaThread::exception_pc_offset()), exception_pc); | |
774 | |
775 // compute the exception handler. | |
776 // the exception oop and the throwing pc are read from the fields in JavaThread | |
777 int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)); | |
778 oop_maps->add_gc_map(call_offset, oop_map); | |
779 | |
780 // rax,: handler address | |
781 // will be the deopt blob if nmethod was deoptimized while we looked up | |
782 // handler regardless of whether handler existed in the nmethod. | |
783 | |
784 // only rax, is valid at this time, all other registers have been destroyed by the runtime call | |
785 __ invalidate_registers(false, true, true, true, true, true); | |
786 | |
787 #ifdef ASSERT | |
788 // Do we have an exception handler in the nmethod? | |
789 Label done; | |
790 __ testptr(rax, rax); | |
791 __ jcc(Assembler::notZero, done); | |
792 __ stop("no handler found"); | |
793 __ bind(done); | |
794 #endif | |
795 | |
796 // exception handler found | |
797 // patch the return address -> the stub will directly return to the exception handler | |
798 __ movptr(Address(rbp, 1*BytesPerWord), rax); | |
799 | |
800 // restore registers | |
801 restore_live_registers(sasm, false); | |
802 | |
803 // return to exception handler | |
804 __ leave(); | |
805 __ ret(0); | |
718 } | 806 } |
719 | 807 |
720 | 808 |
721 void Runtime1::generate_unwind_exception(StubAssembler *sasm) { | 809 void Runtime1::generate_unwind_exception(StubAssembler *sasm) { |
722 // incoming parameters | 810 // incoming parameters |
923 | 1011 |
924 return oop_maps; | 1012 return oop_maps; |
925 | 1013 |
926 } | 1014 } |
927 | 1015 |
1016 JRT_ENTRY(void, c1x_create_null_exception(JavaThread* thread)) | |
1017 thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_NullPointerException(), NULL)()); | |
1018 JRT_END | |
1019 | |
1020 | |
1021 | |
928 | 1022 |
929 OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { | 1023 OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { |
930 | 1024 |
931 // for better readability | 1025 // for better readability |
932 const bool must_gc_arguments = true; | 1026 const bool must_gc_arguments = true; |
1305 generate_handle_exception(sasm, oop_maps, oop_map, save_fpu_registers); | 1399 generate_handle_exception(sasm, oop_maps, oop_map, save_fpu_registers); |
1306 } | 1400 } |
1307 break; | 1401 break; |
1308 | 1402 |
1309 case unwind_exception_id: | 1403 case unwind_exception_id: |
1310 { __ set_info("unwind_exception", dont_gc_arguments); | 1404 { |
1405 __ set_info("unwind_exception", dont_gc_arguments); | |
1311 // note: no stubframe since we are about to leave the current | 1406 // note: no stubframe since we are about to leave the current |
1312 // activation and we are calling a leaf VM function only. | 1407 // activation and we are calling a leaf VM function only. |
1313 generate_unwind_exception(sasm); | 1408 generate_unwind_exception(sasm); |
1314 } | 1409 } |
1315 break; | 1410 break; |
1733 | 1828 |
1734 } | 1829 } |
1735 break; | 1830 break; |
1736 #endif // !SERIALGC | 1831 #endif // !SERIALGC |
1737 | 1832 |
1833 case c1x_unwind_exception_call_id: | |
1834 { | |
1835 // remove the frame from the stack | |
1836 __ movptr(rsp, rbp); | |
1837 __ pop(rbp); | |
1838 // exception_oop is passed using ordinary java calling conventions | |
1839 __ movptr(rax, j_rarg0); | |
1840 | |
1841 Label nonNullExceptionOop; | |
1842 __ testptr(rax, rax); | |
1843 __ jcc(Assembler::notZero, nonNullExceptionOop); | |
1844 { | |
1845 __ enter(); | |
1846 oop_maps = new OopMapSet(); | |
1847 OopMap* oop_map = save_live_registers(sasm, 0); | |
1848 int call_offset = __ call_RT(rax, noreg, (address)c1x_create_null_exception, 0); | |
1849 oop_maps->add_gc_map(call_offset, oop_map); | |
1850 __ leave(); | |
1851 } | |
1852 __ bind(nonNullExceptionOop); | |
1853 | |
1854 __ set_info("unwind_exception", dont_gc_arguments); | |
1855 // note: no stubframe since we are about to leave the current | |
1856 // activation and we are calling a leaf VM function only. | |
1857 generate_unwind_exception(sasm); | |
1858 __ should_not_reach_here(); | |
1859 } | |
1860 break; | |
1861 | |
1862 case c1x_handle_exception_id: | |
1863 { StubFrame f(sasm, "c1x_handle_exception", dont_gc_arguments); | |
1864 oop_maps = new OopMapSet(); | |
1865 OopMap* oop_map = save_live_registers(sasm, 1, false); | |
1866 c1x_generate_handle_exception(sasm, oop_maps, oop_map); | |
1867 } | |
1868 break; | |
1869 | |
1870 case c1x_global_implicit_null_id: | |
1871 { | |
1872 __ push(rax); | |
1873 __ push(rax); | |
1874 // move saved fp to make space for the inserted return address | |
1875 __ get_thread(rax); | |
1876 __ movptr(rax, Address(rax, JavaThread::saved_exception_pc_offset())); | |
1877 __ movptr(Address(rsp, HeapWordSize), rax); | |
1878 __ pop(rax); | |
1879 | |
1880 { StubFrame f(sasm, "c1x_global_implicit_null_id", dont_gc_arguments); | |
1881 oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false); | |
1882 } | |
1883 } | |
1884 break; | |
1885 | |
1886 case c1x_throw_div0_exception_id: | |
1887 { | |
1888 __ push(rax); | |
1889 __ push(rax); | |
1890 // move saved fp to make space for the inserted return address | |
1891 __ get_thread(rax); | |
1892 __ movptr(rax, Address(rax, JavaThread::saved_exception_pc_offset())); | |
1893 __ movptr(Address(rsp, HeapWordSize), rax); | |
1894 __ pop(rax); | |
1895 | |
1896 { StubFrame f(sasm, "throw_div0_exception", dont_gc_arguments); | |
1897 oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false); | |
1898 } | |
1899 } | |
1900 break; | |
1901 | |
1902 case c1x_slow_subtype_check_id: | |
1903 { | |
1904 Label success; | |
1905 Label miss; | |
1906 | |
1907 // TODO this should really be within the XirSnippets | |
1908 __ check_klass_subtype_fast_path(j_rarg0, j_rarg1, j_rarg2, &success, &miss, NULL); | |
1909 __ check_klass_subtype_slow_path(j_rarg0, j_rarg1, j_rarg2, j_rarg3, NULL, &miss); | |
1910 | |
1911 // fallthrough on success: | |
1912 __ bind(success); | |
1913 __ movptr(rax, 1); | |
1914 __ ret(0); | |
1915 | |
1916 __ bind(miss); | |
1917 __ movptr(rax, NULL_WORD); | |
1918 __ ret(0); | |
1919 } | |
1920 break; | |
1738 default: | 1921 default: |
1739 { StubFrame f(sasm, "unimplemented entry", dont_gc_arguments); | 1922 { StubFrame f(sasm, "unimplemented entry", dont_gc_arguments); |
1740 __ movptr(rax, (int)id); | 1923 __ movptr(rax, (int)id); |
1741 __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax); | 1924 __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax); |
1742 __ should_not_reach_here(); | 1925 __ should_not_reach_here(); |