1 /*
2 * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #ifndef CPU_X86_NATIVEINST_X86_HPP
26 #define CPU_X86_NATIVEINST_X86_HPP
27
28 #include "asm/assembler.hpp"
29 #include "runtime/icache.hpp"
30 #include "runtime/safepointMechanism.hpp"
31
32 // We have interfaces for the following instructions:
33 // - NativeInstruction
34 // - - NativeCall
35 // - - NativeMovConstReg
36 // - - NativeMovConstRegPatching
37 // - - NativeMovRegMem
38 // - - NativeMovRegMemPatching
39 // - - NativeJump
40 // - - NativeIllegalOpCode
41 // - - NativeGeneralJump
42 // - - NativeReturn
43 // - - NativeReturnX (return with argument)
44 // - - NativePushConst
45 // - - NativeTstRegMem
46
47 // The base class for different kinds of native instruction abstractions.
48 // Provides the primitive operations to manipulate code relative to this.
49
50 class NativeInstruction {
51 friend class Relocation;
52
53 public:
54 enum Intel_specific_constants {
55 nop_instruction_code = 0x90,
56 nop_instruction_size = 1
57 };
58
59 bool is_nop() { return ubyte_at(0) == nop_instruction_code; }
60 inline bool is_call();
61 inline bool is_call_reg();
62 inline bool is_illegal();
63 inline bool is_return();
64 inline bool is_jump();
65 inline bool is_jump_reg();
66 inline bool is_cond_jump();
67 inline bool is_safepoint_poll();
68 inline bool is_mov_literal64();
69
70 protected:
71 address addr_at(int offset) const { return address(this) + offset; }
72
73 s_char sbyte_at(int offset) const { return *(s_char*) addr_at(offset); }
74 u_char ubyte_at(int offset) const { return *(u_char*) addr_at(offset); }
75
76 jint int_at(int offset) const { return *(jint*) addr_at(offset); }
77
78 intptr_t ptr_at(int offset) const { return *(intptr_t*) addr_at(offset); }
79
80 oop oop_at (int offset) const { return *(oop*) addr_at(offset); }
81
82
83 void set_char_at(int offset, u_char c) { *addr_at(offset) = c; wrote(offset); }
84 void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; wrote(offset); }
85 void set_ptr_at (int offset, intptr_t ptr) { *(intptr_t*) addr_at(offset) = ptr; wrote(offset); }
86 void set_oop_at (int offset, oop o) { *(oop*) addr_at(offset) = o; wrote(offset); }
87
88 // This doesn't really do anything on Intel, but it is the place where
89 // cache invalidation belongs, generically:
90 void wrote(int offset);
91
92 public:
93 bool has_rex2_prefix() const { return ubyte_at(0) == Assembler::REX2; }
94
95 inline friend NativeInstruction* nativeInstruction_at(address address);
96 };
97
98 inline NativeInstruction* nativeInstruction_at(address address) {
99 NativeInstruction* inst = (NativeInstruction*)address;
100 #ifdef ASSERT
101 //inst->verify();
102 #endif
103 return inst;
104 }
105
106 class NativeCall;
107 inline NativeCall* nativeCall_at(address address);
108 // The NativeCall is an abstraction for accessing/manipulating native call imm32/rel32off
109 // instructions (used to manipulate inline caches, primitive & dll calls, etc.).
110
111 class NativeCall: public NativeInstruction {
112 public:
113 enum Intel_specific_constants {
114 instruction_code = 0xE8,
115 instruction_size = 5,
116 instruction_offset = 0,
117 displacement_offset = 1,
118 return_address_offset = 5
119 };
120
121 static int byte_size() { return instruction_size; }
122 address instruction_address() const { return addr_at(instruction_offset); }
123 address next_instruction_address() const { return addr_at(return_address_offset); }
124 int displacement() const { return (jint) int_at(displacement_offset); }
125 address displacement_address() const { return addr_at(displacement_offset); }
126 address return_address() const { return addr_at(return_address_offset); }
127 address destination() const;
128 void set_destination(address dest) {
129 intptr_t disp = dest - return_address();
130 guarantee(disp == (intptr_t)(jint)disp, "must be 32-bit offset: " INTPTR_FORMAT ", dest: " INTPTR_FORMAT ", ret_pc: " INTPTR_FORMAT, disp, p2i(dest), p2i(return_address()));
131 set_int_at(displacement_offset, (int)(dest - return_address()));
132 }
133 // Returns whether the 4-byte displacement operand is 4-byte aligned.
134 bool is_displacement_aligned();
135 void set_destination_mt_safe(address dest);
136
137 void verify_alignment() { assert(is_displacement_aligned(), "displacement of call is not aligned"); }
138 void verify();
139 void print();
140
141 // Creation
142 inline friend NativeCall* nativeCall_at(address address);
143 inline friend NativeCall* nativeCall_before(address return_address);
144
145 static bool is_call_at(address instr) {
146 return ((*instr) & 0xFF) == NativeCall::instruction_code;
147 }
148
149 static bool is_call_before(address return_address) {
150 return is_call_at(return_address - NativeCall::return_address_offset);
151 }
152
153 static bool is_call_to(address instr, address target) {
154 return nativeInstruction_at(instr)->is_call() &&
155 nativeCall_at(instr)->destination() == target;
156 }
157
158 // MT-safe patching of a call instruction.
159 static void insert(address code_pos, address entry);
160
161 static void replace_mt_safe(address instr_addr, address code_buffer);
162 };
163
164 inline NativeCall* nativeCall_at(address address) {
165 NativeCall* call = (NativeCall*)(address - NativeCall::instruction_offset);
166 #ifdef ASSERT
167 call->verify();
168 #endif
169 return call;
170 }
171
172 inline NativeCall* nativeCall_before(address return_address) {
173 NativeCall* call = (NativeCall*)(return_address - NativeCall::return_address_offset);
174 #ifdef ASSERT
175 call->verify();
176 #endif
177 return call;
178 }
179
180 // Call with target address in a general purpose register(indirect absolute addressing).
181 // Encoding : FF /2 CALL r/m32
182 // Primary Opcode: FF
183 // Opcode Extension(part of ModRM.REG): /2
184 // Operand ModRM.RM = r/m32
185 class NativeCallReg: public NativeInstruction {
186 public:
187 enum Intel_specific_constants {
188 instruction_code = 0xFF,
189 instruction_offset = 0,
190 return_address_offset_norex = 2,
191 return_address_offset_rex = 3,
192 return_address_offset_rex2 = 4
193 };
194
195 int next_instruction_offset() const {
196 if (ubyte_at(0) == NativeCallReg::instruction_code) {
197 return return_address_offset_norex;
198 } else if (has_rex2_prefix()) {
199 return return_address_offset_rex2;
200 } else {
201 assert((ubyte_at(0) & 0xF0) == Assembler::REX, "");
202 return return_address_offset_rex;
203 }
204 }
205 };
206
207 // An interface for accessing/manipulating native mov reg, imm32 instructions.
208 // (used to manipulate inlined 32bit data dll calls, etc.)
209 // Instruction format for implied addressing mode immediate operand move to register instruction:
210 // [REX/REX2] [OPCODE] [IMM32]
211 class NativeMovConstReg: public NativeInstruction {
212 static const bool has_rex = true;
213 static const int rex_size = 1;
214 static const int rex2_size = 2;
215 public:
216 enum Intel_specific_constants {
217 instruction_code = 0xB8,
218 instruction_offset = 0,
219 instruction_size_rex = 1 + rex_size + wordSize,
220 instruction_size_rex2 = 1 + rex2_size + wordSize,
221 data_offset_rex = 1 + rex_size,
222 data_offset_rex2 = 1 + rex2_size,
223 next_instruction_offset_rex = instruction_size_rex,
224 next_instruction_offset_rex2 = instruction_size_rex2,
225 register_mask = 0x07
226 };
227
228 int instruction_size() const { return has_rex2_prefix() ? instruction_size_rex2 : instruction_size_rex; }
229 int next_inst_offset() const { return has_rex2_prefix() ? next_instruction_offset_rex2 : next_instruction_offset_rex; }
230 int data_byte_offset() const { return has_rex2_prefix() ? data_offset_rex2 : data_offset_rex;}
231 address instruction_address() const { return addr_at(instruction_offset); }
232 address next_instruction_address() const { return addr_at(next_inst_offset()); }
233 intptr_t data() const { return ptr_at(data_byte_offset()); }
234 void set_data(intptr_t x) { set_ptr_at(data_byte_offset(), x); }
235
236 void verify();
237 void print();
238
239 // Creation
240 inline friend NativeMovConstReg* nativeMovConstReg_at(address address);
241 inline friend NativeMovConstReg* nativeMovConstReg_before(address address);
242 };
243
244 inline NativeMovConstReg* nativeMovConstReg_at(address address) {
245 NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_offset);
246 #ifdef ASSERT
247 test->verify();
248 #endif
249 return test;
250 }
251
252 inline NativeMovConstReg* nativeMovConstReg_before(address address) {
253 int instruction_size = ((NativeInstruction*)(address))->has_rex2_prefix() ?
254 NativeMovConstReg::instruction_size_rex2 :
255 NativeMovConstReg::instruction_size_rex;
256 NativeMovConstReg* test = (NativeMovConstReg*)(address - instruction_size - NativeMovConstReg::instruction_offset);
257 #ifdef ASSERT
258 test->verify();
259 #endif
260 return test;
261 }
262
263 class NativeMovConstRegPatching: public NativeMovConstReg {
264 private:
265 friend NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) {
266 NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_offset);
267 #ifdef ASSERT
268 test->verify();
269 #endif
270 return test;
271 }
272 };
273
274 // An interface for accessing/manipulating native moves of the form:
275 // mov[b/w/l/q] [reg + offset], reg (instruction_code_reg2mem)
276 // mov[b/w/l/q] reg, [reg+offset] (instruction_code_mem2reg
277 // mov[s/z]x[w/b/q] [reg + offset], reg
278 // fld_s [reg+offset]
279 // fld_d [reg+offset]
280 // fstp_s [reg + offset]
281 // fstp_d [reg + offset]
282 // mov_literal64 scratch,<pointer> ; mov[b/w/l/q] 0(scratch),reg | mov[b/w/l/q] reg,0(scratch)
283 //
284 // Warning: These routines must be able to handle any instruction sequences
285 // that are generated as a result of the load/store byte,word,long
286 // macros. For example: The load_unsigned_byte instruction generates
287 // an xor reg,reg inst prior to generating the movb instruction. This
288 // class must skip the xor instruction.
289
290 class NativeMovRegMem: public NativeInstruction {
291 public:
292 enum Intel_specific_constants {
293 instruction_prefix_wide_lo = Assembler::REX,
294 instruction_prefix_wide_hi = Assembler::REX_WRXB,
295 instruction_code_xor = 0x33,
296 instruction_extended_prefix = 0x0F,
297
298 // Legacy encoding MAP1 instructions promotable to REX2 encoding.
299 instruction_code_mem2reg_movslq = 0x63,
300 instruction_code_mem2reg_movzxb = 0xB6,
301 instruction_code_mem2reg_movsxb = 0xBE,
302 instruction_code_mem2reg_movzxw = 0xB7,
303 instruction_code_mem2reg_movsxw = 0xBF,
304 instruction_operandsize_prefix = 0x66,
305
306 // Legacy encoding MAP0 instructions promotable to REX2 encoding.
307 instruction_code_reg2mem = 0x89,
308 instruction_code_mem2reg = 0x8b,
309 instruction_code_reg2memb = 0x88,
310 instruction_code_mem2regb = 0x8a,
311 instruction_code_lea = 0x8d,
312
313 instruction_code_float_s = 0xd9,
314 instruction_code_float_d = 0xdd,
315 instruction_code_long_volatile = 0xdf,
316
317 // VEX/EVEX/Legacy encodeded MAP1 instructions promotable to REX2 encoding.
318 instruction_code_xmm_ss_prefix = 0xf3,
319 instruction_code_xmm_sd_prefix = 0xf2,
320
321 instruction_code_xmm_code = 0x0f,
322
323 // Address operand load/store/ldp are promotable to REX2 to accomodate
324 // extended SIB encoding.
325 instruction_code_xmm_load = 0x10,
326 instruction_code_xmm_store = 0x11,
327 instruction_code_xmm_lpd = 0x12,
328
329 instruction_VEX_prefix_2bytes = Assembler::VEX_2bytes,
330 instruction_VEX_prefix_3bytes = Assembler::VEX_3bytes,
331 instruction_EVEX_prefix_4bytes = Assembler::EVEX_4bytes,
332 instruction_REX2_prefix = Assembler::REX2,
333
334 instruction_offset = 0,
335 data_offset = 2,
336 next_instruction_offset_rex = 4,
337 next_instruction_offset_rex2 = 5
338 };
339
340 // helper
341 int instruction_start() const;
342
343 address instruction_address() const {
344 return addr_at(instruction_start());
345 }
346
347 int num_bytes_to_end_of_patch() const {
348 return patch_offset() + sizeof(jint);
349 }
350
351 int offset() const {
352 return int_at(patch_offset());
353 }
354
355 void set_offset(int x) {
356 set_int_at(patch_offset(), x);
357 }
358
359 void add_offset_in_bytes(int add_offset) {
360 int patch_off = patch_offset();
361 set_int_at(patch_off, int_at(patch_off) + add_offset);
362 }
363
364 void verify();
365 void print ();
366
367 private:
368 int patch_offset() const;
369 inline friend NativeMovRegMem* nativeMovRegMem_at (address address);
370 };
371
372 inline NativeMovRegMem* nativeMovRegMem_at (address address) {
373 NativeMovRegMem* test = (NativeMovRegMem*)(address - NativeMovRegMem::instruction_offset);
374 #ifdef ASSERT
375 test->verify();
376 #endif
377 return test;
378 }
379
380
381 // An interface for accessing/manipulating native leal instruction of form:
382 // leal reg, [reg + offset]
383
384 class NativeLoadAddress: public NativeMovRegMem {
385 static const bool has_rex = true;
386 static const int rex_size = 1;
387 public:
388 enum Intel_specific_constants {
389 instruction_prefix_wide = Assembler::REX_W,
390 instruction_prefix_wide_extended = Assembler::REX_WB,
391 lea_instruction_code = 0x8D,
392 mov64_instruction_code = 0xB8
393 };
394
395 void verify();
396 void print ();
397
398 private:
399 friend NativeLoadAddress* nativeLoadAddress_at (address address) {
400 NativeLoadAddress* test = (NativeLoadAddress*)(address - instruction_offset);
401 #ifdef ASSERT
402 test->verify();
403 #endif
404 return test;
405 }
406 };
407
408 class NativeJump: public NativeInstruction {
409 public:
410 enum Intel_specific_constants {
411 instruction_code = 0xe9,
412 instruction_size = 5,
413 instruction_offset = 0,
414 data_offset = 1,
415 next_instruction_offset = 5
416 };
417
418 address instruction_address() const { return addr_at(instruction_offset); }
419 address next_instruction_address() const { return addr_at(next_instruction_offset); }
420 address jump_destination() const {
421 address dest = (int_at(data_offset)+next_instruction_address());
422 // 32bit used to encode unresolved jmp as jmp -1
423 // 64bit can't produce this so it used jump to self.
424 // Now 32bit and 64bit use jump to self as the unresolved address
425 // which the inline cache code (and relocs) know about
426
427 // return -1 if jump to self
428 dest = (dest == (address) this) ? (address) -1 : dest;
429 return dest;
430 }
431
432 void set_jump_destination(address dest) {
433 intptr_t val = dest - next_instruction_address();
434 if (dest == (address) -1) {
435 val = -5; // jump to self
436 }
437 assert((labs(val) & 0xFFFFFFFF00000000) == 0 || dest == (address)-1, "must be 32bit offset or -1");
438 set_int_at(data_offset, (jint)val);
439 }
440
441 // Creation
442 inline friend NativeJump* nativeJump_at(address address);
443
444 void verify();
445
446 // Insertion of native jump instruction
447 static void insert(address code_pos, address entry);
448 };
449
450 inline NativeJump* nativeJump_at(address address) {
451 NativeJump* jump = (NativeJump*)(address - NativeJump::instruction_offset);
452 #ifdef ASSERT
453 jump->verify();
454 #endif
455 return jump;
456 }
457
458 // Handles all kinds of jump on Intel. Long/far, conditional/unconditional with relative offsets
459 // barring register indirect jumps.
460 class NativeGeneralJump: public NativeInstruction {
461 public:
462 enum Intel_specific_constants {
463 // Constants does not apply, since the lengths and offsets depends on the actual jump
464 // used
465 // Instruction codes:
466 // Unconditional jumps: 0xE9 (rel32off), 0xEB (rel8off)
467 // Conditional jumps: 0x0F8x (rel32off), 0x7x (rel8off)
468 unconditional_long_jump = 0xe9,
469 unconditional_short_jump = 0xeb,
470 instruction_size = 5
471 };
472
473 address instruction_address() const { return addr_at(0); }
474 address jump_destination() const;
475
476 // Creation
477 inline friend NativeGeneralJump* nativeGeneralJump_at(address address);
478
479 // Insertion of native general jump instruction
480 static void insert_unconditional(address code_pos, address entry);
481 static void replace_mt_safe(address instr_addr, address code_buffer);
482
483 void verify();
484 };
485
486 inline NativeGeneralJump* nativeGeneralJump_at(address address) {
487 NativeGeneralJump* jump = (NativeGeneralJump*)(address);
488 DEBUG_ONLY(jump->verify();)
489 return jump;
490 }
491
492 class NativeIllegalInstruction: public NativeInstruction {
493 public:
494 enum Intel_specific_constants {
495 instruction_code = 0x0B0F, // Real byte order is: 0x0F, 0x0B
496 instruction_size = 2,
497 instruction_offset = 0,
498 next_instruction_offset = 2
499 };
500
501 // Insert illegal opcode as specific address
502 static void insert(address code_pos);
503 };
504
505 // return instruction that does not pop values of the stack
506 class NativeReturn: public NativeInstruction {
507 public:
508 enum Intel_specific_constants {
509 instruction_code = 0xC3,
510 instruction_size = 1,
511 instruction_offset = 0,
512 next_instruction_offset = 1
513 };
514 };
515
516 // return instruction that does pop values of the stack
517 class NativeReturnX: public NativeInstruction {
518 public:
519 enum Intel_specific_constants {
520 instruction_code = 0xC2,
521 instruction_size = 2,
522 instruction_offset = 0,
523 next_instruction_offset = 2
524 };
525 };
526
527 // Simple test vs memory
528 class NativeTstRegMem: public NativeInstruction {
529 public:
530 enum Intel_specific_constants {
531 instruction_rex_prefix_mask = 0xF0,
532 instruction_rex_prefix = Assembler::REX,
533 instruction_rex_b_prefix = Assembler::REX_B,
534 instruction_code_memXregl = 0x85,
535 modrm_mask = 0x38, // select reg from the ModRM byte
536 modrm_reg = 0x00 // rax
537 };
538 };
539
540 inline bool NativeInstruction::is_illegal() { return (short)int_at(0) == (short)NativeIllegalInstruction::instruction_code; }
541 inline bool NativeInstruction::is_call() { return ubyte_at(0) == NativeCall::instruction_code; }
542 inline bool NativeInstruction::is_call_reg() { return ubyte_at(0) == NativeCallReg::instruction_code ||
543 (ubyte_at(1) == NativeCallReg::instruction_code &&
544 (ubyte_at(0) == Assembler::REX || ubyte_at(0) == Assembler::REX_B)); }
545 inline bool NativeInstruction::is_return() { return ubyte_at(0) == NativeReturn::instruction_code ||
546 ubyte_at(0) == NativeReturnX::instruction_code; }
547 inline bool NativeInstruction::is_jump() { return ubyte_at(0) == NativeJump::instruction_code ||
548 ubyte_at(0) == 0xEB; /* short jump */ }
549 inline bool NativeInstruction::is_jump_reg() {
550 int pos = 0;
551 if (ubyte_at(0) == Assembler::REX_B) pos = 1;
552 return ubyte_at(pos) == 0xFF && (ubyte_at(pos + 1) & 0xF0) == 0xE0;
553 }
554 inline bool NativeInstruction::is_cond_jump() { return (int_at(0) & 0xF0FF) == 0x800F /* long jump */ ||
555 (ubyte_at(0) & 0xF0) == 0x70; /* short jump */ }
556 inline bool NativeInstruction::is_safepoint_poll() {
557 const bool has_rex_prefix = ubyte_at(0) == NativeTstRegMem::instruction_rex_b_prefix;
558 const int test_offset = has_rex2_prefix() ? 2 : (has_rex_prefix ? 1 : 0);
559 const bool is_test_opcode = ubyte_at(test_offset) == NativeTstRegMem::instruction_code_memXregl;
560 const bool is_rax_target = (ubyte_at(test_offset + 1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg;
561 return is_test_opcode && is_rax_target;
562 }
563
564 inline bool NativeInstruction::is_mov_literal64() {
565 bool valid_rex_prefix = ubyte_at(0) == Assembler::REX_W || ubyte_at(0) == Assembler::REX_WB;
566 bool valid_rex2_prefix = ubyte_at(0) == Assembler::REX2 &&
567 (ubyte_at(1) == Assembler::REX2BIT_W ||
568 ubyte_at(1) == Assembler::REX2BIT_WB ||
569 ubyte_at(1) == Assembler::REX2BIT_WB4);
570
571 int opcode = has_rex2_prefix() ? ubyte_at(2) : ubyte_at(1);
572 return ((valid_rex_prefix || valid_rex2_prefix) && (opcode & (0xff ^ NativeMovConstReg::register_mask)) == 0xB8);
573 }
574
575 class NativePostCallNop: public NativeInstruction {
576 public:
577 enum Intel_specific_constants {
578 instruction_code = 0x0f,
579 instruction_size = 8,
580 instruction_offset = 0,
581 displacement_offset = 4
582 };
583
584 bool check() const { return int_at(0) == 0x841f0f; }
585 bool decode(int32_t& oopmap_slot, int32_t& cb_offset) const {
586 int32_t data = int_at(displacement_offset);
587 if (data == 0) {
588 return false; // no information encoded
589 }
590 cb_offset = (data & 0xffffff);
591 oopmap_slot = (data >> 24) & 0xff;
592 return true; // decoding succeeded
593 }
594 bool patch(int32_t oopmap_slot, int32_t cb_offset);
595 void make_deopt();
596 };
597
598 inline NativePostCallNop* nativePostCallNop_at(address address) {
599 NativePostCallNop* nop = (NativePostCallNop*) address;
600 if (nop->check()) {
601 return nop;
602 }
603 return nullptr;
604 }
605
606 inline NativePostCallNop* nativePostCallNop_unsafe_at(address address) {
607 NativePostCallNop* nop = (NativePostCallNop*) address;
608 assert(nop->check(), "");
609 return nop;
610 }
611
612 class NativeDeoptInstruction: public NativeInstruction {
613 public:
614 enum Intel_specific_constants {
615 instruction_prefix = 0x0F,
616 instruction_code = 0xFF,
617 instruction_size = 3,
618 instruction_offset = 0,
619 };
620
621 address instruction_address() const { return addr_at(instruction_offset); }
622 address next_instruction_address() const { return addr_at(instruction_size); }
623
624 void verify();
625
626 static bool is_deopt_at(address instr) {
627 return ((*instr) & 0xFF) == NativeDeoptInstruction::instruction_prefix &&
628 ((*(instr+1)) & 0xFF) == NativeDeoptInstruction::instruction_code;
629 }
630
631 // MT-safe patching
632 static void insert(address code_pos, bool invalidate = true);
633 };
634
635 #endif // CPU_X86_NATIVEINST_X86_HPP