📄 assembler-ia32.h.svn-base
字号:
// Copyright (c) 1994-2006 Sun Microsystems Inc.// All Rights Reserved.//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// - Redistributions of source code must retain the above copyright notice,// this list of conditions and the following disclaimer.//// - Redistribution in binary form must reproduce the above copyright// notice, this list of conditions and the following disclaimer in the// documentation and/or other materials provided with the distribution.//// - Neither the name of Sun Microsystems or the names of contributors may// be used to endorse or promote products derived from this software without// specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.// The original source code covered by the above license above has been// modified significantly by Google Inc.// Copyright 2006-2008 the V8 project authors. All rights reserved.// A light-weight IA32 Assembler.#ifndef V8_ASSEMBLER_IA32_H_#define V8_ASSEMBLER_IA32_H_namespace v8 { namespace internal {// CPU Registers.//// 1) We would prefer to use an enum, but enum values are assignment-// compatible with int, which has caused code-generation bugs.//// 2) We would prefer to use a class instead of a struct but we don't like// the register initialization to depend on the particular initialization// order (which appears to be different on OS X, Linux, and Windows for the// installed versions of C++ we tried). Using a struct permits C-style// "initialization". Also, the Register objects cannot be const as this// forces initialization stubs in MSVC, making us dependent on initialization// order.//// 3) By not using an enum, we are possibly preventing the compiler from// doing certain constant folds, which may significantly reduce the// code generated for some assembly instructions (because they boil down// to a few constants). If this is a problem, we could change the code// such that we use an enum in optimized mode, and the struct in debug// mode. This way we get the compile-time error checking in debug mode// and best performance in optimized code.//struct Register { bool is_valid() const { return 0 <= code_ && code_ < 8; } bool is(Register reg) const { return code_ == reg.code_; } int code() const { ASSERT(is_valid()); return code_; } int bit() const { ASSERT(is_valid()); return 1 << code_; } // (unfortunately we can't make this private in a struct) int code_;};extern Register eax;extern Register ecx;extern Register edx;extern Register ebx;extern Register esp;extern Register ebp;extern Register esi;extern Register edi;extern Register no_reg;struct XMMRegister { bool is_valid() const { return 0 <= code_ && code_ < 2; } // currently int code() const { ASSERT(is_valid()); return code_; } int code_;};extern XMMRegister xmm0;extern XMMRegister xmm1;extern XMMRegister xmm2;extern XMMRegister xmm3;extern XMMRegister xmm4;extern XMMRegister xmm5;extern XMMRegister xmm6;extern XMMRegister xmm7;enum Condition { // any value < 0 is considered no_condition no_condition = -1, overflow = 0, no_overflow = 1, below = 2, above_equal = 3, equal = 4, not_equal = 5, below_equal = 6, above = 7, sign = 8, not_sign = 9, parity_even = 10, parity_odd = 11, less = 12, greater_equal = 13, less_equal = 14, greater = 15, // aliases zero = equal, not_zero = not_equal, negative = sign, positive = not_sign};// Returns the equivalent of !cc.// Negation of the default no_condition (-1) results in a non-default// no_condition value (-2). As long as tests for no_condition check// for condition < 0, this will work as expected.inline Condition NegateCondition(Condition cc);// Corresponds to transposing the operands of a comparison.inline Condition ReverseCondition(Condition cc) { switch (cc) { case below: return above; case above: return below; case above_equal: return below_equal; case below_equal: return above_equal; case less: return greater; case greater: return less; case greater_equal: return less_equal; case less_equal: return greater_equal; default: return cc; };}enum Hint { no_hint = 0, not_taken = 0x2e, taken = 0x3e};// -----------------------------------------------------------------------------// Machine instruction Immediatesclass Immediate BASE_EMBEDDED { public: inline explicit Immediate(int x); inline explicit Immediate(const char* s); inline explicit Immediate(const ExternalReference& ext); inline explicit Immediate(Handle<Object> handle); inline explicit Immediate(Smi* value); bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; } bool is_int8() const { return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE; } private: int x_; RelocInfo::Mode rmode_; friend class Assembler;};// -----------------------------------------------------------------------------// Machine instruction Operandsenum ScaleFactor { times_1 = 0, times_2 = 1, times_4 = 2, times_8 = 3};class Operand BASE_EMBEDDED { public: // reg INLINE(explicit Operand(Register reg)); // [disp/r] INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode)); // disp only must always be relocated // [base + disp/r] explicit Operand(Register base, int32_t disp, RelocInfo::Mode rmode = RelocInfo::NONE); // [base + index*scale + disp/r] explicit Operand(Register base, Register index, ScaleFactor scale, int32_t disp, RelocInfo::Mode rmode = RelocInfo::NONE); // [index*scale + disp/r] explicit Operand(Register index, ScaleFactor scale, int32_t disp, RelocInfo::Mode rmode = RelocInfo::NONE); static Operand StaticVariable(const ExternalReference& ext) { return Operand(reinterpret_cast<int32_t>(ext.address()), RelocInfo::EXTERNAL_REFERENCE); } static Operand StaticArray(Register index, ScaleFactor scale, const ExternalReference& arr) { return Operand(index, scale, reinterpret_cast<int32_t>(arr.address()), RelocInfo::EXTERNAL_REFERENCE); } // Returns true if this Operand is a wrapper for the specified register. bool is_reg(Register reg) const; private: // Mutable because reg in ModR/M byte is set by Assembler via set_reg(). mutable byte buf_[6]; // The number of bytes in buf_. unsigned int len_; // Only valid if len_ > 4. RelocInfo::Mode rmode_; inline void set_modrm(int mod, // reg == 0 Register rm); inline void set_sib(ScaleFactor scale, Register index, Register base); inline void set_disp8(int8_t disp); inline void set_dispr(int32_t disp, RelocInfo::Mode rmode); inline void set_reg(Register reg) const; friend class Assembler;};// -----------------------------------------------------------------------------// A Displacement describes the 32bit immediate field of an instruction which// may be used together with a Label in order to refer to a yet unknown code// position. Displacements stored in the instruction stream are used to describe// the instruction and to chain a list of instructions using the same Label.// A Displacement contains 2 different fields://// next field: position of next displacement in the chain (0 = end of list)// type field: instruction type//// A next value of null (0) indicates the end of a chain (note that there can// be no displacement at position zero, because there is always at least one// instruction byte before the displacement).//// Displacement _data field layout//// |31.....1| ......0|// [ next | type |class Displacement BASE_EMBEDDED { public: enum Type { UNCONDITIONAL_JUMP, OTHER }; int data() const { return data_; } Type type() const { return TypeField::decode(data_); } void next(Label* L) const { int n = NextField::decode(data_); n > 0 ? L->link_to(n) : L->Unuse(); } void link_to(Label* L) { init(L, type()); } explicit Displacement(int data) { data_ = data; } Displacement(Label* L, Type type) { init(L, type); } void print() { PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"), NextField::decode(data_)); } private: int data_; class TypeField: public BitField<Type, 0, 1> {}; class NextField: public BitField<int, 1, 32-1> {}; void init(Label* L, Type type);};// CpuFeatures keeps track of which features are supported by the target CPU.// Supported features must be enabled by a Scope before use.// Example:// if (CpuFeatures::IsSupported(SSE2)) {// CpuFeatures::Scope fscope(SSE2);// // Generate SSE2 floating point code.// } else {// // Generate standard x87 floating point code.// }class CpuFeatures : public AllStatic { public: // Feature flags bit positions. They are mostly based on the CPUID spec. // (We assign CPUID itself to one of the currently reserved bits -- // feel free to change this if needed.) enum Feature { SSE2 = 26, CMOV = 15, RDTSC = 4, CPUID = 10 }; // Detect features of the target CPU. Set safe defaults if the serializer // is enabled (snapshots must be portable). static void Probe(); // Check whether a feature is supported by the target CPU. static bool IsSupported(Feature f) { return supported_ & (1 << f); } // Check whether a feature is currently enabled. static bool IsEnabled(Feature f) { return enabled_ & (1 << f); } // Enable a specified feature within a scope. class Scope BASE_EMBEDDED {#ifdef DEBUG public: explicit Scope(Feature f) { ASSERT(CpuFeatures::IsSupported(f)); old_enabled_ = CpuFeatures::enabled_; CpuFeatures::enabled_ |= (1 << f); } ~Scope() { CpuFeatures::enabled_ = old_enabled_; } private: uint32_t old_enabled_;#else public: explicit Scope(Feature f) {}#endif }; private: static uint32_t supported_; static uint32_t enabled_;};class Assembler : public Malloced { private: // The relocation writer's position is kGap bytes below the end of // the generated instructions. This leaves enough space for the // longest possible ia32 instruction (17 bytes as of 9/26/06) and // allows for a single, fast space check per instruction. static const int kGap = 32; public: // Create an assembler. Instructions and relocation information are emitted // into a buffer, with the instructions starting from the beginning and the // relocation information starting from the end of the buffer. See CodeDesc // for a detailed comment on the layout (globals.h). // // If the provided buffer is NULL, the assembler allocates and grows its own // buffer, and buffer_size determines the initial buffer size. The buffer is // owned by the assembler and deallocated upon destruction of the assembler. // // If the provided buffer is not NULL, the assembler uses the provided buffer // for code generation and assumes its size to be buffer_size. If the buffer // is too small, a fatal error occurs. No deallocation of the buffer is done // upon destruction of the assembler. Assembler(void* buffer, int buffer_size); ~Assembler(); // GetCode emits any pending (non-emitted) code and fills the descriptor // desc. GetCode() is idempotent; it returns the same result if no other // Assembler functions are invoked inbetween GetCode() calls. void GetCode(CodeDesc* desc); // Read/Modify the code target in the branch/call instruction at pc. inline static Address target_address_at(Address pc); inline static void set_target_address_at(Address pc, Address target); // Distance between the address of the code target in the call instruction // and the return address static const int kTargetAddrToReturnAddrDist = kPointerSize; // --------------------------------------------------------------------------- // Code generation //
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -