jniFastGetField_x86_64.cpp revision 3883:cd3d6a6b95d9
1/*
2 * Copyright (c) 2004, 2010, 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 "memory/resourceArea.hpp"
28#include "prims/jniFastGetField.hpp"
29#include "prims/jvm_misc.hpp"
30#include "runtime/safepoint.hpp"
31
32#define __ masm->
33
34#define BUFFER_SIZE 30*wordSize
35
36// Instead of issuing lfence for LoadLoad barrier, we create data dependency
37// between loads, which is more efficient than lfence.
38
39// Common register usage:
40// rax/xmm0: result
41// c_rarg0:    jni env
42// c_rarg1:    obj
43// c_rarg2:    jfield id
44
45static const Register robj          = r9;
46static const Register rcounter      = r10;
47static const Register roffset       = r11;
48static 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
53address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
54  const char *name;
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  if (os::is_MP()) {
78    __ xorptr(robj, rcounter);
79    __ xorptr(robj, rcounter);                   // obj, since
80                                                // robj ^ rcounter ^ rcounter == robj
81                                                // robj is data dependent on rcounter.
82  }
83  __ movptr(robj, Address(robj, 0));             // *obj
84  __ mov   (roffset, c_rarg2);
85  __ shrptr(roffset, 2);                         // offset
86
87  assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
88  speculative_load_pclist[count] = __ pc();
89  switch (type) {
90    case T_BOOLEAN: __ movzbl (rax, Address(robj, roffset, Address::times_1)); break;
91    case T_BYTE:    __ movsbl (rax, Address(robj, roffset, Address::times_1)); break;
92    case T_CHAR:    __ movzwl (rax, Address(robj, roffset, Address::times_1)); break;
93    case T_SHORT:   __ movswl (rax, Address(robj, roffset, Address::times_1)); break;
94    case T_INT:     __ movl   (rax, Address(robj, roffset, Address::times_1)); break;
95    case T_LONG:    __ movq   (rax, Address(robj, roffset, Address::times_1)); break;
96    default:        ShouldNotReachHere();
97  }
98
99  if (os::is_MP()) {
100    __ lea(rcounter_addr, counter);
101    // ca is data dependent on rax.
102    __ xorptr(rcounter_addr, rax);
103    __ xorptr(rcounter_addr, rax);
104    __ cmpl (rcounter, Address(rcounter_addr, 0));
105  } else {
106    __ cmp32 (rcounter, counter);
107  }
108  __ jcc (Assembler::notEqual, slow);
109
110  __ ret (0);
111
112  slowcase_entry_pclist[count++] = __ pc();
113  __ bind (slow);
114  address slow_case_addr;
115  switch (type) {
116    case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break;
117    case T_BYTE:    slow_case_addr = jni_GetByteField_addr();    break;
118    case T_CHAR:    slow_case_addr = jni_GetCharField_addr();    break;
119    case T_SHORT:   slow_case_addr = jni_GetShortField_addr();   break;
120    case T_INT:     slow_case_addr = jni_GetIntField_addr();     break;
121    case T_LONG:    slow_case_addr = jni_GetLongField_addr();
122  }
123  // tail call
124  __ jump (ExternalAddress(slow_case_addr));
125
126  __ flush ();
127
128  return fast_entry;
129}
130
131address JNI_FastGetField::generate_fast_get_boolean_field() {
132  return generate_fast_get_int_field0(T_BOOLEAN);
133}
134
135address JNI_FastGetField::generate_fast_get_byte_field() {
136  return generate_fast_get_int_field0(T_BYTE);
137}
138
139address JNI_FastGetField::generate_fast_get_char_field() {
140  return generate_fast_get_int_field0(T_CHAR);
141}
142
143address JNI_FastGetField::generate_fast_get_short_field() {
144  return generate_fast_get_int_field0(T_SHORT);
145}
146
147address JNI_FastGetField::generate_fast_get_int_field() {
148  return generate_fast_get_int_field0(T_INT);
149}
150
151address JNI_FastGetField::generate_fast_get_long_field() {
152  return generate_fast_get_int_field0(T_LONG);
153}
154
155address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
156  const char *name;
157  switch (type) {
158    case T_FLOAT:     name = "jni_fast_GetFloatField";     break;
159    case T_DOUBLE:    name = "jni_fast_GetDoubleField";    break;
160    default:          ShouldNotReachHere();
161  }
162  ResourceMark rm;
163  BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE);
164  CodeBuffer cbuf(blob);
165  MacroAssembler* masm = new MacroAssembler(&cbuf);
166  address fast_entry = __ pc();
167
168  Label slow;
169
170  ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr());
171  __ mov32 (rcounter, counter);
172  __ mov   (robj, c_rarg1);
173  __ testb (rcounter, 1);
174  __ jcc (Assembler::notZero, slow);
175  if (os::is_MP()) {
176    __ xorptr(robj, rcounter);
177    __ xorptr(robj, rcounter);                   // obj, since
178                                                // robj ^ rcounter ^ rcounter == robj
179                                                // robj is data dependent on rcounter.
180  }
181  __ movptr(robj, Address(robj, 0));             // *obj
182  __ mov   (roffset, c_rarg2);
183  __ shrptr(roffset, 2);                         // offset
184
185  assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
186  speculative_load_pclist[count] = __ pc();
187  switch (type) {
188    case T_FLOAT:  __ movflt (xmm0, Address(robj, roffset, Address::times_1)); break;
189    case T_DOUBLE: __ movdbl (xmm0, Address(robj, roffset, Address::times_1)); break;
190    default:        ShouldNotReachHere();
191  }
192
193  if (os::is_MP()) {
194    __ lea(rcounter_addr, counter);
195    __ movdq (rax, xmm0);
196    // counter address is data dependent on xmm0.
197    __ xorptr(rcounter_addr, rax);
198    __ xorptr(rcounter_addr, rax);
199    __ cmpl (rcounter, Address(rcounter_addr, 0));
200  } else {
201    __ cmp32 (rcounter, counter);
202  }
203  __ jcc (Assembler::notEqual, slow);
204
205  __ ret (0);
206
207  slowcase_entry_pclist[count++] = __ pc();
208  __ bind (slow);
209  address slow_case_addr;
210  switch (type) {
211    case T_FLOAT:     slow_case_addr = jni_GetFloatField_addr();  break;
212    case T_DOUBLE:    slow_case_addr = jni_GetDoubleField_addr();
213  }
214  // tail call
215  __ jump (ExternalAddress(slow_case_addr));
216
217  __ flush ();
218
219  return fast_entry;
220}
221
222address JNI_FastGetField::generate_fast_get_float_field() {
223  return generate_fast_get_float_field0(T_FLOAT);
224}
225
226address JNI_FastGetField::generate_fast_get_double_field() {
227  return generate_fast_get_float_field0(T_DOUBLE);
228}
229