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