Thu, 24 May 2018 19:49:50 +0800
some C1 fix
Contributed-by: chenhaoxuan, zhaixiang, aoqi
1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2015, 2018, Loongson Technology. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
26 #ifndef CPU_MIPS_VM_NATIVEINST_MIPS_HPP
27 #define CPU_MIPS_VM_NATIVEINST_MIPS_HPP
29 #include "asm/assembler.hpp"
30 #include "memory/allocation.hpp"
31 #include "runtime/icache.hpp"
32 #include "runtime/os.hpp"
33 #include "utilities/top.hpp"
35 // We have interfaces for the following instructions:
36 // - NativeInstruction
37 // - - NativeCall
38 // - - NativeMovConstReg
39 // - - NativeMovConstRegPatching
40 // - - NativeMovRegMem
41 // - - NativeMovRegMemPatching
42 // - - NativeJump
43 // - - NativeIllegalOpCode
44 // - - NativeGeneralJump
45 // - - NativeReturn
46 // - - NativeReturnX (return with argument)
47 // - - NativePushConst
48 // - - NativeTstRegMem
50 // The base class for different kinds of native instruction abstractions.
51 // Provides the primitive operations to manipulate code relative to this.
53 class NativeInstruction VALUE_OBJ_CLASS_SPEC {
54 friend class Relocation;
56 public:
57 enum mips_specific_constants {
58 nop_instruction_code = 0,
59 nop_instruction_size = 4,
60 sync_instruction_code = 0xf
61 };
63 bool is_nop() { return long_at(0) == nop_instruction_code; }
64 bool is_sync() { return long_at(0) == sync_instruction_code; }
65 bool is_dtrace_trap();
66 inline bool is_call();
67 inline bool is_illegal();
68 inline bool is_return();
69 bool is_jump();
70 inline bool is_cond_jump();
71 bool is_safepoint_poll();
73 //mips has no instruction to generate a illegal instrucion exception
74 //we define ours: break 11
75 static int illegal_instruction();
77 bool is_int_branch();
78 bool is_float_branch();
81 protected:
82 address addr_at(int offset) const { return address(this) + offset; }
83 address instruction_address() const { return addr_at(0); }
84 address next_instruction_address() const { return addr_at(BytesPerInstWord); }
85 address prev_instruction_address() const { return addr_at(-BytesPerInstWord); }
87 s_char sbyte_at(int offset) const { return *(s_char*) addr_at(offset); }
88 u_char ubyte_at(int offset) const { return *(u_char*) addr_at(offset); }
90 jint int_at(int offset) const { return *(jint*) addr_at(offset); }
92 intptr_t ptr_at(int offset) const { return *(intptr_t*) addr_at(offset); }
94 oop oop_at (int offset) const { return *(oop*) addr_at(offset); }
95 int long_at(int offset) const { return *(jint*)addr_at(offset); }
98 void set_char_at(int offset, char c) { *addr_at(offset) = (u_char)c; wrote(offset); }
99 void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; wrote(offset); }
100 void set_ptr_at (int offset, intptr_t ptr) { *(intptr_t*) addr_at(offset) = ptr; wrote(offset); }
101 void set_oop_at (int offset, oop o) { *(oop*) addr_at(offset) = o; wrote(offset); }
102 void set_long_at(int offset, long i);
104 int insn_word() const { return long_at(0); }
105 static bool is_op (int insn, Assembler::ops op) { return Assembler::opcode(insn) == (int)op; }
106 bool is_op (Assembler::ops op) const { return is_op(insn_word(), op); }
107 bool is_rs (int insn, Register rs) const { return Assembler::rs(insn) == (int)rs->encoding(); }
108 bool is_rs (Register rs) const { return is_rs(insn_word(), rs); }
109 bool is_rt (int insn, Register rt) const { return Assembler::rt(insn) == (int)rt->encoding(); }
110 bool is_rt (Register rt) const { return is_rt(insn_word(), rt); }
112 static bool is_special_op (int insn, Assembler::special_ops op) {
113 return is_op(insn, Assembler::special_op) && Assembler::special(insn)==(int)op;
114 }
115 bool is_special_op (Assembler::special_ops op) const { return is_special_op(insn_word(), op); }
117 // This doesn't really do anything on Intel, but it is the place where
118 // cache invalidation belongs, generically:
119 void wrote(int offset);
121 public:
123 // unit test stuff
124 static void test() {} // override for testing
126 inline friend NativeInstruction* nativeInstruction_at(address address);
127 };
129 inline NativeInstruction* nativeInstruction_at(address address) {
130 NativeInstruction* inst = (NativeInstruction*)address;
131 #ifdef ASSERT
132 //inst->verify();
133 #endif
134 return inst;
135 }
137 inline NativeCall* nativeCall_at(address address);
138 // The NativeCall is an abstraction for accessing/manipulating native call imm32/imm64
139 // instructions (used to manipulate inline caches, primitive & dll calls, etc.).
140 // MIPS has no call instruction with imm32/imm64. Usually, a call was done like this:
141 // 32 bits:
142 // lui rt, imm16
143 // addiu rt, rt, imm16
144 // jalr rt
145 // nop
146 //
147 // 64 bits:
148 // lui rd, imm(63...48);
149 // ori rd, rd, imm(47...32);
150 // dsll rd, rd, 16;
151 // ori rd, rd, imm(31...16);
152 // dsll rd, rd, 16;
153 // ori rd, rd, imm(15...0);
154 // jalr rd
155 // nop
156 //
158 // we just consider the above for instruction as one call instruction
159 class NativeCall: public NativeInstruction {
160 public:
161 enum mips_specific_constants {
162 instruction_offset = 0,
163 #ifndef _LP64
164 instruction_size = 4 * BytesPerInstWord,
165 return_address_offset = 4 * BytesPerInstWord,
166 #else
167 instruction_size = 6 * BytesPerInstWord,
168 return_address_offset_short = 4 * BytesPerInstWord,
169 return_address_offset_long = 6 * BytesPerInstWord,
170 #endif
171 displacement_offset = 0
172 };
174 address instruction_address() const { return addr_at(instruction_offset); }
176 address next_instruction_address() const {
177 if (is_special_op(int_at(8), Assembler::jalr_op)) {
178 return addr_at(return_address_offset_short);
179 } else {
180 return addr_at(return_address_offset_long);
181 }
182 }
184 address return_address() const {
185 return next_instruction_address();
186 }
188 address destination() const;
189 void set_destination(address dest);
190 void set_destination_mt_safe(address dest) { set_destination(dest);}
192 void patch_set48_gs(address dest);
193 void patch_set48(address dest);
195 void patch_on_jalr_gs(address dest);
196 void patch_on_jalr(address dest);
198 void patch_on_jal_gs(address dest);
199 void patch_on_jal(address dest);
201 void patch_on_jal_only(address dest);
203 void patch_set32_gs(address dest);
204 void patch_set32(address dest);
206 void verify_alignment() { }
207 void verify();
208 void print();
210 // Creation
211 inline friend NativeCall* nativeCall_at(address address);
212 inline friend NativeCall* nativeCall_before(address return_address);
214 static bool is_call_at(address instr) {
215 return nativeInstruction_at(instr)->is_call();
216 }
218 static bool is_call_before(address return_address) {
219 return is_call_at(return_address - return_address_offset_short) | is_call_at(return_address - return_address_offset_long);
220 }
222 static bool is_call_to(address instr, address target) {
223 return nativeInstruction_at(instr)->is_call() &&
224 nativeCall_at(instr)->destination() == target;
225 }
227 // MT-safe patching of a call instruction.
228 static void insert(address code_pos, address entry);
230 static void replace_mt_safe(address instr_addr, address code_buffer);
231 };
233 inline NativeCall* nativeCall_at(address address) {
234 NativeCall* call = (NativeCall*)(address - NativeCall::instruction_offset);
235 #ifdef ASSERT
236 call->verify();
237 #endif
238 return call;
239 }
241 inline NativeCall* nativeCall_before(address return_address) {
242 NativeCall* call = NULL;
243 if (NativeCall::is_call_at(return_address - NativeCall::return_address_offset_long)) {
244 call = (NativeCall*)(return_address - NativeCall::return_address_offset_long);
245 } else {
246 call = (NativeCall*)(return_address - NativeCall::return_address_offset_short);
247 }
248 #ifdef ASSERT
249 call->verify();
250 #endif
251 return call;
252 }
254 class NativeMovConstReg: public NativeInstruction {
255 public:
256 enum mips_specific_constants {
257 instruction_offset = 0,
258 #ifndef _LP64
259 instruction_size = 2 * BytesPerInstWord,
260 next_instruction_offset = 2 * BytesPerInstWord,
261 #else
262 instruction_size = 4 * BytesPerInstWord,
263 next_instruction_offset = 4 * BytesPerInstWord,
264 #endif
265 };
267 int insn_word() const { return long_at(instruction_offset); }
268 address instruction_address() const { return addr_at(0); }
269 address next_instruction_address() const { return addr_at(next_instruction_offset); }
270 intptr_t data() const;
271 void set_data(intptr_t x);
273 void patch_set48(intptr_t x);
275 void verify();
276 void print();
278 // unit test stuff
279 static void test() {}
281 // Creation
282 inline friend NativeMovConstReg* nativeMovConstReg_at(address address);
283 inline friend NativeMovConstReg* nativeMovConstReg_before(address address);
284 };
286 inline NativeMovConstReg* nativeMovConstReg_at(address address) {
287 NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_offset);
288 #ifdef ASSERT
289 test->verify();
290 #endif
291 return test;
292 }
294 inline NativeMovConstReg* nativeMovConstReg_before(address address) {
295 NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_size - NativeMovConstReg::instruction_offset);
296 #ifdef ASSERT
297 test->verify();
298 #endif
299 return test;
300 }
302 class NativeMovConstRegPatching: public NativeMovConstReg {
303 private:
304 friend NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) {
305 NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_offset);
306 #ifdef ASSERT
307 test->verify();
308 #endif
309 return test;
310 }
311 };
313 // An interface for accessing/manipulating native moves of the form:
314 // lui AT, split_high(offset)
315 // addiu AT, split_low(offset)
316 // add reg, reg, AT
317 // lb/lbu/sb/lh/lhu/sh/lw/sw/lwc1/swc1 dest, reg, 0
318 // [lw/sw/lwc1/swc1 dest, reg, 4]
319 // or
320 // lb/lbu/sb/lh/lhu/sh/lw/sw/lwc1/swc1 dest, reg, offset
321 // [lw/sw/lwc1/swc1 dest, reg, offset+4]
322 //
323 // Warning: These routines must be able to handle any instruction sequences
324 // that are generated as a result of the load/store byte,word,long
325 // macros.
327 class NativeMovRegMem: public NativeInstruction {
328 public:
329 enum mips_specific_constants {
330 instruction_offset = 0,
331 hiword_offset = 4,
332 ldst_offset = 12,
333 immediate_size = 4,
334 ldst_size = 16
335 };
337 //offset is less than 16 bits.
338 bool is_immediate() const { return !is_op(long_at(instruction_offset), Assembler::lui_op); }
339 bool is_64ldst() const {
340 if (is_immediate()) {
341 return (Assembler::opcode(long_at(hiword_offset)) == Assembler::opcode(long_at(instruction_offset))) &&
342 (Assembler::imm_off(long_at(hiword_offset)) == Assembler::imm_off(long_at(instruction_offset)) + wordSize);
343 } else {
344 return (Assembler::opcode(long_at(ldst_offset+hiword_offset)) == Assembler::opcode(long_at(ldst_offset))) &&
345 (Assembler::imm_off(long_at(ldst_offset+hiword_offset)) == Assembler::imm_off(long_at(ldst_offset)) + wordSize);
346 }
347 }
349 address instruction_address() const { return addr_at(instruction_offset); }
350 address next_instruction_address() const {
351 return addr_at( (is_immediate()? immediate_size : ldst_size) + (is_64ldst()? 4 : 0));
352 }
354 int offset() const;
356 void set_offset(int x);
358 void add_offset_in_bytes(int add_offset) { set_offset ( ( offset() + add_offset ) ); }
360 void verify();
361 void print ();
363 // unit test stuff
364 static void test() {}
366 private:
367 inline friend NativeMovRegMem* nativeMovRegMem_at (address address);
368 };
370 inline NativeMovRegMem* nativeMovRegMem_at (address address) {
371 NativeMovRegMem* test = (NativeMovRegMem*)(address - NativeMovRegMem::instruction_offset);
372 #ifdef ASSERT
373 test->verify();
374 #endif
375 return test;
376 }
378 class NativeMovRegMemPatching: public NativeMovRegMem {
379 private:
380 friend NativeMovRegMemPatching* nativeMovRegMemPatching_at (address address) {
381 NativeMovRegMemPatching* test = (NativeMovRegMemPatching*)(address - instruction_offset);
382 #ifdef ASSERT
383 test->verify();
384 #endif
385 return test;
386 }
387 };
390 // Handles all kinds of jump on Loongson. Long/far, conditional/unconditional
391 // 32 bits:
392 // far jump:
393 // lui reg, split_high(addr)
394 // addiu reg, split_low(addr)
395 // jr reg
396 // nop
397 // or
398 // beq ZERO, ZERO, offset
399 // nop
400 //
402 //64 bits:
403 // far jump:
404 // lui rd, imm(63...48);
405 // ori rd, rd, imm(47...32);
406 // dsll rd, rd, 16;
407 // ori rd, rd, imm(31...16);
408 // dsll rd, rd, 16;
409 // ori rd, rd, imm(15...0);
410 // jalr rd
411 // nop
412 //
413 class NativeGeneralJump: public NativeInstruction {
414 public:
415 enum mips_specific_constants {
416 instruction_offset = 0,
417 beq_opcode = 0x10000000,//000100|00000|00000|offset
418 b_mask = 0xffff0000,
419 short_size = 8,
420 #ifndef _LP64
421 instruction_size = 4 * BytesPerInstWord
422 #else
423 instruction_size = 6 * BytesPerInstWord
424 #endif
425 };
427 bool is_short() const { return (long_at(instruction_offset) & b_mask) == beq_opcode; }
428 #ifdef _LP64
429 bool is_b_far();
430 #endif
431 address instruction_address() const { return addr_at(instruction_offset); }
432 address jump_destination();
434 void patch_set48_gs(address dest);
435 void patch_set48(address dest);
437 void patch_on_jr_gs(address dest);
438 void patch_on_jr(address dest);
440 void patch_on_j_gs(address dest);
441 void patch_on_j(address dest);
443 void patch_on_j_only(address dest);
445 void set_jump_destination(address dest);
447 // Creation
448 inline friend NativeGeneralJump* nativeGeneralJump_at(address address);
450 // Insertion of native general jump instruction
451 static void insert_unconditional(address code_pos, address entry);
452 static void replace_mt_safe(address instr_addr, address code_buffer);
453 static void check_verified_entry_alignment(address entry, address verified_entry){}
454 static void patch_verified_entry(address entry, address verified_entry, address dest);
456 void verify();
457 };
459 inline NativeGeneralJump* nativeGeneralJump_at(address address) {
460 NativeGeneralJump* jump = (NativeGeneralJump*)(address);
461 debug_only(jump->verify();)
462 return jump;
463 }
466 class NativeIllegalInstruction: public NativeInstruction {
467 public:
468 enum Intel_specific_constants {
469 instruction_size = 4,
470 instruction_offset = 0,
471 next_instruction_offset = 4
472 };
474 // Insert illegal opcode as specific address
475 static void insert(address code_pos);
476 };
478 // return instruction that does not pop values of the stack
479 // jr RA
480 // delay slot
481 class NativeReturn: public NativeInstruction {
482 public:
483 enum mips_specific_constants {
484 instruction_size = 8,
485 instruction_offset = 0,
486 next_instruction_offset = 8
487 };
488 };
493 class NativeCondJump;
494 inline NativeCondJump* nativeCondJump_at(address address);
495 class NativeCondJump: public NativeInstruction {
496 public:
497 enum mips_specific_constants {
498 instruction_size = 16,
499 instruction_offset = 12,
500 next_instruction_offset = 20
501 };
504 int insn_word() const { return long_at(instruction_offset); }
505 address instruction_address() const { return addr_at(0); }
506 address next_instruction_address() const { return addr_at(next_instruction_offset); }
508 // Creation
509 inline friend NativeCondJump* nativeCondJump_at(address address);
511 address jump_destination() const {
512 return ::nativeCondJump_at(addr_at(12))->jump_destination();
513 }
515 void set_jump_destination(address dest) {
516 ::nativeCondJump_at(addr_at(12))->set_jump_destination(dest);
517 }
519 };
521 inline NativeCondJump* nativeCondJump_at(address address) {
522 NativeCondJump* jump = (NativeCondJump*)(address);
523 return jump;
524 }
528 inline bool NativeInstruction::is_illegal() { return insn_word() == illegal_instruction(); }
530 inline bool NativeInstruction::is_call() {
531 #ifndef _LP64
532 return is_op(long_at(0), Assembler::lui_op) &&
533 is_op(long_at(4), Assembler::addiu_op) &&
534 is_special_op(long_at(8), Assembler::jalr_op);
535 #else
536 // jal target
537 // nop
538 if ( nativeInstruction_at(addr_at(0))->is_op(Assembler::jal_op) &&
539 nativeInstruction_at(addr_at(4))->is_nop() ) {
540 return true;
541 }
543 // nop
544 // nop
545 // nop
546 // nop
547 // jal target
548 // nop
549 if ( is_nop() &&
550 nativeInstruction_at(addr_at(4))->is_nop() &&
551 nativeInstruction_at(addr_at(8))->is_nop() &&
552 nativeInstruction_at(addr_at(12))->is_nop() &&
553 nativeInstruction_at(addr_at(16))->is_op(Assembler::jal_op) &&
554 nativeInstruction_at(addr_at(20))->is_nop() ) {
555 return true;
556 }
558 // li64
559 if ( is_op(Assembler::lui_op) &&
560 is_op(int_at(4), Assembler::ori_op) &&
561 is_special_op(int_at(8), Assembler::dsll_op) &&
562 is_op(int_at(12), Assembler::ori_op) &&
563 is_special_op(int_at(16), Assembler::dsll_op) &&
564 is_op(int_at(20), Assembler::ori_op) &&
565 is_special_op(int_at(24), Assembler::jalr_op) ) {
566 return true;
567 }
569 //lui dst, imm16
570 //ori dst, dst, imm16
571 //dsll dst, dst, 16
572 //ori dst, dst, imm16
573 if ( is_op(Assembler::lui_op) &&
574 is_op (int_at(4), Assembler::ori_op) &&
575 is_special_op(int_at(8), Assembler::dsll_op) &&
576 is_op (int_at(12), Assembler::ori_op) &&
577 is_special_op(int_at(16), Assembler::jalr_op) ) {
578 return true;
579 }
581 //ori dst, R0, imm16
582 //dsll dst, dst, 16
583 //ori dst, dst, imm16
584 //nop
585 if ( is_op(Assembler::ori_op) &&
586 is_special_op(int_at(4), Assembler::dsll_op) &&
587 is_op (int_at(8), Assembler::ori_op) &&
588 nativeInstruction_at(addr_at(12))->is_nop() &&
589 is_special_op(int_at(16), Assembler::jalr_op) ) {
590 return true;
591 }
593 //ori dst, R0, imm16
594 //dsll dst, dst, 16
595 //nop
596 //nop
597 if ( is_op(Assembler::ori_op) &&
598 is_special_op(int_at(4), Assembler::dsll_op) &&
599 nativeInstruction_at(addr_at(8))->is_nop() &&
600 nativeInstruction_at(addr_at(12))->is_nop() &&
601 is_special_op(int_at(16), Assembler::jalr_op) ) {
602 return true;
603 }
605 //daddiu dst, R0, imm16
606 //nop
607 //nop
608 //nop
609 if ( is_op(Assembler::daddiu_op) &&
610 nativeInstruction_at(addr_at(4))->is_nop() &&
611 nativeInstruction_at(addr_at(8))->is_nop() &&
612 nativeInstruction_at(addr_at(12))->is_nop() &&
613 is_special_op(int_at(16), Assembler::jalr_op) ) {
614 return true;
615 }
617 //lui dst, imm16
618 //ori dst, dst, imm16
619 //nop
620 //nop
621 if ( is_op(Assembler::lui_op) &&
622 is_op (int_at(4), Assembler::ori_op) &&
623 nativeInstruction_at(addr_at(8))->is_nop() &&
624 nativeInstruction_at(addr_at(12))->is_nop() &&
625 is_special_op(int_at(16), Assembler::jalr_op) ) {
626 return true;
627 }
629 //lui dst, imm16
630 //nop
631 //nop
632 //nop
633 if ( is_op(Assembler::lui_op) &&
634 nativeInstruction_at(addr_at(4))->is_nop() &&
635 nativeInstruction_at(addr_at(8))->is_nop() &&
636 nativeInstruction_at(addr_at(12))->is_nop() &&
637 is_special_op(int_at(16), Assembler::jalr_op) ) {
638 return true;
639 }
642 //daddiu dst, R0, imm16
643 //nop
644 if ( is_op(Assembler::daddiu_op) &&
645 nativeInstruction_at(addr_at(4))->is_nop() &&
646 is_special_op(int_at(8), Assembler::jalr_op) ) {
647 return true;
648 }
650 //lui dst, imm16
651 //ori dst, dst, imm16
652 if ( is_op(Assembler::lui_op) &&
653 is_op (int_at(4), Assembler::ori_op) &&
654 is_special_op(int_at(8), Assembler::jalr_op) ) {
655 return true;
656 }
658 //lui dst, imm16
659 //nop
660 if ( is_op(Assembler::lui_op) &&
661 nativeInstruction_at(addr_at(4))->is_nop() &&
662 is_special_op(int_at(8), Assembler::jalr_op) ) {
663 return true;
664 }
666 return false;
668 #endif
669 }
671 inline bool NativeInstruction::is_return() { return is_special_op(Assembler::jr_op) && is_rs(RA);}
673 inline bool NativeInstruction::is_cond_jump() { return is_int_branch() || is_float_branch(); }
675 #endif // CPU_MIPS_VM_NATIVEINST_MIPS_HPP