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