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 | |