| 1 | /* |
| 2 | * Copyright (c) 2004, 2017, 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 "precompiled.hpp" |
| 26 | #include "asm/macroAssembler.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 "runtime/safepoint.hpp" |
| 33 | |
| 34 | #define __ masm-> |
| 35 | |
| 36 | #define BUFFER_SIZE 30*wordSize |
| 37 | |
| 38 | // Common register usage: |
| 39 | // rax/xmm0: result |
| 40 | // c_rarg0: jni env |
| 41 | // c_rarg1: obj |
| 42 | // c_rarg2: jfield id |
| 43 | |
| 44 | static const Register rtmp = r8; |
| 45 | static const Register robj = r9; |
| 46 | static const Register rcounter = r10; |
| 47 | static const Register roffset = r11; |
| 48 | static const Register rcounter_addr = r11; |
| 49 | |
| 50 | // Warning: do not use rip relative addressing after the first counter load |
| 51 | // since that may scratch r10! |
| 52 | |
| 53 | address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { |
| 54 | const char *name = NULL; |
| 55 | switch (type) { |
| 56 | case T_BOOLEAN: name = "jni_fast_GetBooleanField" ; break; |
| 57 | case T_BYTE: name = "jni_fast_GetByteField" ; break; |
| 58 | case T_CHAR: name = "jni_fast_GetCharField" ; break; |
| 59 | case T_SHORT: name = "jni_fast_GetShortField" ; break; |
| 60 | case T_INT: name = "jni_fast_GetIntField" ; break; |
| 61 | case T_LONG: name = "jni_fast_GetLongField" ; break; |
| 62 | default: ShouldNotReachHere(); |
| 63 | } |
| 64 | ResourceMark rm; |
| 65 | BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); |
| 66 | CodeBuffer cbuf(blob); |
| 67 | MacroAssembler* masm = new MacroAssembler(&cbuf); |
| 68 | address fast_entry = __ pc(); |
| 69 | |
| 70 | Label slow; |
| 71 | |
| 72 | ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr()); |
| 73 | __ mov32 (rcounter, counter); |
| 74 | __ mov (robj, c_rarg1); |
| 75 | __ testb (rcounter, 1); |
| 76 | __ jcc (Assembler::notZero, slow); |
| 77 | __ mov (roffset, c_rarg2); |
| 78 | __ shrptr(roffset, 2); // offset |
| 79 | |
| 80 | // Both robj and rtmp are clobbered by try_resolve_jobject_in_native. |
| 81 | BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); |
| 82 | bs->try_resolve_jobject_in_native(masm, /* jni_env */ c_rarg0, robj, rtmp, slow); |
| 83 | DEBUG_ONLY(__ movl(rtmp, 0xDEADC0DE);) |
| 84 | |
| 85 | assert(count < LIST_CAPACITY, "LIST_CAPACITY too small" ); |
| 86 | speculative_load_pclist[count] = __ pc(); |
| 87 | switch (type) { |
| 88 | case T_BOOLEAN: __ movzbl (rax, Address(robj, roffset, Address::times_1)); break; |
| 89 | case T_BYTE: __ movsbl (rax, Address(robj, roffset, Address::times_1)); break; |
| 90 | case T_CHAR: __ movzwl (rax, Address(robj, roffset, Address::times_1)); break; |
| 91 | case T_SHORT: __ movswl (rax, Address(robj, roffset, Address::times_1)); break; |
| 92 | case T_INT: __ movl (rax, Address(robj, roffset, Address::times_1)); break; |
| 93 | case T_LONG: __ movq (rax, Address(robj, roffset, Address::times_1)); break; |
| 94 | default: ShouldNotReachHere(); |
| 95 | } |
| 96 | |
| 97 | __ cmp32 (rcounter, counter); |
| 98 | __ jcc (Assembler::notEqual, slow); |
| 99 | |
| 100 | __ ret (0); |
| 101 | |
| 102 | slowcase_entry_pclist[count++] = __ pc(); |
| 103 | __ bind (slow); |
| 104 | address slow_case_addr = NULL; |
| 105 | switch (type) { |
| 106 | case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break; |
| 107 | case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break; |
| 108 | case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break; |
| 109 | case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break; |
| 110 | case T_INT: slow_case_addr = jni_GetIntField_addr(); break; |
| 111 | case T_LONG: slow_case_addr = jni_GetLongField_addr(); break; |
| 112 | default: break; |
| 113 | } |
| 114 | // tail call |
| 115 | __ jump (ExternalAddress(slow_case_addr)); |
| 116 | |
| 117 | __ flush (); |
| 118 | |
| 119 | return fast_entry; |
| 120 | } |
| 121 | |
| 122 | address JNI_FastGetField::generate_fast_get_boolean_field() { |
| 123 | return generate_fast_get_int_field0(T_BOOLEAN); |
| 124 | } |
| 125 | |
| 126 | address JNI_FastGetField::generate_fast_get_byte_field() { |
| 127 | return generate_fast_get_int_field0(T_BYTE); |
| 128 | } |
| 129 | |
| 130 | address JNI_FastGetField::generate_fast_get_char_field() { |
| 131 | return generate_fast_get_int_field0(T_CHAR); |
| 132 | } |
| 133 | |
| 134 | address JNI_FastGetField::generate_fast_get_short_field() { |
| 135 | return generate_fast_get_int_field0(T_SHORT); |
| 136 | } |
| 137 | |
| 138 | address JNI_FastGetField::generate_fast_get_int_field() { |
| 139 | return generate_fast_get_int_field0(T_INT); |
| 140 | } |
| 141 | |
| 142 | address JNI_FastGetField::generate_fast_get_long_field() { |
| 143 | return generate_fast_get_int_field0(T_LONG); |
| 144 | } |
| 145 | |
| 146 | address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { |
| 147 | const char *name = NULL; |
| 148 | switch (type) { |
| 149 | case T_FLOAT: name = "jni_fast_GetFloatField" ; break; |
| 150 | case T_DOUBLE: name = "jni_fast_GetDoubleField" ; break; |
| 151 | default: ShouldNotReachHere(); |
| 152 | } |
| 153 | ResourceMark rm; |
| 154 | BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); |
| 155 | CodeBuffer cbuf(blob); |
| 156 | MacroAssembler* masm = new MacroAssembler(&cbuf); |
| 157 | address fast_entry = __ pc(); |
| 158 | |
| 159 | Label slow; |
| 160 | |
| 161 | ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr()); |
| 162 | __ mov32 (rcounter, counter); |
| 163 | __ mov (robj, c_rarg1); |
| 164 | __ testb (rcounter, 1); |
| 165 | __ jcc (Assembler::notZero, slow); |
| 166 | |
| 167 | // Both robj and rtmp are clobbered by try_resolve_jobject_in_native. |
| 168 | BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); |
| 169 | bs->try_resolve_jobject_in_native(masm, /* jni_env */ c_rarg0, robj, rtmp, slow); |
| 170 | DEBUG_ONLY(__ movl(rtmp, 0xDEADC0DE);) |
| 171 | |
| 172 | __ mov (roffset, c_rarg2); |
| 173 | __ shrptr(roffset, 2); // offset |
| 174 | |
| 175 | assert(count < LIST_CAPACITY, "LIST_CAPACITY too small" ); |
| 176 | speculative_load_pclist[count] = __ pc(); |
| 177 | switch (type) { |
| 178 | case T_FLOAT: __ movflt (xmm0, Address(robj, roffset, Address::times_1)); break; |
| 179 | case T_DOUBLE: __ movdbl (xmm0, Address(robj, roffset, Address::times_1)); break; |
| 180 | default: ShouldNotReachHere(); |
| 181 | } |
| 182 | __ cmp32 (rcounter, counter); |
| 183 | __ jcc (Assembler::notEqual, slow); |
| 184 | |
| 185 | __ ret (0); |
| 186 | |
| 187 | slowcase_entry_pclist[count++] = __ pc(); |
| 188 | __ bind (slow); |
| 189 | address slow_case_addr = NULL; |
| 190 | switch (type) { |
| 191 | case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; |
| 192 | case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; |
| 193 | default: break; |
| 194 | } |
| 195 | // tail call |
| 196 | __ jump (ExternalAddress(slow_case_addr)); |
| 197 | |
| 198 | __ flush (); |
| 199 | |
| 200 | return fast_entry; |
| 201 | } |
| 202 | |
| 203 | address JNI_FastGetField::generate_fast_get_float_field() { |
| 204 | return generate_fast_get_float_field0(T_FLOAT); |
| 205 | } |
| 206 | |
| 207 | address JNI_FastGetField::generate_fast_get_double_field() { |
| 208 | return generate_fast_get_float_field0(T_DOUBLE); |
| 209 | } |
| 210 | |