Wed, 27 Nov 2013 16:16:21 -0800
8029015: PPC64 (part 216): opto: trap based null and range checks
Summary: On PPC64 use tdi instruction that does a compare and raises SIGTRAP for NULL and range checks.
Reviewed-by: kvn
goetz@6458 | 1 | /* |
goetz@6458 | 2 | * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. |
goetz@6458 | 3 | * Copyright 2012, 2013 SAP AG. All rights reserved. |
goetz@6458 | 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
goetz@6458 | 5 | * |
goetz@6458 | 6 | * This code is free software; you can redistribute it and/or modify it |
goetz@6458 | 7 | * under the terms of the GNU General Public License version 2 only, as |
goetz@6458 | 8 | * published by the Free Software Foundation. |
goetz@6458 | 9 | * |
goetz@6458 | 10 | * This code is distributed in the hope that it will be useful, but WITHOUT |
goetz@6458 | 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
goetz@6458 | 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
goetz@6458 | 13 | * version 2 for more details (a copy is included in the LICENSE file that |
goetz@6458 | 14 | * accompanied this code). |
goetz@6458 | 15 | * |
goetz@6458 | 16 | * You should have received a copy of the GNU General Public License version |
goetz@6458 | 17 | * 2 along with this work; if not, write to the Free Software Foundation, |
goetz@6458 | 18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
goetz@6458 | 19 | * |
goetz@6458 | 20 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
goetz@6458 | 21 | * or visit www.oracle.com if you need additional information or have any |
goetz@6458 | 22 | * questions. |
goetz@6458 | 23 | * |
goetz@6458 | 24 | */ |
goetz@6458 | 25 | |
goetz@6458 | 26 | #ifndef CPU_PPC_VM_NATIVEINST_PPC_HPP |
goetz@6458 | 27 | #define CPU_PPC_VM_NATIVEINST_PPC_HPP |
goetz@6458 | 28 | |
goetz@6458 | 29 | #include "asm/assembler.hpp" |
goetz@6458 | 30 | #include "asm/macroAssembler.hpp" |
goetz@6458 | 31 | #include "memory/allocation.hpp" |
goetz@6458 | 32 | #include "runtime/icache.hpp" |
goetz@6458 | 33 | #include "runtime/os.hpp" |
goetz@6458 | 34 | #include "utilities/top.hpp" |
goetz@6458 | 35 | |
goetz@6458 | 36 | // We have interfaces for the following instructions: |
goetz@6458 | 37 | // |
goetz@6458 | 38 | // - NativeInstruction |
goetz@6458 | 39 | // - NativeCall |
goetz@6458 | 40 | // - NativeFarCall |
goetz@6458 | 41 | // - NativeMovConstReg |
goetz@6458 | 42 | // - NativeJump |
goetz@6458 | 43 | // - NativeIllegalInstruction |
goetz@6458 | 44 | // - NativeConditionalFarBranch |
goetz@6458 | 45 | // - NativeCallTrampolineStub |
goetz@6458 | 46 | |
goetz@6458 | 47 | // The base class for different kinds of native instruction abstractions. |
goetz@6458 | 48 | // It provides the primitive operations to manipulate code relative to this. |
goetz@6458 | 49 | class NativeInstruction VALUE_OBJ_CLASS_SPEC { |
goetz@6458 | 50 | friend class Relocation; |
goetz@6458 | 51 | |
goetz@6458 | 52 | public: |
goetz@6458 | 53 | bool is_sigtrap_ic_miss_check() { |
goetz@6458 | 54 | assert(UseSIGTRAP, "precondition"); |
goetz@6458 | 55 | return MacroAssembler::is_trap_ic_miss_check(long_at(0)); |
goetz@6458 | 56 | } |
goetz@6458 | 57 | |
goetz@6458 | 58 | bool is_sigtrap_null_check() { |
goetz@6458 | 59 | assert(UseSIGTRAP && TrapBasedNullChecks, "precondition"); |
goetz@6458 | 60 | return MacroAssembler::is_trap_null_check(long_at(0)); |
goetz@6458 | 61 | } |
goetz@6458 | 62 | |
goetz@6458 | 63 | // We use a special trap for marking a method as not_entrant or zombie |
goetz@6458 | 64 | // iff UseSIGTRAP. |
goetz@6458 | 65 | bool is_sigtrap_zombie_not_entrant() { |
goetz@6458 | 66 | assert(UseSIGTRAP, "precondition"); |
goetz@6458 | 67 | return MacroAssembler::is_trap_zombie_not_entrant(long_at(0)); |
goetz@6458 | 68 | } |
goetz@6458 | 69 | |
goetz@6458 | 70 | // We use an illtrap for marking a method as not_entrant or zombie |
goetz@6458 | 71 | // iff !UseSIGTRAP. |
goetz@6458 | 72 | bool is_sigill_zombie_not_entrant() { |
goetz@6458 | 73 | assert(!UseSIGTRAP, "precondition"); |
goetz@6458 | 74 | // Work around a C++ compiler bug which changes 'this'. |
goetz@6458 | 75 | return NativeInstruction::is_sigill_zombie_not_entrant_at(addr_at(0)); |
goetz@6458 | 76 | } |
goetz@6458 | 77 | static bool is_sigill_zombie_not_entrant_at(address addr); |
goetz@6458 | 78 | |
goetz@6490 | 79 | #ifdef COMPILER2 |
goetz@6458 | 80 | // SIGTRAP-based implicit range checks |
goetz@6458 | 81 | bool is_sigtrap_range_check() { |
goetz@6458 | 82 | assert(UseSIGTRAP && TrapBasedRangeChecks, "precondition"); |
goetz@6458 | 83 | return MacroAssembler::is_trap_range_check(long_at(0)); |
goetz@6458 | 84 | } |
goetz@6490 | 85 | #endif |
goetz@6458 | 86 | |
goetz@6458 | 87 | // 'should not reach here'. |
goetz@6458 | 88 | bool is_sigtrap_should_not_reach_here() { |
goetz@6458 | 89 | return MacroAssembler::is_trap_should_not_reach_here(long_at(0)); |
goetz@6458 | 90 | } |
goetz@6458 | 91 | |
goetz@6458 | 92 | bool is_safepoint_poll() { |
goetz@6458 | 93 | // Is the current instruction a POTENTIAL read access to the polling page? |
goetz@6458 | 94 | // The current arguments of the instruction are not checked! |
goetz@6458 | 95 | return MacroAssembler::is_load_from_polling_page(long_at(0), NULL); |
goetz@6458 | 96 | } |
goetz@6458 | 97 | |
goetz@6458 | 98 | bool is_memory_serialization(JavaThread *thread, void *ucontext) { |
goetz@6458 | 99 | // Is the current instruction a write access of thread to the |
goetz@6458 | 100 | // memory serialization page? |
goetz@6458 | 101 | return MacroAssembler::is_memory_serialization(long_at(0), thread, ucontext); |
goetz@6458 | 102 | } |
goetz@6458 | 103 | |
goetz@6458 | 104 | address get_stack_bang_address(void *ucontext) { |
goetz@6458 | 105 | // If long_at(0) is not a stack bang, return 0. Otherwise, return |
goetz@6458 | 106 | // banged address. |
goetz@6458 | 107 | return MacroAssembler::get_stack_bang_address(long_at(0), ucontext); |
goetz@6458 | 108 | } |
goetz@6458 | 109 | |
goetz@6458 | 110 | protected: |
goetz@6458 | 111 | address addr_at(int offset) const { return address(this) + offset; } |
goetz@6458 | 112 | int long_at(int offset) const { return *(int*)addr_at(offset); } |
goetz@6458 | 113 | |
goetz@6458 | 114 | public: |
goetz@6458 | 115 | void verify() NOT_DEBUG_RETURN; |
goetz@6458 | 116 | }; |
goetz@6458 | 117 | |
goetz@6458 | 118 | inline NativeInstruction* nativeInstruction_at(address address) { |
goetz@6458 | 119 | NativeInstruction* inst = (NativeInstruction*)address; |
goetz@6458 | 120 | inst->verify(); |
goetz@6458 | 121 | return inst; |
goetz@6458 | 122 | } |
goetz@6458 | 123 | |
goetz@6458 | 124 | // The NativeCall is an abstraction for accessing/manipulating call |
goetz@6458 | 125 | // instructions. It is used to manipulate inline caches, primitive & |
goetz@6458 | 126 | // dll calls, etc. |
goetz@6458 | 127 | // |
goetz@6458 | 128 | // Sparc distinguishes `NativeCall' and `NativeFarCall'. On PPC64, |
goetz@6458 | 129 | // at present, we provide a single class `NativeCall' representing the |
goetz@6458 | 130 | // sequence `load_const, mtctr, bctrl' or the sequence 'ld_from_toc, |
goetz@6458 | 131 | // mtctr, bctrl'. |
goetz@6458 | 132 | class NativeCall: public NativeInstruction { |
goetz@6458 | 133 | public: |
goetz@6458 | 134 | |
goetz@6458 | 135 | enum specific_constants { |
goetz@6458 | 136 | load_const_instruction_size = 28, |
goetz@6458 | 137 | load_const_from_method_toc_instruction_size = 16, |
goetz@6458 | 138 | instruction_size = 16 // Used in shared code for calls with reloc_info. |
goetz@6458 | 139 | }; |
goetz@6458 | 140 | |
goetz@6458 | 141 | static bool is_call_at(address a) { |
goetz@6458 | 142 | return Assembler::is_bl(*(int*)(a)); |
goetz@6458 | 143 | } |
goetz@6458 | 144 | |
goetz@6458 | 145 | static bool is_call_before(address return_address) { |
goetz@6458 | 146 | return NativeCall::is_call_at(return_address - 4); |
goetz@6458 | 147 | } |
goetz@6458 | 148 | |
goetz@6458 | 149 | address instruction_address() const { |
goetz@6458 | 150 | return addr_at(0); |
goetz@6458 | 151 | } |
goetz@6458 | 152 | |
goetz@6458 | 153 | address next_instruction_address() const { |
goetz@6458 | 154 | // We have only bl. |
goetz@6458 | 155 | assert(MacroAssembler::is_bl(*(int*)instruction_address()), "Should be bl instruction!"); |
goetz@6458 | 156 | return addr_at(4); |
goetz@6458 | 157 | } |
goetz@6458 | 158 | |
goetz@6458 | 159 | address return_address() const { |
goetz@6458 | 160 | return next_instruction_address(); |
goetz@6458 | 161 | } |
goetz@6458 | 162 | |
goetz@6458 | 163 | address destination() const; |
goetz@6458 | 164 | |
goetz@6458 | 165 | // The parameter assert_lock disables the assertion during code generation. |
goetz@6458 | 166 | void set_destination_mt_safe(address dest, bool assert_lock = true); |
goetz@6458 | 167 | |
goetz@6458 | 168 | address get_trampoline(); |
goetz@6458 | 169 | |
goetz@6458 | 170 | void verify_alignment() {} // do nothing on ppc |
goetz@6458 | 171 | void verify() NOT_DEBUG_RETURN; |
goetz@6458 | 172 | }; |
goetz@6458 | 173 | |
goetz@6458 | 174 | inline NativeCall* nativeCall_at(address instr) { |
goetz@6458 | 175 | NativeCall* call = (NativeCall*)instr; |
goetz@6458 | 176 | call->verify(); |
goetz@6458 | 177 | return call; |
goetz@6458 | 178 | } |
goetz@6458 | 179 | |
goetz@6458 | 180 | inline NativeCall* nativeCall_before(address return_address) { |
goetz@6458 | 181 | NativeCall* call = NULL; |
goetz@6458 | 182 | if (MacroAssembler::is_bl(*(int*)(return_address - 4))) |
goetz@6458 | 183 | call = (NativeCall*)(return_address - 4); |
goetz@6458 | 184 | call->verify(); |
goetz@6458 | 185 | return call; |
goetz@6458 | 186 | } |
goetz@6458 | 187 | |
goetz@6458 | 188 | // The NativeFarCall is an abstraction for accessing/manipulating native |
goetz@6458 | 189 | // call-anywhere instructions. |
goetz@6458 | 190 | // Used to call native methods which may be loaded anywhere in the address |
goetz@6458 | 191 | // space, possibly out of reach of a call instruction. |
goetz@6458 | 192 | class NativeFarCall: public NativeInstruction { |
goetz@6458 | 193 | public: |
goetz@6458 | 194 | // We use MacroAssembler::bl64_patchable() for implementing a |
goetz@6458 | 195 | // call-anywhere instruction. |
goetz@6458 | 196 | |
goetz@6458 | 197 | // Checks whether instr points at a NativeFarCall instruction. |
goetz@6458 | 198 | static bool is_far_call_at(address instr) { |
goetz@6458 | 199 | return MacroAssembler::is_bl64_patchable_at(instr); |
goetz@6458 | 200 | } |
goetz@6458 | 201 | |
goetz@6458 | 202 | // Does the NativeFarCall implementation use a pc-relative encoding |
goetz@6458 | 203 | // of the call destination? |
goetz@6458 | 204 | // Used when relocating code. |
goetz@6458 | 205 | bool is_pcrelative() { |
goetz@6458 | 206 | assert(MacroAssembler::is_bl64_patchable_at((address)this), |
goetz@6458 | 207 | "unexpected call type"); |
goetz@6458 | 208 | return MacroAssembler::is_bl64_patchable_pcrelative_at((address)this); |
goetz@6458 | 209 | } |
goetz@6458 | 210 | |
goetz@6458 | 211 | // Returns the NativeFarCall's destination. |
goetz@6458 | 212 | address destination() const { |
goetz@6458 | 213 | assert(MacroAssembler::is_bl64_patchable_at((address)this), |
goetz@6458 | 214 | "unexpected call type"); |
goetz@6458 | 215 | return MacroAssembler::get_dest_of_bl64_patchable_at((address)this); |
goetz@6458 | 216 | } |
goetz@6458 | 217 | |
goetz@6458 | 218 | // Sets the NativeCall's destination, not necessarily mt-safe. |
goetz@6458 | 219 | // Used when relocating code. |
goetz@6458 | 220 | void set_destination(address dest) { |
goetz@6458 | 221 | // Set new destination (implementation of call may change here). |
goetz@6458 | 222 | assert(MacroAssembler::is_bl64_patchable_at((address)this), |
goetz@6458 | 223 | "unexpected call type"); |
goetz@6458 | 224 | MacroAssembler::set_dest_of_bl64_patchable_at((address)this, dest); |
goetz@6458 | 225 | } |
goetz@6458 | 226 | |
goetz@6458 | 227 | void verify() NOT_DEBUG_RETURN; |
goetz@6458 | 228 | }; |
goetz@6458 | 229 | |
goetz@6458 | 230 | // Instantiates a NativeFarCall object starting at the given instruction |
goetz@6458 | 231 | // address and returns the NativeFarCall object. |
goetz@6458 | 232 | inline NativeFarCall* nativeFarCall_at(address instr) { |
goetz@6458 | 233 | NativeFarCall* call = (NativeFarCall*)instr; |
goetz@6458 | 234 | call->verify(); |
goetz@6458 | 235 | return call; |
goetz@6458 | 236 | } |
goetz@6458 | 237 | |
goetz@6458 | 238 | // An interface for accessing/manipulating native set_oop imm, reg instructions. |
goetz@6458 | 239 | // (used to manipulate inlined data references, etc.) |
goetz@6458 | 240 | class NativeMovConstReg: public NativeInstruction { |
goetz@6458 | 241 | public: |
goetz@6458 | 242 | |
goetz@6458 | 243 | enum specific_constants { |
goetz@6458 | 244 | load_const_instruction_size = 20, |
goetz@6458 | 245 | load_const_from_method_toc_instruction_size = 8, |
goetz@6458 | 246 | instruction_size = 8 // Used in shared code for calls with reloc_info. |
goetz@6458 | 247 | }; |
goetz@6458 | 248 | |
goetz@6458 | 249 | address instruction_address() const { |
goetz@6458 | 250 | return addr_at(0); |
goetz@6458 | 251 | } |
goetz@6458 | 252 | |
goetz@6458 | 253 | address next_instruction_address() const; |
goetz@6458 | 254 | |
goetz@6458 | 255 | // (The [set_]data accessor respects oop_type relocs also.) |
goetz@6458 | 256 | intptr_t data() const; |
goetz@6458 | 257 | |
goetz@6458 | 258 | // Patch the code stream. |
goetz@6458 | 259 | address set_data_plain(intptr_t x, CodeBlob *code); |
goetz@6458 | 260 | // Patch the code stream and oop pool. |
goetz@6458 | 261 | void set_data(intptr_t x); |
goetz@6458 | 262 | |
goetz@6458 | 263 | // Patch narrow oop constants. Use this also for narrow klass. |
goetz@6458 | 264 | void set_narrow_oop(narrowOop data, CodeBlob *code = NULL); |
goetz@6458 | 265 | |
goetz@6458 | 266 | void verify() NOT_DEBUG_RETURN; |
goetz@6458 | 267 | }; |
goetz@6458 | 268 | |
goetz@6458 | 269 | inline NativeMovConstReg* nativeMovConstReg_at(address address) { |
goetz@6458 | 270 | NativeMovConstReg* test = (NativeMovConstReg*)address; |
goetz@6458 | 271 | test->verify(); |
goetz@6458 | 272 | return test; |
goetz@6458 | 273 | } |
goetz@6458 | 274 | |
goetz@6458 | 275 | // The NativeJump is an abstraction for accessing/manipulating native |
goetz@6458 | 276 | // jump-anywhere instructions. |
goetz@6458 | 277 | class NativeJump: public NativeInstruction { |
goetz@6458 | 278 | public: |
goetz@6458 | 279 | // We use MacroAssembler::b64_patchable() for implementing a |
goetz@6458 | 280 | // jump-anywhere instruction. |
goetz@6458 | 281 | |
goetz@6458 | 282 | enum specific_constants { |
goetz@6458 | 283 | instruction_size = MacroAssembler::b64_patchable_size |
goetz@6458 | 284 | }; |
goetz@6458 | 285 | |
goetz@6458 | 286 | // Checks whether instr points at a NativeJump instruction. |
goetz@6458 | 287 | static bool is_jump_at(address instr) { |
goetz@6458 | 288 | return MacroAssembler::is_b64_patchable_at(instr) |
goetz@6458 | 289 | || ( MacroAssembler::is_load_const_from_method_toc_at(instr) |
goetz@6458 | 290 | && Assembler::is_mtctr(*(int*)(instr + 2 * 4)) |
goetz@6458 | 291 | && Assembler::is_bctr(*(int*)(instr + 3 * 4))); |
goetz@6458 | 292 | } |
goetz@6458 | 293 | |
goetz@6458 | 294 | // Does the NativeJump implementation use a pc-relative encoding |
goetz@6458 | 295 | // of the call destination? |
goetz@6458 | 296 | // Used when relocating code or patching jumps. |
goetz@6458 | 297 | bool is_pcrelative() { |
goetz@6458 | 298 | return MacroAssembler::is_b64_patchable_pcrelative_at((address)this); |
goetz@6458 | 299 | } |
goetz@6458 | 300 | |
goetz@6458 | 301 | // Returns the NativeJump's destination. |
goetz@6458 | 302 | address jump_destination() const { |
goetz@6458 | 303 | if (MacroAssembler::is_b64_patchable_at((address)this)) { |
goetz@6458 | 304 | return MacroAssembler::get_dest_of_b64_patchable_at((address)this); |
goetz@6458 | 305 | } else if (MacroAssembler::is_load_const_from_method_toc_at((address)this) |
goetz@6458 | 306 | && Assembler::is_mtctr(*(int*)((address)this + 2 * 4)) |
goetz@6458 | 307 | && Assembler::is_bctr(*(int*)((address)this + 3 * 4))) { |
goetz@6458 | 308 | return (address)((NativeMovConstReg *)this)->data(); |
goetz@6458 | 309 | } else { |
goetz@6458 | 310 | ShouldNotReachHere(); |
goetz@6458 | 311 | return NULL; |
goetz@6458 | 312 | } |
goetz@6458 | 313 | } |
goetz@6458 | 314 | |
goetz@6458 | 315 | // Sets the NativeJump's destination, not necessarily mt-safe. |
goetz@6458 | 316 | // Used when relocating code or patching jumps. |
goetz@6458 | 317 | void set_jump_destination(address dest) { |
goetz@6458 | 318 | // Set new destination (implementation of call may change here). |
goetz@6458 | 319 | if (MacroAssembler::is_b64_patchable_at((address)this)) { |
goetz@6458 | 320 | MacroAssembler::set_dest_of_b64_patchable_at((address)this, dest); |
goetz@6458 | 321 | } else if (MacroAssembler::is_load_const_from_method_toc_at((address)this) |
goetz@6458 | 322 | && Assembler::is_mtctr(*(int*)((address)this + 2 * 4)) |
goetz@6458 | 323 | && Assembler::is_bctr(*(int*)((address)this + 3 * 4))) { |
goetz@6458 | 324 | ((NativeMovConstReg *)this)->set_data((intptr_t)dest); |
goetz@6458 | 325 | } else { |
goetz@6458 | 326 | ShouldNotReachHere(); |
goetz@6458 | 327 | } |
goetz@6458 | 328 | } |
goetz@6458 | 329 | |
goetz@6458 | 330 | // MT-safe insertion of native jump at verified method entry |
goetz@6458 | 331 | static void patch_verified_entry(address entry, address verified_entry, address dest); |
goetz@6458 | 332 | |
goetz@6458 | 333 | void verify() NOT_DEBUG_RETURN; |
goetz@6458 | 334 | |
goetz@6458 | 335 | static void check_verified_entry_alignment(address entry, address verified_entry) { |
goetz@6458 | 336 | // We just patch one instruction on ppc64, so the jump doesn't have to |
goetz@6458 | 337 | // be aligned. Nothing to do here. |
goetz@6458 | 338 | } |
goetz@6458 | 339 | }; |
goetz@6458 | 340 | |
goetz@6458 | 341 | // Instantiates a NativeJump object starting at the given instruction |
goetz@6458 | 342 | // address and returns the NativeJump object. |
goetz@6458 | 343 | inline NativeJump* nativeJump_at(address instr) { |
goetz@6458 | 344 | NativeJump* call = (NativeJump*)instr; |
goetz@6458 | 345 | call->verify(); |
goetz@6458 | 346 | return call; |
goetz@6458 | 347 | } |
goetz@6458 | 348 | |
goetz@6458 | 349 | // NativeConditionalFarBranch is abstraction for accessing/manipulating |
goetz@6458 | 350 | // conditional far branches. |
goetz@6458 | 351 | class NativeConditionalFarBranch : public NativeInstruction { |
goetz@6458 | 352 | public: |
goetz@6458 | 353 | |
goetz@6458 | 354 | static bool is_conditional_far_branch_at(address instr) { |
goetz@6458 | 355 | return MacroAssembler::is_bc_far_at(instr); |
goetz@6458 | 356 | } |
goetz@6458 | 357 | |
goetz@6458 | 358 | address branch_destination() const { |
goetz@6458 | 359 | return MacroAssembler::get_dest_of_bc_far_at((address)this); |
goetz@6458 | 360 | } |
goetz@6458 | 361 | |
goetz@6458 | 362 | void set_branch_destination(address dest) { |
goetz@6458 | 363 | MacroAssembler::set_dest_of_bc_far_at((address)this, dest); |
goetz@6458 | 364 | } |
goetz@6458 | 365 | }; |
goetz@6458 | 366 | |
goetz@6458 | 367 | inline NativeConditionalFarBranch* NativeConditionalFarBranch_at(address address) { |
goetz@6458 | 368 | assert(NativeConditionalFarBranch::is_conditional_far_branch_at(address), |
goetz@6458 | 369 | "must be a conditional far branch"); |
goetz@6458 | 370 | return (NativeConditionalFarBranch*)address; |
goetz@6458 | 371 | } |
goetz@6458 | 372 | |
goetz@6458 | 373 | // Call trampoline stubs. |
goetz@6458 | 374 | class NativeCallTrampolineStub : public NativeInstruction { |
goetz@6458 | 375 | private: |
goetz@6458 | 376 | |
goetz@6458 | 377 | address encoded_destination_addr() const; |
goetz@6458 | 378 | |
goetz@6458 | 379 | public: |
goetz@6458 | 380 | |
goetz@6458 | 381 | address destination() const; |
goetz@6458 | 382 | int destination_toc_offset() const; |
goetz@6458 | 383 | |
goetz@6458 | 384 | void set_destination(address new_destination); |
goetz@6458 | 385 | }; |
goetz@6458 | 386 | |
goetz@6458 | 387 | |
goetz@6458 | 388 | inline bool is_NativeCallTrampolineStub_at(address address) { |
goetz@6458 | 389 | int first_instr = *(int*)address; |
goetz@6458 | 390 | return Assembler::is_addis(first_instr) && |
goetz@6458 | 391 | (Register)(intptr_t)Assembler::inv_rt_field(first_instr) == R12_scratch2; |
goetz@6458 | 392 | } |
goetz@6458 | 393 | |
goetz@6458 | 394 | inline NativeCallTrampolineStub* NativeCallTrampolineStub_at(address address) { |
goetz@6458 | 395 | assert(is_NativeCallTrampolineStub_at(address), "no call trampoline found"); |
goetz@6458 | 396 | return (NativeCallTrampolineStub*)address; |
goetz@6458 | 397 | } |
goetz@6458 | 398 | |
goetz@6458 | 399 | #endif // CPU_PPC_VM_NATIVEINST_PPC_HPP |