1 /*
2 * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2014, Red Hat Inc. All rights reserved.
4 * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 *
7 * This code is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 only, as
9 * published by the Free Software Foundation.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
718 assert_cond(map != nullptr);
719
720 const int bci_off = 0;
721 const int method_off = 1;
722 // Retrieve bci
723 __ lw(bci, Address(fp, bci_off * BytesPerWord));
724 // And a pointer to the Method*
725 __ ld(method, Address(fp, method_off * BytesPerWord));
726 int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, counter_overflow), bci, method);
727 oop_maps = new OopMapSet();
728 assert_cond(oop_maps != nullptr);
729 oop_maps->add_gc_map(call_offset, map);
730 restore_live_registers(sasm);
731 __ leave();
732 __ ret();
733 }
734 break;
735
736 case StubId::c1_new_type_array_id:
737 case StubId::c1_new_object_array_id:
738 {
739 Register length = x9; // Incoming
740 Register klass = x13; // Incoming
741 Register obj = x10; // Result
742
743 if (id == StubId::c1_new_type_array_id) {
744 __ set_info("new_type_array", dont_gc_arguments);
745 } else {
746 __ set_info("new_object_array", dont_gc_arguments);
747 }
748
749 #ifdef ASSERT
750 // assert object type is really an array of the proper kind
751 {
752 Label ok;
753 Register tmp = obj;
754 __ lwu(tmp, Address(klass, Klass::layout_helper_offset()));
755 __ sraiw(tmp, tmp, Klass::_lh_array_tag_shift);
756 int tag = ((id == StubId::c1_new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value);
757 __ mv(t0, tag);
758 __ beq(t0, tmp, ok);
759 __ stop("assert(is an array klass)");
760 __ should_not_reach_here();
761 __ bind(ok);
762 }
763 #endif // ASSERT
764
765 __ enter();
766 OopMap* map = save_live_registers(sasm);
767 assert_cond(map != nullptr);
768 int call_offset = 0;
769 if (id == StubId::c1_new_type_array_id) {
770 call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length);
771 } else {
772 call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
773 }
774
775 oop_maps = new OopMapSet();
776 assert_cond(oop_maps != nullptr);
777 oop_maps->add_gc_map(call_offset, map);
778 restore_live_registers_except_r10(sasm);
779
780 __ verify_oop(obj);
781 __ leave();
782 __ ret();
783
784 // x10: new array
785 }
786 break;
787
788 case StubId::c1_new_multi_array_id:
789 {
790 StubFrame f(sasm, "new_multi_array", dont_gc_arguments);
791 // x10: klass
792 // x9: rank
793 // x12: address of 1st dimension
794 OopMap* map = save_live_registers(sasm);
795 assert_cond(map != nullptr);
796 __ mv(c_rarg1, x10);
797 __ mv(c_rarg3, x12);
798 __ mv(c_rarg2, x9);
799 int call_offset = __ call_RT(x10, noreg, CAST_FROM_FN_PTR(address, new_multi_array), x11, x12, x13);
800
801 oop_maps = new OopMapSet();
802 assert_cond(oop_maps != nullptr);
803 oop_maps->add_gc_map(call_offset, map);
804 restore_live_registers_except_r10(sasm);
805
806 // x10: new multi array
807 __ verify_oop(x10);
808 }
809 break;
810
811 case StubId::c1_register_finalizer_id:
812 {
813 __ set_info("register_finalizer", dont_gc_arguments);
814
815 // This is called via call_runtime so the arguments
816 // will be place in C abi locations
817 __ verify_oop(c_rarg0);
818
819 // load the klass and check the has finalizer flag
820 Label register_finalizer;
821 Register t = x15;
822 __ load_klass(t, x10);
823 __ lbu(t, Address(t, Klass::misc_flags_offset()));
824 __ test_bit(t0, t, exact_log2(KlassFlags::_misc_has_finalizer));
825 __ bnez(t0, register_finalizer);
826 __ ret();
827
828 __ bind(register_finalizer);
829 __ enter();
830 OopMap* oop_map = save_live_registers(sasm);
834 assert_cond(oop_maps != nullptr);
835 oop_maps->add_gc_map(call_offset, oop_map);
836
837 // Now restore all the live registers
838 restore_live_registers(sasm);
839
840 __ leave();
841 __ ret();
842 }
843 break;
844
845 case StubId::c1_throw_class_cast_exception_id:
846 {
847 StubFrame f(sasm, "throw_class_cast_exception", dont_gc_arguments, does_not_return);
848 oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
849 }
850 break;
851
852 case StubId::c1_throw_incompatible_class_change_error_id:
853 {
854 StubFrame f(sasm, "throw_incompatible_class_cast_exception", dont_gc_arguments, does_not_return);
855 oop_maps = generate_exception_throw(sasm,
856 CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
857 }
858 break;
859
860 case StubId::c1_slow_subtype_check_id:
861 {
862 // Typical calling sequence:
863 // push klass_RInfo (object klass or other subclass)
864 // push sup_k_RInfo (array element klass or other superclass)
865 // jump to slow_subtype_check
866 // Note that the subclass is pushed first, and is therefore deepest.
867 enum layout {
868 x10_off, x10_off_hi,
869 x12_off, x12_off_hi,
870 x14_off, x14_off_hi,
871 x15_off, x15_off_hi,
872 sup_k_off, sup_k_off_hi,
873 klass_off, klass_off_hi,
874 framesize,
875 result_off = sup_k_off
876 };
877
878 __ set_info("slow_subtype_check", dont_gc_arguments);
879 __ push_reg(RegSet::of(x10, x12, x14, x15), sp);
|
1 /*
2 * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2014, Red Hat Inc. All rights reserved.
4 * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved.
5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 *
7 * This code is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 only, as
9 * published by the Free Software Foundation.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
718 assert_cond(map != nullptr);
719
720 const int bci_off = 0;
721 const int method_off = 1;
722 // Retrieve bci
723 __ lw(bci, Address(fp, bci_off * BytesPerWord));
724 // And a pointer to the Method*
725 __ ld(method, Address(fp, method_off * BytesPerWord));
726 int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, counter_overflow), bci, method);
727 oop_maps = new OopMapSet();
728 assert_cond(oop_maps != nullptr);
729 oop_maps->add_gc_map(call_offset, map);
730 restore_live_registers(sasm);
731 __ leave();
732 __ ret();
733 }
734 break;
735
736 case StubId::c1_new_type_array_id:
737 case StubId::c1_new_object_array_id:
738 case StubId::c1_new_null_free_array_id:
739 {
740 Register length = x9; // Incoming
741 Register klass = x13; // Incoming
742 Register obj = x10; // Result
743
744 if (id == StubId::c1_new_type_array_id) {
745 __ set_info("new_type_array", dont_gc_arguments);
746 } else if (id == StubId::c1_new_object_array_id) {
747 __ set_info("new_object_array", dont_gc_arguments);
748 } else {
749 assert(id == StubId::c1_new_null_free_array_id, "must be");
750 __ set_info("new_null_free_array", dont_gc_arguments);
751 }
752
753 #ifdef ASSERT
754 // assert object type is really an array of the proper kind
755 {
756 Label ok;
757 Register tmp = obj;
758 __ lwu(tmp, Address(klass, Klass::layout_helper_offset()));
759 __ sraiw(tmp, tmp, Klass::_lh_array_tag_shift);
760
761 switch (id) {
762 case StubId::c1_new_type_array_id:
763 __ mv(t0, (int)Klass::_lh_array_tag_type_value);
764 __ beq(t0, tmp, ok);
765 __ stop("assert(is a type array klass)");
766 break;
767 case StubId::c1_new_object_array_id:
768 __ mv(t0, (int)Klass::_lh_array_tag_ref_value); // new "[Ljava/lang/Object;"
769 __ beq(t0, tmp, ok);
770 __ mv(t0, (int)Klass::_lh_array_tag_flat_value); // new "[LVT;"
771 __ beq(t0, tmp, ok);
772 __ stop("assert(is an object or inline type array klass)");
773 break;
774 case StubId::c1_new_null_free_array_id:
775 __ mv(t0, (int)Klass::_lh_array_tag_flat_value); // the array can be a flat array.
776 __ beq(t0, tmp, ok);
777 __ mv(t0, (int)Klass::_lh_array_tag_ref_value); // the array cannot be a flat array (due to the InlineArrayElementMaxFlatSize, etc.)
778 __ beq(t0, tmp, ok);
779 __ stop("assert(is an object or inline type array klass)");
780 break;
781 default: ShouldNotReachHere();
782 }
783
784 __ should_not_reach_here();
785 __ bind(ok);
786 }
787 #endif // ASSERT
788
789 __ enter();
790 OopMap* map = save_live_registers(sasm);
791 assert_cond(map != nullptr);
792 int call_offset = 0;
793 if (id == StubId::c1_new_type_array_id) {
794 call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length);
795 } else if (id == StubId::c1_new_object_array_id) {
796 call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length);
797 } else {
798 call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_null_free_array), klass, length);
799 }
800
801 oop_maps = new OopMapSet();
802 assert_cond(oop_maps != nullptr);
803 oop_maps->add_gc_map(call_offset, map);
804 restore_live_registers_except_r10(sasm);
805
806 __ verify_oop(obj);
807 __ leave();
808 __ ret();
809
810 // x10: new array
811 }
812 break;
813
814 case StubId::c1_new_multi_array_id:
815 {
816 StubFrame f(sasm, "new_multi_array", dont_gc_arguments);
817 // x10: klass
818 // x9: rank
819 // x12: address of 1st dimension
820 OopMap* map = save_live_registers(sasm);
821 assert_cond(map != nullptr);
822 __ mv(c_rarg1, x10);
823 __ mv(c_rarg3, x12);
824 __ mv(c_rarg2, x9);
825 int call_offset = __ call_RT(x10, noreg, CAST_FROM_FN_PTR(address, new_multi_array), x11, x12, x13);
826
827 oop_maps = new OopMapSet();
828 assert_cond(oop_maps != nullptr);
829 oop_maps->add_gc_map(call_offset, map);
830 restore_live_registers_except_r10(sasm);
831
832 // x10: new multi array
833 __ verify_oop(x10);
834 }
835 break;
836
837 case StubId::c1_buffer_inline_args_id:
838 case StubId::c1_buffer_inline_args_no_receiver_id:
839 {
840 const char* name = (id == StubId::c1_buffer_inline_args_id) ?
841 "buffer_inline_args" : "buffer_inline_args_no_receiver";
842 StubFrame f(sasm, name, dont_gc_arguments);
843 OopMap* map = save_live_registers(sasm);
844 Register method = x9; // Incoming
845 address entry = (id == StubId::c1_buffer_inline_args_id) ?
846 CAST_FROM_FN_PTR(address, buffer_inline_args) :
847 CAST_FROM_FN_PTR(address, buffer_inline_args_no_receiver);
848 // This is called from a C1 method's scalarized entry point
849 // where x10-x17 may be holding live argument values so we can't
850 // return the result in x10 as the other stubs do. RA is used as
851 // a temporary below to avoid the result being clobbered by
852 // restore_live_registers. It's saved and restored by
853 // StubAssembler::prologue and epilogue anyway.
854 int call_offset = __ call_RT(ra, noreg, entry, method);
855 oop_maps = new OopMapSet();
856 oop_maps->add_gc_map(call_offset, map);
857 restore_live_registers(sasm);
858 __ mv(x18, ra);
859 __ verify_oop(x18); // x18: an array of buffered value objects
860 }
861 break;
862
863 case StubId::c1_load_flat_array_id:
864 {
865 StubFrame f(sasm, "load_flat_array", dont_gc_arguments);
866 OopMap* map = save_live_registers(sasm);
867
868 // Called with store_parameter and not C abi
869
870 f.load_argument(1, x10); // x10,: array
871 f.load_argument(0, x11); // x11,: index
872 int call_offset = __ call_RT(x10, noreg, CAST_FROM_FN_PTR(address, load_flat_array), x10, x11);
873
874 // Ensure the stores that initialize the buffer are visible
875 // before many subsequent store that publishes this reference.
876 __ membar(MacroAssembler::StoreStore);
877
878 oop_maps = new OopMapSet();
879 oop_maps->add_gc_map(call_offset, map);
880 restore_live_registers_except_r10(sasm);
881
882 // x10: loaded element at array[index]
883 __ verify_oop(x10);
884 }
885 break;
886
887 case StubId::c1_store_flat_array_id:
888 {
889 StubFrame f(sasm, "store_flat_array", dont_gc_arguments);
890 OopMap* map = save_live_registers(sasm);
891
892 // Called with store_parameter and not C abi
893
894 f.load_argument(2, x10); // x10: array
895 f.load_argument(1, x11); // x11: index
896 f.load_argument(0, x12); // x12: value
897 int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, store_flat_array), x10, x11, x12);
898
899 oop_maps = new OopMapSet();
900 oop_maps->add_gc_map(call_offset, map);
901 restore_live_registers_except_r10(sasm);
902 }
903 break;
904
905 case StubId::c1_substitutability_check_id:
906 {
907 StubFrame f(sasm, "substitutability_check", dont_gc_arguments);
908 OopMap* map = save_live_registers(sasm);
909
910 // Called with store_parameter and not C abi
911
912 f.load_argument(1, x11); // x11,: left
913 f.load_argument(0, x12); // x12,: right
914 int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, substitutability_check), x11, x12);
915
916 oop_maps = new OopMapSet();
917 oop_maps->add_gc_map(call_offset, map);
918 restore_live_registers_except_r10(sasm);
919
920 // x10,: are the two operands substitutable
921 }
922 break;
923
924 case StubId::c1_register_finalizer_id:
925 {
926 __ set_info("register_finalizer", dont_gc_arguments);
927
928 // This is called via call_runtime so the arguments
929 // will be place in C abi locations
930 __ verify_oop(c_rarg0);
931
932 // load the klass and check the has finalizer flag
933 Label register_finalizer;
934 Register t = x15;
935 __ load_klass(t, x10);
936 __ lbu(t, Address(t, Klass::misc_flags_offset()));
937 __ test_bit(t0, t, exact_log2(KlassFlags::_misc_has_finalizer));
938 __ bnez(t0, register_finalizer);
939 __ ret();
940
941 __ bind(register_finalizer);
942 __ enter();
943 OopMap* oop_map = save_live_registers(sasm);
947 assert_cond(oop_maps != nullptr);
948 oop_maps->add_gc_map(call_offset, oop_map);
949
950 // Now restore all the live registers
951 restore_live_registers(sasm);
952
953 __ leave();
954 __ ret();
955 }
956 break;
957
958 case StubId::c1_throw_class_cast_exception_id:
959 {
960 StubFrame f(sasm, "throw_class_cast_exception", dont_gc_arguments, does_not_return);
961 oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true);
962 }
963 break;
964
965 case StubId::c1_throw_incompatible_class_change_error_id:
966 {
967 StubFrame f(sasm, "throw_incompatible_class_change_error", dont_gc_arguments, does_not_return);
968 oop_maps = generate_exception_throw(sasm,
969 CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false);
970 }
971 break;
972
973 case StubId::c1_throw_illegal_monitor_state_exception_id:
974 { StubFrame f(sasm, "throw_illegal_monitor_state_exception", dont_gc_arguments);
975 oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_illegal_monitor_state_exception), false);
976 }
977 break;
978
979 case StubId::c1_throw_identity_exception_id:
980 { StubFrame f(sasm, "throw_identity_exception", dont_gc_arguments);
981 oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_identity_exception), true);
982 }
983 break;
984
985 case StubId::c1_slow_subtype_check_id:
986 {
987 // Typical calling sequence:
988 // push klass_RInfo (object klass or other subclass)
989 // push sup_k_RInfo (array element klass or other superclass)
990 // jump to slow_subtype_check
991 // Note that the subclass is pushed first, and is therefore deepest.
992 enum layout {
993 x10_off, x10_off_hi,
994 x12_off, x12_off_hi,
995 x14_off, x14_off_hi,
996 x15_off, x15_off_hi,
997 sup_k_off, sup_k_off_hi,
998 klass_off, klass_off_hi,
999 framesize,
1000 result_off = sup_k_off
1001 };
1002
1003 __ set_info("slow_subtype_check", dont_gc_arguments);
1004 __ push_reg(RegSet::of(x10, x12, x14, x15), sp);
|