author | redestad |
Mon, 03 Jul 2017 09:01:34 +0200 | |
changeset 46608 | b0da00b77053 |
parent 42556 | c03d98321ad1 |
permissions | -rw-r--r-- |
42065 | 1 |
/* |
2 |
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. |
|
3 |
* Copyright (c) 2016 SAP SE. All rights reserved. |
|
4 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
5 |
* |
|
6 |
* This code is free software; you can redistribute it and/or modify it |
|
7 |
* under the terms of the GNU General Public License version 2 only, as |
|
8 |
* published by the Free Software Foundation. |
|
9 |
* |
|
10 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
11 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
12 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
13 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
14 |
* accompanied this code). |
|
15 |
* |
|
16 |
* You should have received a copy of the GNU General Public License version |
|
17 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
18 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
19 |
* |
|
20 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
21 |
* or visit www.oracle.com if you need additional information or have any |
|
22 |
* questions. |
|
23 |
* |
|
24 |
*/ |
|
25 |
||
26 |
// Major contributions by JL, LS |
|
27 |
||
28 |
#include "precompiled.hpp" |
|
29 |
#include "asm/macroAssembler.inline.hpp" |
|
30 |
#include "memory/resourceArea.hpp" |
|
31 |
#include "nativeInst_s390.hpp" |
|
32 |
#include "oops/oop.inline.hpp" |
|
33 |
#include "runtime/handles.hpp" |
|
34 |
#include "runtime/sharedRuntime.hpp" |
|
35 |
#include "runtime/stubRoutines.hpp" |
|
36 |
#include "utilities/ostream.hpp" |
|
37 |
#ifdef COMPILER1 |
|
38 |
#include "c1/c1_Runtime1.hpp" |
|
39 |
#endif |
|
40 |
||
41 |
#define LUCY_DBG |
|
42 |
||
43 |
//------------------------------------- |
|
44 |
// N a t i v e I n s t r u c t i o n |
|
45 |
//------------------------------------- |
|
46 |
||
47 |
// Define this switch to prevent identity updates. |
|
48 |
// In high-concurrency scenarios, it is beneficial to prevent |
|
49 |
// identity updates. It has a positive effect on cache line steals. |
|
50 |
// and invalidations. |
|
51 |
// Test runs of JVM98, JVM2008, and JBB2005 show a very low frequency |
|
52 |
// of identity updates. Detection is therefore disabled. |
|
53 |
#undef SUPPRESS_IDENTITY_UPDATE |
|
54 |
||
55 |
void NativeInstruction::verify() { |
|
56 |
// Make sure code pattern is actually an instruction address. |
|
57 |
// Do not allow: |
|
58 |
// - NULL |
|
59 |
// - any address in first page (0x0000 .. 0x0fff) |
|
60 |
// - odd address (will cause a "specification exception") |
|
61 |
address addr = addr_at(0); |
|
62 |
if ((addr == 0) || (((unsigned long)addr & ~0x0fff) == 0) || ((intptr_t)addr & 1) != 0) { |
|
63 |
tty->print_cr(INTPTR_FORMAT ": bad instruction address", p2i(addr)); |
|
64 |
fatal("not an instruction address"); |
|
65 |
} |
|
66 |
} |
|
67 |
||
68 |
// Print location and value (hex representation) of current NativeInstruction |
|
69 |
void NativeInstruction::print(const char* msg) const { |
|
70 |
int len = Assembler::instr_len(addr_at(0)); |
|
71 |
if (msg == NULL) { // Output line without trailing blanks. |
|
72 |
switch (len) { |
|
73 |
case 2: tty->print_cr(INTPTR_FORMAT "(len=%d): %4.4x", p2i(addr_at(0)), len, halfword_at(0)); break; |
|
74 |
case 4: tty->print_cr(INTPTR_FORMAT "(len=%d): %4.4x %4.4x", p2i(addr_at(0)), len, halfword_at(0), halfword_at(2)); break; |
|
75 |
case 6: tty->print_cr(INTPTR_FORMAT "(len=%d): %4.4x %4.4x %4.4x", p2i(addr_at(0)), len, halfword_at(0), halfword_at(2), halfword_at(4)); break; |
|
76 |
default: // Never reached. instr_len() always returns one of the above values. Keep the compiler happy. |
|
77 |
ShouldNotReachHere(); |
|
78 |
break; |
|
79 |
} |
|
80 |
} else { // Output line with filler blanks to have msg aligned. |
|
81 |
switch (len) { |
|
82 |
case 2: tty->print_cr(INTPTR_FORMAT "(len=%d): %4.4x %s", p2i(addr_at(0)), len, halfword_at(0), msg); break; |
|
83 |
case 4: tty->print_cr(INTPTR_FORMAT "(len=%d): %4.4x %4.4x %s", p2i(addr_at(0)), len, halfword_at(0), halfword_at(2), msg); break; |
|
84 |
case 6: tty->print_cr(INTPTR_FORMAT "(len=%d): %4.4x %4.4x %4.4x %s", p2i(addr_at(0)), len, halfword_at(0), halfword_at(2), halfword_at(4), msg); break; |
|
85 |
default: // Never reached. instr_len() always returns one of the above values. Keep the compiler happy. |
|
86 |
ShouldNotReachHere(); |
|
87 |
break; |
|
88 |
} |
|
89 |
} |
|
90 |
} |
|
91 |
void NativeInstruction::print() const { |
|
92 |
print(NULL); |
|
93 |
} |
|
94 |
||
95 |
// Hex-Dump of storage around current NativeInstruction. Also try disassembly. |
|
96 |
void NativeInstruction::dump(const unsigned int range, const char* msg) const { |
|
97 |
Assembler::dump_code_range(tty, addr_at(0), range, (msg == NULL) ? "":msg); |
|
98 |
} |
|
99 |
||
100 |
void NativeInstruction::dump(const unsigned int range) const { |
|
101 |
dump(range, NULL); |
|
102 |
} |
|
103 |
||
104 |
void NativeInstruction::dump() const { |
|
105 |
dump(32, NULL); |
|
106 |
} |
|
107 |
||
108 |
void NativeInstruction::set_halfword_at(int offset, short i) { |
|
109 |
address addr = addr_at(offset); |
|
110 |
#ifndef SUPPRESS_IDENTITY_UPDATE |
|
111 |
*(short*)addr = i; |
|
112 |
#else |
|
113 |
if (*(short*)addr != i) { |
|
114 |
*(short*)addr = i; |
|
115 |
} |
|
116 |
#endif |
|
117 |
ICache::invalidate_word(addr); |
|
118 |
} |
|
119 |
||
120 |
void NativeInstruction::set_word_at(int offset, int i) { |
|
121 |
address addr = addr_at(offset); |
|
122 |
#ifndef SUPPRESS_IDENTITY_UPDATE |
|
123 |
*(int*)addr = i; |
|
124 |
#else |
|
125 |
if (*(int*)addr != i) { |
|
126 |
*(int*)addr = i; |
|
127 |
} |
|
128 |
#endif |
|
129 |
ICache::invalidate_word(addr); |
|
130 |
} |
|
131 |
||
132 |
void NativeInstruction::set_jlong_at(int offset, jlong i) { |
|
133 |
address addr = addr_at(offset); |
|
134 |
#ifndef SUPPRESS_IDENTITY_UPDATE |
|
135 |
*(jlong*)addr = i; |
|
136 |
#else |
|
137 |
if (*(jlong*)addr != i) { |
|
138 |
*(jlong*)addr = i; |
|
139 |
} |
|
140 |
#endif |
|
141 |
// Don't need to invalidate 2 words here, because |
|
142 |
// the flush instruction operates on doublewords. |
|
143 |
ICache::invalidate_word(addr); |
|
144 |
} |
|
145 |
||
146 |
#undef SUPPRESS_IDENTITY_UPDATE |
|
147 |
||
148 |
//------------------------------------------------------------ |
|
149 |
||
150 |
int NativeInstruction::illegal_instruction() { |
|
151 |
return 0; |
|
152 |
} |
|
153 |
||
154 |
bool NativeInstruction::is_illegal() { |
|
155 |
// An instruction with main opcode 0x00 (leftmost byte) is not a valid instruction |
|
156 |
// (and will never be) and causes a SIGILL where the pc points to the next instruction. |
|
157 |
// The caller of this method wants to know if such a situation exists at the current pc. |
|
158 |
// |
|
159 |
// The result of this method is unsharp with respect to the following facts: |
|
160 |
// - Stepping backwards in the instruction stream is not possible on z/Architecture. |
|
161 |
// - z/Architecture instructions are 2, 4, or 6 bytes in length. |
|
162 |
// - The instruction length is coded in the leftmost two bits of the main opcode. |
|
163 |
// - The result is exact if the caller knows by some other means that the |
|
164 |
// instruction is of length 2. |
|
165 |
// |
|
166 |
// If this method returns false, then the 2-byte instruction at *-2 is not a 0x00 opcode. |
|
167 |
// If this method returns true, then the 2-byte instruction at *-2 is a 0x00 opcode. |
|
168 |
return halfword_at(-2) == illegal_instruction(); |
|
169 |
} |
|
170 |
||
171 |
// We use an illtrap for marking a method as not_entrant or zombie. |
|
172 |
bool NativeInstruction::is_sigill_zombie_not_entrant() { |
|
173 |
if (!is_illegal()) return false; // Just a quick path. |
|
174 |
||
175 |
// One-sided error of is_illegal tolerable here |
|
176 |
// (see implementation of is_illegal() for details). |
|
177 |
||
178 |
CodeBlob* cb = CodeCache::find_blob_unsafe(addr_at(0)); |
|
179 |
if (cb == NULL || !cb->is_nmethod()) { |
|
180 |
return false; |
|
181 |
} |
|
182 |
||
183 |
nmethod *nm = (nmethod *)cb; |
|
184 |
// This method is not_entrant or zombie if the illtrap instruction |
|
185 |
// is located at the verified entry point. |
|
186 |
// BE AWARE: the current pc (this) points to the instruction after the |
|
187 |
// "illtrap" location. |
|
188 |
address sig_addr = ((address) this) - 2; |
|
189 |
return nm->verified_entry_point() == sig_addr; |
|
190 |
} |
|
191 |
||
192 |
bool NativeInstruction::is_jump() { |
|
193 |
unsigned long inst; |
|
194 |
Assembler::get_instruction((address)this, &inst); |
|
195 |
return MacroAssembler::is_branch_pcrelative_long(inst); |
|
196 |
} |
|
197 |
||
198 |
//--------------------------------------------------- |
|
199 |
// N a t i v e I l l e g a l I n s t r u c t i o n |
|
200 |
//--------------------------------------------------- |
|
201 |
||
202 |
void NativeIllegalInstruction::insert(address code_pos) { |
|
203 |
NativeIllegalInstruction* nii = (NativeIllegalInstruction*) nativeInstruction_at(code_pos); |
|
204 |
nii->set_halfword_at(0, illegal_instruction()); |
|
205 |
} |
|
206 |
||
207 |
//----------------------- |
|
208 |
// N a t i v e C a l l |
|
209 |
//----------------------- |
|
210 |
||
211 |
void NativeCall::verify() { |
|
212 |
if (NativeCall::is_call_at(addr_at(0))) return; |
|
213 |
||
214 |
fatal("this is not a `NativeCall' site"); |
|
215 |
} |
|
216 |
||
217 |
address NativeCall::destination() const { |
|
218 |
if (MacroAssembler::is_call_far_pcrelative(instruction_address())) { |
|
219 |
address here = addr_at(MacroAssembler::nop_size()); |
|
220 |
return MacroAssembler::get_target_addr_pcrel(here); |
|
221 |
} |
|
222 |
||
223 |
return (address)((NativeMovConstReg *)this)->data(); |
|
224 |
} |
|
225 |
||
226 |
// Similar to replace_mt_safe, but just changes the destination. The |
|
227 |
// important thing is that free-running threads are able to execute this |
|
228 |
// call instruction at all times. Thus, the displacement field must be |
|
229 |
// 4-byte-aligned. We enforce this on z/Architecture by inserting a nop |
|
230 |
// instruction in front of 'brasl' when needed. |
|
231 |
// |
|
232 |
// Used in the runtime linkage of calls; see class CompiledIC. |
|
233 |
void NativeCall::set_destination_mt_safe(address dest) { |
|
234 |
if (MacroAssembler::is_call_far_pcrelative(instruction_address())) { |
|
235 |
address iaddr = addr_at(MacroAssembler::nop_size()); |
|
236 |
// Ensure that patching is atomic hence mt safe. |
|
237 |
assert(((long)addr_at(MacroAssembler::call_far_pcrelative_size()) & (call_far_pcrelative_displacement_alignment-1)) == 0, |
|
238 |
"constant must be 4-byte aligned"); |
|
239 |
set_word_at(MacroAssembler::call_far_pcrelative_size() - 4, Assembler::z_pcrel_off(dest, iaddr)); |
|
240 |
} else { |
|
241 |
assert(MacroAssembler::is_load_const_from_toc(instruction_address()), "unsupported instruction"); |
|
242 |
nativeMovConstReg_at(instruction_address())->set_data(((intptr_t)dest)); |
|
243 |
} |
|
244 |
} |
|
245 |
||
246 |
//----------------------------- |
|
247 |
// N a t i v e F a r C a l l |
|
248 |
//----------------------------- |
|
249 |
||
250 |
void NativeFarCall::verify() { |
|
251 |
NativeInstruction::verify(); |
|
252 |
if (NativeFarCall::is_far_call_at(addr_at(0))) return; |
|
253 |
fatal("not a NativeFarCall"); |
|
254 |
} |
|
255 |
||
256 |
address NativeFarCall::destination() { |
|
257 |
assert(MacroAssembler::is_call_far_patchable_at((address)this), "unexpected call type"); |
|
258 |
address ctable = NULL; |
|
42556
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
259 |
return MacroAssembler::get_dest_of_call_far_patchable_at((address)this, ctable); |
42065 | 260 |
} |
261 |
||
262 |
||
263 |
// Handles both patterns of patchable far calls. |
|
264 |
void NativeFarCall::set_destination(address dest, int toc_offset) { |
|
265 |
address inst_addr = (address)this; |
|
266 |
||
267 |
// Set new destination (implementation of call may change here). |
|
268 |
assert(MacroAssembler::is_call_far_patchable_at(inst_addr), "unexpected call type"); |
|
269 |
||
270 |
if (!MacroAssembler::is_call_far_patchable_pcrelative_at(inst_addr)) { |
|
271 |
address ctable = CodeCache::find_blob(inst_addr)->ctable_begin(); |
|
272 |
// Need distance of TOC entry from current instruction. |
|
273 |
toc_offset = (ctable + toc_offset) - inst_addr; |
|
274 |
// Call is via constant table entry. |
|
275 |
MacroAssembler::set_dest_of_call_far_patchable_at(inst_addr, dest, toc_offset); |
|
276 |
} else { |
|
277 |
// Here, we have a pc-relative call (brasl). |
|
278 |
// Be aware: dest may have moved in this case, so really patch the displacement, |
|
279 |
// when necessary! |
|
280 |
// This while loop will also consume the nop which always preceeds a call_far_pcrelative. |
|
281 |
// We need to revert this after the loop. Pc-relative calls are always assumed to have a leading nop. |
|
282 |
unsigned int nop_sz = MacroAssembler::nop_size(); |
|
283 |
unsigned int nop_bytes = 0; |
|
284 |
while(MacroAssembler::is_z_nop(inst_addr+nop_bytes)) { |
|
285 |
nop_bytes += nop_sz; |
|
286 |
} |
|
287 |
if (nop_bytes > 0) { |
|
288 |
inst_addr += nop_bytes - nop_sz; |
|
289 |
} |
|
290 |
||
291 |
assert(MacroAssembler::is_call_far_pcrelative(inst_addr), "not a pc-relative call"); |
|
292 |
address target = MacroAssembler::get_target_addr_pcrel(inst_addr + nop_sz); |
|
293 |
if (target != dest) { |
|
294 |
NativeCall *call = nativeCall_at(inst_addr); |
|
295 |
call->set_destination_mt_safe(dest); |
|
296 |
} |
|
297 |
} |
|
298 |
} |
|
299 |
||
300 |
//------------------------------------- |
|
301 |
// N a t i v e M o v C o n s t R e g |
|
302 |
//------------------------------------- |
|
303 |
||
304 |
// Do not use an assertion here. Let clients decide whether they only |
|
305 |
// want this when assertions are enabled. |
|
306 |
void NativeMovConstReg::verify() { |
|
307 |
address loc = addr_at(0); |
|
308 |
||
309 |
// This while loop will also consume the nop which always preceeds a |
|
310 |
// call_far_pcrelative. We need to revert this after the |
|
311 |
// loop. Pc-relative calls are always assumed to have a leading nop. |
|
312 |
unsigned int nop_sz = MacroAssembler::nop_size(); |
|
313 |
unsigned int nop_bytes = 0; |
|
314 |
while(MacroAssembler::is_z_nop(loc+nop_bytes)) { |
|
315 |
nop_bytes += nop_sz; |
|
316 |
} |
|
317 |
||
318 |
if (nop_bytes > 0) { |
|
319 |
if (MacroAssembler::is_call_far_pcrelative(loc+nop_bytes-nop_sz)) return; |
|
320 |
loc += nop_bytes; |
|
321 |
} |
|
322 |
||
323 |
if (!MacroAssembler::is_load_const_from_toc(loc) && // Load const from TOC. |
|
324 |
!MacroAssembler::is_load_const(loc) && // Load const inline. |
|
325 |
!MacroAssembler::is_load_narrow_oop(loc) && // Load narrow oop. |
|
326 |
!MacroAssembler::is_load_narrow_klass(loc) && // Load narrow Klass ptr. |
|
327 |
!MacroAssembler::is_compare_immediate_narrow_oop(loc) && // Compare immediate narrow. |
|
328 |
!MacroAssembler::is_compare_immediate_narrow_klass(loc) && // Compare immediate narrow. |
|
329 |
!MacroAssembler::is_pcrelative_instruction(loc)) { // Just to make it run. |
|
330 |
tty->cr(); |
|
331 |
tty->print_cr("NativeMovConstReg::verify(): verifying addr %p(0x%x), %d leading nops", loc, *(uint*)loc, nop_bytes/nop_sz); |
|
332 |
tty->cr(); |
|
333 |
((NativeMovConstReg*)loc)->dump(64, "NativeMovConstReg::verify()"); |
|
334 |
#ifdef LUCY_DBG |
|
335 |
VM_Version::z_SIGSEGV(); |
|
336 |
#endif |
|
337 |
fatal("this is not a `NativeMovConstReg' site"); |
|
338 |
} |
|
339 |
} |
|
340 |
||
341 |
address NativeMovConstReg::next_instruction_address(int offset) const { |
|
342 |
address inst_addr = addr_at(offset); |
|
343 |
||
344 |
// Load address (which is a constant) pc-relative. |
|
345 |
if (MacroAssembler::is_load_addr_pcrel(inst_addr)) { return addr_at(offset+MacroAssembler::load_addr_pcrel_size()); } |
|
346 |
||
347 |
// Load constant from TOC. |
|
348 |
if (MacroAssembler::is_load_const_from_toc(inst_addr)) { return addr_at(offset+MacroAssembler::load_const_from_toc_size()); } |
|
349 |
||
350 |
// Load constant inline. |
|
351 |
if (MacroAssembler::is_load_const(inst_addr)) { return addr_at(offset+MacroAssembler::load_const_size()); } |
|
352 |
||
353 |
// Load constant narrow inline. |
|
354 |
if (MacroAssembler::is_load_narrow_oop(inst_addr)) { return addr_at(offset+MacroAssembler::load_narrow_oop_size()); } |
|
355 |
if (MacroAssembler::is_load_narrow_klass(inst_addr)) { return addr_at(offset+MacroAssembler::load_narrow_klass_size()); } |
|
356 |
||
357 |
// Compare constant narrow inline. |
|
358 |
if (MacroAssembler::is_compare_immediate_narrow_oop(inst_addr)) { return addr_at(offset+MacroAssembler::compare_immediate_narrow_oop_size()); } |
|
359 |
if (MacroAssembler::is_compare_immediate_narrow_klass(inst_addr)) { return addr_at(offset+MacroAssembler::compare_immediate_narrow_klass_size()); } |
|
360 |
||
361 |
if (MacroAssembler::is_call_far_patchable_pcrelative_at(inst_addr)) { return addr_at(offset+MacroAssembler::call_far_patchable_size()); } |
|
362 |
||
363 |
if (MacroAssembler::is_pcrelative_instruction(inst_addr)) { return addr_at(offset+Assembler::instr_len(inst_addr)); } |
|
364 |
||
365 |
((NativeMovConstReg*)inst_addr)->dump(64, "NativeMovConstReg site is not recognized as such"); |
|
366 |
#ifdef LUCY_DBG |
|
367 |
VM_Version::z_SIGSEGV(); |
|
368 |
#else |
|
369 |
guarantee(false, "Not a NativeMovConstReg site"); |
|
370 |
#endif |
|
371 |
return NULL; |
|
372 |
} |
|
373 |
||
374 |
intptr_t NativeMovConstReg::data() const { |
|
375 |
address loc = addr_at(0); |
|
376 |
if (MacroAssembler::is_load_const(loc)) { |
|
377 |
return MacroAssembler::get_const(loc); |
|
378 |
} else if (MacroAssembler::is_load_narrow_oop(loc) || |
|
379 |
MacroAssembler::is_compare_immediate_narrow_oop(loc) || |
|
380 |
MacroAssembler::is_load_narrow_klass(loc) || |
|
381 |
MacroAssembler::is_compare_immediate_narrow_klass(loc)) { |
|
382 |
((NativeMovConstReg*)loc)->dump(32, "NativeMovConstReg::data(): cannot extract data from narrow ptr (oop or klass)"); |
|
383 |
#ifdef LUCY_DBG |
|
384 |
VM_Version::z_SIGSEGV(); |
|
385 |
#else |
|
386 |
ShouldNotReachHere(); |
|
387 |
#endif |
|
388 |
return *(intptr_t *)NULL; |
|
389 |
} else { |
|
390 |
// Otherwise, assume data resides in TOC. Is asserted in called method. |
|
391 |
return MacroAssembler::get_const_from_toc(loc); |
|
392 |
} |
|
393 |
} |
|
394 |
||
395 |
||
396 |
// Patch in a new constant. |
|
397 |
// |
|
398 |
// There are situations where we have multiple (hopefully two at most) |
|
399 |
// relocations connected to one instruction. Loading an oop from CP |
|
400 |
// using pcrelative addressing would one such example. Here we have an |
|
401 |
// oop relocation, modifying the oop itself, and an internal word relocation, |
|
402 |
// modifying the relative address. |
|
403 |
// |
|
404 |
// NativeMovConstReg::set_data is then called once for each relocation. To be |
|
405 |
// able to distinguish between the relocations, we use a rather dirty hack: |
|
406 |
// |
|
407 |
// All calls that deal with an internal word relocation to fix their relative |
|
408 |
// address are on a faked, odd instruction address. The instruction can be |
|
409 |
// found on the next lower, even address. |
|
410 |
// |
|
411 |
// All other calls are "normal", i.e. on even addresses. |
|
412 |
address NativeMovConstReg::set_data_plain(intptr_t src, CodeBlob *cb) { |
|
413 |
unsigned long x = (unsigned long)src; |
|
414 |
address loc = instruction_address(); |
|
415 |
address next_address; |
|
416 |
||
417 |
if (MacroAssembler::is_load_addr_pcrel(loc)) { |
|
418 |
MacroAssembler::patch_target_addr_pcrel(loc, (address)src); |
|
419 |
ICache::invalidate_range(loc, MacroAssembler::load_addr_pcrel_size()); |
|
420 |
next_address = next_instruction_address(); |
|
421 |
} else if (MacroAssembler::is_load_const_from_toc(loc)) { // Load constant from TOC. |
|
422 |
MacroAssembler::set_const_in_toc(loc, src, cb); |
|
423 |
next_address = next_instruction_address(); |
|
424 |
} else if (MacroAssembler::is_load_const(loc)) { |
|
425 |
// Not mt safe, ok in methods like CodeBuffer::copy_code(). |
|
426 |
MacroAssembler::patch_const(loc, x); |
|
427 |
ICache::invalidate_range(loc, MacroAssembler::load_const_size()); |
|
428 |
next_address = next_instruction_address(); |
|
429 |
} |
|
430 |
// cOops |
|
431 |
else if (MacroAssembler::is_load_narrow_oop(loc)) { |
|
432 |
MacroAssembler::patch_load_narrow_oop(loc, (oop) (void*) x); |
|
433 |
ICache::invalidate_range(loc, MacroAssembler::load_narrow_oop_size()); |
|
434 |
next_address = next_instruction_address(); |
|
435 |
} |
|
436 |
// compressed klass ptrs |
|
437 |
else if (MacroAssembler::is_load_narrow_klass(loc)) { |
|
438 |
MacroAssembler::patch_load_narrow_klass(loc, (Klass*)x); |
|
439 |
ICache::invalidate_range(loc, MacroAssembler::load_narrow_klass_size()); |
|
440 |
next_address = next_instruction_address(); |
|
441 |
} |
|
442 |
// cOops |
|
443 |
else if (MacroAssembler::is_compare_immediate_narrow_oop(loc)) { |
|
444 |
MacroAssembler::patch_compare_immediate_narrow_oop(loc, (oop) (void*) x); |
|
445 |
ICache::invalidate_range(loc, MacroAssembler::compare_immediate_narrow_oop_size()); |
|
446 |
next_address = next_instruction_address(); |
|
447 |
} |
|
448 |
// compressed klass ptrs |
|
449 |
else if (MacroAssembler::is_compare_immediate_narrow_klass(loc)) { |
|
450 |
MacroAssembler::patch_compare_immediate_narrow_klass(loc, (Klass*)x); |
|
451 |
ICache::invalidate_range(loc, MacroAssembler::compare_immediate_narrow_klass_size()); |
|
452 |
next_address = next_instruction_address(); |
|
453 |
} |
|
454 |
else if (MacroAssembler::is_call_far_patchable_pcrelative_at(loc)) { |
|
455 |
assert(ShortenBranches, "Wait a minute! A pc-relative call w/o ShortenBranches?"); |
|
456 |
// This NativeMovConstReg site does not need to be patched. It was |
|
457 |
// patched when it was converted to a call_pcrelative site |
|
458 |
// before. The value of the src argument is not related to the |
|
459 |
// branch target. |
|
460 |
next_address = next_instruction_address(); |
|
461 |
} |
|
462 |
||
463 |
else { |
|
464 |
tty->print_cr("WARNING: detected an unrecognized code pattern at loc = %p -> 0x%8.8x %8.8x", |
|
465 |
loc, *((unsigned int*)loc), *((unsigned int*)(loc+4))); |
|
466 |
next_address = next_instruction_address(); // Failure should be handled in next_instruction_address(). |
|
467 |
#ifdef LUCY_DBG |
|
468 |
VM_Version::z_SIGSEGV(); |
|
469 |
#endif |
|
470 |
} |
|
471 |
||
472 |
return next_address; |
|
473 |
} |
|
474 |
||
475 |
// Divided up in set_data_plain() which patches the instruction in the |
|
476 |
// code stream and set_data() which additionally patches the oop pool |
|
477 |
// if necessary. |
|
478 |
void NativeMovConstReg::set_data(intptr_t src) { |
|
479 |
// Also store the value into an oop_Relocation cell, if any. |
|
480 |
CodeBlob *cb = CodeCache::find_blob(instruction_address()); |
|
481 |
address next_address = set_data_plain(src, cb); |
|
482 |
||
483 |
relocInfo::update_oop_pool(instruction_address(), next_address, (address)src, cb); |
|
484 |
} |
|
485 |
||
486 |
void NativeMovConstReg::set_narrow_oop(intptr_t data) { |
|
487 |
const address start = addr_at(0); |
|
488 |
int range = 0; |
|
489 |
if (MacroAssembler::is_load_narrow_oop(start)) { |
|
490 |
range = MacroAssembler::patch_load_narrow_oop(start, cast_to_oop <intptr_t> (data)); |
|
491 |
} else if (MacroAssembler::is_compare_immediate_narrow_oop(start)) { |
|
492 |
range = MacroAssembler::patch_compare_immediate_narrow_oop(start, cast_to_oop <intptr_t>(data)); |
|
493 |
} else { |
|
494 |
fatal("this is not a `NativeMovConstReg::narrow_oop' site"); |
|
495 |
} |
|
496 |
ICache::invalidate_range(start, range); |
|
497 |
} |
|
498 |
||
499 |
// Compressed klass ptrs. patch narrow klass constant. |
|
500 |
void NativeMovConstReg::set_narrow_klass(intptr_t data) { |
|
501 |
const address start = addr_at(0); |
|
502 |
int range = 0; |
|
503 |
if (MacroAssembler::is_load_narrow_klass(start)) { |
|
504 |
range = MacroAssembler::patch_load_narrow_klass(start, (Klass*)data); |
|
505 |
} else if (MacroAssembler::is_compare_immediate_narrow_klass(start)) { |
|
506 |
range = MacroAssembler::patch_compare_immediate_narrow_klass(start, (Klass*)data); |
|
507 |
} else { |
|
508 |
fatal("this is not a `NativeMovConstReg::narrow_klass' site"); |
|
509 |
} |
|
510 |
ICache::invalidate_range(start, range); |
|
511 |
} |
|
512 |
||
513 |
void NativeMovConstReg::set_pcrel_addr(intptr_t newTarget, CompiledMethod *passed_nm /* = NULL */, bool copy_back_to_oop_pool) { |
|
514 |
address next_address; |
|
515 |
address loc = addr_at(0); |
|
516 |
||
517 |
if (MacroAssembler::is_load_addr_pcrel(loc)) { |
|
518 |
address oldTarget = MacroAssembler::get_target_addr_pcrel(loc); |
|
519 |
MacroAssembler::patch_target_addr_pcrel(loc, (address)newTarget); |
|
520 |
||
521 |
ICache::invalidate_range(loc, MacroAssembler::load_addr_pcrel_size()); |
|
522 |
next_address = loc + MacroAssembler::load_addr_pcrel_size(); |
|
523 |
} else if (MacroAssembler::is_load_const_from_toc_pcrelative(loc) ) { // Load constant from TOC. |
|
524 |
address oldTarget = MacroAssembler::get_target_addr_pcrel(loc); |
|
525 |
MacroAssembler::patch_target_addr_pcrel(loc, (address)newTarget); |
|
526 |
||
527 |
ICache::invalidate_range(loc, MacroAssembler::load_const_from_toc_size()); |
|
528 |
next_address = loc + MacroAssembler::load_const_from_toc_size(); |
|
529 |
} else if (MacroAssembler::is_call_far_patchable_pcrelative_at(loc)) { |
|
530 |
assert(ShortenBranches, "Wait a minute! A pc-relative call w/o ShortenBranches?"); |
|
531 |
next_address = next_instruction_address(); |
|
532 |
} else { |
|
533 |
assert(false, "Not a NativeMovConstReg site for set_pcrel_addr"); |
|
534 |
next_address = next_instruction_address(); // Failure should be handled in next_instruction_address(). |
|
535 |
} |
|
536 |
||
537 |
if (copy_back_to_oop_pool) { |
|
538 |
if (relocInfo::update_oop_pool(instruction_address(), next_address, (address)newTarget, NULL)) { |
|
539 |
((NativeMovConstReg*)instruction_address())->dump(64, "NativeMovConstReg::set_pcrel_addr(): found oop reloc for pcrel_addr"); |
|
540 |
#ifdef LUCY_DBG |
|
541 |
VM_Version::z_SIGSEGV(); |
|
542 |
#else |
|
543 |
assert(false, "Ooooops: found oop reloc for pcrel_addr"); |
|
544 |
#endif |
|
545 |
} |
|
546 |
} |
|
547 |
} |
|
548 |
||
549 |
void NativeMovConstReg::set_pcrel_data(intptr_t newData, CompiledMethod *passed_nm /* = NULL */, bool copy_back_to_oop_pool) { |
|
550 |
address next_address; |
|
551 |
address loc = addr_at(0); |
|
552 |
||
553 |
if (MacroAssembler::is_load_const_from_toc(loc) ) { // Load constant from TOC. |
|
554 |
// Offset is +/- 2**32 -> use long. |
|
555 |
long offset = MacroAssembler::get_load_const_from_toc_offset(loc); |
|
556 |
address target = MacroAssembler::get_target_addr_pcrel(loc); |
|
557 |
intptr_t oldData = *(intptr_t*)target; |
|
558 |
if (oldData != newData) { // Update only if data changes. Prevents cache invalidation. |
|
559 |
*(intptr_t *)(target) = newData; |
|
560 |
} |
|
561 |
||
562 |
// ICache::invalidate_range(target, sizeof(unsigned long)); // No ICache invalidate for CP data. |
|
563 |
next_address = loc + MacroAssembler::load_const_from_toc_size(); |
|
564 |
} else if (MacroAssembler::is_call_far_pcrelative(loc)) { |
|
565 |
((NativeMovConstReg*)loc)->dump(64, "NativeMovConstReg::set_pcrel_data() has a problem: setting data for a pc-relative call?"); |
|
566 |
#ifdef LUCY_DBG |
|
567 |
VM_Version::z_SIGSEGV(); |
|
568 |
#else |
|
569 |
assert(false, "Ooooops: setting data for a pc-relative call"); |
|
570 |
#endif |
|
571 |
next_address = next_instruction_address(); |
|
572 |
} else { |
|
573 |
assert(false, "Not a NativeMovConstReg site for set_pcrel_data"); |
|
574 |
next_address = next_instruction_address(); // Failure should be handled in next_instruction_address(). |
|
575 |
} |
|
576 |
||
577 |
if (copy_back_to_oop_pool) { |
|
578 |
if (relocInfo::update_oop_pool(instruction_address(), next_address, (address)newData, NULL)) { |
|
579 |
((NativeMovConstReg*)instruction_address())->dump(64, "NativeMovConstReg::set_pcrel_data(): found oop reloc for pcrel_data"); |
|
580 |
#ifdef LUCY_DBG |
|
581 |
VM_Version::z_SIGSEGV(); |
|
582 |
#else |
|
583 |
assert(false, "Ooooops: found oop reloc for pcrel_data"); |
|
584 |
#endif |
|
585 |
} |
|
586 |
} |
|
587 |
} |
|
588 |
||
589 |
#ifdef COMPILER1 |
|
590 |
//-------------------------------- |
|
591 |
// N a t i v e M o v R e g M e m |
|
592 |
//-------------------------------- |
|
593 |
||
594 |
void NativeMovRegMem::verify() { |
|
595 |
address l1 = addr_at(0); |
|
596 |
address l2 = addr_at(MacroAssembler::load_const_size()); |
|
597 |
||
598 |
if (!MacroAssembler::is_load_const(l1)) { |
|
599 |
tty->cr(); |
|
600 |
tty->print_cr("NativeMovRegMem::verify(): verifying addr " PTR_FORMAT, p2i(l1)); |
|
601 |
tty->cr(); |
|
602 |
((NativeMovRegMem*)l1)->dump(64, "NativeMovConstReg::verify()"); |
|
603 |
fatal("this is not a `NativeMovRegMem' site"); |
|
604 |
} |
|
605 |
||
606 |
unsigned long inst1; |
|
607 |
Assembler::get_instruction(l2, &inst1); |
|
608 |
||
42556
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
609 |
if (!Assembler::is_z_lb(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
610 |
!Assembler::is_z_llgh(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
611 |
!Assembler::is_z_lh(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
612 |
!Assembler::is_z_l(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
613 |
!Assembler::is_z_llgf(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
614 |
!Assembler::is_z_lg(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
615 |
!Assembler::is_z_le(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
616 |
!Assembler::is_z_ld(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
617 |
!Assembler::is_z_stc(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
618 |
!Assembler::is_z_sth(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
619 |
!Assembler::is_z_st(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
620 |
!UseCompressedOops && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
621 |
!Assembler::is_z_stg(inst1) && |
c03d98321ad1
8169317: [s390] Various minor bug fixes and adaptions.
goetz
parents:
42065
diff
changeset
|
622 |
!Assembler::is_z_ste(inst1) && |
42065 | 623 |
!Assembler::is_z_std(inst1)) { |
624 |
tty->cr(); |
|
625 |
tty->print_cr("NativeMovRegMem::verify(): verifying addr " PTR_FORMAT |
|
626 |
": wrong or missing load or store at " PTR_FORMAT, p2i(l1), p2i(l2)); |
|
627 |
tty->cr(); |
|
628 |
((NativeMovRegMem*)l1)->dump(64, "NativeMovConstReg::verify()"); |
|
629 |
fatal("this is not a `NativeMovRegMem' site"); |
|
630 |
} |
|
631 |
} |
|
632 |
#endif // COMPILER1 |
|
633 |
||
634 |
//----------------------- |
|
635 |
// N a t i v e J u m p |
|
636 |
//----------------------- |
|
637 |
||
638 |
void NativeJump::verify() { |
|
639 |
if (NativeJump::is_jump_at(addr_at(0))) return; |
|
640 |
fatal("this is not a `NativeJump' site"); |
|
641 |
} |
|
642 |
||
643 |
// Patch atomically with an illtrap. |
|
644 |
void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { |
|
645 |
ResourceMark rm; |
|
646 |
int code_size = 2; |
|
647 |
CodeBuffer cb(verified_entry, code_size + 1); |
|
648 |
MacroAssembler* a = new MacroAssembler(&cb); |
|
649 |
#ifdef COMPILER2 |
|
650 |
assert(dest == SharedRuntime::get_handle_wrong_method_stub(), "expected fixed destination of patch"); |
|
651 |
#endif |
|
652 |
a->z_illtrap(); |
|
653 |
ICache::invalidate_range(verified_entry, code_size); |
|
654 |
} |
|
655 |
||
656 |
#undef LUCY_DBG |
|
657 |
||
658 |
//------------------------------------- |
|
659 |
// N a t i v e G e n e r a l J u m p |
|
660 |
//------------------------------------- |
|
661 |
||
662 |
#ifndef PRODUCT |
|
663 |
void NativeGeneralJump::verify() { |
|
664 |
unsigned long inst; |
|
665 |
Assembler::get_instruction((address)this, &inst); |
|
666 |
assert(MacroAssembler::is_branch_pcrelative_long(inst), "not a general jump instruction"); |
|
667 |
} |
|
668 |
#endif |
|
669 |
||
670 |
void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { |
|
671 |
uint64_t instr = BRCL_ZOPC | |
|
672 |
Assembler::uimm4(Assembler::bcondAlways, 8, 48) | |
|
673 |
Assembler::simm32(RelAddr::pcrel_off32(entry, code_pos), 16, 48); |
|
674 |
*(uint64_t*) code_pos = (instr << 16); // Must shift into big end, then the brcl will be written to code_pos. |
|
675 |
ICache::invalidate_range(code_pos, instruction_size); |
|
676 |
} |
|
677 |
||
678 |
void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { |
|
679 |
assert(((intptr_t)instr_addr & (BytesPerWord-1)) == 0, "requirement for mt safe patching"); |
|
680 |
// Bytes_after_jump cannot change, because we own the Patching_lock. |
|
681 |
assert(Patching_lock->owned_by_self(), "must hold lock to patch instruction"); |
|
682 |
intptr_t bytes_after_jump = (*(intptr_t*)instr_addr) & 0x000000000000ffffL; // 2 bytes after jump. |
|
683 |
intptr_t load_const_bytes = (*(intptr_t*)code_buffer) & 0xffffffffffff0000L; |
|
684 |
*(intptr_t*)instr_addr = load_const_bytes | bytes_after_jump; |
|
685 |
ICache::invalidate_range(instr_addr, 6); |
|
686 |
} |