1 /* 2 * Copyright (c) 2008, 2016, 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 "assembler_arm.inline.hpp" 27 #include "code/codeCache.hpp" 28 #include "code/codeCacheExtensions.hpp" 29 #include "memory/resourceArea.hpp" 30 #include "nativeInst_arm.hpp" 31 #include "oops/oop.inline.hpp" 32 #include "runtime/handles.hpp" 33 #include "runtime/sharedRuntime.hpp" 34 #include "runtime/stubRoutines.hpp" 35 #include "utilities/ostream.hpp" 36 #ifdef COMPILER1 37 #include "c1/c1_Runtime1.hpp" 38 #endif 39 #include "code/icBuffer.hpp" 40 41 int NativeMovRegMem::offset() const { 42 switch (kind()) { 43 case instr_ldr_str: 44 return encoding() & 0xfff; 45 case instr_ldrh_strh: 46 return (encoding() & 0x0f) | ((encoding() >> 4) & 0xf0); 47 case instr_fld_fst: 48 return (encoding() & 0xff) << 2; 49 default: 50 ShouldNotReachHere(); 51 return 0; 52 } 53 } 54 55 void NativeMovRegMem::set_offset(int x) { 56 assert(x >= 0 && x < 65536, "encoding constraint"); 57 const int Rt = Rtemp->encoding(); 58 59 // If offset is too large to be placed into single ldr/str instruction, we replace 60 // ldr Rd, [Rn, #offset] 61 // nop 62 // with 63 // add Rtemp, Rn, #offset_hi 64 // ldr Rd, [Rtemp, #offset_lo] 65 switch (kind()) { 66 case instr_ldr_str: 67 if (x < 4096) { 68 set_encoding((encoding() & 0xfffff000) | x); 69 } else { 70 NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address()); 71 assert(next->is_nop(), "must be"); 72 next->set_encoding((encoding() & 0xfff0f000) | Rt << 16 | (x & 0xfff)); 73 this->set_encoding((encoding() & 0x000f0000) | Rt << 12 | x >> 12 | 0xe2800a00); 74 } 75 break; 76 case instr_ldrh_strh: 77 if (x < 256) { 78 set_encoding((encoding() & 0xfffff0f0) | (x & 0x0f) | (x & 0xf0) << 4); 79 } else { 80 NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address()); 81 assert(next->is_nop(), "must be"); 82 next->set_encoding((encoding() & 0xfff0f0f0) | Rt << 16 | (x & 0x0f) | (x & 0xf0) << 4); 83 this->set_encoding((encoding() & 0x000f0000) | Rt << 12 | x >> 8 | 0xe2800c00); 84 } 85 break; 86 case instr_fld_fst: 87 if (x < 1024) { 88 set_encoding((encoding() & 0xffffff00) | (x >> 2)); 89 } else { 90 NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address()); 91 assert(next->is_nop(), "must be"); 92 next->set_encoding((encoding() & 0xfff0ff00) | Rt << 16 | ((x >> 2) & 0xff)); 93 this->set_encoding((encoding() & 0x000f0000) | Rt << 12 | x >> 10 | 0xe2800b00); 94 } 95 break; 96 default: 97 ShouldNotReachHere(); 98 } 99 } 100 101 intptr_t NativeMovConstReg::data() const { 102 RawNativeInstruction* next = next_raw(); 103 if (is_movw()) { 104 // Oop embedded in movw/movt instructions 105 assert(VM_Version::supports_movw(), "must be"); 106 return (this->encoding() & 0x00000fff) | (this->encoding() & 0x000f0000) >> 4 | 107 (next->encoding() & 0x00000fff) << 16 | (next->encoding() & 0x000f0000) << 12; 108 } else { 109 // Oop is loaded from oops section or inlined in the code 110 int oop_offset; 111 if (is_ldr_literal()) { 112 // ldr Rd, [PC, #offset] 113 oop_offset = ldr_offset(); 114 } else { 115 assert(next->is_ldr(), "must be"); 116 oop_offset = (this->encoding() & 0xff) << 12 | (next->encoding() & 0xfff); 117 if (is_add_pc()) { 118 // add Rd, PC, #offset_hi 119 // ldr Rd, [Rd, #offset_lo] 120 assert(next->encoding() & (1 << 23), "sign mismatch"); 121 // offset OK (both positive) 122 } else { 123 assert(is_sub_pc(), "must be"); 124 // sub Rd, PC, #offset_hi 125 // ldr Rd, [Rd, -#offset_lo] 126 assert(!(next->encoding() & (1 << 23)), "sign mismatch"); 127 // negative offsets 128 oop_offset = -oop_offset; 129 } 130 } 131 return *(int*)(instruction_address() + 8 + oop_offset); 132 } 133 } 134 135 void NativeMovConstReg::set_data(intptr_t x, address pc) { 136 // Find and replace the oop corresponding to this instruction in oops section 137 RawNativeInstruction* next = next_raw(); 138 oop* oop_addr = NULL; 139 Metadata** metadata_addr = NULL; 140 CodeBlob* cb = CodeCache::find_blob(instruction_address()); 141 if (cb != NULL) { 142 nmethod* nm = cb->as_nmethod_or_null(); 143 if (nm != NULL) { 144 RelocIterator iter(nm, instruction_address(), next->instruction_address()); 145 while (iter.next()) { 146 if (iter.type() == relocInfo::oop_type) { 147 oop_addr = iter.oop_reloc()->oop_addr(); 148 *oop_addr = cast_to_oop(x); 149 break; 150 } else if (iter.type() == relocInfo::metadata_type) { 151 metadata_addr = iter.metadata_reloc()->metadata_addr(); 152 *metadata_addr = (Metadata*)x; 153 break; 154 } 155 } 156 } 157 } 158 159 if (is_movw()) { 160 // data embedded in movw/movt instructions 161 assert(VM_Version::supports_movw(), "must be"); 162 unsigned int lo = (unsigned int)x; 163 unsigned int hi = (unsigned int)(x >> 16); 164 this->set_encoding((this->encoding() & 0xfff0f000) | (lo & 0xf000) << 4 | (lo & 0xfff)); 165 next->set_encoding((next->encoding() & 0xfff0f000) | (hi & 0xf000) << 4 | (hi & 0xfff)); 166 } else if (oop_addr == NULL & metadata_addr == NULL) { 167 // A static ldr_literal (without oop or metadata relocation) 168 assert(is_ldr_literal(), "must be"); 169 int offset = ldr_offset(); 170 oop_addr = (oop*)(instruction_address() + 8 + offset); 171 *oop_addr = cast_to_oop(x); 172 } else { 173 // data is loaded from oop or metadata section 174 int offset; 175 176 address addr = oop_addr != NULL ? (address)oop_addr : (address)metadata_addr; 177 178 if(pc == 0) { 179 offset = addr - instruction_address() - 8; 180 } else { 181 offset = addr - pc - 8; 182 } 183 184 int sign = (offset >= 0) ? (1 << 23) : 0; 185 int delta = (offset >= 0) ? offset : (-offset); 186 assert(delta < 0x100000, "within accessible range"); 187 if (is_ldr_literal()) { 188 // fix the ldr with the real offset to the oop/metadata table 189 assert(next->is_nop(), "must be"); 190 if (delta < 4096) { 191 // ldr Rd, [PC, #offset] 192 set_encoding((encoding() & 0xff7ff000) | delta | sign); 193 assert(ldr_offset() == offset, "check encoding"); 194 } else { 195 int cc = encoding() & 0xf0000000; 196 int Rd = (encoding() >> 12) & 0xf; 197 int Rt = Rd; 198 assert(Rt != 0xf, "Illegal destination register"); // or fix by using Rtemp 199 // move the ldr, fixing delta_lo and the source register 200 next->set_encoding((encoding() & 0xff70f000) | (Rt << 16) | (delta & 0xfff) | sign); 201 assert(next->is_ldr(), "must be"); 202 if (offset > 0) { 203 // add Rt, PC, #delta_hi 204 // ldr Rd, [Rt, #delta_lo] 205 this->set_encoding((Rt << 12) | (delta >> 12) | 0x028f0a00 | cc); 206 assert(is_add_pc(), "must be"); 207 } else { 208 // sub Rt, PC, #delta_hi 209 // ldr Rd, [Rt, -#delta_lo] 210 this->set_encoding((Rt << 12) | (delta >> 12) | 0x024f0a00 | cc); 211 assert(is_sub_pc(), "must be"); 212 } 213 } 214 } else { 215 assert(is_pc_rel(), "must be"); 216 assert(next->is_ldr(), "must be"); 217 if (offset > 0) { 218 // add Rt, PC, #delta_hi 219 this->set_encoding((this->encoding() & 0xf00ff000) | 0x02800a00 | (delta >> 12)); 220 assert(is_add_pc(), "must be"); 221 } else { 222 // sub Rt, PC, #delta_hi 223 this->set_encoding((this->encoding() & 0xf00ff000) | 0x02400a00 | (delta >> 12)); 224 assert(is_sub_pc(), "must be"); 225 } 226 // ldr Rd, Rt, #delta_lo (or -#delta_lo) 227 next->set_encoding((next->encoding() & 0xff7ff000) | (delta & 0xfff) | sign); 228 } 229 } 230 } 231 232 void NativeMovConstReg::set_pc_relative_offset(address addr, address pc) { 233 int offset; 234 if (pc == 0) { 235 offset = addr - instruction_address() - 8; 236 } else { 237 offset = addr - pc - 8; 238 } 239 240 RawNativeInstruction* next = next_raw(); 241 242 int sign = (offset >= 0) ? (1 << 23) : 0; 243 int delta = (offset >= 0) ? offset : (-offset); 244 assert(delta < 0x100000, "within accessible range"); 245 if (is_ldr_literal()) { 246 if (delta < 4096) { 247 // ldr Rd, [PC, #offset] 248 set_encoding((encoding() & 0xff7ff000) | delta | sign); 249 assert(ldr_offset() == offset, "check encoding"); 250 } else { 251 assert(next->is_nop(), "must be"); 252 int cc = encoding() & 0xf0000000; 253 int Rd = (encoding() >> 12) & 0xf; 254 int Rt = Rd; 255 assert(Rt != 0xf, "Illegal destination register"); // or fix by using Rtemp 256 // move the ldr, fixing delta_lo and the source register 257 next->set_encoding((encoding() & 0xff70f000) | (Rt << 16) | (delta & 0xfff) | sign); 258 assert(next->is_ldr(), "must be"); 259 if (offset > 0) { 260 // add Rt, PC, #delta_hi 261 // ldr Rd, [Rt, #delta_lo] 262 this->set_encoding((Rt << 12) | (delta >> 12) | 0x028f0a00 | cc); 263 assert(is_add_pc(), "must be"); 264 } else { 265 // sub Rt, PC, #delta_hi 266 // ldr Rd, [Rt, -#delta_lo] 267 this->set_encoding((Rt << 12) | (delta >> 12) | 0x024f0a00 | cc); 268 assert(is_sub_pc(), "must be"); 269 } 270 } 271 } else { 272 assert(is_pc_rel(), "must be"); 273 assert(next->is_ldr(), "must be"); 274 if (offset > 0) { 275 // add Rt, PC, #delta_hi 276 this->set_encoding((this->encoding() & 0xf00ff000) | 0x02800a00 | (delta >> 12)); 277 assert(is_add_pc(), "must be"); 278 } else { 279 // sub Rt, PC, #delta_hi 280 this->set_encoding((this->encoding() & 0xf00ff000) | 0x02400a00 | (delta >> 12)); 281 assert(is_sub_pc(), "must be"); 282 } 283 // ldr Rd, Rt, #delta_lo (or -#delta_lo) 284 next->set_encoding((next->encoding() & 0xff7ff000) | (delta & 0xfff) | sign); 285 } 286 } 287 288 void RawNativeJump::check_verified_entry_alignment(address entry, address verified_entry) { 289 } 290 291 void RawNativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { 292 assert(dest == SharedRuntime::get_handle_wrong_method_stub(), "should be"); 293 int *a = (int *)verified_entry; 294 a[0] = zombie_illegal_instruction; // always illegal 295 ICache::invalidate_range((address)&a[0], sizeof a[0]); 296 } 297 298 void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { 299 int offset = (int)(entry - code_pos - 8); 300 assert(offset < 0x2000000 && offset > -0x2000000, "encoding constraint"); 301 nativeInstruction_at(code_pos)->set_encoding(0xea000000 | ((unsigned int)offset << 6 >> 8)); 302 } 303 304 static address raw_call_for(address return_address) { 305 CodeBlob* cb = CodeCache::find_blob(return_address); 306 nmethod* nm = cb->as_nmethod_or_null(); 307 if (nm == NULL) { 308 ShouldNotReachHere(); 309 return NULL; 310 } 311 // Look back 4 instructions, to allow for ic_call 312 address begin = MAX2(return_address - 4*NativeInstruction::instruction_size, nm->code_begin()); 313 RelocIterator iter(nm, begin, return_address); 314 while (iter.next()) { 315 Relocation* reloc = iter.reloc(); 316 if (reloc->is_call()) { 317 address call = reloc->addr(); 318 if (nativeInstruction_at(call)->is_call()) { 319 if (nativeCall_at(call)->return_address() == return_address) { 320 return call; 321 } 322 } else { 323 // Some "calls" are really jumps 324 assert(nativeInstruction_at(call)->is_jump(), "must be call or jump"); 325 } 326 } 327 } 328 return NULL; 329 } 330 331 bool RawNativeCall::is_call_before(address return_address) { 332 return (raw_call_for(return_address) != NULL); 333 } 334 335 NativeCall* rawNativeCall_before(address return_address) { 336 address call = raw_call_for(return_address); 337 assert(call != NULL, "must be"); 338 return nativeCall_at(call); 339 } 340