|
1 /* |
|
2 * Copyright (c) 1997, 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 #ifndef CPU_SPARC_VM_NATIVEINST_SPARC_HPP |
|
26 #define CPU_SPARC_VM_NATIVEINST_SPARC_HPP |
|
27 |
|
28 #include "asm/macroAssembler.hpp" |
|
29 #include "memory/allocation.hpp" |
|
30 #include "runtime/icache.hpp" |
|
31 #include "runtime/os.hpp" |
|
32 |
|
33 // We have interface for the following instructions: |
|
34 // - NativeInstruction |
|
35 // - - NativeCall |
|
36 // - - NativeFarCall |
|
37 // - - NativeMovConstReg |
|
38 // - - NativeMovConstRegPatching |
|
39 // - - NativeMovRegMem |
|
40 // - - NativeJump |
|
41 // - - NativeGeneralJump |
|
42 // - - NativeIllegalInstruction |
|
43 // The base class for different kinds of native instruction abstractions. |
|
44 // Provides the primitive operations to manipulate code relative to this. |
|
45 class NativeInstruction VALUE_OBJ_CLASS_SPEC { |
|
46 friend class Relocation; |
|
47 |
|
48 public: |
|
49 enum Sparc_specific_constants { |
|
50 nop_instruction_size = 4 |
|
51 }; |
|
52 |
|
53 bool is_nop() { return long_at(0) == nop_instruction(); } |
|
54 bool is_call() { return is_op(long_at(0), Assembler::call_op); } |
|
55 bool is_call_reg() { return is_op(long_at(0), Assembler::arith_op); } |
|
56 bool is_sethi() { return (is_op2(long_at(0), Assembler::sethi_op2) |
|
57 && inv_rd(long_at(0)) != G0); } |
|
58 |
|
59 bool sets_cc() { |
|
60 // conservative (returns true for some instructions that do not set the |
|
61 // the condition code, such as, "save". |
|
62 // Does not return true for the deprecated tagged instructions, such as, TADDcc |
|
63 int x = long_at(0); |
|
64 return (is_op(x, Assembler::arith_op) && |
|
65 (inv_op3(x) & Assembler::cc_bit_op3) == Assembler::cc_bit_op3); |
|
66 } |
|
67 bool is_illegal(); |
|
68 bool is_zombie() { |
|
69 int x = long_at(0); |
|
70 return (is_op3(x, Assembler::ldsw_op3, Assembler::ldst_op) && |
|
71 inv_rs1(x) == G0 && inv_rd(x) == O7); |
|
72 } |
|
73 bool is_ic_miss_trap(); // Inline-cache uses a trap to detect a miss |
|
74 bool is_return() { |
|
75 // is it the output of MacroAssembler::ret or MacroAssembler::retl? |
|
76 int x = long_at(0); |
|
77 const int pc_return_offset = 8; // see frame_sparc.hpp |
|
78 return is_op3(x, Assembler::jmpl_op3, Assembler::arith_op) |
|
79 && (inv_rs1(x) == I7 || inv_rs1(x) == O7) |
|
80 && inv_immed(x) && inv_simm(x, 13) == pc_return_offset |
|
81 && inv_rd(x) == G0; |
|
82 } |
|
83 bool is_int_jump() { |
|
84 // is it the output of MacroAssembler::b? |
|
85 int x = long_at(0); |
|
86 return is_op2(x, Assembler::bp_op2) || is_op2(x, Assembler::br_op2); |
|
87 } |
|
88 bool is_float_jump() { |
|
89 // is it the output of MacroAssembler::fb? |
|
90 int x = long_at(0); |
|
91 return is_op2(x, Assembler::fbp_op2) || is_op2(x, Assembler::fb_op2); |
|
92 } |
|
93 bool is_jump() { |
|
94 return is_int_jump() || is_float_jump(); |
|
95 } |
|
96 bool is_cond_jump() { |
|
97 int x = long_at(0); |
|
98 return (is_int_jump() && Assembler::inv_cond(x) != Assembler::always) || |
|
99 (is_float_jump() && Assembler::inv_cond(x) != Assembler::f_always); |
|
100 } |
|
101 |
|
102 bool is_stack_bang() { |
|
103 int x = long_at(0); |
|
104 return is_op3(x, Assembler::stw_op3, Assembler::ldst_op) && |
|
105 (inv_rd(x) == G0) && (inv_rs1(x) == SP) && (inv_rs2(x) == G3_scratch); |
|
106 } |
|
107 |
|
108 bool is_prefetch() { |
|
109 int x = long_at(0); |
|
110 return is_op3(x, Assembler::prefetch_op3, Assembler::ldst_op); |
|
111 } |
|
112 |
|
113 bool is_membar() { |
|
114 int x = long_at(0); |
|
115 return is_op3(x, Assembler::membar_op3, Assembler::arith_op) && |
|
116 (inv_rd(x) == G0) && (inv_rs1(x) == O7); |
|
117 } |
|
118 |
|
119 bool is_safepoint_poll() { |
|
120 int x = long_at(0); |
|
121 return is_op3(x, Assembler::ldx_op3, Assembler::ldst_op) && |
|
122 (inv_rd(x) == G0) && (inv_immed(x) ? Assembler::inv_simm13(x) == 0 : inv_rs2(x) == G0); |
|
123 } |
|
124 |
|
125 bool is_zero_test(Register ®); |
|
126 bool is_load_store_with_small_offset(Register reg); |
|
127 |
|
128 public: |
|
129 static int nop_instruction() { return Assembler::op(Assembler::branch_op) | Assembler::op2(Assembler::sethi_op2); } |
|
130 static int illegal_instruction(); // the output of __ breakpoint_trap() |
|
131 static int call_instruction(address destination, address pc) { return Assembler::op(Assembler::call_op) | Assembler::wdisp((intptr_t)destination, (intptr_t)pc, 30); } |
|
132 |
|
133 protected: |
|
134 address addr_at(int offset) const { return address(this) + offset; } |
|
135 int long_at(int offset) const { return *(int*)addr_at(offset); } |
|
136 void set_long_at(int offset, int i); /* deals with I-cache */ |
|
137 void set_jlong_at(int offset, jlong i); /* deals with I-cache */ |
|
138 void set_addr_at(int offset, address x); /* deals with I-cache */ |
|
139 |
|
140 address instruction_address() const { return addr_at(0); } |
|
141 address next_instruction_address() const { return addr_at(BytesPerInstWord); } |
|
142 |
|
143 static bool is_op( int x, Assembler::ops opval) { |
|
144 return Assembler::inv_op(x) == opval; |
|
145 } |
|
146 static bool is_op2(int x, Assembler::op2s op2val) { |
|
147 return Assembler::inv_op(x) == Assembler::branch_op && Assembler::inv_op2(x) == op2val; |
|
148 } |
|
149 static bool is_op3(int x, Assembler::op3s op3val, Assembler::ops opval) { |
|
150 return Assembler::inv_op(x) == opval && Assembler::inv_op3(x) == op3val; |
|
151 } |
|
152 |
|
153 // utilities to help subclasses decode: |
|
154 static Register inv_rd( int x ) { return Assembler::inv_rd( x); } |
|
155 static Register inv_rs1( int x ) { return Assembler::inv_rs1(x); } |
|
156 static Register inv_rs2( int x ) { return Assembler::inv_rs2(x); } |
|
157 |
|
158 static bool inv_immed( int x ) { return Assembler::inv_immed(x); } |
|
159 static bool inv_annul( int x ) { return (Assembler::annul(true) & x) != 0; } |
|
160 static int inv_cond( int x ) { return Assembler::inv_cond(x); } |
|
161 |
|
162 static int inv_op( int x ) { return Assembler::inv_op( x); } |
|
163 static int inv_op2( int x ) { return Assembler::inv_op2(x); } |
|
164 static int inv_op3( int x ) { return Assembler::inv_op3(x); } |
|
165 |
|
166 static int inv_simm( int x, int nbits ) { return Assembler::inv_simm(x, nbits); } |
|
167 static intptr_t inv_wdisp( int x, int nbits ) { return Assembler::inv_wdisp( x, 0, nbits); } |
|
168 static intptr_t inv_wdisp16( int x ) { return Assembler::inv_wdisp16(x, 0); } |
|
169 static int branch_destination_offset(int x) { return MacroAssembler::branch_destination(x, 0); } |
|
170 static int patch_branch_destination_offset(int dest_offset, int x) { |
|
171 return MacroAssembler::patched_branch(dest_offset, x, 0); |
|
172 } |
|
173 |
|
174 // utility for checking if x is either of 2 small constants |
|
175 static bool is_either(int x, int k1, int k2) { |
|
176 // return x == k1 || x == k2; |
|
177 return (1 << x) & (1 << k1 | 1 << k2); |
|
178 } |
|
179 |
|
180 // utility for checking overflow of signed instruction fields |
|
181 static bool fits_in_simm(int x, int nbits) { |
|
182 // cf. Assembler::assert_signed_range() |
|
183 // return -(1 << nbits-1) <= x && x < ( 1 << nbits-1), |
|
184 return (unsigned)(x + (1 << nbits-1)) < (unsigned)(1 << nbits); |
|
185 } |
|
186 |
|
187 // set a signed immediate field |
|
188 static int set_simm(int insn, int imm, int nbits) { |
|
189 return (insn &~ Assembler::simm(-1, nbits)) | Assembler::simm(imm, nbits); |
|
190 } |
|
191 |
|
192 // set a wdisp field (disp should be the difference of two addresses) |
|
193 static int set_wdisp(int insn, intptr_t disp, int nbits) { |
|
194 return (insn &~ Assembler::wdisp((intptr_t)-4, (intptr_t)0, nbits)) | Assembler::wdisp(disp, 0, nbits); |
|
195 } |
|
196 |
|
197 static int set_wdisp16(int insn, intptr_t disp) { |
|
198 return (insn &~ Assembler::wdisp16((intptr_t)-4, 0)) | Assembler::wdisp16(disp, 0); |
|
199 } |
|
200 |
|
201 // get a simm13 field from an arithmetic or memory instruction |
|
202 static int get_simm13(int insn) { |
|
203 assert(is_either(Assembler::inv_op(insn), |
|
204 Assembler::arith_op, Assembler::ldst_op) && |
|
205 (insn & Assembler::immed(true)), "must have a simm13 field"); |
|
206 return Assembler::inv_simm(insn, 13); |
|
207 } |
|
208 |
|
209 // set the simm13 field of an arithmetic or memory instruction |
|
210 static bool set_simm13(int insn, int imm) { |
|
211 get_simm13(insn); // tickle the assertion check |
|
212 return set_simm(insn, imm, 13); |
|
213 } |
|
214 |
|
215 // combine the fields of a sethi stream (7 instructions ) and an add, jmp or ld/st |
|
216 static intptr_t data64( address pc, int arith_insn ) { |
|
217 assert(is_op2(*(unsigned int *)pc, Assembler::sethi_op2), "must be sethi"); |
|
218 intptr_t hi = (intptr_t)gethi( (unsigned int *)pc ); |
|
219 intptr_t lo = (intptr_t)get_simm13(arith_insn); |
|
220 assert((unsigned)lo < (1 << 10), "offset field of set_metadata must be 10 bits"); |
|
221 return hi | lo; |
|
222 } |
|
223 |
|
224 // Regenerate the instruction sequence that performs the 64 bit |
|
225 // sethi. This only does the sethi. The disp field (bottom 10 bits) |
|
226 // must be handled separately. |
|
227 static void set_data64_sethi(address instaddr, intptr_t x); |
|
228 static void verify_data64_sethi(address instaddr, intptr_t x); |
|
229 |
|
230 // combine the fields of a sethi/simm13 pair (simm13 = or, add, jmpl, ld/st) |
|
231 static int data32(int sethi_insn, int arith_insn) { |
|
232 assert(is_op2(sethi_insn, Assembler::sethi_op2), "must be sethi"); |
|
233 int hi = Assembler::inv_hi22(sethi_insn); |
|
234 int lo = get_simm13(arith_insn); |
|
235 assert((unsigned)lo < (1 << 10), "offset field of set_metadata must be 10 bits"); |
|
236 return hi | lo; |
|
237 } |
|
238 |
|
239 static int set_data32_sethi(int sethi_insn, int imm) { |
|
240 // note that Assembler::hi22 clips the low 10 bits for us |
|
241 assert(is_op2(sethi_insn, Assembler::sethi_op2), "must be sethi"); |
|
242 return (sethi_insn &~ Assembler::hi22(-1)) | Assembler::hi22(imm); |
|
243 } |
|
244 |
|
245 static int set_data32_simm13(int arith_insn, int imm) { |
|
246 get_simm13(arith_insn); // tickle the assertion check |
|
247 int imm10 = Assembler::low10(imm); |
|
248 return (arith_insn &~ Assembler::simm(-1, 13)) | Assembler::simm(imm10, 13); |
|
249 } |
|
250 |
|
251 static int low10(int imm) { |
|
252 return Assembler::low10(imm); |
|
253 } |
|
254 |
|
255 // Perform the inverse of the LP64 Macroassembler::sethi |
|
256 // routine. Extracts the 54 bits of address from the instruction |
|
257 // stream. This routine must agree with the sethi routine in |
|
258 // assembler_inline_sparc.hpp |
|
259 static address gethi( unsigned int *pc ) { |
|
260 int i = 0; |
|
261 uintptr_t adr; |
|
262 // We first start out with the real sethi instruction |
|
263 assert(is_op2(*pc, Assembler::sethi_op2), "in gethi - must be sethi"); |
|
264 adr = (unsigned int)Assembler::inv_hi22( *(pc++) ); |
|
265 i++; |
|
266 while ( i < 7 ) { |
|
267 // We're done if we hit a nop |
|
268 if ( (int)*pc == nop_instruction() ) break; |
|
269 assert ( Assembler::inv_op(*pc) == Assembler::arith_op, "in gethi - must be arith_op" ); |
|
270 switch ( Assembler::inv_op3(*pc) ) { |
|
271 case Assembler::xor_op3: |
|
272 adr ^= (intptr_t)get_simm13( *pc ); |
|
273 return ( (address)adr ); |
|
274 break; |
|
275 case Assembler::sll_op3: |
|
276 adr <<= ( *pc & 0x3f ); |
|
277 break; |
|
278 case Assembler::or_op3: |
|
279 adr |= (intptr_t)get_simm13( *pc ); |
|
280 break; |
|
281 default: |
|
282 assert ( 0, "in gethi - Should not reach here" ); |
|
283 break; |
|
284 } |
|
285 pc++; |
|
286 i++; |
|
287 } |
|
288 return ( (address)adr ); |
|
289 } |
|
290 |
|
291 public: |
|
292 void verify(); |
|
293 void print(); |
|
294 |
|
295 // unit test stuff |
|
296 static void test() {} // override for testing |
|
297 |
|
298 inline friend NativeInstruction* nativeInstruction_at(address address); |
|
299 }; |
|
300 |
|
301 inline NativeInstruction* nativeInstruction_at(address address) { |
|
302 NativeInstruction* inst = (NativeInstruction*)address; |
|
303 #ifdef ASSERT |
|
304 inst->verify(); |
|
305 #endif |
|
306 return inst; |
|
307 } |
|
308 |
|
309 |
|
310 |
|
311 //----------------------------------------------------------------------------- |
|
312 |
|
313 // The NativeCall is an abstraction for accessing/manipulating native call imm32 instructions. |
|
314 // (used to manipulate inline caches, primitive & dll calls, etc.) |
|
315 inline NativeCall* nativeCall_at(address instr); |
|
316 inline NativeCall* nativeCall_overwriting_at(address instr, |
|
317 address destination); |
|
318 inline NativeCall* nativeCall_before(address return_address); |
|
319 class NativeCall: public NativeInstruction { |
|
320 public: |
|
321 enum Sparc_specific_constants { |
|
322 instruction_size = 8, |
|
323 return_address_offset = 8, |
|
324 call_displacement_width = 30, |
|
325 displacement_offset = 0, |
|
326 instruction_offset = 0 |
|
327 }; |
|
328 address instruction_address() const { return addr_at(0); } |
|
329 address next_instruction_address() const { return addr_at(instruction_size); } |
|
330 address return_address() const { return addr_at(return_address_offset); } |
|
331 |
|
332 address destination() const { return inv_wdisp(long_at(0), call_displacement_width) + instruction_address(); } |
|
333 address displacement_address() const { return addr_at(displacement_offset); } |
|
334 void set_destination(address dest) { set_long_at(0, set_wdisp(long_at(0), dest - instruction_address(), call_displacement_width)); } |
|
335 void set_destination_mt_safe(address dest); |
|
336 |
|
337 void verify_alignment() {} // do nothing on sparc |
|
338 void verify(); |
|
339 void print(); |
|
340 |
|
341 // unit test stuff |
|
342 static void test(); |
|
343 |
|
344 // Creation |
|
345 friend inline NativeCall* nativeCall_at(address instr); |
|
346 friend NativeCall* nativeCall_overwriting_at(address instr, address destination = NULL) { |
|
347 // insert a "blank" call: |
|
348 NativeCall* call = (NativeCall*)instr; |
|
349 call->set_long_at(0 * BytesPerInstWord, call_instruction(destination, instr)); |
|
350 call->set_long_at(1 * BytesPerInstWord, nop_instruction()); |
|
351 assert(call->addr_at(2 * BytesPerInstWord) - instr == instruction_size, "instruction size"); |
|
352 // check its structure now: |
|
353 assert(nativeCall_at(instr)->destination() == destination, "correct call destination"); |
|
354 return call; |
|
355 } |
|
356 |
|
357 friend inline NativeCall* nativeCall_before(address return_address) { |
|
358 NativeCall* call = (NativeCall*)(return_address - return_address_offset); |
|
359 #ifdef ASSERT |
|
360 call->verify(); |
|
361 #endif |
|
362 return call; |
|
363 } |
|
364 |
|
365 static bool is_call_at(address instr) { |
|
366 return nativeInstruction_at(instr)->is_call(); |
|
367 } |
|
368 |
|
369 static bool is_call_before(address instr) { |
|
370 return nativeInstruction_at(instr - return_address_offset)->is_call(); |
|
371 } |
|
372 |
|
373 static bool is_call_to(address instr, address target) { |
|
374 return nativeInstruction_at(instr)->is_call() && |
|
375 nativeCall_at(instr)->destination() == target; |
|
376 } |
|
377 |
|
378 // MT-safe patching of a call instruction. |
|
379 static void insert(address code_pos, address entry) { |
|
380 (void)nativeCall_overwriting_at(code_pos, entry); |
|
381 } |
|
382 |
|
383 static void replace_mt_safe(address instr_addr, address code_buffer); |
|
384 }; |
|
385 inline NativeCall* nativeCall_at(address instr) { |
|
386 NativeCall* call = (NativeCall*)instr; |
|
387 #ifdef ASSERT |
|
388 call->verify(); |
|
389 #endif |
|
390 return call; |
|
391 } |
|
392 |
|
393 class NativeCallReg: public NativeInstruction { |
|
394 public: |
|
395 enum Sparc_specific_constants { |
|
396 instruction_size = 8, |
|
397 return_address_offset = 8, |
|
398 instruction_offset = 0 |
|
399 }; |
|
400 |
|
401 address next_instruction_address() const { |
|
402 return addr_at(instruction_size); |
|
403 } |
|
404 }; |
|
405 |
|
406 // The NativeFarCall is an abstraction for accessing/manipulating native call-anywhere |
|
407 // instructions in the sparcv9 vm. Used to call native methods which may be loaded |
|
408 // anywhere in the address space, possibly out of reach of a call instruction. |
|
409 |
|
410 // The format of this extended-range call is: |
|
411 // jumpl_to addr, lreg |
|
412 // == sethi %hi54(addr), O7 ; jumpl O7, %lo10(addr), O7 ; <delay> |
|
413 // That is, it is essentially the same as a NativeJump. |
|
414 class NativeFarCall; |
|
415 inline NativeFarCall* nativeFarCall_overwriting_at(address instr, address destination); |
|
416 inline NativeFarCall* nativeFarCall_at(address instr); |
|
417 class NativeFarCall: public NativeInstruction { |
|
418 public: |
|
419 enum Sparc_specific_constants { |
|
420 // instruction_size includes the delay slot instruction. |
|
421 instruction_size = 9 * BytesPerInstWord, |
|
422 return_address_offset = 9 * BytesPerInstWord, |
|
423 jmpl_offset = 7 * BytesPerInstWord, |
|
424 displacement_offset = 0, |
|
425 instruction_offset = 0 |
|
426 }; |
|
427 address instruction_address() const { return addr_at(0); } |
|
428 address next_instruction_address() const { return addr_at(instruction_size); } |
|
429 address return_address() const { return addr_at(return_address_offset); } |
|
430 |
|
431 address destination() const { |
|
432 return (address) data64(addr_at(0), long_at(jmpl_offset)); |
|
433 } |
|
434 address displacement_address() const { return addr_at(displacement_offset); } |
|
435 void set_destination(address dest); |
|
436 |
|
437 bool destination_is_compiled_verified_entry_point(); |
|
438 |
|
439 void verify(); |
|
440 void print(); |
|
441 |
|
442 // unit test stuff |
|
443 static void test(); |
|
444 |
|
445 // Creation |
|
446 friend inline NativeFarCall* nativeFarCall_at(address instr) { |
|
447 NativeFarCall* call = (NativeFarCall*)instr; |
|
448 #ifdef ASSERT |
|
449 call->verify(); |
|
450 #endif |
|
451 return call; |
|
452 } |
|
453 |
|
454 friend inline NativeFarCall* nativeFarCall_overwriting_at(address instr, address destination = NULL) { |
|
455 Unimplemented(); |
|
456 NativeFarCall* call = (NativeFarCall*)instr; |
|
457 return call; |
|
458 } |
|
459 |
|
460 friend NativeFarCall* nativeFarCall_before(address return_address) { |
|
461 NativeFarCall* call = (NativeFarCall*)(return_address - return_address_offset); |
|
462 #ifdef ASSERT |
|
463 call->verify(); |
|
464 #endif |
|
465 return call; |
|
466 } |
|
467 |
|
468 static bool is_call_at(address instr); |
|
469 |
|
470 // MT-safe patching of a call instruction. |
|
471 static void insert(address code_pos, address entry) { |
|
472 (void)nativeFarCall_overwriting_at(code_pos, entry); |
|
473 } |
|
474 static void replace_mt_safe(address instr_addr, address code_buffer); |
|
475 }; |
|
476 |
|
477 |
|
478 // An interface for accessing/manipulating 32 bit native set_metadata imm, reg instructions |
|
479 // (used to manipulate inlined data references, etc.) |
|
480 // set_metadata imm, reg |
|
481 // == sethi %hi22(imm), reg ; add reg, %lo10(imm), reg |
|
482 class NativeMovConstReg32; |
|
483 inline NativeMovConstReg32* nativeMovConstReg32_at(address address); |
|
484 class NativeMovConstReg32: public NativeInstruction { |
|
485 public: |
|
486 enum Sparc_specific_constants { |
|
487 sethi_offset = 0, |
|
488 add_offset = 4, |
|
489 instruction_size = 8 |
|
490 }; |
|
491 |
|
492 address instruction_address() const { return addr_at(0); } |
|
493 address next_instruction_address() const { return addr_at(instruction_size); } |
|
494 |
|
495 // (The [set_]data accessor respects oop_type relocs also.) |
|
496 intptr_t data() const; |
|
497 void set_data(intptr_t x); |
|
498 |
|
499 // report the destination register |
|
500 Register destination() { return inv_rd(long_at(sethi_offset)); } |
|
501 |
|
502 void verify(); |
|
503 void print(); |
|
504 |
|
505 // unit test stuff |
|
506 static void test(); |
|
507 |
|
508 // Creation |
|
509 friend inline NativeMovConstReg32* nativeMovConstReg32_at(address address) { |
|
510 NativeMovConstReg32* test = (NativeMovConstReg32*)address; |
|
511 #ifdef ASSERT |
|
512 test->verify(); |
|
513 #endif |
|
514 return test; |
|
515 } |
|
516 }; |
|
517 |
|
518 // An interface for accessing/manipulating native set_metadata imm, reg instructions. |
|
519 // (used to manipulate inlined data references, etc.) |
|
520 // set_metadata imm, reg |
|
521 // == sethi %hi22(imm), reg ; add reg, %lo10(imm), reg |
|
522 class NativeMovConstReg; |
|
523 inline NativeMovConstReg* nativeMovConstReg_at(address address); |
|
524 class NativeMovConstReg: public NativeInstruction { |
|
525 public: |
|
526 enum Sparc_specific_constants { |
|
527 sethi_offset = 0, |
|
528 add_offset = 7 * BytesPerInstWord, |
|
529 instruction_size = 8 * BytesPerInstWord |
|
530 }; |
|
531 |
|
532 address instruction_address() const { return addr_at(0); } |
|
533 address next_instruction_address() const { return addr_at(instruction_size); } |
|
534 |
|
535 // (The [set_]data accessor respects oop_type relocs also.) |
|
536 intptr_t data() const; |
|
537 void set_data(intptr_t x); |
|
538 |
|
539 // report the destination register |
|
540 Register destination() { return inv_rd(long_at(sethi_offset)); } |
|
541 |
|
542 void verify(); |
|
543 void print(); |
|
544 |
|
545 // unit test stuff |
|
546 static void test(); |
|
547 |
|
548 // Creation |
|
549 friend inline NativeMovConstReg* nativeMovConstReg_at(address address) { |
|
550 NativeMovConstReg* test = (NativeMovConstReg*)address; |
|
551 #ifdef ASSERT |
|
552 test->verify(); |
|
553 #endif |
|
554 return test; |
|
555 } |
|
556 |
|
557 |
|
558 friend NativeMovConstReg* nativeMovConstReg_before(address address) { |
|
559 NativeMovConstReg* test = (NativeMovConstReg*)(address - instruction_size); |
|
560 #ifdef ASSERT |
|
561 test->verify(); |
|
562 #endif |
|
563 return test; |
|
564 } |
|
565 |
|
566 }; |
|
567 |
|
568 |
|
569 // An interface for accessing/manipulating native set_metadata imm, reg instructions. |
|
570 // (used to manipulate inlined data references, etc.) |
|
571 // set_metadata imm, reg |
|
572 // == sethi %hi22(imm), reg; nop; add reg, %lo10(imm), reg |
|
573 // |
|
574 // Note that it is identical to NativeMovConstReg with the exception of a nop between the |
|
575 // sethi and the add. The nop is required to be in the delay slot of the call instruction |
|
576 // which overwrites the sethi during patching. |
|
577 class NativeMovConstRegPatching; |
|
578 inline NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address);class NativeMovConstRegPatching: public NativeInstruction { |
|
579 public: |
|
580 enum Sparc_specific_constants { |
|
581 sethi_offset = 0, |
|
582 nop_offset = 7 * BytesPerInstWord, |
|
583 add_offset = nop_offset + BytesPerInstWord, |
|
584 instruction_size = add_offset + BytesPerInstWord |
|
585 }; |
|
586 |
|
587 address instruction_address() const { return addr_at(0); } |
|
588 address next_instruction_address() const { return addr_at(instruction_size); } |
|
589 |
|
590 // (The [set_]data accessor respects oop_type relocs also.) |
|
591 int data() const; |
|
592 void set_data(int x); |
|
593 |
|
594 // report the destination register |
|
595 Register destination() { return inv_rd(long_at(sethi_offset)); } |
|
596 |
|
597 void verify(); |
|
598 void print(); |
|
599 |
|
600 // unit test stuff |
|
601 static void test(); |
|
602 |
|
603 // Creation |
|
604 friend inline NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) { |
|
605 NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)address; |
|
606 #ifdef ASSERT |
|
607 test->verify(); |
|
608 #endif |
|
609 return test; |
|
610 } |
|
611 |
|
612 |
|
613 friend NativeMovConstRegPatching* nativeMovConstRegPatching_before(address address) { |
|
614 NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_size); |
|
615 #ifdef ASSERT |
|
616 test->verify(); |
|
617 #endif |
|
618 return test; |
|
619 } |
|
620 |
|
621 }; |
|
622 |
|
623 |
|
624 // An interface for accessing/manipulating native memory ops |
|
625 // ld* [reg + offset], reg |
|
626 // st* reg, [reg + offset] |
|
627 // sethi %hi(imm), reg; add reg, %lo(imm), reg; ld* [reg1 + reg], reg2 |
|
628 // sethi %hi(imm), reg; add reg, %lo(imm), reg; st* reg2, [reg1 + reg] |
|
629 // Ops covered: {lds,ldu,st}{w,b,h}, {ld,st}{d,x} |
|
630 // |
|
631 class NativeMovRegMem; |
|
632 inline NativeMovRegMem* nativeMovRegMem_at (address address); |
|
633 class NativeMovRegMem: public NativeInstruction { |
|
634 public: |
|
635 enum Sparc_specific_constants { |
|
636 op3_mask_ld = 1 << Assembler::lduw_op3 | |
|
637 1 << Assembler::ldub_op3 | |
|
638 1 << Assembler::lduh_op3 | |
|
639 1 << Assembler::ldd_op3 | |
|
640 1 << Assembler::ldsw_op3 | |
|
641 1 << Assembler::ldsb_op3 | |
|
642 1 << Assembler::ldsh_op3 | |
|
643 1 << Assembler::ldx_op3, |
|
644 op3_mask_st = 1 << Assembler::stw_op3 | |
|
645 1 << Assembler::stb_op3 | |
|
646 1 << Assembler::sth_op3 | |
|
647 1 << Assembler::std_op3 | |
|
648 1 << Assembler::stx_op3, |
|
649 op3_ldst_int_limit = Assembler::ldf_op3, |
|
650 op3_mask_ldf = 1 << (Assembler::ldf_op3 - op3_ldst_int_limit) | |
|
651 1 << (Assembler::lddf_op3 - op3_ldst_int_limit), |
|
652 op3_mask_stf = 1 << (Assembler::stf_op3 - op3_ldst_int_limit) | |
|
653 1 << (Assembler::stdf_op3 - op3_ldst_int_limit), |
|
654 |
|
655 offset_width = 13, |
|
656 sethi_offset = 0, |
|
657 add_offset = 7 * BytesPerInstWord, |
|
658 ldst_offset = add_offset + BytesPerInstWord |
|
659 }; |
|
660 bool is_immediate() const { |
|
661 // check if instruction is ld* [reg + offset], reg or st* reg, [reg + offset] |
|
662 int i0 = long_at(0); |
|
663 return (is_op(i0, Assembler::ldst_op)); |
|
664 } |
|
665 |
|
666 address instruction_address() const { return addr_at(0); } |
|
667 address next_instruction_address() const { |
|
668 return addr_at(is_immediate() ? 4 : (7 * BytesPerInstWord)); |
|
669 } |
|
670 intptr_t offset() const { |
|
671 return is_immediate()? inv_simm(long_at(0), offset_width) : |
|
672 nativeMovConstReg_at(addr_at(0))->data(); |
|
673 } |
|
674 void set_offset(intptr_t x) { |
|
675 if (is_immediate()) { |
|
676 guarantee(fits_in_simm(x, offset_width), "data block offset overflow"); |
|
677 set_long_at(0, set_simm(long_at(0), x, offset_width)); |
|
678 } else |
|
679 nativeMovConstReg_at(addr_at(0))->set_data(x); |
|
680 } |
|
681 |
|
682 void add_offset_in_bytes(intptr_t radd_offset) { |
|
683 set_offset (offset() + radd_offset); |
|
684 } |
|
685 |
|
686 void copy_instruction_to(address new_instruction_address); |
|
687 |
|
688 void verify(); |
|
689 void print (); |
|
690 |
|
691 // unit test stuff |
|
692 static void test(); |
|
693 |
|
694 private: |
|
695 friend inline NativeMovRegMem* nativeMovRegMem_at (address address) { |
|
696 NativeMovRegMem* test = (NativeMovRegMem*)address; |
|
697 #ifdef ASSERT |
|
698 test->verify(); |
|
699 #endif |
|
700 return test; |
|
701 } |
|
702 }; |
|
703 |
|
704 |
|
705 // An interface for accessing/manipulating native jumps |
|
706 // jump_to addr |
|
707 // == sethi %hi22(addr), temp ; jumpl reg, %lo10(addr), G0 ; <delay> |
|
708 // jumpl_to addr, lreg |
|
709 // == sethi %hi22(addr), temp ; jumpl reg, %lo10(addr), lreg ; <delay> |
|
710 class NativeJump; |
|
711 inline NativeJump* nativeJump_at(address address); |
|
712 class NativeJump: public NativeInstruction { |
|
713 private: |
|
714 void guarantee_displacement(int disp, int width) { |
|
715 guarantee(fits_in_simm(disp, width + 2), "branch displacement overflow"); |
|
716 } |
|
717 |
|
718 public: |
|
719 enum Sparc_specific_constants { |
|
720 sethi_offset = 0, |
|
721 jmpl_offset = 7 * BytesPerInstWord, |
|
722 instruction_size = 9 * BytesPerInstWord // includes delay slot |
|
723 }; |
|
724 |
|
725 address instruction_address() const { return addr_at(0); } |
|
726 address next_instruction_address() const { return addr_at(instruction_size); } |
|
727 |
|
728 address jump_destination() const { |
|
729 return (address) data64(instruction_address(), long_at(jmpl_offset)); |
|
730 } |
|
731 void set_jump_destination(address dest) { |
|
732 set_data64_sethi( instruction_address(), (intptr_t)dest); |
|
733 set_long_at(jmpl_offset, set_data32_simm13( long_at(jmpl_offset), (intptr_t)dest)); |
|
734 } |
|
735 |
|
736 // Creation |
|
737 friend inline NativeJump* nativeJump_at(address address) { |
|
738 NativeJump* jump = (NativeJump*)address; |
|
739 #ifdef ASSERT |
|
740 jump->verify(); |
|
741 #endif |
|
742 return jump; |
|
743 } |
|
744 |
|
745 void verify(); |
|
746 void print(); |
|
747 |
|
748 // Unit testing stuff |
|
749 static void test(); |
|
750 |
|
751 // Insertion of native jump instruction |
|
752 static void insert(address code_pos, address entry); |
|
753 // MT-safe insertion of native jump at verified method entry |
|
754 static void check_verified_entry_alignment(address entry, address verified_entry) { |
|
755 // nothing to do for sparc. |
|
756 } |
|
757 static void patch_verified_entry(address entry, address verified_entry, address dest); |
|
758 }; |
|
759 |
|
760 |
|
761 |
|
762 // Despite the name, handles only simple branches. |
|
763 class NativeGeneralJump; |
|
764 inline NativeGeneralJump* nativeGeneralJump_at(address address); |
|
765 class NativeGeneralJump: public NativeInstruction { |
|
766 public: |
|
767 enum Sparc_specific_constants { |
|
768 instruction_size = 8 |
|
769 }; |
|
770 |
|
771 address instruction_address() const { return addr_at(0); } |
|
772 address jump_destination() const { return addr_at(0) + branch_destination_offset(long_at(0)); } |
|
773 void set_jump_destination(address dest) { |
|
774 int patched_instr = patch_branch_destination_offset(dest - addr_at(0), long_at(0)); |
|
775 set_long_at(0, patched_instr); |
|
776 } |
|
777 NativeInstruction *delay_slot_instr() { return nativeInstruction_at(addr_at(4));} |
|
778 void fill_delay_slot(int instr) { set_long_at(4, instr);} |
|
779 Assembler::Condition condition() { |
|
780 int x = long_at(0); |
|
781 return (Assembler::Condition) Assembler::inv_cond(x); |
|
782 } |
|
783 |
|
784 // Creation |
|
785 friend inline NativeGeneralJump* nativeGeneralJump_at(address address) { |
|
786 NativeGeneralJump* jump = (NativeGeneralJump*)(address); |
|
787 #ifdef ASSERT |
|
788 jump->verify(); |
|
789 #endif |
|
790 return jump; |
|
791 } |
|
792 |
|
793 // Insertion of native general jump instruction |
|
794 static void insert_unconditional(address code_pos, address entry); |
|
795 static void replace_mt_safe(address instr_addr, address code_buffer); |
|
796 |
|
797 void verify(); |
|
798 }; |
|
799 |
|
800 |
|
801 class NativeIllegalInstruction: public NativeInstruction { |
|
802 public: |
|
803 enum Sparc_specific_constants { |
|
804 instruction_size = 4 |
|
805 }; |
|
806 |
|
807 // Insert illegal opcode as specific address |
|
808 static void insert(address code_pos); |
|
809 }; |
|
810 |
|
811 #endif // CPU_SPARC_VM_NATIVEINST_SPARC_HPP |