src/cpu/sparc/vm/nativeInst_sparc.hpp

Thu, 07 Apr 2011 09:53:20 -0700

author
johnc
date
Thu, 07 Apr 2011 09:53:20 -0700
changeset 2781
e1162778c1c8
parent 2657
d673ef06fe96
child 2708
1d1603768966
permissions
-rw-r--r--

7009266: G1: assert(obj->is_oop_or_null(true )) failed: Error
Summary: A referent object that is only weakly reachable at the start of concurrent marking but is re-attached to the strongly reachable object graph during marking may not be marked as live. This can cause the reference object to be processed prematurely and leave dangling pointers to the referent object. Implement a read barrier for the java.lang.ref.Reference::referent field by intrinsifying the Reference.get() method, and intercepting accesses though JNI, reflection, and Unsafe, so that when a non-null referent object is read it is also logged in an SATB buffer.
Reviewed-by: kvn, iveresov, never, tonyp, dholmes

duke@435 1 /*
stefank@2314 2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
duke@435 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@435 4 *
duke@435 5 * This code is free software; you can redistribute it and/or modify it
duke@435 6 * under the terms of the GNU General Public License version 2 only, as
duke@435 7 * published by the Free Software Foundation.
duke@435 8 *
duke@435 9 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@435 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@435 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@435 12 * version 2 for more details (a copy is included in the LICENSE file that
duke@435 13 * accompanied this code).
duke@435 14 *
duke@435 15 * You should have received a copy of the GNU General Public License version
duke@435 16 * 2 along with this work; if not, write to the Free Software Foundation,
duke@435 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@435 18 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
duke@435 22 *
duke@435 23 */
duke@435 24
stefank@2314 25 #ifndef CPU_SPARC_VM_NATIVEINST_SPARC_HPP
stefank@2314 26 #define CPU_SPARC_VM_NATIVEINST_SPARC_HPP
stefank@2314 27
stefank@2314 28 #include "asm/assembler.hpp"
stefank@2314 29 #include "memory/allocation.hpp"
stefank@2314 30 #include "runtime/icache.hpp"
stefank@2314 31 #include "runtime/os.hpp"
stefank@2314 32 #include "utilities/top.hpp"
stefank@2314 33
duke@435 34 // We have interface for the following instructions:
duke@435 35 // - NativeInstruction
duke@435 36 // - - NativeCall
duke@435 37 // - - NativeFarCall
duke@435 38 // - - NativeMovConstReg
duke@435 39 // - - NativeMovConstRegPatching
duke@435 40 // - - NativeMovRegMem
duke@435 41 // - - NativeMovRegMemPatching
duke@435 42 // - - NativeJump
duke@435 43 // - - NativeGeneralJump
duke@435 44 // - - NativeIllegalInstruction
duke@435 45 // The base class for different kinds of native instruction abstractions.
duke@435 46 // Provides the primitive operations to manipulate code relative to this.
duke@435 47 class NativeInstruction VALUE_OBJ_CLASS_SPEC {
duke@435 48 friend class Relocation;
duke@435 49
duke@435 50 public:
duke@435 51 enum Sparc_specific_constants {
duke@435 52 nop_instruction_size = 4
duke@435 53 };
duke@435 54
kamg@551 55 bool is_dtrace_trap();
duke@435 56 bool is_nop() { return long_at(0) == nop_instruction(); }
duke@435 57 bool is_call() { return is_op(long_at(0), Assembler::call_op); }
duke@435 58 bool is_sethi() { return (is_op2(long_at(0), Assembler::sethi_op2)
duke@435 59 && inv_rd(long_at(0)) != G0); }
duke@435 60
duke@435 61 bool sets_cc() {
duke@435 62 // conservative (returns true for some instructions that do not set the
duke@435 63 // the condition code, such as, "save".
duke@435 64 // Does not return true for the deprecated tagged instructions, such as, TADDcc
duke@435 65 int x = long_at(0);
duke@435 66 return (is_op(x, Assembler::arith_op) &&
duke@435 67 (inv_op3(x) & Assembler::cc_bit_op3) == Assembler::cc_bit_op3);
duke@435 68 }
duke@435 69 bool is_illegal();
duke@435 70 bool is_zombie() {
duke@435 71 int x = long_at(0);
duke@435 72 return is_op3(x,
duke@435 73 VM_Version::v9_instructions_work() ?
duke@435 74 Assembler::ldsw_op3 : Assembler::lduw_op3,
duke@435 75 Assembler::ldst_op)
duke@435 76 && Assembler::inv_rs1(x) == G0
duke@435 77 && Assembler::inv_rd(x) == O7;
duke@435 78 }
duke@435 79 bool is_ic_miss_trap(); // Inline-cache uses a trap to detect a miss
duke@435 80 bool is_return() {
duke@435 81 // is it the output of MacroAssembler::ret or MacroAssembler::retl?
duke@435 82 int x = long_at(0);
duke@435 83 const int pc_return_offset = 8; // see frame_sparc.hpp
duke@435 84 return is_op3(x, Assembler::jmpl_op3, Assembler::arith_op)
duke@435 85 && (inv_rs1(x) == I7 || inv_rs1(x) == O7)
duke@435 86 && inv_immed(x) && inv_simm(x, 13) == pc_return_offset
duke@435 87 && inv_rd(x) == G0;
duke@435 88 }
duke@435 89 bool is_int_jump() {
duke@435 90 // is it the output of MacroAssembler::b?
duke@435 91 int x = long_at(0);
duke@435 92 return is_op2(x, Assembler::bp_op2) || is_op2(x, Assembler::br_op2);
duke@435 93 }
duke@435 94 bool is_float_jump() {
duke@435 95 // is it the output of MacroAssembler::fb?
duke@435 96 int x = long_at(0);
duke@435 97 return is_op2(x, Assembler::fbp_op2) || is_op2(x, Assembler::fb_op2);
duke@435 98 }
duke@435 99 bool is_jump() {
duke@435 100 return is_int_jump() || is_float_jump();
duke@435 101 }
duke@435 102 bool is_cond_jump() {
duke@435 103 int x = long_at(0);
duke@435 104 return (is_int_jump() && Assembler::inv_cond(x) != Assembler::always) ||
duke@435 105 (is_float_jump() && Assembler::inv_cond(x) != Assembler::f_always);
duke@435 106 }
duke@435 107
duke@435 108 bool is_stack_bang() {
duke@435 109 int x = long_at(0);
duke@435 110 return is_op3(x, Assembler::stw_op3, Assembler::ldst_op) &&
duke@435 111 (inv_rd(x) == G0) && (inv_rs1(x) == SP) && (inv_rs2(x) == G3_scratch);
duke@435 112 }
duke@435 113
duke@435 114 bool is_prefetch() {
duke@435 115 int x = long_at(0);
duke@435 116 return is_op3(x, Assembler::prefetch_op3, Assembler::ldst_op);
duke@435 117 }
duke@435 118
duke@435 119 bool is_membar() {
duke@435 120 int x = long_at(0);
duke@435 121 return is_op3(x, Assembler::membar_op3, Assembler::arith_op) &&
duke@435 122 (inv_rd(x) == G0) && (inv_rs1(x) == O7);
duke@435 123 }
duke@435 124
duke@435 125 bool is_safepoint_poll() {
duke@435 126 int x = long_at(0);
duke@435 127 #ifdef _LP64
duke@435 128 return is_op3(x, Assembler::ldx_op3, Assembler::ldst_op) &&
duke@435 129 #else
duke@435 130 return is_op3(x, Assembler::lduw_op3, Assembler::ldst_op) &&
duke@435 131 #endif
duke@435 132 (inv_rd(x) == G0) && (inv_immed(x) ? Assembler::inv_simm13(x) == 0 : inv_rs2(x) == G0);
duke@435 133 }
duke@435 134
duke@435 135 bool is_zero_test(Register &reg);
duke@435 136 bool is_load_store_with_small_offset(Register reg);
duke@435 137
duke@435 138 public:
duke@435 139 #ifdef ASSERT
duke@435 140 static int rdpc_instruction() { return Assembler::op(Assembler::arith_op ) | Assembler::op3(Assembler::rdreg_op3) | Assembler::u_field(5, 18, 14) | Assembler::rd(O7); }
duke@435 141 #else
duke@435 142 // Temporary fix: in optimized mode, u_field is a macro for efficiency reasons (see Assembler::u_field) - needs to be fixed
duke@435 143 static int rdpc_instruction() { return Assembler::op(Assembler::arith_op ) | Assembler::op3(Assembler::rdreg_op3) | u_field(5, 18, 14) | Assembler::rd(O7); }
duke@435 144 #endif
duke@435 145 static int nop_instruction() { return Assembler::op(Assembler::branch_op) | Assembler::op2(Assembler::sethi_op2); }
duke@435 146 static int illegal_instruction(); // the output of __ breakpoint_trap()
duke@435 147 static int call_instruction(address destination, address pc) { return Assembler::op(Assembler::call_op) | Assembler::wdisp((intptr_t)destination, (intptr_t)pc, 30); }
duke@435 148
duke@435 149 static int branch_instruction(Assembler::op2s op2val, Assembler::Condition c, bool a) {
duke@435 150 return Assembler::op(Assembler::branch_op) | Assembler::op2(op2val) | Assembler::annul(a) | Assembler::cond(c);
duke@435 151 }
duke@435 152
duke@435 153 static int op3_instruction(Assembler::ops opval, Register rd, Assembler::op3s op3val, Register rs1, int simm13a) {
duke@435 154 return Assembler::op(opval) | Assembler::rd(rd) | Assembler::op3(op3val) | Assembler::rs1(rs1) | Assembler::immed(true) | Assembler::simm(simm13a, 13);
duke@435 155 }
duke@435 156
duke@435 157 static int sethi_instruction(Register rd, int imm22a) {
duke@435 158 return Assembler::op(Assembler::branch_op) | Assembler::rd(rd) | Assembler::op2(Assembler::sethi_op2) | Assembler::hi22(imm22a);
duke@435 159 }
duke@435 160
duke@435 161 protected:
duke@435 162 address addr_at(int offset) const { return address(this) + offset; }
duke@435 163 int long_at(int offset) const { return *(int*)addr_at(offset); }
duke@435 164 void set_long_at(int offset, int i); /* deals with I-cache */
duke@435 165 void set_jlong_at(int offset, jlong i); /* deals with I-cache */
duke@435 166 void set_addr_at(int offset, address x); /* deals with I-cache */
duke@435 167
duke@435 168 address instruction_address() const { return addr_at(0); }
duke@435 169 address next_instruction_address() const { return addr_at(BytesPerInstWord); }
duke@435 170
duke@435 171 static bool is_op( int x, Assembler::ops opval) {
duke@435 172 return Assembler::inv_op(x) == opval;
duke@435 173 }
duke@435 174 static bool is_op2(int x, Assembler::op2s op2val) {
duke@435 175 return Assembler::inv_op(x) == Assembler::branch_op && Assembler::inv_op2(x) == op2val;
duke@435 176 }
duke@435 177 static bool is_op3(int x, Assembler::op3s op3val, Assembler::ops opval) {
duke@435 178 return Assembler::inv_op(x) == opval && Assembler::inv_op3(x) == op3val;
duke@435 179 }
duke@435 180
duke@435 181 // utilities to help subclasses decode:
duke@435 182 static Register inv_rd( int x ) { return Assembler::inv_rd( x); }
duke@435 183 static Register inv_rs1( int x ) { return Assembler::inv_rs1(x); }
duke@435 184 static Register inv_rs2( int x ) { return Assembler::inv_rs2(x); }
duke@435 185
duke@435 186 static bool inv_immed( int x ) { return Assembler::inv_immed(x); }
duke@435 187 static bool inv_annul( int x ) { return (Assembler::annul(true) & x) != 0; }
duke@435 188 static int inv_cond( int x ) { return Assembler::inv_cond(x); }
duke@435 189
duke@435 190 static int inv_op( int x ) { return Assembler::inv_op( x); }
duke@435 191 static int inv_op2( int x ) { return Assembler::inv_op2(x); }
duke@435 192 static int inv_op3( int x ) { return Assembler::inv_op3(x); }
duke@435 193
duke@435 194 static int inv_simm( int x, int nbits ) { return Assembler::inv_simm(x, nbits); }
duke@435 195 static intptr_t inv_wdisp( int x, int nbits ) { return Assembler::inv_wdisp( x, 0, nbits); }
duke@435 196 static intptr_t inv_wdisp16( int x ) { return Assembler::inv_wdisp16(x, 0); }
duke@435 197 static int branch_destination_offset(int x) { return Assembler::branch_destination(x, 0); }
duke@435 198 static int patch_branch_destination_offset(int dest_offset, int x) {
duke@435 199 return Assembler::patched_branch(dest_offset, x, 0);
duke@435 200 }
duke@435 201 void set_annul_bit() { set_long_at(0, long_at(0) | Assembler::annul(true)); }
duke@435 202
duke@435 203 // utility for checking if x is either of 2 small constants
duke@435 204 static bool is_either(int x, int k1, int k2) {
duke@435 205 // return x == k1 || x == k2;
duke@435 206 return (1 << x) & (1 << k1 | 1 << k2);
duke@435 207 }
duke@435 208
duke@435 209 // utility for checking overflow of signed instruction fields
duke@435 210 static bool fits_in_simm(int x, int nbits) {
duke@435 211 // cf. Assembler::assert_signed_range()
duke@435 212 // return -(1 << nbits-1) <= x && x < ( 1 << nbits-1),
duke@435 213 return (unsigned)(x + (1 << nbits-1)) < (unsigned)(1 << nbits);
duke@435 214 }
duke@435 215
duke@435 216 // set a signed immediate field
duke@435 217 static int set_simm(int insn, int imm, int nbits) {
duke@435 218 return (insn &~ Assembler::simm(-1, nbits)) | Assembler::simm(imm, nbits);
duke@435 219 }
duke@435 220
duke@435 221 // set a wdisp field (disp should be the difference of two addresses)
duke@435 222 static int set_wdisp(int insn, intptr_t disp, int nbits) {
duke@435 223 return (insn &~ Assembler::wdisp((intptr_t)-4, (intptr_t)0, nbits)) | Assembler::wdisp(disp, 0, nbits);
duke@435 224 }
duke@435 225
duke@435 226 static int set_wdisp16(int insn, intptr_t disp) {
duke@435 227 return (insn &~ Assembler::wdisp16((intptr_t)-4, 0)) | Assembler::wdisp16(disp, 0);
duke@435 228 }
duke@435 229
duke@435 230 // get a simm13 field from an arithmetic or memory instruction
duke@435 231 static int get_simm13(int insn) {
duke@435 232 assert(is_either(Assembler::inv_op(insn),
duke@435 233 Assembler::arith_op, Assembler::ldst_op) &&
duke@435 234 (insn & Assembler::immed(true)), "must have a simm13 field");
duke@435 235 return Assembler::inv_simm(insn, 13);
duke@435 236 }
duke@435 237
duke@435 238 // set the simm13 field of an arithmetic or memory instruction
duke@435 239 static bool set_simm13(int insn, int imm) {
duke@435 240 get_simm13(insn); // tickle the assertion check
duke@435 241 return set_simm(insn, imm, 13);
duke@435 242 }
duke@435 243
duke@435 244 // combine the fields of a sethi stream (7 instructions ) and an add, jmp or ld/st
duke@435 245 static intptr_t data64( address pc, int arith_insn ) {
duke@435 246 assert(is_op2(*(unsigned int *)pc, Assembler::sethi_op2), "must be sethi");
duke@435 247 intptr_t hi = (intptr_t)gethi( (unsigned int *)pc );
duke@435 248 intptr_t lo = (intptr_t)get_simm13(arith_insn);
duke@435 249 assert((unsigned)lo < (1 << 10), "offset field of set_oop must be 10 bits");
duke@435 250 return hi | lo;
duke@435 251 }
duke@435 252
duke@435 253 // Regenerate the instruction sequence that performs the 64 bit
duke@435 254 // sethi. This only does the sethi. The disp field (bottom 10 bits)
twisti@1040 255 // must be handled separately.
duke@435 256 static void set_data64_sethi(address instaddr, intptr_t x);
never@2657 257 static void verify_data64_sethi(address instaddr, intptr_t x);
duke@435 258
duke@435 259 // combine the fields of a sethi/simm13 pair (simm13 = or, add, jmpl, ld/st)
duke@435 260 static int data32(int sethi_insn, int arith_insn) {
duke@435 261 assert(is_op2(sethi_insn, Assembler::sethi_op2), "must be sethi");
duke@435 262 int hi = Assembler::inv_hi22(sethi_insn);
duke@435 263 int lo = get_simm13(arith_insn);
duke@435 264 assert((unsigned)lo < (1 << 10), "offset field of set_oop must be 10 bits");
duke@435 265 return hi | lo;
duke@435 266 }
duke@435 267
duke@435 268 static int set_data32_sethi(int sethi_insn, int imm) {
duke@435 269 // note that Assembler::hi22 clips the low 10 bits for us
duke@435 270 assert(is_op2(sethi_insn, Assembler::sethi_op2), "must be sethi");
duke@435 271 return (sethi_insn &~ Assembler::hi22(-1)) | Assembler::hi22(imm);
duke@435 272 }
duke@435 273
duke@435 274 static int set_data32_simm13(int arith_insn, int imm) {
duke@435 275 get_simm13(arith_insn); // tickle the assertion check
duke@435 276 int imm10 = Assembler::low10(imm);
duke@435 277 return (arith_insn &~ Assembler::simm(-1, 13)) | Assembler::simm(imm10, 13);
duke@435 278 }
duke@435 279
duke@435 280 static int low10(int imm) {
duke@435 281 return Assembler::low10(imm);
duke@435 282 }
duke@435 283
duke@435 284 // Perform the inverse of the LP64 Macroassembler::sethi
duke@435 285 // routine. Extracts the 54 bits of address from the instruction
duke@435 286 // stream. This routine must agree with the sethi routine in
duke@435 287 // assembler_inline_sparc.hpp
duke@435 288 static address gethi( unsigned int *pc ) {
duke@435 289 int i = 0;
duke@435 290 uintptr_t adr;
duke@435 291 // We first start out with the real sethi instruction
duke@435 292 assert(is_op2(*pc, Assembler::sethi_op2), "in gethi - must be sethi");
duke@435 293 adr = (unsigned int)Assembler::inv_hi22( *(pc++) );
duke@435 294 i++;
duke@435 295 while ( i < 7 ) {
duke@435 296 // We're done if we hit a nop
duke@435 297 if ( (int)*pc == nop_instruction() ) break;
duke@435 298 assert ( Assembler::inv_op(*pc) == Assembler::arith_op, "in gethi - must be arith_op" );
duke@435 299 switch ( Assembler::inv_op3(*pc) ) {
duke@435 300 case Assembler::xor_op3:
duke@435 301 adr ^= (intptr_t)get_simm13( *pc );
duke@435 302 return ( (address)adr );
duke@435 303 break;
duke@435 304 case Assembler::sll_op3:
duke@435 305 adr <<= ( *pc & 0x3f );
duke@435 306 break;
duke@435 307 case Assembler::or_op3:
duke@435 308 adr |= (intptr_t)get_simm13( *pc );
duke@435 309 break;
duke@435 310 default:
duke@435 311 assert ( 0, "in gethi - Should not reach here" );
duke@435 312 break;
duke@435 313 }
duke@435 314 pc++;
duke@435 315 i++;
duke@435 316 }
duke@435 317 return ( (address)adr );
duke@435 318 }
duke@435 319
duke@435 320 public:
duke@435 321 void verify();
duke@435 322 void print();
duke@435 323
duke@435 324 // unit test stuff
duke@435 325 static void test() {} // override for testing
duke@435 326
duke@435 327 inline friend NativeInstruction* nativeInstruction_at(address address);
duke@435 328 };
duke@435 329
duke@435 330 inline NativeInstruction* nativeInstruction_at(address address) {
duke@435 331 NativeInstruction* inst = (NativeInstruction*)address;
duke@435 332 #ifdef ASSERT
duke@435 333 inst->verify();
duke@435 334 #endif
duke@435 335 return inst;
duke@435 336 }
duke@435 337
duke@435 338
duke@435 339
duke@435 340 //-----------------------------------------------------------------------------
duke@435 341
duke@435 342 // The NativeCall is an abstraction for accessing/manipulating native call imm32 instructions.
duke@435 343 // (used to manipulate inline caches, primitive & dll calls, etc.)
duke@435 344 inline NativeCall* nativeCall_at(address instr);
duke@435 345 inline NativeCall* nativeCall_overwriting_at(address instr,
duke@435 346 address destination);
duke@435 347 inline NativeCall* nativeCall_before(address return_address);
duke@435 348 class NativeCall: public NativeInstruction {
duke@435 349 public:
duke@435 350 enum Sparc_specific_constants {
duke@435 351 instruction_size = 8,
duke@435 352 return_address_offset = 8,
duke@435 353 call_displacement_width = 30,
duke@435 354 displacement_offset = 0,
duke@435 355 instruction_offset = 0
duke@435 356 };
duke@435 357 address instruction_address() const { return addr_at(0); }
duke@435 358 address next_instruction_address() const { return addr_at(instruction_size); }
duke@435 359 address return_address() const { return addr_at(return_address_offset); }
duke@435 360
duke@435 361 address destination() const { return inv_wdisp(long_at(0), call_displacement_width) + instruction_address(); }
duke@435 362 address displacement_address() const { return addr_at(displacement_offset); }
duke@435 363 void set_destination(address dest) { set_long_at(0, set_wdisp(long_at(0), dest - instruction_address(), call_displacement_width)); }
duke@435 364 void set_destination_mt_safe(address dest);
duke@435 365
duke@435 366 void verify_alignment() {} // do nothing on sparc
duke@435 367 void verify();
duke@435 368 void print();
duke@435 369
duke@435 370 // unit test stuff
duke@435 371 static void test();
duke@435 372
duke@435 373 // Creation
duke@435 374 friend inline NativeCall* nativeCall_at(address instr);
duke@435 375 friend NativeCall* nativeCall_overwriting_at(address instr, address destination = NULL) {
duke@435 376 // insert a "blank" call:
duke@435 377 NativeCall* call = (NativeCall*)instr;
duke@435 378 call->set_long_at(0 * BytesPerInstWord, call_instruction(destination, instr));
duke@435 379 call->set_long_at(1 * BytesPerInstWord, nop_instruction());
duke@435 380 assert(call->addr_at(2 * BytesPerInstWord) - instr == instruction_size, "instruction size");
duke@435 381 // check its structure now:
duke@435 382 assert(nativeCall_at(instr)->destination() == destination, "correct call destination");
duke@435 383 return call;
duke@435 384 }
duke@435 385
duke@435 386 friend inline NativeCall* nativeCall_before(address return_address) {
duke@435 387 NativeCall* call = (NativeCall*)(return_address - return_address_offset);
duke@435 388 #ifdef ASSERT
duke@435 389 call->verify();
duke@435 390 #endif
duke@435 391 return call;
duke@435 392 }
duke@435 393
duke@435 394 static bool is_call_at(address instr) {
duke@435 395 return nativeInstruction_at(instr)->is_call();
duke@435 396 }
duke@435 397
duke@435 398 static bool is_call_before(address instr) {
duke@435 399 return nativeInstruction_at(instr - return_address_offset)->is_call();
duke@435 400 }
duke@435 401
duke@435 402 static bool is_call_to(address instr, address target) {
duke@435 403 return nativeInstruction_at(instr)->is_call() &&
duke@435 404 nativeCall_at(instr)->destination() == target;
duke@435 405 }
duke@435 406
duke@435 407 // MT-safe patching of a call instruction.
duke@435 408 static void insert(address code_pos, address entry) {
duke@435 409 (void)nativeCall_overwriting_at(code_pos, entry);
duke@435 410 }
duke@435 411
duke@435 412 static void replace_mt_safe(address instr_addr, address code_buffer);
duke@435 413 };
duke@435 414 inline NativeCall* nativeCall_at(address instr) {
duke@435 415 NativeCall* call = (NativeCall*)instr;
duke@435 416 #ifdef ASSERT
duke@435 417 call->verify();
duke@435 418 #endif
duke@435 419 return call;
duke@435 420 }
duke@435 421
duke@435 422 // The NativeFarCall is an abstraction for accessing/manipulating native call-anywhere
duke@435 423 // instructions in the sparcv9 vm. Used to call native methods which may be loaded
duke@435 424 // anywhere in the address space, possibly out of reach of a call instruction.
duke@435 425
duke@435 426 #ifndef _LP64
duke@435 427
duke@435 428 // On 32-bit systems, a far call is the same as a near one.
duke@435 429 class NativeFarCall;
duke@435 430 inline NativeFarCall* nativeFarCall_at(address instr);
duke@435 431 class NativeFarCall : public NativeCall {
duke@435 432 public:
duke@435 433 friend inline NativeFarCall* nativeFarCall_at(address instr) { return (NativeFarCall*)nativeCall_at(instr); }
duke@435 434 friend NativeFarCall* nativeFarCall_overwriting_at(address instr, address destination = NULL)
duke@435 435 { return (NativeFarCall*)nativeCall_overwriting_at(instr, destination); }
duke@435 436 friend NativeFarCall* nativeFarCall_before(address return_address)
duke@435 437 { return (NativeFarCall*)nativeCall_before(return_address); }
duke@435 438 };
duke@435 439
duke@435 440 #else
duke@435 441
duke@435 442 // The format of this extended-range call is:
duke@435 443 // jumpl_to addr, lreg
duke@435 444 // == sethi %hi54(addr), O7 ; jumpl O7, %lo10(addr), O7 ; <delay>
duke@435 445 // That is, it is essentially the same as a NativeJump.
duke@435 446 class NativeFarCall;
duke@435 447 inline NativeFarCall* nativeFarCall_overwriting_at(address instr, address destination);
duke@435 448 inline NativeFarCall* nativeFarCall_at(address instr);
duke@435 449 class NativeFarCall: public NativeInstruction {
duke@435 450 public:
duke@435 451 enum Sparc_specific_constants {
duke@435 452 // instruction_size includes the delay slot instruction.
duke@435 453 instruction_size = 9 * BytesPerInstWord,
duke@435 454 return_address_offset = 9 * BytesPerInstWord,
duke@435 455 jmpl_offset = 7 * BytesPerInstWord,
duke@435 456 displacement_offset = 0,
duke@435 457 instruction_offset = 0
duke@435 458 };
duke@435 459 address instruction_address() const { return addr_at(0); }
duke@435 460 address next_instruction_address() const { return addr_at(instruction_size); }
duke@435 461 address return_address() const { return addr_at(return_address_offset); }
duke@435 462
duke@435 463 address destination() const {
duke@435 464 return (address) data64(addr_at(0), long_at(jmpl_offset));
duke@435 465 }
duke@435 466 address displacement_address() const { return addr_at(displacement_offset); }
duke@435 467 void set_destination(address dest);
duke@435 468
duke@435 469 bool destination_is_compiled_verified_entry_point();
duke@435 470
duke@435 471 void verify();
duke@435 472 void print();
duke@435 473
duke@435 474 // unit test stuff
duke@435 475 static void test();
duke@435 476
duke@435 477 // Creation
duke@435 478 friend inline NativeFarCall* nativeFarCall_at(address instr) {
duke@435 479 NativeFarCall* call = (NativeFarCall*)instr;
duke@435 480 #ifdef ASSERT
duke@435 481 call->verify();
duke@435 482 #endif
duke@435 483 return call;
duke@435 484 }
duke@435 485
duke@435 486 friend inline NativeFarCall* nativeFarCall_overwriting_at(address instr, address destination = NULL) {
duke@435 487 Unimplemented();
duke@435 488 NativeFarCall* call = (NativeFarCall*)instr;
duke@435 489 return call;
duke@435 490 }
duke@435 491
duke@435 492 friend NativeFarCall* nativeFarCall_before(address return_address) {
duke@435 493 NativeFarCall* call = (NativeFarCall*)(return_address - return_address_offset);
duke@435 494 #ifdef ASSERT
duke@435 495 call->verify();
duke@435 496 #endif
duke@435 497 return call;
duke@435 498 }
duke@435 499
duke@435 500 static bool is_call_at(address instr);
duke@435 501
duke@435 502 // MT-safe patching of a call instruction.
duke@435 503 static void insert(address code_pos, address entry) {
duke@435 504 (void)nativeFarCall_overwriting_at(code_pos, entry);
duke@435 505 }
duke@435 506 static void replace_mt_safe(address instr_addr, address code_buffer);
duke@435 507 };
duke@435 508
duke@435 509 #endif // _LP64
duke@435 510
duke@435 511 // An interface for accessing/manipulating native set_oop imm, reg instructions.
duke@435 512 // (used to manipulate inlined data references, etc.)
duke@435 513 // set_oop imm, reg
duke@435 514 // == sethi %hi22(imm), reg ; add reg, %lo10(imm), reg
duke@435 515 class NativeMovConstReg;
duke@435 516 inline NativeMovConstReg* nativeMovConstReg_at(address address);
duke@435 517 class NativeMovConstReg: public NativeInstruction {
duke@435 518 public:
duke@435 519 enum Sparc_specific_constants {
duke@435 520 sethi_offset = 0,
duke@435 521 #ifdef _LP64
duke@435 522 add_offset = 7 * BytesPerInstWord,
duke@435 523 instruction_size = 8 * BytesPerInstWord
duke@435 524 #else
duke@435 525 add_offset = 4,
duke@435 526 instruction_size = 8
duke@435 527 #endif
duke@435 528 };
duke@435 529
duke@435 530 address instruction_address() const { return addr_at(0); }
duke@435 531 address next_instruction_address() const { return addr_at(instruction_size); }
duke@435 532
duke@435 533 // (The [set_]data accessor respects oop_type relocs also.)
duke@435 534 intptr_t data() const;
duke@435 535 void set_data(intptr_t x);
duke@435 536
duke@435 537 // report the destination register
duke@435 538 Register destination() { return inv_rd(long_at(sethi_offset)); }
duke@435 539
duke@435 540 void verify();
duke@435 541 void print();
duke@435 542
duke@435 543 // unit test stuff
duke@435 544 static void test();
duke@435 545
duke@435 546 // Creation
duke@435 547 friend inline NativeMovConstReg* nativeMovConstReg_at(address address) {
duke@435 548 NativeMovConstReg* test = (NativeMovConstReg*)address;
duke@435 549 #ifdef ASSERT
duke@435 550 test->verify();
duke@435 551 #endif
duke@435 552 return test;
duke@435 553 }
duke@435 554
duke@435 555
duke@435 556 friend NativeMovConstReg* nativeMovConstReg_before(address address) {
duke@435 557 NativeMovConstReg* test = (NativeMovConstReg*)(address - instruction_size);
duke@435 558 #ifdef ASSERT
duke@435 559 test->verify();
duke@435 560 #endif
duke@435 561 return test;
duke@435 562 }
duke@435 563
duke@435 564 };
duke@435 565
duke@435 566
duke@435 567 // An interface for accessing/manipulating native set_oop imm, reg instructions.
duke@435 568 // (used to manipulate inlined data references, etc.)
duke@435 569 // set_oop imm, reg
duke@435 570 // == sethi %hi22(imm), reg; nop; add reg, %lo10(imm), reg
duke@435 571 //
duke@435 572 // Note that it is identical to NativeMovConstReg with the exception of a nop between the
duke@435 573 // sethi and the add. The nop is required to be in the delay slot of the call instruction
duke@435 574 // which overwrites the sethi during patching.
duke@435 575 class NativeMovConstRegPatching;
duke@435 576 inline NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address);class NativeMovConstRegPatching: public NativeInstruction {
duke@435 577 public:
duke@435 578 enum Sparc_specific_constants {
duke@435 579 sethi_offset = 0,
duke@435 580 #ifdef _LP64
duke@435 581 nop_offset = 7 * BytesPerInstWord,
duke@435 582 #else
duke@435 583 nop_offset = sethi_offset + BytesPerInstWord,
duke@435 584 #endif
duke@435 585 add_offset = nop_offset + BytesPerInstWord,
duke@435 586 instruction_size = add_offset + BytesPerInstWord
duke@435 587 };
duke@435 588
duke@435 589 address instruction_address() const { return addr_at(0); }
duke@435 590 address next_instruction_address() const { return addr_at(instruction_size); }
duke@435 591
duke@435 592 // (The [set_]data accessor respects oop_type relocs also.)
duke@435 593 int data() const;
duke@435 594 void set_data(int x);
duke@435 595
duke@435 596 // report the destination register
duke@435 597 Register destination() { return inv_rd(long_at(sethi_offset)); }
duke@435 598
duke@435 599 void verify();
duke@435 600 void print();
duke@435 601
duke@435 602 // unit test stuff
duke@435 603 static void test();
duke@435 604
duke@435 605 // Creation
duke@435 606 friend inline NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) {
duke@435 607 NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)address;
duke@435 608 #ifdef ASSERT
duke@435 609 test->verify();
duke@435 610 #endif
duke@435 611 return test;
duke@435 612 }
duke@435 613
duke@435 614
duke@435 615 friend NativeMovConstRegPatching* nativeMovConstRegPatching_before(address address) {
duke@435 616 NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_size);
duke@435 617 #ifdef ASSERT
duke@435 618 test->verify();
duke@435 619 #endif
duke@435 620 return test;
duke@435 621 }
duke@435 622
duke@435 623 };
duke@435 624
duke@435 625
duke@435 626 // An interface for accessing/manipulating native memory ops
duke@435 627 // ld* [reg + offset], reg
duke@435 628 // st* reg, [reg + offset]
duke@435 629 // sethi %hi(imm), reg; add reg, %lo(imm), reg; ld* [reg1 + reg], reg2
duke@435 630 // sethi %hi(imm), reg; add reg, %lo(imm), reg; st* reg2, [reg1 + reg]
duke@435 631 // Ops covered: {lds,ldu,st}{w,b,h}, {ld,st}{d,x}
duke@435 632 //
duke@435 633 class NativeMovRegMem;
duke@435 634 inline NativeMovRegMem* nativeMovRegMem_at (address address);
duke@435 635 class NativeMovRegMem: public NativeInstruction {
duke@435 636 public:
duke@435 637 enum Sparc_specific_constants {
duke@435 638 op3_mask_ld = 1 << Assembler::lduw_op3 |
duke@435 639 1 << Assembler::ldub_op3 |
duke@435 640 1 << Assembler::lduh_op3 |
duke@435 641 1 << Assembler::ldd_op3 |
duke@435 642 1 << Assembler::ldsw_op3 |
duke@435 643 1 << Assembler::ldsb_op3 |
duke@435 644 1 << Assembler::ldsh_op3 |
duke@435 645 1 << Assembler::ldx_op3,
duke@435 646 op3_mask_st = 1 << Assembler::stw_op3 |
duke@435 647 1 << Assembler::stb_op3 |
duke@435 648 1 << Assembler::sth_op3 |
duke@435 649 1 << Assembler::std_op3 |
duke@435 650 1 << Assembler::stx_op3,
duke@435 651 op3_ldst_int_limit = Assembler::ldf_op3,
duke@435 652 op3_mask_ldf = 1 << (Assembler::ldf_op3 - op3_ldst_int_limit) |
duke@435 653 1 << (Assembler::lddf_op3 - op3_ldst_int_limit),
duke@435 654 op3_mask_stf = 1 << (Assembler::stf_op3 - op3_ldst_int_limit) |
duke@435 655 1 << (Assembler::stdf_op3 - op3_ldst_int_limit),
duke@435 656
duke@435 657 offset_width = 13,
duke@435 658 sethi_offset = 0,
duke@435 659 #ifdef _LP64
duke@435 660 add_offset = 7 * BytesPerInstWord,
duke@435 661 #else
duke@435 662 add_offset = 4,
duke@435 663 #endif
duke@435 664 ldst_offset = add_offset + BytesPerInstWord
duke@435 665 };
duke@435 666 bool is_immediate() const {
duke@435 667 // check if instruction is ld* [reg + offset], reg or st* reg, [reg + offset]
duke@435 668 int i0 = long_at(0);
duke@435 669 return (is_op(i0, Assembler::ldst_op));
duke@435 670 }
duke@435 671
duke@435 672 address instruction_address() const { return addr_at(0); }
duke@435 673 address next_instruction_address() const {
duke@435 674 #ifdef _LP64
duke@435 675 return addr_at(is_immediate() ? 4 : (7 * BytesPerInstWord));
duke@435 676 #else
duke@435 677 return addr_at(is_immediate() ? 4 : 12);
duke@435 678 #endif
duke@435 679 }
duke@435 680 intptr_t offset() const {
duke@435 681 return is_immediate()? inv_simm(long_at(0), offset_width) :
duke@435 682 nativeMovConstReg_at(addr_at(0))->data();
duke@435 683 }
duke@435 684 void set_offset(intptr_t x) {
duke@435 685 if (is_immediate()) {
duke@435 686 guarantee(fits_in_simm(x, offset_width), "data block offset overflow");
duke@435 687 set_long_at(0, set_simm(long_at(0), x, offset_width));
duke@435 688 } else
duke@435 689 nativeMovConstReg_at(addr_at(0))->set_data(x);
duke@435 690 }
duke@435 691
duke@435 692 void add_offset_in_bytes(intptr_t radd_offset) {
duke@435 693 set_offset (offset() + radd_offset);
duke@435 694 }
duke@435 695
duke@435 696 void copy_instruction_to(address new_instruction_address);
duke@435 697
duke@435 698 void verify();
duke@435 699 void print ();
duke@435 700
duke@435 701 // unit test stuff
duke@435 702 static void test();
duke@435 703
duke@435 704 private:
duke@435 705 friend inline NativeMovRegMem* nativeMovRegMem_at (address address) {
duke@435 706 NativeMovRegMem* test = (NativeMovRegMem*)address;
duke@435 707 #ifdef ASSERT
duke@435 708 test->verify();
duke@435 709 #endif
duke@435 710 return test;
duke@435 711 }
duke@435 712 };
duke@435 713
duke@435 714
duke@435 715 // An interface for accessing/manipulating native memory ops
duke@435 716 // ld* [reg + offset], reg
duke@435 717 // st* reg, [reg + offset]
duke@435 718 // sethi %hi(imm), reg; nop; add reg, %lo(imm), reg; ld* [reg1 + reg], reg2
duke@435 719 // sethi %hi(imm), reg; nop; add reg, %lo(imm), reg; st* reg2, [reg1 + reg]
duke@435 720 // Ops covered: {lds,ldu,st}{w,b,h}, {ld,st}{d,x}
duke@435 721 //
duke@435 722 // Note that it is identical to NativeMovRegMem with the exception of a nop between the
duke@435 723 // sethi and the add. The nop is required to be in the delay slot of the call instruction
duke@435 724 // which overwrites the sethi during patching.
duke@435 725 class NativeMovRegMemPatching;
duke@435 726 inline NativeMovRegMemPatching* nativeMovRegMemPatching_at (address address);
duke@435 727 class NativeMovRegMemPatching: public NativeInstruction {
duke@435 728 public:
duke@435 729 enum Sparc_specific_constants {
duke@435 730 op3_mask_ld = 1 << Assembler::lduw_op3 |
duke@435 731 1 << Assembler::ldub_op3 |
duke@435 732 1 << Assembler::lduh_op3 |
duke@435 733 1 << Assembler::ldd_op3 |
duke@435 734 1 << Assembler::ldsw_op3 |
duke@435 735 1 << Assembler::ldsb_op3 |
duke@435 736 1 << Assembler::ldsh_op3 |
duke@435 737 1 << Assembler::ldx_op3,
duke@435 738 op3_mask_st = 1 << Assembler::stw_op3 |
duke@435 739 1 << Assembler::stb_op3 |
duke@435 740 1 << Assembler::sth_op3 |
duke@435 741 1 << Assembler::std_op3 |
duke@435 742 1 << Assembler::stx_op3,
duke@435 743 op3_ldst_int_limit = Assembler::ldf_op3,
duke@435 744 op3_mask_ldf = 1 << (Assembler::ldf_op3 - op3_ldst_int_limit) |
duke@435 745 1 << (Assembler::lddf_op3 - op3_ldst_int_limit),
duke@435 746 op3_mask_stf = 1 << (Assembler::stf_op3 - op3_ldst_int_limit) |
duke@435 747 1 << (Assembler::stdf_op3 - op3_ldst_int_limit),
duke@435 748
duke@435 749 offset_width = 13,
duke@435 750 sethi_offset = 0,
duke@435 751 #ifdef _LP64
duke@435 752 nop_offset = 7 * BytesPerInstWord,
duke@435 753 #else
duke@435 754 nop_offset = 4,
duke@435 755 #endif
duke@435 756 add_offset = nop_offset + BytesPerInstWord,
duke@435 757 ldst_offset = add_offset + BytesPerInstWord
duke@435 758 };
duke@435 759 bool is_immediate() const {
duke@435 760 // check if instruction is ld* [reg + offset], reg or st* reg, [reg + offset]
duke@435 761 int i0 = long_at(0);
duke@435 762 return (is_op(i0, Assembler::ldst_op));
duke@435 763 }
duke@435 764
duke@435 765 address instruction_address() const { return addr_at(0); }
duke@435 766 address next_instruction_address() const {
duke@435 767 return addr_at(is_immediate()? 4 : 16);
duke@435 768 }
duke@435 769 int offset() const {
duke@435 770 return is_immediate()? inv_simm(long_at(0), offset_width) :
duke@435 771 nativeMovConstRegPatching_at(addr_at(0))->data();
duke@435 772 }
duke@435 773 void set_offset(int x) {
duke@435 774 if (is_immediate()) {
duke@435 775 guarantee(fits_in_simm(x, offset_width), "data block offset overflow");
duke@435 776 set_long_at(0, set_simm(long_at(0), x, offset_width));
duke@435 777 }
duke@435 778 else
duke@435 779 nativeMovConstRegPatching_at(addr_at(0))->set_data(x);
duke@435 780 }
duke@435 781
duke@435 782 void add_offset_in_bytes(intptr_t radd_offset) {
duke@435 783 set_offset (offset() + radd_offset);
duke@435 784 }
duke@435 785
duke@435 786 void copy_instruction_to(address new_instruction_address);
duke@435 787
duke@435 788 void verify();
duke@435 789 void print ();
duke@435 790
duke@435 791 // unit test stuff
duke@435 792 static void test();
duke@435 793
duke@435 794 private:
duke@435 795 friend inline NativeMovRegMemPatching* nativeMovRegMemPatching_at (address address) {
duke@435 796 NativeMovRegMemPatching* test = (NativeMovRegMemPatching*)address;
duke@435 797 #ifdef ASSERT
duke@435 798 test->verify();
duke@435 799 #endif
duke@435 800 return test;
duke@435 801 }
duke@435 802 };
duke@435 803
duke@435 804
duke@435 805 // An interface for accessing/manipulating native jumps
duke@435 806 // jump_to addr
duke@435 807 // == sethi %hi22(addr), temp ; jumpl reg, %lo10(addr), G0 ; <delay>
duke@435 808 // jumpl_to addr, lreg
duke@435 809 // == sethi %hi22(addr), temp ; jumpl reg, %lo10(addr), lreg ; <delay>
duke@435 810 class NativeJump;
duke@435 811 inline NativeJump* nativeJump_at(address address);
duke@435 812 class NativeJump: public NativeInstruction {
duke@435 813 private:
duke@435 814 void guarantee_displacement(int disp, int width) {
duke@435 815 guarantee(fits_in_simm(disp, width + 2), "branch displacement overflow");
duke@435 816 }
duke@435 817
duke@435 818 public:
duke@435 819 enum Sparc_specific_constants {
duke@435 820 sethi_offset = 0,
duke@435 821 #ifdef _LP64
duke@435 822 jmpl_offset = 7 * BytesPerInstWord,
duke@435 823 instruction_size = 9 * BytesPerInstWord // includes delay slot
duke@435 824 #else
duke@435 825 jmpl_offset = 1 * BytesPerInstWord,
duke@435 826 instruction_size = 3 * BytesPerInstWord // includes delay slot
duke@435 827 #endif
duke@435 828 };
duke@435 829
duke@435 830 address instruction_address() const { return addr_at(0); }
duke@435 831 address next_instruction_address() const { return addr_at(instruction_size); }
duke@435 832
duke@435 833 #ifdef _LP64
duke@435 834 address jump_destination() const {
duke@435 835 return (address) data64(instruction_address(), long_at(jmpl_offset));
duke@435 836 }
duke@435 837 void set_jump_destination(address dest) {
duke@435 838 set_data64_sethi( instruction_address(), (intptr_t)dest);
duke@435 839 set_long_at(jmpl_offset, set_data32_simm13( long_at(jmpl_offset), (intptr_t)dest));
duke@435 840 }
duke@435 841 #else
duke@435 842 address jump_destination() const {
duke@435 843 return (address) data32(long_at(sethi_offset), long_at(jmpl_offset));
duke@435 844 }
duke@435 845 void set_jump_destination(address dest) {
duke@435 846 set_long_at(sethi_offset, set_data32_sethi( long_at(sethi_offset), (intptr_t)dest));
duke@435 847 set_long_at(jmpl_offset, set_data32_simm13( long_at(jmpl_offset), (intptr_t)dest));
duke@435 848 }
duke@435 849 #endif
duke@435 850
duke@435 851 // Creation
duke@435 852 friend inline NativeJump* nativeJump_at(address address) {
duke@435 853 NativeJump* jump = (NativeJump*)address;
duke@435 854 #ifdef ASSERT
duke@435 855 jump->verify();
duke@435 856 #endif
duke@435 857 return jump;
duke@435 858 }
duke@435 859
duke@435 860 void verify();
duke@435 861 void print();
duke@435 862
duke@435 863 // Unit testing stuff
duke@435 864 static void test();
duke@435 865
duke@435 866 // Insertion of native jump instruction
duke@435 867 static void insert(address code_pos, address entry);
duke@435 868 // MT-safe insertion of native jump at verified method entry
duke@435 869 static void check_verified_entry_alignment(address entry, address verified_entry) {
duke@435 870 // nothing to do for sparc.
duke@435 871 }
duke@435 872 static void patch_verified_entry(address entry, address verified_entry, address dest);
duke@435 873 };
duke@435 874
duke@435 875
duke@435 876
duke@435 877 // Despite the name, handles only simple branches.
duke@435 878 class NativeGeneralJump;
duke@435 879 inline NativeGeneralJump* nativeGeneralJump_at(address address);
duke@435 880 class NativeGeneralJump: public NativeInstruction {
duke@435 881 public:
duke@435 882 enum Sparc_specific_constants {
duke@435 883 instruction_size = 8
duke@435 884 };
duke@435 885
duke@435 886 address instruction_address() const { return addr_at(0); }
duke@435 887 address jump_destination() const { return addr_at(0) + branch_destination_offset(long_at(0)); }
duke@435 888 void set_jump_destination(address dest) {
duke@435 889 int patched_instr = patch_branch_destination_offset(dest - addr_at(0), long_at(0));
duke@435 890 set_long_at(0, patched_instr);
duke@435 891 }
duke@435 892 void set_annul() { set_annul_bit(); }
duke@435 893 NativeInstruction *delay_slot_instr() { return nativeInstruction_at(addr_at(4));}
duke@435 894 void fill_delay_slot(int instr) { set_long_at(4, instr);}
duke@435 895 Assembler::Condition condition() {
duke@435 896 int x = long_at(0);
duke@435 897 return (Assembler::Condition) Assembler::inv_cond(x);
duke@435 898 }
duke@435 899
duke@435 900 // Creation
duke@435 901 friend inline NativeGeneralJump* nativeGeneralJump_at(address address) {
duke@435 902 NativeGeneralJump* jump = (NativeGeneralJump*)(address);
duke@435 903 #ifdef ASSERT
duke@435 904 jump->verify();
duke@435 905 #endif
duke@435 906 return jump;
duke@435 907 }
duke@435 908
duke@435 909 // Insertion of native general jump instruction
duke@435 910 static void insert_unconditional(address code_pos, address entry);
duke@435 911 static void replace_mt_safe(address instr_addr, address code_buffer);
duke@435 912
duke@435 913 void verify();
duke@435 914 };
duke@435 915
duke@435 916
duke@435 917 class NativeIllegalInstruction: public NativeInstruction {
duke@435 918 public:
duke@435 919 enum Sparc_specific_constants {
duke@435 920 instruction_size = 4
duke@435 921 };
duke@435 922
duke@435 923 // Insert illegal opcode as specific address
duke@435 924 static void insert(address code_pos);
duke@435 925 };
stefank@2314 926
stefank@2314 927 #endif // CPU_SPARC_VM_NATIVEINST_SPARC_HPP

mercurial