25 */
26
27 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
28 #include "gc/shenandoah/mode/shenandoahMode.hpp"
29 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
30 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
31 #include "gc/shenandoah/shenandoahForwarding.hpp"
32 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
33 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
34 #include "gc/shenandoah/shenandoahRuntime.hpp"
35 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
36 #include "interpreter/interp_masm.hpp"
37 #include "interpreter/interpreter.hpp"
38 #include "runtime/javaThread.hpp"
39 #include "runtime/sharedRuntime.hpp"
40 #ifdef COMPILER1
41 #include "c1/c1_LIRAssembler.hpp"
42 #include "c1/c1_MacroAssembler.hpp"
43 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
44 #endif
45
46 #define __ masm->
47
48 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
49 Register src, Register dst, Register count, RegSet saved_regs) {
50 if (is_oop) {
51 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
52 if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
53
54 Label done;
55
56 // Avoid calling runtime if count == 0
57 __ cbz(count, done);
58
59 // Is GC active?
60 assert(!saved_regs.contains(rscratch1), "Sanity: about to clobber rscratch1");
61 assert(!saved_regs.contains(rscratch2), "Sanity: about to clobber rscratch2");
62 Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
63 __ ldrb(rscratch1, gc_state);
64 if (ShenandoahSATBBarrier && dest_uninitialized) {
814 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow)));
815 } else {
816 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)));
817 }
818 } else {
819 assert(is_phantom, "only remaining strength");
820 assert(is_native, "phantom must only be called off-heap");
821 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom)));
822 }
823 __ blr(lr);
824 __ mov(rscratch1, r0);
825 __ pop_call_clobbered_registers();
826 __ mov(r0, rscratch1);
827
828 __ epilogue();
829 }
830
831 #undef __
832
833 #endif // COMPILER1
|
25 */
26
27 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
28 #include "gc/shenandoah/mode/shenandoahMode.hpp"
29 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
30 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
31 #include "gc/shenandoah/shenandoahForwarding.hpp"
32 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
33 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
34 #include "gc/shenandoah/shenandoahRuntime.hpp"
35 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
36 #include "interpreter/interp_masm.hpp"
37 #include "interpreter/interpreter.hpp"
38 #include "runtime/javaThread.hpp"
39 #include "runtime/sharedRuntime.hpp"
40 #ifdef COMPILER1
41 #include "c1/c1_LIRAssembler.hpp"
42 #include "c1/c1_MacroAssembler.hpp"
43 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
44 #endif
45 #ifdef COMPILER2
46 #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
47 #include "opto/output.hpp"
48 #endif
49
50 #define __ masm->
51
52 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
53 Register src, Register dst, Register count, RegSet saved_regs) {
54 if (is_oop) {
55 bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;
56 if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahLoadRefBarrier) {
57
58 Label done;
59
60 // Avoid calling runtime if count == 0
61 __ cbz(count, done);
62
63 // Is GC active?
64 assert(!saved_regs.contains(rscratch1), "Sanity: about to clobber rscratch1");
65 assert(!saved_regs.contains(rscratch2), "Sanity: about to clobber rscratch2");
66 Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
67 __ ldrb(rscratch1, gc_state);
68 if (ShenandoahSATBBarrier && dest_uninitialized) {
818 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow)));
819 } else {
820 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)));
821 }
822 } else {
823 assert(is_phantom, "only remaining strength");
824 assert(is_native, "phantom must only be called off-heap");
825 __ lea(lr, RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom)));
826 }
827 __ blr(lr);
828 __ mov(rscratch1, r0);
829 __ pop_call_clobbered_registers();
830 __ mov(r0, rscratch1);
831
832 __ epilogue();
833 }
834
835 #undef __
836
837 #endif // COMPILER1
838
839 #ifdef COMPILER2
840
841 #undef __
842 #define __ masm->
843
844
845 void ShenandoahBarrierSetAssembler::load_c2(const MachNode* node, MacroAssembler* masm, Register dst, Address src, Register tmp1, Register tmp2, bool is_narrow, bool is_acquire) {
846 // Do the actual load. This load is the candidate for implicit null check, and MUST come first.
847 if (is_narrow) {
848 if (is_acquire) {
849 assert(src.getMode() == Address::base_plus_offset && src.offset() == 0,
850 "is_acquire path requires address to be base-only");
851 __ ldarw(dst, src.base());
852 } else {
853 __ ldrw(dst, src);
854 }
855 } else {
856 if (is_acquire) {
857 assert(src.getMode() == Address::base_plus_offset && src.offset() == 0,
858 "is_acquire path requires address to be base-only");
859 __ ldar(dst, src.base());
860 } else {
861 __ ldr(dst, src);
862 }
863 }
864
865 ShenandoahBarrierStubC2::load_post(masm, node, dst, src, tmp1, tmp2, is_narrow);
866 }
867
868 void ShenandoahBarrierSetAssembler::store_c2(const MachNode* node, MacroAssembler* masm, Address dst, bool dst_narrow,
869 Register src, bool src_narrow, Register tmp1, Register tmp2, Register tmp3, bool is_volatile) {
870
871 ShenandoahBarrierStubC2::store_pre(masm, node, tmp1, dst, tmp2, tmp3, dst_narrow);
872
873 // Do the actual store
874 if (dst_narrow) {
875 if (!src_narrow) {
876 // Need to encode into rscratch, because we cannot clobber src.
877 if ((node->barrier_data() & ShenandoahBitNotNull) == 0) {
878 __ encode_heap_oop(tmp2, src);
879 } else {
880 __ encode_heap_oop_not_null(tmp2, src);
881 }
882 src = tmp2;
883 }
884
885 if (is_volatile) {
886 assert(dst.getMode() == Address::base_plus_offset && dst.offset() == 0,
887 "is_acquire path requires address to be base-only");
888 __ stlrw(src, dst.base());
889 } else {
890 __ strw(src, dst);
891 }
892 } else {
893 if (is_volatile) {
894 assert(dst.getMode() == Address::base_plus_offset && dst.offset() == 0,
895 "is_acquire path requires address to be base-only");
896 __ stlr(src, dst.base());
897 } else {
898 __ str(src, dst);
899 }
900 }
901
902 ShenandoahBarrierStubC2::store_post(masm, node, dst, tmp2, tmp3);
903 }
904
905 void ShenandoahBarrierSetAssembler::compare_and_set_c2(const MachNode* node, MacroAssembler* masm, Register res, Register addr,
906 Register oldval, Register newval, Register tmp1, Register tmp2, Register tmp3, bool exchange, bool narrow, bool weak, bool acquire) {
907 Assembler::operand_size op_size = narrow ? Assembler::word : Assembler::xword;
908
909 ShenandoahBarrierStubC2::load_store_pre(masm, node, tmp1, addr, tmp2, tmp3, narrow);
910
911 // CAS!
912 __ cmpxchg(addr, oldval, newval, op_size, acquire, /* release */ true, weak, exchange ? res : noreg);
913
914 // If we need a boolean result out of CAS, set the flag appropriately and promote the result.
915 if (!exchange) {
916 assert(res != noreg, "need result register");
917 __ cset(res, Assembler::EQ);
918 }
919
920 ShenandoahBarrierStubC2::load_store_post(masm, node, Address(addr, 0), tmp2, tmp3);
921 }
922
923 void ShenandoahBarrierSetAssembler::get_and_set_c2(const MachNode* node, MacroAssembler* masm, Register preval,
924 Register newval, Register addr, Register tmp1, Register tmp2, Register tmp3, bool is_acquire) {
925 bool is_narrow = node->bottom_type()->isa_narrowoop();
926
927 ShenandoahBarrierStubC2::load_store_pre(masm, node, tmp1, addr, tmp2, tmp3, is_narrow);
928
929 if (is_narrow) {
930 if (is_acquire) {
931 __ atomic_xchgalw(preval, newval, addr);
932 } else {
933 __ atomic_xchgw(preval, newval, addr);
934 }
935 } else {
936 if (is_acquire) {
937 __ atomic_xchgal(preval, newval, addr);
938 } else {
939 __ atomic_xchg(preval, newval, addr);
940 }
941 }
942
943 ShenandoahBarrierStubC2::load_store_post(masm, node, Address(addr, 0), tmp2, tmp3);
944 }
945
946 #undef __
947 #define __ masm.
948
949 void ShenandoahBarrierStubC2::cardtable(MacroAssembler& masm, Address address, Register tmp1, Register tmp2) {
950 assert(CardTable::dirty_card_val() == 0, "must be");
951 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
952
953 // tmp1 = card table base (holder)
954 Address curr_ct_holder_addr(rthread, in_bytes(ShenandoahThreadLocalData::card_table_offset()));
955 __ ldr(tmp1, curr_ct_holder_addr);
956
957 // tmp2 = effective address
958 __ lea(tmp2, address);
959
960 // tmp2 = &card_table[ addr >> CardTable::card_shift() ] ; card index
961 __ add(tmp2, tmp1, tmp2, Assembler::LSR, CardTable::card_shift());
962
963 if (UseCondCardMark) {
964 Label L_already_dirty;
965 __ ldrb(tmp1, Address(tmp2));
966 __ cbz(tmp1, L_already_dirty);
967 __ strb(zr, Address(tmp2));
968 __ bind(L_already_dirty);
969 } else {
970 __ strb(zr, Address(tmp2));
971 }
972 }
973
974 void ShenandoahBarrierStubC2::enter_if_gc_state(MacroAssembler& masm, const char test_state, Register tmp) {
975 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
976 PhaseOutput* const output = Compile::current()->output();
977 Address gc_state_fast(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(test_state)));
978
979 // We piggyback on scratch_emit_size mode to compute the slowpath stub size.
980 // We'll use that information to decide whether we need a far jump to the
981 // stub entry point or not. In scratch_emit_size mode we don't bind entry()
982 // because otherwise it will be rebound when we later emit the instructions
983 // for real.
984 if (_needs_far_jump) {
985 __ ldrb(tmp, gc_state_fast);
986 __ cbz(tmp, *continuation());
987 __ b(output->in_scratch_emit_size() ? *continuation() : *entry());
988 } else {
989 __ ldrb(tmp, gc_state_fast);
990 __ cbnz(tmp, output->in_scratch_emit_size() ? *continuation() : *entry());
991 }
992
993 // This is were the slowpath stub will return to or the code above will
994 // jump to if the checks are false
995 __ bind(*continuation());
996 }
997
998 void ShenandoahBarrierStubC2::emit_code(MacroAssembler& masm) {
999 Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
1000 assert(_needs_keep_alive_barrier || _needs_load_ref_barrier, "Why are you here?");
1001 PhaseOutput* const output = Compile::current()->output();
1002
1003 // We piggyback on scratch_emit_size mode to compute the slowpath stub size.
1004 // We'll use that information to decide whether we need a far jump to the
1005 // stub entry point or not. In scratch_emit_size mode we don't bind entry()
1006 // because otherwise it will be rebound when we later emit the instructions
1007 // for real.
1008 if (!output->in_scratch_emit_size()) {
1009 __ bind(*entry());
1010 }
1011
1012 // If we need to load ourselves, do it here.
1013 if (_do_load) {
1014 if (_narrow) {
1015 __ ldrw(_obj, _addr);
1016 } else {
1017 __ ldr(_obj, _addr);
1018 }
1019 }
1020
1021 // If the object is null, there is no point in applying barriers.
1022 maybe_far_jump_if_zero(masm, _obj);
1023
1024 // We need to make sure that loads done by callers survive across slow-path calls.
1025 // For self-loads, we need to care about the case when both KA and LRB are enabled (rare).
1026 bool needs_both_barriers = _needs_keep_alive_barrier && _needs_load_ref_barrier;
1027 if (!_do_load || needs_both_barriers) {
1028 preserve(_obj);
1029 }
1030
1031 // Go for barriers. Barriers can return straight to continuation, as long
1032 // as another barrier is not needed and we can reach the fastpath.
1033 if (needs_both_barriers) {
1034 // The Load match rule in the .ad file may have legitimized the load
1035 // address using a TEMP register and in that case we need to explicitly
1036 // preserve them here, because the RA does not consider TEMP as live-in,
1037 // and the KA runtime call may clobber them and cause a crash on the
1038 // subsequent LRB stub.
1039 if (_addr.base() != noreg) {
1040 preserve(_addr.base());
1041 }
1042 if (_addr.index() != noreg) {
1043 preserve(_addr.index());
1044 }
1045 keepalive(masm, nullptr);
1046 lrb(masm);
1047 } else if (_needs_keep_alive_barrier) {
1048 keepalive(masm, continuation());
1049 } else if (_needs_load_ref_barrier) {
1050 lrb(masm);
1051 } else {
1052 ShouldNotReachHere();
1053 }
1054 }
1055
1056 void ShenandoahBarrierStubC2::maybe_far_jump_if_zero(MacroAssembler& masm, Register reg) {
1057 if (_needs_far_jump) {
1058 Label L_short_jump;
1059 __ cbnz(reg, L_short_jump);
1060 __ b(*continuation());
1061 __ bind(L_short_jump);
1062 } else {
1063 __ cbz(reg, *continuation());
1064 }
1065 }
1066
1067 void ShenandoahBarrierStubC2::keepalive(MacroAssembler& masm, Label* L_done) {
1068 Address gcstate(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::MARKING)));
1069 Address index(rthread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
1070 Address buffer(rthread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
1071 Label L_through, L_slowpath;
1072
1073 // If another barrier is enabled as well, do a runtime check for a specific barrier.
1074 if (_needs_load_ref_barrier) {
1075 assert(L_done == nullptr, "L_done is always null when _needs_load_ref_barrier is true");
1076 __ ldrb(_tmp1, gcstate);
1077 __ cbz(_tmp1, L_through);
1078 }
1079
1080 // Fast-path: put object into buffer.
1081 // If buffer is already full, go slow.
1082 __ ldr(_tmp1, index);
1083 __ cbz(_tmp1, L_slowpath);
1084 __ sub(_tmp1, _tmp1, wordSize);
1085 __ str(_tmp1, index);
1086 __ ldr(_tmp2, buffer);
1087
1088 // Store the object in queue.
1089 // If object is narrow, we need to decode it before inserting.
1090 if (_narrow) {
1091 __ add(_tmp2, _tmp2, _tmp1);
1092 __ decode_heap_oop_not_null(_tmp1, _obj);
1093 __ str(_tmp1, Address(_tmp2));
1094 } else {
1095 // Buffer is 64-bit address, must be in base register.
1096 __ str(_obj, Address(_tmp2, _tmp1));
1097 }
1098
1099 // Fast-path exits here.
1100 if (L_done != nullptr) {
1101 __ b(*L_done);
1102 } else {
1103 __ b(L_through);
1104 }
1105
1106 // Slow-path: call runtime to handle.
1107 __ bind(L_slowpath);
1108
1109 {
1110 SaveLiveRegisters slr(&masm, this);
1111
1112 // Go to runtime and handle the rest there.
1113 __ mov(c_rarg0, _obj);
1114 __ mov(lr, keepalive_runtime_entry_addr());
1115 __ blr(lr);
1116 }
1117 if (L_done != nullptr) {
1118 __ b(*L_done);
1119 } else {
1120 __ bind(L_through);
1121 }
1122 }
1123
1124 void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
1125 Label L_slow;
1126
1127 // If another barrier is enabled as well, do a runtime check for a specific barrier.
1128 if (_needs_keep_alive_barrier) {
1129 char state_to_check = ShenandoahHeap::HAS_FORWARDED | (_needs_load_ref_weak_barrier ? ShenandoahHeap::WEAK_ROOTS : 0);
1130 Address gc_state_fast(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(state_to_check)));
1131 __ ldrb(_tmp1, gc_state_fast);
1132 maybe_far_jump_if_zero(masm, _tmp1);
1133 }
1134
1135 // If weak references are being processed, weak/phantom loads need to go slow,
1136 // regardless of their cset status.
1137 if (_needs_load_ref_weak_barrier) {
1138 Address gc_state_fast(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_fast_array_offset(ShenandoahHeap::WEAK_ROOTS)));
1139 __ ldrb(_tmp1, gc_state_fast);
1140 __ cbnz(_tmp1, L_slow);
1141 }
1142
1143 // Cset-check. Fall-through to slow if in collection set.
1144 bool is_aot = AOTCodeCache::is_on_for_dump();
1145 if (!is_aot) {
1146 __ mov(_tmp1, ShenandoahHeap::in_cset_fast_test_addr());
1147 if (_narrow) {
1148 __ decode_heap_oop_not_null(_tmp2, _obj);
1149 __ add(_tmp1, _tmp1, _tmp2, Assembler::LSR, ShenandoahHeapRegion::region_size_bytes_shift_jint());
1150 } else {
1151 __ add(_tmp1, _tmp1, _obj, Assembler::LSR, ShenandoahHeapRegion::region_size_bytes_shift_jint());
1152 }
1153 } else {
1154 // Generating AOT code, pull the cset bitmap and region shift from AOT table.
1155 if (_narrow) {
1156 __ decode_heap_oop_not_null(_tmp1, _obj);
1157 } else {
1158 __ mov(_tmp1, _obj);
1159 }
1160 __ lea(_tmp2, ExternalAddress(AOTRuntimeConstants::grain_shift_address()));
1161 __ ldrw(_tmp2, Address(_tmp2));
1162 __ lsrv(_tmp2, _tmp1, _tmp2);
1163 __ lea(_tmp1, ExternalAddress(AOTRuntimeConstants::cset_base_address()));
1164 __ ldr(_tmp1, Address(_tmp1));
1165 __ add(_tmp1, _tmp1, _tmp2);
1166 }
1167 __ ldrb(_tmp1, Address(_tmp1, 0));
1168 maybe_far_jump_if_zero(masm, _tmp1);
1169
1170 // Slow path
1171 __ bind(L_slow);
1172
1173 // Obj is the result, need to temporarily stop preserving it.
1174 bool is_obj_preserved = is_preserved(_obj);
1175 if (is_obj_preserved) {
1176 dont_preserve(_obj);
1177 }
1178 {
1179 SaveLiveRegisters slr(&masm, this);
1180
1181 // Shuffle in the arguments. The end result should be:
1182 // c_rarg0 <-- obj
1183 // c_rarg1 <-- lea(addr)
1184 if (c_rarg0 == _obj) {
1185 __ lea(c_rarg1, _addr);
1186 } else if (c_rarg1 == _obj) {
1187 // Set up arguments in reverse, and then flip them
1188 __ lea(c_rarg0, _addr);
1189 // flip them
1190 __ mov(_tmp1, c_rarg0);
1191 __ mov(c_rarg0, c_rarg1);
1192 __ mov(c_rarg1, _tmp1);
1193 } else {
1194 assert_different_registers(c_rarg1, _obj);
1195 __ lea(c_rarg1, _addr);
1196 __ mov(c_rarg0, _obj);
1197 }
1198
1199 // Go to runtime and handle the rest there.
1200 __ mov(lr, lrb_runtime_entry_addr());
1201 __ blr(lr);
1202
1203 // Save the result where needed. Narrow entries return narrowOop (32 bits)
1204 // and AAPCS does not guarantee the upper 32 bits of x0 are zero.
1205 if (_narrow) {
1206 __ movw(_obj, r0);
1207 } else if (_obj != r0) {
1208 __ mov(_obj, r0);
1209 }
1210 }
1211 if (is_obj_preserved) {
1212 preserve(_obj);
1213 }
1214
1215 __ b(*continuation());
1216 }
1217
1218 int ShenandoahBarrierStubC2::available_gp_registers() {
1219 Unimplemented(); // Not used
1220 return 0;
1221 }
1222
1223 bool ShenandoahBarrierStubC2::is_special_register(Register r) {
1224 Unimplemented(); // Not used
1225 return true;
1226 }
1227
1228 static ShenandoahBarrierSetC2State* barrier_set_state() {
1229 return reinterpret_cast<ShenandoahBarrierSetC2State*>(Compile::current()->barrier_set_state());
1230 }
1231
1232 static int get_stub_size(ShenandoahBarrierStubC2* stub) {
1233 PhaseOutput* const output = Compile::current()->output();
1234 assert(output->in_scratch_emit_size(), "only used when in scratch_emit_size.");
1235 BufferBlob* const blob = output->scratch_buffer_blob();
1236 CodeBuffer cb(blob->content_begin(), (address)output->scratch_locs_memory() - blob->content_begin());
1237 MacroAssembler masm(&cb);
1238 stub->emit_code(masm);
1239 return cb.insts_size();
1240 }
1241
1242 void ShenandoahBarrierStubC2::post_init() {
1243 // If we are in scratch emit mode we assume worst case, and force the use of
1244 // far branches.
1245 PhaseOutput* const output = Compile::current()->output();
1246 ShenandoahBarrierSetC2State* state = barrier_set_state();
1247 if (output->in_scratch_emit_size()) {
1248 state->inc_stubs_current_total_size(get_stub_size(this));
1249 _needs_far_jump = true;
1250 return;
1251 }
1252
1253 // The logic implemented in this stub only uses short jumps (cbz, cbnz) if
1254 // the aggregation of all relevant code sections of a method is less than 1MB
1255 // - 2KB. We could be more aggressive and try and compute the distance
1256 // between the fastpath branch and the stub entry but in practice not many
1257 // methods reach the 1MB size.
1258 const BufferSizingData* sizing = output->buffer_sizing_data();
1259 const int code_size = sizing->_code + state->stubs_current_total_size();
1260
1261 // Maximum backward range is 1M. Maximum forward reach is 1M - 4bytes.
1262 // Subtract 2K to be ultra conservative.
1263 const int cond_branch_max_reach = (int)(1*M - 2*K);
1264 _needs_far_jump = code_size >= cond_branch_max_reach;
1265 }
1266
1267 #endif // COMPILER2
|