nativeInst_arm_32.cpp revision 12422:98fe046473c9
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
40int 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
54void 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
100intptr_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
134void 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
231void 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
287void RawNativeJump::check_verified_entry_alignment(address entry, address verified_entry) {
288}
289
290void 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
297void 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
303static 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
330bool RawNativeCall::is_call_before(address return_address) {
331  return (raw_call_for(return_address) != NULL);
332}
333
334NativeCall* 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
340