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.
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.
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).
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.
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
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"
36
#include "c1/c1_Runtime1.hpp"
39
int NativeMovRegMem::offset() const {
42
return encoding() & 0xfff;
44
return (encoding() & 0x0f) | ((encoding() >> 4) & 0xf0);
46
return (encoding() & 0xff) << 2;
53
void NativeMovRegMem::set_offset(int x) {
54
assert(x >= 0 && x < 65536, "encoding constraint");
55
const int Rt = Rtemp->encoding();
57
// If offset is too large to be placed into single ldr/str instruction, we replace
58
// ldr Rd, [Rn, #offset]
61
// add Rtemp, Rn, #offset_hi
62
// ldr Rd, [Rtemp, #offset_lo]
66
set_encoding((encoding() & 0xfffff000) | x);
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);
76
set_encoding((encoding() & 0xfffff0f0) | (x & 0x0f) | (x & 0xf0) << 4);
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);
86
set_encoding((encoding() & 0xffffff00) | (x >> 2));
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);
99
intptr_t NativeMovConstReg::data() const {
100
RawNativeInstruction* next = next_raw();
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;
107
// Oop is loaded from oops section or inlined in the code
109
if (is_ldr_literal()) {
110
// ldr Rd, [PC, #offset]
111
oop_offset = ldr_offset();
113
assert(next->is_ldr(), "must be");
114
oop_offset = (this->encoding() & 0xff) << 12 | (next->encoding() & 0xfff);
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)
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");
126
oop_offset = -oop_offset;
129
return *(int*)(instruction_address() + 8 + oop_offset);
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());
140
nmethod* nm = cb->as_nmethod_or_null();
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);
148
} else if (iter.type() == relocInfo::metadata_type) {
149
metadata_addr = iter.metadata_reloc()->metadata_addr();
150
*metadata_addr = (Metadata*)x;
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);
171
// data is loaded from oop or metadata section
174
address addr = oop_addr != nullptr ? (address)oop_addr : (address)metadata_addr;
177
offset = addr - instruction_address() - 8;
179
offset = addr - pc - 8;
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");
189
// ldr Rd, [PC, #offset]
190
set_encoding((encoding() & 0xff7ff000) | delta | sign);
191
assert(ldr_offset() == offset, "check encoding");
193
int cc = encoding() & 0xf0000000;
194
int Rd = (encoding() >> 12) & 0xf;
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");
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");
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");
213
assert(is_pc_rel(), "must be");
214
assert(next->is_ldr(), "must be");
216
// add Rt, PC, #delta_hi
217
this->set_encoding((this->encoding() & 0xf00ff000) | 0x02800a00 | (delta >> 12));
218
assert(is_add_pc(), "must be");
220
// sub Rt, PC, #delta_hi
221
this->set_encoding((this->encoding() & 0xf00ff000) | 0x02400a00 | (delta >> 12));
222
assert(is_sub_pc(), "must be");
224
// ldr Rd, Rt, #delta_lo (or -#delta_lo)
225
next->set_encoding((next->encoding() & 0xff7ff000) | (delta & 0xfff) | sign);
230
void NativeMovConstReg::set_pc_relative_offset(address addr, address pc) {
233
offset = addr - instruction_address() - 8;
235
offset = addr - pc - 8;
238
RawNativeInstruction* next = next_raw();
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()) {
245
// ldr Rd, [PC, #offset]
246
set_encoding((encoding() & 0xff7ff000) | delta | sign);
247
assert(ldr_offset() == offset, "check encoding");
249
assert(next->is_nop(), "must be");
250
int cc = encoding() & 0xf0000000;
251
int Rd = (encoding() >> 12) & 0xf;
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");
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");
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");
270
assert(is_pc_rel(), "must be");
271
assert(next->is_ldr(), "must be");
273
// add Rt, PC, #delta_hi
274
this->set_encoding((this->encoding() & 0xf00ff000) | 0x02800a00 | (delta >> 12));
275
assert(is_add_pc(), "must be");
277
// sub Rt, PC, #delta_hi
278
this->set_encoding((this->encoding() & 0xf00ff000) | 0x02400a00 | (delta >> 12));
279
assert(is_sub_pc(), "must be");
281
// ldr Rd, Rt, #delta_lo (or -#delta_lo)
282
next->set_encoding((next->encoding() & 0xff7ff000) | (delta & 0xfff) | sign);
286
void RawNativeJump::check_verified_entry_alignment(address entry, address verified_entry) {
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]);
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));
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();
306
ShouldNotReachHere();
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) {
321
// Some "calls" are really jumps
322
assert(nativeInstruction_at(call)->is_jump(), "must be call or jump");
329
bool RawNativeCall::is_call_before(address return_address) {
330
return (raw_call_for(return_address) != nullptr);
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);
339
void NativePostCallNop::make_deopt() {
340
NativeDeoptInstruction::insert(addr_at(0));
343
void NativeDeoptInstruction::verify() {
346
// Inserts an undefined instruction at a given pc
347
void NativeDeoptInstruction::insert(address code_pos) {
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;
355
ICache::invalidate_range(code_pos, 4);