Wed, 29 Mar 2017 09:41:51 +0800
#4662 TieredCompilation is turned off.
TieredCompilation is not supported yet.
1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2015, 2016, 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 };
62 bool is_nop() { return long_at(0) == nop_instruction_code; }
63 bool is_dtrace_trap();
64 inline bool is_call();
65 inline bool is_illegal();
66 inline bool is_return();
67 bool is_jump();
68 inline bool is_cond_jump();
69 bool is_safepoint_poll();
71 //mips has no instruction to generate a illegal instrucion exception
72 //we define ours: break 11
73 static int illegal_instruction();
75 bool is_int_branch();
76 bool is_float_branch();
79 protected:
80 address addr_at(int offset) const { return address(this) + offset; }
81 address instruction_address() const { return addr_at(0); }
82 address next_instruction_address() const { return addr_at(BytesPerInstWord); }
83 address prev_instruction_address() const { return addr_at(-BytesPerInstWord); }
85 s_char sbyte_at(int offset) const { return *(s_char*) addr_at(offset); }
86 u_char ubyte_at(int offset) const { return *(u_char*) addr_at(offset); }
87 jint int_at(int offset) const { return *(jint*) addr_at(offset); }
88 intptr_t ptr_at(int offset) const { return *(intptr_t*) addr_at(offset); }
89 oop oop_at (int offset) const { return *(oop*) addr_at(offset); }
90 int long_at(int offset) const { return *(jint*)addr_at(offset); }
93 void set_char_at(int offset, char c) { *addr_at(offset) = (u_char)c; wrote(offset); }
94 void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; wrote(offset); }
95 void set_ptr_at (int offset, intptr_t ptr) { *(intptr_t*) addr_at(offset) = ptr; wrote(offset); }
96 void set_oop_at (int offset, oop o) { *(oop*) addr_at(offset) = o; wrote(offset); }
97 void set_long_at(int offset, long i);
98 //void set_jlong_at(int offset, jlong i);
99 //void set_addr_at(int offset, address x);
101 int insn_word() const { return long_at(0); }
102 static bool is_op (int insn, Assembler::ops op) { return Assembler::opcode(insn) == (int)op; }
103 bool is_op (Assembler::ops op) const { return is_op(insn_word(), op); }
104 bool is_rs (int insn, Register rs) const { return Assembler::rs(insn) == (int)rs->encoding(); }
105 bool is_rs (Register rs) const { return is_rs(insn_word(), rs); }
106 bool is_rt (int insn, Register rt) const { return Assembler::rt(insn) == (int)rt->encoding(); }
107 bool is_rt (Register rt) const { return is_rt(insn_word(), rt); }
109 static bool is_special_op (int insn, Assembler::special_ops op) {
110 return is_op(insn, Assembler::special_op) && Assembler::special(insn)==(int)op;
111 }
112 bool is_special_op (Assembler::special_ops op) const { return is_special_op(insn_word(), op); }
114 // This doesn't really do anything on Intel, but it is the place where
115 // cache invalidation belongs, generically:
116 void wrote(int offset);
118 public:
120 // unit test stuff
121 static void test() {} // override for testing
123 inline friend NativeInstruction* nativeInstruction_at(address address);
124 };
126 inline NativeInstruction* nativeInstruction_at(address address) {
127 NativeInstruction* inst = (NativeInstruction*)address;
128 #ifdef ASSERT
129 //inst->verify();
130 #endif
131 return inst;
132 }
134 inline NativeCall* nativeCall_at(address address);
135 // The NativeCall is an abstraction for accessing/manipulating native call imm32/imm64
136 // instructions (used to manipulate inline caches, primitive & dll calls, etc.).
137 // MIPS has no call instruction with imm32/imm64. Usually, a call was done like this:
138 // 32 bits:
139 // lui rt, imm16
140 // addiu rt, rt, imm16
141 // jalr rt
142 // nop
143 //
144 // 64 bits:
145 // lui rd, imm(63...48);
146 // ori rd, rd, imm(47...32);
147 // dsll rd, rd, 16;
148 // ori rd, rd, imm(31...16);
149 // dsll rd, rd, 16;
150 // ori rd, rd, imm(15...0);
151 // jalr rd
152 // nop
153 //
155 // we just consider the above for instruction as one call instruction
156 class NativeCall: public NativeInstruction {
157 public:
158 enum mips_specific_constants {
159 instruction_offset = 0,
160 #ifndef _LP64
161 instruction_size = 4 * BytesPerInstWord,
162 return_address_offset = 4 * BytesPerInstWord,
163 #else
164 instruction_size = 6 * BytesPerInstWord,
165 return_address_offset_short = 4 * BytesPerInstWord,
166 return_address_offset_long = 6 * BytesPerInstWord,
167 #endif
168 displacement_offset = 0
169 };
171 address instruction_address() const { return addr_at(instruction_offset); }
173 address next_instruction_address() const {
174 if (is_special_op(int_at(8), Assembler::jalr_op)) {
175 return addr_at(return_address_offset_short);
176 } else {
177 return addr_at(return_address_offset_long);
178 }
179 }
181 address return_address() const {
182 return next_instruction_address();
183 }
185 address destination() const;
186 void set_destination(address dest);
187 void set_destination_mt_safe(address dest) { set_destination(dest);}
189 void patch_set48_gs(address dest);
190 void patch_set48(address dest);
192 void patch_on_jalr_gs(address dest);
193 void patch_on_jalr(address dest);
195 void patch_on_jal_gs(address dest);
196 void patch_on_jal(address dest);
198 void patch_set32_gs(address dest);
199 void patch_set32(address dest);
201 void verify_alignment() { }
202 void verify();
203 void print();
205 // Creation
206 inline friend NativeCall* nativeCall_at(address address);
207 inline friend NativeCall* nativeCall_before(address return_address);
209 static bool is_call_at(address instr) {
210 return nativeInstruction_at(instr)->is_call();
211 }
213 static bool is_call_before(address return_address) {
214 return is_call_at(return_address - return_address_offset_short) | is_call_at(return_address - return_address_offset_long);
215 }
217 static bool is_call_to(address instr, address target) {
218 return nativeInstruction_at(instr)->is_call() &&
219 nativeCall_at(instr)->destination() == target;
220 }
222 // MT-safe patching of a call instruction.
223 static void insert(address code_pos, address entry);
225 static void replace_mt_safe(address instr_addr, address code_buffer);
226 };
228 inline NativeCall* nativeCall_at(address address) {
229 NativeCall* call = (NativeCall*)(address - NativeCall::instruction_offset);
230 #ifdef ASSERT
231 call->verify();
232 #endif
233 return call;
234 }
236 inline NativeCall* nativeCall_before(address return_address) {
237 NativeCall* call = NULL;
238 if (NativeCall::is_call_at(return_address - NativeCall::return_address_offset_long)) {
239 call = (NativeCall*)(return_address - NativeCall::return_address_offset_long);
240 } else {
241 call = (NativeCall*)(return_address - NativeCall::return_address_offset_short);
242 }
243 #ifdef ASSERT
244 call->verify();
245 #endif
246 return call;
247 }
249 class NativeMovConstReg: public NativeInstruction {
250 public:
251 enum mips_specific_constants {
252 instruction_offset = 0,
253 #ifndef _LP64
254 instruction_size = 2 * BytesPerInstWord,
255 next_instruction_offset = 2 * BytesPerInstWord,
256 #else
257 instruction_size = 4 * BytesPerInstWord,
258 next_instruction_offset = 4 * BytesPerInstWord,
259 #endif
260 };
262 int insn_word() const { return long_at(instruction_offset); }
263 address instruction_address() const { return addr_at(0); }
264 address next_instruction_address() const { return addr_at(next_instruction_offset); }
265 intptr_t data() const;
266 void set_data(intptr_t x);
268 void patch_set48(intptr_t x);
270 void verify();
271 void print();
273 // unit test stuff
274 static void test() {}
276 // Creation
277 inline friend NativeMovConstReg* nativeMovConstReg_at(address address);
278 inline friend NativeMovConstReg* nativeMovConstReg_before(address address);
279 };
281 inline NativeMovConstReg* nativeMovConstReg_at(address address) {
282 NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_offset);
283 #ifdef ASSERT
284 test->verify();
285 #endif
286 return test;
287 }
289 inline NativeMovConstReg* nativeMovConstReg_before(address address) {
290 NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_size - NativeMovConstReg::instruction_offset);
291 #ifdef ASSERT
292 test->verify();
293 #endif
294 return test;
295 }
297 class NativeMovConstRegPatching: public NativeMovConstReg {
298 private:
299 friend NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) {
300 NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_offset);
301 #ifdef ASSERT
302 test->verify();
303 #endif
304 return test;
305 }
306 };
308 // An interface for accessing/manipulating native moves of the form:
309 // lui AT, split_high(offset)
310 // addiu AT, split_low(offset)
311 // add reg, reg, AT
312 // lb/lbu/sb/lh/lhu/sh/lw/sw/lwc1/swc1 dest, reg, 0
313 // [lw/sw/lwc1/swc1 dest, reg, 4]
314 // or
315 // lb/lbu/sb/lh/lhu/sh/lw/sw/lwc1/swc1 dest, reg, offset
316 // [lw/sw/lwc1/swc1 dest, reg, offset+4]
317 //
318 // Warning: These routines must be able to handle any instruction sequences
319 // that are generated as a result of the load/store byte,word,long
320 // macros.
322 class NativeMovRegMem: public NativeInstruction {
323 public:
324 enum mips_specific_constants {
325 instruction_offset = 0,
326 hiword_offset = 4,
327 ldst_offset = 12,
328 immediate_size = 4,
329 ldst_size = 16
330 };
332 //offset is less than 16 bits.
333 bool is_immediate() const { return !is_op(long_at(instruction_offset), Assembler::lui_op); }
334 bool is_64ldst() const {
335 if (is_immediate()) {
336 return (Assembler::opcode(long_at(hiword_offset)) == Assembler::opcode(long_at(instruction_offset))) &&
337 (Assembler::imm_off(long_at(hiword_offset)) == Assembler::imm_off(long_at(instruction_offset)) + wordSize);
338 } else {
339 return (Assembler::opcode(long_at(ldst_offset+hiword_offset)) == Assembler::opcode(long_at(ldst_offset))) &&
340 (Assembler::imm_off(long_at(ldst_offset+hiword_offset)) == Assembler::imm_off(long_at(ldst_offset)) + wordSize);
341 }
342 }
344 address instruction_address() const { return addr_at(instruction_offset); }
345 address next_instruction_address() const {
346 return addr_at( (is_immediate()? immediate_size : ldst_size) + (is_64ldst()? 4 : 0));
347 }
348 /* // helper
349 int instruction_start() const;
351 address instruction_address() const;
353 address next_instruction_address() const;
354 */
356 int offset() const;
358 void set_offset(int x);
360 void add_offset_in_bytes(int add_offset) { set_offset ( ( offset() + add_offset ) ); }
362 void verify();
363 void print ();
365 // unit test stuff
366 static void test() {}
368 private:
369 inline friend NativeMovRegMem* nativeMovRegMem_at (address address);
370 };
372 inline NativeMovRegMem* nativeMovRegMem_at (address address) {
373 NativeMovRegMem* test = (NativeMovRegMem*)(address - NativeMovRegMem::instruction_offset);
374 #ifdef ASSERT
375 test->verify();
376 #endif
377 return test;
378 }
380 class NativeMovRegMemPatching: public NativeMovRegMem {
381 private:
382 friend NativeMovRegMemPatching* nativeMovRegMemPatching_at (address address) {
383 NativeMovRegMemPatching* test = (NativeMovRegMemPatching*)(address - instruction_offset);
384 #ifdef ASSERT
385 test->verify();
386 #endif
387 return test;
388 }
389 };
392 // Handles all kinds of jump on Loongson. Long/far, conditional/unconditional
393 // 32 bits:
394 // far jump:
395 // lui reg, split_high(addr)
396 // addiu reg, split_low(addr)
397 // jr reg
398 // nop
399 // or
400 // beq ZERO, ZERO, offset
401 // nop
402 //
404 //64 bits:
405 // far jump:
406 // lui rd, imm(63...48);
407 // ori rd, rd, imm(47...32);
408 // dsll rd, rd, 16;
409 // ori rd, rd, imm(31...16);
410 // dsll rd, rd, 16;
411 // ori rd, rd, imm(15...0);
412 // jalr rd
413 // nop
414 //
415 class NativeGeneralJump: public NativeInstruction {
416 public:
417 enum mips_specific_constants {
418 instruction_offset = 0,
419 beq_opcode = 0x10000000,//000100|00000|00000|offset
420 b_mask = 0xffff0000,
421 short_size = 8,
422 #ifndef _LP64
423 instruction_size = 4 * BytesPerInstWord
424 #else
425 instruction_size = 6 * BytesPerInstWord
426 #endif
427 };
429 bool is_short() const { return (long_at(instruction_offset) & b_mask) == beq_opcode; }
430 #ifdef _LP64
431 bool is_b_far();
432 #endif
433 address instruction_address() const { return addr_at(instruction_offset); }
434 address jump_destination();
436 void patch_set48_gs(address dest);
437 void patch_set48(address dest);
439 void patch_on_jr_gs(address dest);
440 void patch_on_jr(address dest);
442 void patch_on_j_gs(address dest);
443 void patch_on_j(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 }
465 /*class NativePopReg : public NativeInstruction {
466 public:
467 enum Intel_specific_constants {
468 instruction_code = 0x58,
469 instruction_size = 1,
470 instruction_offset = 0,
471 data_offset = 1,
472 next_instruction_offset = 1
473 };
475 // Insert a pop instruction
476 static void insert(address code_pos, Register reg);
477 };*/
480 class NativeIllegalInstruction: public NativeInstruction {
481 public:
482 enum Intel_specific_constants {
483 instruction_size = 4,
484 instruction_offset = 0,
485 next_instruction_offset = 4
486 };
488 // Insert illegal opcode as specific address
489 static void insert(address code_pos);
490 };
492 // return instruction that does not pop values of the stack
493 // jr RA
494 // delay slot
495 class NativeReturn: public NativeInstruction {
496 public:
497 enum mips_specific_constants {
498 instruction_size = 8,
499 instruction_offset = 0,
500 next_instruction_offset = 8
501 };
502 };
507 class NativeCondJump;
508 inline NativeCondJump* nativeCondJump_at(address address);
509 class NativeCondJump: public NativeInstruction {
510 public:
511 enum mips_specific_constants {
512 instruction_size = 16,
513 instruction_offset = 12,
514 next_instruction_offset = 20
515 };
518 int insn_word() const { return long_at(instruction_offset); }
519 address instruction_address() const { return addr_at(0); }
520 address next_instruction_address() const { return addr_at(next_instruction_offset); }
522 // Creation
523 inline friend NativeCondJump* nativeCondJump_at(address address);
525 address jump_destination() const {
526 return ::nativeCondJump_at(addr_at(12))->jump_destination();
527 }
529 void set_jump_destination(address dest) {
530 ::nativeCondJump_at(addr_at(12))->set_jump_destination(dest);
531 }
533 };
535 inline NativeCondJump* nativeCondJump_at(address address) {
536 NativeCondJump* jump = (NativeCondJump*)(address);
537 return jump;
538 }
542 inline bool NativeInstruction::is_illegal() { return insn_word() == illegal_instruction(); }
544 inline bool NativeInstruction::is_call() {
545 #ifndef _LP64
546 return is_op(long_at(0), Assembler::lui_op) &&
547 is_op(long_at(4), Assembler::addiu_op) &&
548 is_special_op(long_at(8), Assembler::jalr_op);
549 #else
551 // nop
552 // nop
553 // nop
554 // nop
555 // jal target
556 // nop
557 if ( is_nop() &&
558 nativeInstruction_at(addr_at(4))->is_nop() &&
559 nativeInstruction_at(addr_at(8))->is_nop() &&
560 nativeInstruction_at(addr_at(12))->is_nop() &&
561 nativeInstruction_at(addr_at(16))->is_op(Assembler::jal_op) &&
562 nativeInstruction_at(addr_at(20))->is_nop() ) {
563 return true;
564 }
566 // li64
567 if ( is_op(Assembler::lui_op) &&
568 is_op(int_at(4), Assembler::ori_op) &&
569 is_special_op(int_at(8), Assembler::dsll_op) &&
570 is_op(int_at(12), Assembler::ori_op) &&
571 is_special_op(int_at(16), Assembler::dsll_op) &&
572 is_op(int_at(20), Assembler::ori_op) &&
573 is_special_op(int_at(24), Assembler::jalr_op) ) {
574 return true;
575 }
577 //lui dst, imm16
578 //ori dst, dst, imm16
579 //dsll dst, dst, 16
580 //ori dst, dst, imm16
581 if ( is_op(Assembler::lui_op) &&
582 is_op (int_at(4), Assembler::ori_op) &&
583 is_special_op(int_at(8), Assembler::dsll_op) &&
584 is_op (int_at(12), Assembler::ori_op) &&
585 is_special_op(int_at(16), Assembler::jalr_op) ) {
586 return true;
587 }
589 //ori dst, R0, imm16
590 //dsll dst, dst, 16
591 //ori dst, dst, imm16
592 //nop
593 if ( is_op(Assembler::ori_op) &&
594 is_special_op(int_at(4), Assembler::dsll_op) &&
595 is_op (int_at(8), Assembler::ori_op) &&
596 nativeInstruction_at(addr_at(12))->is_nop() &&
597 is_special_op(int_at(16), Assembler::jalr_op) ) {
598 return true;
599 }
601 //ori dst, R0, imm16
602 //dsll dst, dst, 16
603 //nop
604 //nop
605 if ( is_op(Assembler::ori_op) &&
606 is_special_op(int_at(4), Assembler::dsll_op) &&
607 nativeInstruction_at(addr_at(8))->is_nop() &&
608 nativeInstruction_at(addr_at(12))->is_nop() &&
609 is_special_op(int_at(16), Assembler::jalr_op) ) {
610 return true;
611 }
613 //daddiu dst, R0, imm16
614 //nop
615 //nop
616 //nop
617 if ( is_op(Assembler::daddiu_op) &&
618 nativeInstruction_at(addr_at(4))->is_nop() &&
619 nativeInstruction_at(addr_at(8))->is_nop() &&
620 nativeInstruction_at(addr_at(12))->is_nop() &&
621 is_special_op(int_at(16), Assembler::jalr_op) ) {
622 return true;
623 }
625 //lui dst, imm16
626 //ori dst, dst, imm16
627 //nop
628 //nop
629 if ( is_op(Assembler::lui_op) &&
630 is_op (int_at(4), Assembler::ori_op) &&
631 nativeInstruction_at(addr_at(8))->is_nop() &&
632 nativeInstruction_at(addr_at(12))->is_nop() &&
633 is_special_op(int_at(16), Assembler::jalr_op) ) {
634 return true;
635 }
637 //lui dst, imm16
638 //nop
639 //nop
640 //nop
641 if ( is_op(Assembler::lui_op) &&
642 nativeInstruction_at(addr_at(4))->is_nop() &&
643 nativeInstruction_at(addr_at(8))->is_nop() &&
644 nativeInstruction_at(addr_at(12))->is_nop() &&
645 is_special_op(int_at(16), Assembler::jalr_op) ) {
646 return true;
647 }
650 //daddiu dst, R0, imm16
651 //nop
652 if ( is_op(Assembler::daddiu_op) &&
653 nativeInstruction_at(addr_at(4))->is_nop() &&
654 is_special_op(int_at(8), Assembler::jalr_op) ) {
655 return true;
656 }
658 //lui dst, imm16
659 //ori dst, dst, imm16
660 if ( is_op(Assembler::lui_op) &&
661 is_op (int_at(4), Assembler::ori_op) &&
662 is_special_op(int_at(8), Assembler::jalr_op) ) {
663 return true;
664 }
666 //lui dst, imm16
667 //nop
668 if ( is_op(Assembler::lui_op) &&
669 nativeInstruction_at(addr_at(4))->is_nop() &&
670 is_special_op(int_at(8), Assembler::jalr_op) ) {
671 return true;
672 }
674 return false;
676 #endif
677 }
679 inline bool NativeInstruction::is_return() { return is_special_op(Assembler::jr_op) && is_rs(RA);}
681 inline bool NativeInstruction::is_cond_jump() { return is_int_branch() || is_float_branch(); }
682 #endif // CPU_MIPS_VM_NATIVEINST_MIPS_HPP