nativeInst_x86.cpp revision 1472
609N/A * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. 609N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 609N/A * This code is free software; you can redistribute it and/or modify it 609N/A * under the terms of the GNU General Public License version 2 only, as 609N/A * published by the Free Software Foundation. 609N/A * This code is distributed in the hope that it will be useful, but WITHOUT 609N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 609N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 609N/A * version 2 for more details (a copy is included in the LICENSE file that 609N/A * accompanied this code). 609N/A * You should have received a copy of the GNU General Public License version 609N/A * 2 along with this work; if not, write to the Free Software Foundation, 609N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 609N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 609N/A#
include "incls/_precompiled.incl" 609N/A // Make sure code pattern is actually a call imm32 instruction. fatal(
"not a call disp32");
// Getting the destination of a call isn't safe because that call can // be getting patched while you're calling this. There's only special // places where this can be called but not automatically verifiable by // checking which locks are held. The solution is true atomic patching // Inserts a native call instruction at a given pc // MT-safe patching of a call instruction. // First patches first word of instruction to two jmp's that jmps to them // selfs (spinlock). Then patches the last byte, and then atomicly replaces // the jmp's with the first 4 byte of the new instruction. // First patch dummy jmp in place patch[0] =
0xEB;
// jmp rel8 patch[
1] =
0xFE;
// jmp to self // First patch dummy jmp in place // Invalidate. Opteron requires a flush after every write. // Similar to replace_mt_safe, but just changes the destination. The // important thing is that free-running threads are able to execute this // call instruction at all times. If the displacement field is aligned // we can simply rely on atomicity of 32-bit writes to make sure other threads // will see no intermediate states. Otherwise, the first two bytes of the // call are guaranteed to be aligned, and can be atomically patched to a // self-loop to guard the instruction while we change the other bytes. // We cannot rely on locks here, since the free-running threads must run at // Used in the runtime linkage of calls; see class CompiledIC. // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) // Make sure patching code is locked. No two threads can patch at the same // time but one may be executing this code. // Both C1 and C2 should now be generating code which aligns the patched address // to be within a single cache line except that C1 does not do the alignment on // Simple case: The destination lies within a single cache line. // Tricky case: The instruction prefix lies within a single cache line. // First patch dummy jump in place: // Invalidate. Opteron requires a flush after every write. // (Note: We assume any reader which has already started to read // the unpatched call will completely read the whole unpatched call // without seeing the next writes we are about to make.) // Next, patch the last three bytes: // Invalidate. Opteron requires a flush after every write. // (Note: We assume that any reader which reads the opcode we are // about to repatch will also read the writes we just made.) // Finally, overwrite the jump: // Invalidate. Opteron requires a flush after every write. // Impossible: One or the other must be atomically writable. // make sure code pattern is actually a mov reg64, imm64 instruction fatal(
"not a REX.W[B] mov reg64, imm64");
// make sure code pattern is actually a mov reg, imm32 instruction //------------------------------------------------------------------- // First check to see if we have a (prefixed or not) xor // Now look for the real instruction and the many prefix/size specifiers. off++;
// Not SSE instructions fatal(
"should have skipped instruction_operandsize_prefix");
fatal(
"should have skipped instruction_extended_prefix");
// If there is an SIB then instruction is longer than expected fatal(
"should have skipped xor lead in");
fatal(
"not a NativeMovRegMem");
// nnnn(r12|rsp) isn't coded as simple mod/rm since that is // the encoding to use an SIB byte. Which will have the nnnn // nnnn(r12|rsp) isn't coded as simple mod/rm since that is // the encoding to use an SIB byte. Which will have the nnnn // make sure code pattern is actually a mov [reg+offset], reg instruction fatal (
"not a mov [reg+offs], reg instruction");
//------------------------------------------------------------------- // make sure code pattern is actually a mov [reg+offset], reg instruction fatal (
"not a lea reg, [reg+offs] instruction");
//-------------------------------------------------------------------------------- fatal(
"not a jump instruction");
// Patching to not_entrant can happen while activations of the method are // in use. The patching in that instance must happen only when certain // alignment restrictions are true. These guarantees check those // Must be wordSize aligned "illegal address for code patching 2");
// First 5 bytes must be within the same cache line - 4827828 "illegal address for code patching 3");
// MT safe inserting of a jump over an unknown instruction sequence (used by nmethod::makeZombie) // The problem: jmp <dest> is a 5-byte instruction. Atomical write can be only with 4 bytes. // First patches the first word atomically to be a jump to itself. // Then patches the last byte and then atomically patches the first word (4-bytes), // thus inserting the desired jump // This code is mt-safe with the following conditions: entry point is 4 byte aligned, // entry point is in same cache line as unverified entry point, and the instruction being // patched is >= 5 byte (size of patch). // In C2 the 5+ byte sized instruction is enforced by code in MachPrologNode::emit. // In C1 the restriction is enforced by CodeEmitter::method_entry // complete jump instruction (to be inserted) is in code_buffer; // Can't call nativeJump_at() because it's asserts jump exists //First patch dummy jmp in place patch[0] =
0xEB;
// jmp rel8 patch[
1] =
0xFE;
// jmp to self // First patch dummy jmp in place // Patch 5th byte (from jump instruction) // Patch bytes 0-3 (from jump instruction) // Invalidate. Opteron requires a flush after every write. // MT-safe patching of a long jump instruction. // First patches first word of instruction to two jmp's that jmps to them // selfs (spinlock). Then patches the last byte, and then atomicly replaces // the jmp's with the first 4 byte of the new instruction. patch[0] =
0xEB;
// jmp rel8 patch[
1] =
0xFE;
// jmp to self // First patch dummy jmp in place return (*(
int32_t*)
this &
0xff) ==
0xcc;