jdk

Форк
0
/
nativeInst_arm_32.cpp 
356 строк · 12.8 Кб
1
/*
2
 * Copyright (c) 2008, 2024, 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 "asm/assembler.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

39
int NativeMovRegMem::offset() const {
40
  switch (kind()) {
41
    case instr_ldr_str:
42
      return encoding() & 0xfff;
43
    case instr_ldrh_strh:
44
      return (encoding() & 0x0f) | ((encoding() >> 4) & 0xf0);
45
    case instr_fld_fst:
46
      return (encoding() & 0xff) << 2;
47
    default:
48
      ShouldNotReachHere();
49
      return 0;
50
  }
51
}
52

53
void NativeMovRegMem::set_offset(int x) {
54
  assert(x >= 0 && x < 65536, "encoding constraint");
55
  const int Rt = Rtemp->encoding();
56

57
  // If offset is too large to be placed into single ldr/str instruction, we replace
58
  //   ldr  Rd, [Rn, #offset]
59
  //   nop
60
  // with
61
  //   add  Rtemp, Rn, #offset_hi
62
  //   ldr  Rd, [Rtemp, #offset_lo]
63
  switch (kind()) {
64
    case instr_ldr_str:
65
      if (x < 4096) {
66
        set_encoding((encoding() & 0xfffff000) | x);
67
      } else {
68
        NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address());
69
        assert(next->is_nop(), "must be");
70
        next->set_encoding((encoding() & 0xfff0f000) | Rt << 16 | (x & 0xfff));
71
        this->set_encoding((encoding() & 0x000f0000) | Rt << 12 | x >> 12 | 0xe2800a00);
72
      }
73
      break;
74
    case instr_ldrh_strh:
75
      if (x < 256) {
76
        set_encoding((encoding() & 0xfffff0f0) | (x & 0x0f) | (x & 0xf0) << 4);
77
      } else {
78
        NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address());
79
        assert(next->is_nop(), "must be");
80
        next->set_encoding((encoding() & 0xfff0f0f0) | Rt << 16 | (x & 0x0f) | (x & 0xf0) << 4);
81
        this->set_encoding((encoding() & 0x000f0000) | Rt << 12 | x >> 8 | 0xe2800c00);
82
      }
83
      break;
84
    case instr_fld_fst:
85
      if (x < 1024) {
86
        set_encoding((encoding() & 0xffffff00) | (x >> 2));
87
      } else {
88
        NativeInstruction* next = nativeInstruction_at(next_raw_instruction_address());
89
        assert(next->is_nop(), "must be");
90
        next->set_encoding((encoding() & 0xfff0ff00) | Rt << 16 | ((x >> 2) & 0xff));
91
        this->set_encoding((encoding() & 0x000f0000) | Rt << 12 | x >> 10 | 0xe2800b00);
92
      }
93
      break;
94
    default:
95
      ShouldNotReachHere();
96
  }
97
}
98

99
intptr_t NativeMovConstReg::data() const {
100
  RawNativeInstruction* next = next_raw();
101
  if (is_movw()) {
102
    // Oop embedded in movw/movt instructions
103
    assert(VM_Version::supports_movw(), "must be");
104
    return (this->encoding() & 0x00000fff)       | (this->encoding() & 0x000f0000) >> 4 |
105
           (next->encoding() & 0x00000fff) << 16 | (next->encoding() & 0x000f0000) << 12;
106
  } else {
107
    // Oop is loaded from oops section or inlined in the code
108
    int oop_offset;
109
    if (is_ldr_literal()) {
110
      //   ldr  Rd, [PC, #offset]
111
      oop_offset = ldr_offset();
112
    } else {
113
      assert(next->is_ldr(), "must be");
114
      oop_offset = (this->encoding() & 0xff) << 12 | (next->encoding() & 0xfff);
115
      if (is_add_pc()) {
116
        //   add  Rd, PC, #offset_hi
117
        //   ldr  Rd, [Rd, #offset_lo]
118
        assert(next->encoding() & (1 << 23), "sign mismatch");
119
        // offset OK (both positive)
120
      } else {
121
        assert(is_sub_pc(), "must be");
122
        //   sub  Rd, PC, #offset_hi
123
        //   ldr  Rd, [Rd, -#offset_lo]
124
        assert(!(next->encoding() & (1 << 23)), "sign mismatch");
125
        // negative offsets
126
        oop_offset = -oop_offset;
127
      }
128
    }
129
    return *(int*)(instruction_address() + 8 + oop_offset);
130
  }
131
}
132

133
void NativeMovConstReg::set_data(intptr_t x, address pc) {
134
  // Find and replace the oop corresponding to this instruction in oops section
135
  RawNativeInstruction* next = next_raw();
136
  oop* oop_addr = nullptr;
137
  Metadata** metadata_addr = nullptr;
138
  CodeBlob* cb = CodeCache::find_blob(instruction_address());
139
  if (cb != nullptr) {
140
    nmethod* nm = cb->as_nmethod_or_null();
141
    if (nm != nullptr) {
142
      RelocIterator iter(nm, instruction_address(), next->instruction_address());
143
      while (iter.next()) {
144
        if (iter.type() == relocInfo::oop_type) {
145
          oop_addr = iter.oop_reloc()->oop_addr();
146
          *oop_addr = cast_to_oop(x);
147
          break;
148
        } else if (iter.type() == relocInfo::metadata_type) {
149
          metadata_addr = iter.metadata_reloc()->metadata_addr();
150
          *metadata_addr = (Metadata*)x;
151
          break;
152
        }
153
      }
154
    }
155
  }
156

157
  if (is_movw()) {
158
    // data embedded in movw/movt instructions
159
    assert(VM_Version::supports_movw(), "must be");
160
    unsigned int lo = (unsigned int)x;
161
    unsigned int hi = (unsigned int)(x >> 16);
162
    this->set_encoding((this->encoding() & 0xfff0f000) | (lo & 0xf000) << 4 | (lo & 0xfff));
163
    next->set_encoding((next->encoding() & 0xfff0f000) | (hi & 0xf000) << 4 | (hi & 0xfff));
164
  } else if (oop_addr == nullptr && metadata_addr == nullptr) {
165
    // A static ldr_literal (without oop or metadata relocation)
166
    assert(is_ldr_literal(), "must be");
167
    int offset = ldr_offset();
168
    oop_addr = (oop*)(instruction_address() + 8 + offset);
169
    *oop_addr = cast_to_oop(x);
170
  } else {
171
    // data is loaded from oop or metadata section
172
    int offset;
173

174
    address addr = oop_addr != nullptr ? (address)oop_addr : (address)metadata_addr;
175

176
    if(pc == 0) {
177
      offset = addr - instruction_address() - 8;
178
    } else {
179
      offset = addr - pc - 8;
180
    }
181

182
    int sign = (offset >= 0) ? (1 << 23) : 0;
183
    int delta = (offset >= 0) ? offset : (-offset);
184
    assert(delta < 0x100000, "within accessible range");
185
    if (is_ldr_literal()) {
186
      // fix the ldr with the real offset to the oop/metadata table
187
      assert(next->is_nop(), "must be");
188
      if (delta < 4096) {
189
        //   ldr  Rd, [PC, #offset]
190
        set_encoding((encoding() & 0xff7ff000) | delta | sign);
191
        assert(ldr_offset() == offset, "check encoding");
192
      } else {
193
        int cc = encoding() & 0xf0000000;
194
        int Rd = (encoding() >> 12) & 0xf;
195
        int Rt = Rd;
196
        assert(Rt != 0xf, "Illegal destination register"); // or fix by using Rtemp
197
        // move the ldr, fixing delta_lo and the source register
198
        next->set_encoding((encoding() & 0xff70f000) | (Rt << 16) | (delta & 0xfff) | sign);
199
        assert(next->is_ldr(), "must be");
200
        if (offset > 0) {
201
          //   add  Rt, PC, #delta_hi
202
          //   ldr  Rd, [Rt, #delta_lo]
203
          this->set_encoding((Rt << 12) | (delta >> 12) | 0x028f0a00 | cc);
204
          assert(is_add_pc(), "must be");
205
        } else {
206
          //   sub Rt, PC, #delta_hi
207
          //   ldr  Rd, [Rt, -#delta_lo]
208
          this->set_encoding((Rt << 12) | (delta >> 12) | 0x024f0a00 | cc);
209
          assert(is_sub_pc(), "must be");
210
        }
211
      }
212
    } else {
213
      assert(is_pc_rel(), "must be");
214
      assert(next->is_ldr(), "must be");
215
      if (offset > 0) {
216
        //   add Rt, PC, #delta_hi
217
        this->set_encoding((this->encoding() & 0xf00ff000) | 0x02800a00 | (delta >> 12));
218
        assert(is_add_pc(), "must be");
219
      } else {
220
        //   sub Rt, PC, #delta_hi
221
        this->set_encoding((this->encoding() & 0xf00ff000) | 0x02400a00 | (delta >> 12));
222
        assert(is_sub_pc(), "must be");
223
      }
224
      //    ldr Rd, Rt, #delta_lo (or -#delta_lo)
225
      next->set_encoding((next->encoding() & 0xff7ff000) | (delta & 0xfff) | sign);
226
    }
227
  }
228
}
229

230
void NativeMovConstReg::set_pc_relative_offset(address addr, address pc) {
231
  int offset;
232
  if (pc == 0) {
233
    offset = addr - instruction_address() - 8;
234
  } else {
235
    offset = addr - pc - 8;
236
  }
237

238
  RawNativeInstruction* next = next_raw();
239

240
  int sign = (offset >= 0) ? (1 << 23) : 0;
241
  int delta = (offset >= 0) ? offset : (-offset);
242
  assert(delta < 0x100000, "within accessible range");
243
  if (is_ldr_literal()) {
244
    if (delta < 4096) {
245
      //   ldr  Rd, [PC, #offset]
246
      set_encoding((encoding() & 0xff7ff000) | delta | sign);
247
      assert(ldr_offset() == offset, "check encoding");
248
    } else {
249
      assert(next->is_nop(), "must be");
250
      int cc = encoding() & 0xf0000000;
251
      int Rd = (encoding() >> 12) & 0xf;
252
      int Rt = Rd;
253
      assert(Rt != 0xf, "Illegal destination register"); // or fix by using Rtemp
254
      // move the ldr, fixing delta_lo and the source register
255
      next->set_encoding((encoding() & 0xff70f000) | (Rt << 16) | (delta & 0xfff) | sign);
256
      assert(next->is_ldr(), "must be");
257
      if (offset > 0) {
258
        //   add  Rt, PC, #delta_hi
259
        //   ldr  Rd, [Rt, #delta_lo]
260
        this->set_encoding((Rt << 12) | (delta >> 12) | 0x028f0a00 | cc);
261
        assert(is_add_pc(), "must be");
262
      } else {
263
        //   sub Rt, PC, #delta_hi
264
        //   ldr Rd, [Rt, -#delta_lo]
265
        this->set_encoding((Rt << 12) | (delta >> 12) | 0x024f0a00 | cc);
266
        assert(is_sub_pc(), "must be");
267
      }
268
    }
269
  } else {
270
    assert(is_pc_rel(), "must be");
271
    assert(next->is_ldr(), "must be");
272
    if (offset > 0) {
273
      //   add Rt, PC, #delta_hi
274
      this->set_encoding((this->encoding() & 0xf00ff000) | 0x02800a00 | (delta >> 12));
275
      assert(is_add_pc(), "must be");
276
    } else {
277
      //   sub Rt, PC, #delta_hi
278
      this->set_encoding((this->encoding() & 0xf00ff000) | 0x02400a00 | (delta >> 12));
279
      assert(is_sub_pc(), "must be");
280
    }
281
    //    ldr Rd, Rt, #delta_lo (or -#delta_lo)
282
    next->set_encoding((next->encoding() & 0xff7ff000) | (delta & 0xfff) | sign);
283
  }
284
}
285

286
void RawNativeJump::check_verified_entry_alignment(address entry, address verified_entry) {
287
}
288

289
void RawNativeJump::patch_verified_entry(address entry, address verified_entry, address dest) {
290
  assert(dest == SharedRuntime::get_handle_wrong_method_stub(), "should be");
291
  int *a = (int *)verified_entry;
292
  a[0] = not_entrant_illegal_instruction; // always illegal
293
  ICache::invalidate_range((address)&a[0], sizeof a[0]);
294
}
295

296
void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
297
  int offset = (int)(entry - code_pos - 8);
298
  assert(offset < 0x2000000 && offset > -0x2000000, "encoding constraint");
299
  nativeInstruction_at(code_pos)->set_encoding(0xea000000 | ((unsigned int)offset << 6 >> 8));
300
}
301

302
static address raw_call_for(address return_address) {
303
  CodeBlob* cb = CodeCache::find_blob(return_address);
304
  nmethod* nm = cb->as_nmethod_or_null();
305
  if (nm == nullptr) {
306
    ShouldNotReachHere();
307
    return nullptr;
308
  }
309
  // Look back 4 instructions, to allow for ic_call
310
  address begin = MAX2(return_address - 4*NativeInstruction::instruction_size, nm->code_begin());
311
  RelocIterator iter(nm, begin, return_address);
312
  while (iter.next()) {
313
    Relocation* reloc = iter.reloc();
314
    if (reloc->is_call()) {
315
      address call = reloc->addr();
316
      if (nativeInstruction_at(call)->is_call()) {
317
        if (nativeCall_at(call)->return_address() == return_address) {
318
          return call;
319
        }
320
      } else {
321
        // Some "calls" are really jumps
322
        assert(nativeInstruction_at(call)->is_jump(), "must be call or jump");
323
      }
324
    }
325
  }
326
  return nullptr;
327
}
328

329
bool RawNativeCall::is_call_before(address return_address) {
330
  return (raw_call_for(return_address) != nullptr);
331
}
332

333
NativeCall* rawNativeCall_before(address return_address) {
334
  address call = raw_call_for(return_address);
335
  assert(call != nullptr, "must be");
336
  return nativeCall_at(call);
337
}
338

339
void NativePostCallNop::make_deopt() {
340
  NativeDeoptInstruction::insert(addr_at(0));
341
}
342

343
void NativeDeoptInstruction::verify() {
344
}
345

346
// Inserts an undefined instruction at a given pc
347
void NativeDeoptInstruction::insert(address code_pos) {
348
  // UDF, Encoding A1:
349
  // 1 1 1 0 | 0 1 1 1 | 1 1 1 1 | imm12 | 1 1 1 1 | imm4 |
350
  // e       | 7       | f       | dec   | f       | a    |
351
  // 0xe7              | 0xfd, 0xec      | 0xfa
352
  uint32_t insn = 0xe7fdecfa;
353
  uint32_t *pos = (uint32_t *) code_pos;
354
  *pos = insn;
355
  ICache::invalidate_range(code_pos, 4);
356
}
357

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.