/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef jit_x86_shared_Patching_x86_shared_h #define jit_x86_shared_Patching_x86_shared_h namespace js { namespace jit { namespace X86Encoding { inline void* GetPointer(const void* where) { void* res; memcpy(&res, (const char*)where - sizeof(void*), sizeof(void*)); return res; } inline void SetPointer(void* where, const void* value) { memcpy((char*)where - sizeof(void*), &value, sizeof(void*)); } inline int32_t GetInt32(const void* where) { int32_t res; memcpy(&res, (const char*)where - sizeof(int32_t), sizeof(int32_t)); return res; } inline void SetInt32(void* where, int32_t value, uint32_t trailing = 0) { memcpy((char*)where - trailing - sizeof(int32_t), &value, sizeof(int32_t)); } inline void SetRel32(void* from, void* to, uint32_t trailing = 0) { intptr_t offset = reinterpret_cast(to) - reinterpret_cast(from); MOZ_ASSERT(offset == static_cast(offset), "offset is too great for a 32-bit relocation"); if (offset != static_cast(offset)) { MOZ_CRASH("offset is too great for a 32-bit relocation"); } SetInt32(from, offset, trailing); } inline void* GetRel32Target(void* where) { int32_t rel = GetInt32(where); return (char*)where + rel; } // JmpSrc represents a positive offset within a code buffer, or an uninitialized // value. Lots of code depends on uninitialized JmpSrc holding the value -1, on // -1 being a legal value of JmpSrc, and on being able to initialize a JmpSrc // with the value -1. // // The value of the `offset` is always positive and <= MaxCodeBytesPerProcess, // see ProcessExecutableMemory.h. The latter quantity in turn must fit in an // i32. But we further require that the value is not precisely INT32_MAX, so as // to allow the JmpSrc value -1 to mean "uninitialized" without ambiguity. // // The quantity `trailing` denotes the number of bytes of data that follow the // patch field in the instruction. The offset points to the end of the // instruction as per normal. The information about trailing bytes is needed // separately from the offset to correctly patch instructions that have // immediates trailing the patch field (eg CMPSS and CMPSD). Currently the only // allowed values for `trailing` are 0 and 1. static_assert(MaxCodeBytesPerProcess < size_t(INT32_MAX), "Invariant"); class JmpSrc { public: JmpSrc() : offset_(INT32_MAX), trailing_(0) {} explicit JmpSrc(int32_t offset) : offset_(offset), trailing_(0) { // offset -1 is stored as INT32_MAX MOZ_ASSERT(offset == -1 || (offset >= 0 && offset < INT32_MAX)); } JmpSrc(int32_t offset, uint32_t trailing) : offset_(offset), trailing_(trailing) { // Disallow offset -1 in this situation, it does not apply. MOZ_ASSERT(offset >= 0 && offset < INT32_MAX); MOZ_ASSERT(trailing <= 1); } int32_t offset() const { return offset_ == INT32_MAX ? -1 : int32_t(offset_); } uint32_t trailing() const { return trailing_; } private: uint32_t offset_ : 31; uint32_t trailing_ : 1; }; class JmpDst { public: explicit JmpDst(int32_t offset) : offset_(offset) {} int32_t offset() const { return offset_; } private: int32_t offset_; }; inline bool CanRelinkJump(void* from, void* to) { intptr_t offset = static_cast(to) - static_cast(from); return (offset == static_cast(offset)); } } // namespace X86Encoding } // namespace jit } // namespace js #endif /* jit_x86_shared_Patching_x86_shared_h */