1 /* 2 * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "asm/macroAssembler.hpp" 26 #include "code/codeBlob.hpp" 27 #include "gc/shared/barrierSet.hpp" 28 #include "gc/shared/barrierSetAssembler.hpp" 29 #include "memory/resourceArea.hpp" 30 #include "prims/jniFastGetField.hpp" 31 #include "prims/jvm_misc.hpp" 32 #include "prims/jvmtiExport.hpp" 33 #include "runtime/safepoint.hpp" 34 35 #define __ masm-> 36 37 #define BUFFER_SIZE 40*wordSize 38 39 // Common register usage: 40 // rax/xmm0: result 41 // c_rarg0: jni env 42 // c_rarg1: obj 43 // c_rarg2: jfield id 44 45 static const Register rtmp = rax; // r8 == c_rarg2 on Windows 46 static const Register robj = r9; 47 static const Register roffset = r10; 48 static const Register rcounter = r11; 49 50 address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { 51 const char *name = nullptr; 52 switch (type) { 53 case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break; 54 case T_BYTE: name = "jni_fast_GetByteField"; break; 55 case T_CHAR: name = "jni_fast_GetCharField"; break; 56 case T_SHORT: name = "jni_fast_GetShortField"; break; 57 case T_INT: name = "jni_fast_GetIntField"; break; 58 case T_LONG: name = "jni_fast_GetLongField"; break; 59 default: ShouldNotReachHere(); 60 } 61 ResourceMark rm; 62 BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); 63 CodeBuffer cbuf(blob); 64 MacroAssembler* masm = new MacroAssembler(&cbuf); 65 address fast_entry = __ pc(); 66 67 Label slow; 68 69 ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr()); 70 __ mov32 (rcounter, counter); 71 __ mov (robj, c_rarg1); 72 __ testb (rcounter, 1); 73 __ jcc (Assembler::notZero, slow); 74 75 if (JvmtiExport::can_post_field_access()) { 76 // Check to see if a field access watch has been set before we take the fast path. 77 assert_different_registers(rscratch1, robj, rcounter); 78 __ cmp32(ExternalAddress(JvmtiExport::get_field_access_count_addr()), 0, rscratch1); 79 __ jcc(Assembler::notZero, slow); 80 } 81 82 __ mov (roffset, c_rarg2); 83 __ shrptr(roffset, 2); // offset 84 85 // Both robj and rtmp are clobbered by try_resolve_jobject_in_native. 86 BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); 87 bs->try_resolve_jobject_in_native(masm, /* jni_env */ c_rarg0, robj, rtmp, slow); 88 DEBUG_ONLY(__ movl(rtmp, 0xDEADC0DE);) 89 90 assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); 91 speculative_load_pclist[count] = __ pc(); 92 switch (type) { 93 case T_BOOLEAN: __ movzbl (rax, Address(robj, roffset, Address::times_1)); break; 94 case T_BYTE: __ movsbl (rax, Address(robj, roffset, Address::times_1)); break; 95 case T_CHAR: __ movzwl (rax, Address(robj, roffset, Address::times_1)); break; 96 case T_SHORT: __ movswl (rax, Address(robj, roffset, Address::times_1)); break; 97 case T_INT: __ movl (rax, Address(robj, roffset, Address::times_1)); break; 98 case T_LONG: __ movq (rax, Address(robj, roffset, Address::times_1)); break; 99 default: ShouldNotReachHere(); 100 } 101 102 __ cmp32 (rcounter, counter, rscratch1); 103 __ jcc (Assembler::notEqual, slow); 104 105 __ ret (0); 106 107 slowcase_entry_pclist[count++] = __ pc(); 108 __ bind (slow); 109 address slow_case_addr = nullptr; 110 switch (type) { 111 case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break; 112 case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break; 113 case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break; 114 case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break; 115 case T_INT: slow_case_addr = jni_GetIntField_addr(); break; 116 case T_LONG: slow_case_addr = jni_GetLongField_addr(); break; 117 default: break; 118 } 119 // tail call 120 __ jump (RuntimeAddress(slow_case_addr), rscratch1); 121 122 __ flush (); 123 124 return fast_entry; 125 } 126 127 address JNI_FastGetField::generate_fast_get_boolean_field() { 128 return generate_fast_get_int_field0(T_BOOLEAN); 129 } 130 131 address JNI_FastGetField::generate_fast_get_byte_field() { 132 return generate_fast_get_int_field0(T_BYTE); 133 } 134 135 address JNI_FastGetField::generate_fast_get_char_field() { 136 return generate_fast_get_int_field0(T_CHAR); 137 } 138 139 address JNI_FastGetField::generate_fast_get_short_field() { 140 return generate_fast_get_int_field0(T_SHORT); 141 } 142 143 address JNI_FastGetField::generate_fast_get_int_field() { 144 return generate_fast_get_int_field0(T_INT); 145 } 146 147 address JNI_FastGetField::generate_fast_get_long_field() { 148 return generate_fast_get_int_field0(T_LONG); 149 } 150 151 address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { 152 const char *name = nullptr; 153 switch (type) { 154 case T_FLOAT: name = "jni_fast_GetFloatField"; break; 155 case T_DOUBLE: name = "jni_fast_GetDoubleField"; break; 156 default: ShouldNotReachHere(); 157 } 158 ResourceMark rm; 159 BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); 160 CodeBuffer cbuf(blob); 161 MacroAssembler* masm = new MacroAssembler(&cbuf); 162 address fast_entry = __ pc(); 163 164 Label slow; 165 166 ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr()); 167 __ mov32 (rcounter, counter); 168 __ mov (robj, c_rarg1); 169 __ testb (rcounter, 1); 170 __ jcc (Assembler::notZero, slow); 171 172 if (JvmtiExport::can_post_field_access()) { 173 // Check to see if a field access watch has been set before we 174 // take the fast path. 175 __ cmp32(ExternalAddress(JvmtiExport::get_field_access_count_addr()), 0, rscratch1); 176 __ jcc(Assembler::notZero, slow); 177 } 178 179 // Both robj and rtmp are clobbered by try_resolve_jobject_in_native. 180 BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); 181 bs->try_resolve_jobject_in_native(masm, /* jni_env */ c_rarg0, robj, rtmp, slow); 182 DEBUG_ONLY(__ movl(rtmp, 0xDEADC0DE);) 183 184 __ mov (roffset, c_rarg2); 185 __ shrptr(roffset, 2); // offset 186 187 assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); 188 speculative_load_pclist[count] = __ pc(); 189 switch (type) { 190 case T_FLOAT: __ movflt (xmm0, Address(robj, roffset, Address::times_1)); break; 191 case T_DOUBLE: __ movdbl (xmm0, Address(robj, roffset, Address::times_1)); break; 192 default: ShouldNotReachHere(); 193 } 194 __ cmp32 (rcounter, counter, rscratch1); 195 __ jcc (Assembler::notEqual, slow); 196 197 __ ret (0); 198 199 slowcase_entry_pclist[count++] = __ pc(); 200 __ bind (slow); 201 address slow_case_addr = nullptr; 202 switch (type) { 203 case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; 204 case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; 205 default: break; 206 } 207 // tail call 208 __ jump (RuntimeAddress(slow_case_addr), rscratch1); 209 210 __ flush (); 211 212 return fast_entry; 213 } 214 215 address JNI_FastGetField::generate_fast_get_float_field() { 216 return generate_fast_get_float_field0(T_FLOAT); 217 } 218 219 address JNI_FastGetField::generate_fast_get_double_field() { 220 return generate_fast_get_float_field0(T_DOUBLE); 221 }