1 /* 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2014, Red Hat Inc. All rights reserved. 4 * Copyright (c) 2015, Linaro Ltd. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 * 25 */ 26 27 #ifndef CPU_AARCH32_VM_NATIVEINST_AARCH32_HPP 28 #define CPU_AARCH32_VM_NATIVEINST_AARCH32_HPP 29 30 #include "asm/assembler.hpp" 31 #include "memory/allocation.hpp" 32 #include "runtime/icache.hpp" 33 #include "runtime/os.hpp" 34 #include "utilities/top.hpp" 35 36 // We have interfaces for the following instructions: 37 // - NativeInstruction 38 // - - NativeCall 39 // - - NativeMovConstReg 40 // - - NativeMovRegMem 41 // - - NativeMovRegMemPatching 42 // - - NativeJump 43 // - - NativeIllegalOpCode 44 // - - NativeGeneralJump 45 // - - NativeReturn 46 // - - NativeReturnX (return with argument) 47 // - - NativePushConst 48 // - - NativeTstRegMem 49 50 // The base class for different kinds of native instruction abstractions. 51 // Provides the primitive operations to manipulate code relative to this. 52 53 class NativeInstruction VALUE_OBJ_CLASS_SPEC { 54 friend class Relocation; 55 friend bool is_NativeCallTrampolineStub_at(address); 56 public: 57 enum { arm_insn_sz = 4 }; 58 59 inline bool is_nop(); 60 inline bool is_illegal(); 61 inline bool is_return(); 62 inline bool is_jump_or_nop(); 63 inline bool is_cond_jump(); 64 bool is_safepoint_poll(); 65 bool is_movt(); 66 bool is_orr(); 67 bool is_sigill_zombie_not_entrant(); 68 69 bool is_movt(Register dst, unsigned imm, Assembler::Condition cond = Assembler::C_DFLT); 70 bool is_movw(Register dst, unsigned imm, Assembler::Condition cond = Assembler::C_DFLT); 71 bool is_ldr(Register dst, Address addr, Assembler::Condition cond = Assembler::C_DFLT); 72 bool is_patched_already() const; 73 74 inline bool is_jump() const; 75 inline bool is_call() const; 76 77 inline bool is_mov_const_reg() const; 78 inline bool is_reg_call() const; 79 inline bool is_imm_call() const; 80 inline bool is_reg_jump() const; 81 inline bool is_imm_jump() const; 82 83 protected: 84 address addr() const { return address(this); } 85 // TODO remove this, every command is 4byte long 86 #if 1 87 address addr_at(int offset) const { return addr() + offset; } 88 89 s_char sbyte_at(int offset) const { return *(s_char*) addr_at(offset); } 90 u_char ubyte_at(int offset) const { return *(u_char*) addr_at(offset); } 91 92 jint int_at(int offset) const { return *(jint*) addr_at(offset); } 93 juint uint_at(int offset) const { return *(juint*) addr_at(offset); } 94 95 address ptr_at(int offset) const { return *(address*) addr_at(offset); } 96 97 oop oop_at (int offset) const { return *(oop*) addr_at(offset); } 98 99 100 void set_char_at(int offset, char c) { *addr_at(offset) = (u_char)c; } 101 void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; } 102 void set_uint_at(int offset, jint i) { *(juint*)addr_at(offset) = i; } 103 void set_ptr_at (int offset, address ptr) { *(address*) addr_at(offset) = ptr; } 104 void set_oop_at (int offset, oop o) { *(oop*) addr_at(offset) = o; } 105 #endif 106 107 static juint as_uint(address addr) { 108 return *(juint *) addr; 109 } 110 111 juint as_uint() const { 112 return as_uint(addr()); 113 } 114 115 void set_uint(juint v) { 116 *(juint *) addr() = v; 117 } 118 119 void atomic_set_ulong_at(int offset, julong v) { 120 address a = addr() + offset; 121 assert(((uintptr_t) a) % 8 == 0, "should be aligned"); 122 Atomic::store(v, (volatile jlong *) a); 123 } 124 125 public: 126 127 // unit test stuff 128 static void test() {} // override for testing 129 130 static bool is_at(address address); 131 static NativeInstruction* from(address address); 132 133 }; 134 135 inline NativeInstruction* nativeInstruction_at(address addr) { 136 return NativeInstruction::from(addr); 137 } 138 139 inline NativeInstruction* nativeInstruction_at(uint32_t *addr) { 140 return NativeInstruction::from(address(addr)); 141 } 142 143 class NativeBranchType: public NativeInstruction { 144 protected: 145 static bool is_branch_type(uint32_t insn); 146 void patch_offset_to(address addr); 147 public: 148 enum { 149 instruction_size = arm_insn_sz, 150 }; 151 152 address next_instruction_address() const { 153 return addr() + arm_insn_sz; 154 } 155 }; 156 157 class NativeMovConstReg: public NativeInstruction { 158 protected: 159 static bool is_movw_movt_at(address instr); 160 static bool is_ldr_literal_at(address instr); 161 public: 162 enum { 163 movw_movt_pair_sz = 2 * arm_insn_sz, 164 ldr_sz = arm_insn_sz, 165 max_instruction_size = movw_movt_pair_sz, 166 min_instruction_size = ldr_sz, 167 }; 168 169 address next_instruction_address() const { 170 if (is_movw_movt_at(addr())) { 171 return addr() + movw_movt_pair_sz; 172 } else if (is_ldr_literal_at(addr())) { 173 return addr() + ldr_sz; 174 } 175 176 // Unknown instruction in NativeMovConstReg 177 ShouldNotReachHere(); 178 return NULL; 179 } 180 181 intptr_t data() const; 182 void set_data(intptr_t x); 183 184 Register destination() const; 185 void set_destination(Register r); 186 187 void flush() { 188 ICache::invalidate_range(addr(), max_instruction_size); 189 } 190 191 void verify(); 192 void print(); 193 194 // unit test stuff 195 static void test() {} 196 197 // Creation 198 inline friend NativeMovConstReg* nativeMovConstReg_at(address address); 199 inline friend NativeMovConstReg* nativeMovConstReg_before(address address); 200 201 static bool is_at(address instr); 202 203 static NativeMovConstReg* from(address addr); 204 }; 205 206 inline NativeMovConstReg* nativeMovConstReg_at(address address) { 207 return NativeMovConstReg::from(address); 208 } 209 210 inline NativeMovConstReg* nativeMovConstReg_before(address addr) { 211 address mov_addr = NULL; 212 if (NativeMovConstReg::is_movw_movt_at(addr - NativeMovConstReg::movw_movt_pair_sz)) { 213 mov_addr = addr - NativeMovConstReg::movw_movt_pair_sz; 214 } else if (NativeMovConstReg::is_ldr_literal_at(addr - NativeMovConstReg::ldr_sz)) { 215 mov_addr = addr - NativeMovConstReg::ldr_sz; 216 } else { 217 ShouldNotReachHere(); 218 } 219 220 NativeMovConstReg* test = (NativeMovConstReg*) mov_addr; 221 #ifdef ASSERT 222 test->verify(); 223 #endif 224 return test; 225 } 226 227 class NativeTrampolineCall: public NativeBranchType { 228 public: 229 enum { 230 instruction_size = 3 * arm_insn_sz 231 }; 232 address destination() const; 233 void set_destination(address dest); 234 void set_destination_mt_safe(address dest, bool assert_lock = true); 235 236 static bool is_at(address address); 237 static NativeTrampolineCall* from(address address); 238 239 address next_instruction_address() const { 240 assert(is_at(addr()), "not call"); 241 return addr() + instruction_size; 242 } 243 }; 244 245 class NativeRegCall: public NativeBranchType { 246 public: 247 248 Register destination() const; 249 void set_destination(Register r); 250 251 static bool is_at(address address); 252 static NativeRegCall* from(address address); 253 }; 254 255 class NativeCall: public NativeInstruction { 256 friend class Relocation; 257 protected: 258 NativeInstruction* is_long_jump_or_call_at(address addr); 259 260 // NativeCall represents: 261 // NativeImmCall, 262 // NativeMovConstReg + NativeBranchType, 263 // NativeTrampolineCall 264 public: 265 enum { 266 instruction_size = 3 * arm_insn_sz 267 }; 268 #ifdef ASSERT 269 StaticAssert<(int) NativeTrampolineCall::instruction_size <= (int) instruction_size> dummy1; 270 StaticAssert<NativeMovConstReg::movw_movt_pair_sz 271 + NativeRegCall::instruction_size <= (int) instruction_size> dummy2; 272 #endif 273 274 address destination() const; 275 void set_destination(address dest); 276 277 void verify_alignment() { ; } 278 void verify(); 279 void print(); 280 281 address instruction_address() const { return addr_at(0); } 282 address next_instruction_address() const; 283 address return_address() const; 284 285 // MT-safe patching of a call instruction. 286 static void insert(address code_pos, address entry); 287 288 // Similar to replace_mt_safe, but just changes the destination. The 289 // important thing is that free-running threads are able to execute 290 // this call instruction at all times. If the call is an immediate BL 291 // instruction we can simply rely on atomicity of 32-bit writes to 292 // make sure other threads will see no intermediate states. 293 294 // We cannot rely on locks here, since the free-running threads must run at 295 // full speed. 296 // 297 // Used in the runtime linkage of calls; see class CompiledIC. 298 // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) 299 300 // The parameter assert_lock disables the assertion during code generation. 301 void set_destination_mt_safe(address dest, bool assert_lock = true); 302 303 static bool is_at(address instr); 304 static NativeCall* from(address instr); 305 306 static bool is_call_before(address return_address); 307 }; 308 309 inline NativeCall* nativeCall_at(address address) { 310 return NativeCall::from(address); 311 } 312 313 inline NativeCall* nativeCall_before(address return_address) { 314 address call_addr = NULL; 315 if (NativeCall::is_at(return_address - NativeBranchType::instruction_size)) { 316 call_addr = return_address - NativeBranchType::instruction_size; 317 } else if (NativeCall::is_at(return_address - NativeCall::instruction_size)) { 318 call_addr = return_address - NativeCall::instruction_size; 319 } else { 320 ShouldNotReachHere(); 321 } 322 323 return NativeCall::from(call_addr); 324 } 325 326 327 // An interface for accessing/manipulating native moves of the form: 328 // mov[b/w/l/q] [reg + offset], reg (instruction_code_reg2mem) 329 // mov[b/w/l/q] reg, [reg+offset] (instruction_code_mem2reg 330 // mov[s/z]x[w/b/q] [reg + offset], reg 331 // fld_s [reg+offset] 332 // fld_d [reg+offset] 333 // fstp_s [reg + offset] 334 // fstp_d [reg + offset] 335 // mov_literal64 scratch,<pointer> ; mov[b/w/l/q] 0(scratch),reg | mov[b/w/l/q] reg,0(scratch) 336 // 337 // Warning: These routines must be able to handle any instruction sequences 338 // that are generated as a result of the load/store byte,word,long 339 // macros. For example: The load_unsigned_byte instruction generates 340 // an xor reg,reg inst prior to generating the movb instruction. This 341 // class must skip the xor instruction. 342 343 344 // TODO Review 345 class NativeMovRegMem: public NativeInstruction { 346 public: 347 enum { 348 instruction_size = 2 * arm_insn_sz, // TODO check this 349 }; 350 // helper 351 int instruction_start() const; 352 353 address instruction_address() const; 354 355 address next_instruction_address() const; 356 357 int offset() const; 358 359 void set_offset(int x); 360 361 void add_offset_in_bytes(int add_offset) { set_offset ( ( offset() + add_offset ) ); } 362 363 void verify(); 364 void print (); 365 366 // unit test stuff 367 static void test() {} 368 369 private: 370 inline friend NativeMovRegMem* nativeMovRegMem_at (address address); 371 }; 372 373 inline NativeMovRegMem* nativeMovRegMem_at (address address) { 374 NativeMovRegMem* test = (NativeMovRegMem*) address; 375 #ifdef ASSERT 376 test->verify(); 377 #endif 378 return test; 379 } 380 381 class NativeMovRegMemPatching: public NativeMovRegMem { 382 private: 383 friend NativeMovRegMemPatching* nativeMovRegMemPatching_at (address address) {Unimplemented(); return 0; } 384 }; 385 386 class NativeJump: public NativeInstruction { 387 public: 388 enum { 389 instruction_size = NativeMovConstReg::movw_movt_pair_sz + NativeBranchType::instruction_size, 390 }; 391 address instruction_address() const { 392 return addr(); 393 } 394 395 address next_instruction_address() const; 396 397 address jump_destination() const; 398 void set_jump_destination(address dest); 399 400 // Creation 401 inline friend NativeJump* nativeJump_at(address address); 402 403 void verify(); 404 405 // Unit testing stuff 406 static void test() {} 407 408 // Insertion of native jump instruction 409 static void insert(address code_pos, address entry); 410 // MT-safe insertion of native jump at verified method entry 411 static void check_verified_entry_alignment(address entry, address verified_entry); 412 static void patch_verified_entry(address entry, address verified_entry, address dest); 413 414 static bool is_at(address instr); 415 static NativeJump* from(address instr); 416 }; 417 418 inline NativeJump* nativeJump_at(address addr) { 419 return NativeJump::from(addr); 420 } 421 422 // TODO We don't really need NativeGeneralJump, NativeJump should be able to do 423 // everything that General Jump would. Make this only interface to NativeJump 424 // from share code (c1_Runtime) 425 class NativeGeneralJump: public NativeJump { 426 public: 427 enum { 428 instruction_size = arm_insn_sz, 429 }; 430 431 static void insert_unconditional(address code_pos, address entry); 432 static void replace_mt_safe(address instr_addr, address code_buffer); 433 static void verify(); 434 }; 435 436 inline NativeGeneralJump* nativeGeneralJump_at(address address) { 437 NativeGeneralJump* jump = (NativeGeneralJump*)(address); 438 debug_only(jump->verify();) 439 return jump; 440 } 441 442 class NativePopReg : public NativeInstruction { 443 public: 444 // Insert a pop instruction 445 static void insert(address code_pos, Register reg); 446 }; 447 448 449 class NativeIllegalInstruction: public NativeInstruction { 450 public: 451 // Insert illegal opcode as specific address 452 static void insert(address code_pos); 453 }; 454 455 // return instruction that does not pop values of the stack 456 class NativeReturn: public NativeInstruction { 457 public: 458 }; 459 460 // return instruction that does pop values of the stack 461 class NativeReturnX: public NativeInstruction { 462 public: 463 }; 464 465 // Simple test vs memory 466 class NativeTstRegMem: public NativeInstruction { 467 public: 468 }; 469 470 inline bool NativeInstruction::is_nop() { 471 return (as_uint() & 0x0fffffff) == 0x0320f000; 472 } 473 474 inline bool NativeInstruction::is_jump_or_nop() { 475 return is_nop() || is_jump(); 476 } 477 478 class NativeImmCall: public NativeBranchType { 479 public: 480 address destination() const; 481 void set_destination(address dest); 482 483 static bool is_at(address address); 484 static NativeImmCall* from(address address); 485 }; 486 487 class NativeImmJump: public NativeBranchType { 488 public: 489 490 address destination() const; 491 void set_destination(address r); 492 493 static bool is_at(address address); 494 static NativeImmJump* from(address address); 495 }; 496 497 class NativeRegJump: public NativeBranchType { 498 public: 499 500 Register destination() const; 501 void set_destination(Register r); 502 503 static bool is_at(address address); 504 static NativeRegJump* from(address address); 505 }; 506 507 inline bool NativeInstruction::is_call() const { return NativeCall::is_at(addr()); } 508 inline bool NativeInstruction::is_jump() const { return NativeJump::is_at(addr()); } 509 inline bool NativeInstruction::is_mov_const_reg() const { return NativeMovConstReg::is_at(addr()); } 510 inline bool NativeInstruction::is_imm_call() const { return NativeImmCall::is_at(addr()); } 511 inline bool NativeInstruction::is_reg_call() const { return NativeRegCall::is_at(addr()); } 512 inline bool NativeInstruction::is_imm_jump() const { return NativeImmJump::is_at(addr()); } 513 inline bool NativeInstruction::is_reg_jump() const { return NativeRegJump::is_at(addr()); } 514 515 #endif // CPU_AARCH32_VM_NATIVEINST_AARCH32_HPP