| // 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 2012 the V8 project authors. All rights reserved. | 
 |  | 
 | // A light-weight ARM Assembler | 
 | // Generates user mode instructions for the ARM architecture up to version 5 | 
 |  | 
 | #ifndef V8_ARM_ASSEMBLER_ARM_H_ | 
 | #define V8_ARM_ASSEMBLER_ARM_H_ | 
 | #include <stdio.h> | 
 | #include "assembler.h" | 
 | #include "constants-arm.h" | 
 | #include "serialize.h" | 
 |  | 
 | namespace v8 { | 
 | namespace internal { | 
 |  | 
 | // CpuFeatures keeps track of which features are supported by the target CPU. | 
 | // Supported features must be enabled by a CpuFeatureScope before use. | 
 | class CpuFeatures : public AllStatic { | 
 |  public: | 
 |   // Detect features of the target CPU. Set safe defaults if the serializer | 
 |   // is enabled (snapshots must be portable). | 
 |   static void Probe(); | 
 |  | 
 |   // Display target use when compiling. | 
 |   static void PrintTarget(); | 
 |  | 
 |   // Display features. | 
 |   static void PrintFeatures(); | 
 |  | 
 |   // Check whether a feature is supported by the target CPU. | 
 |   static bool IsSupported(CpuFeature f) { | 
 |     ASSERT(initialized_); | 
 |     return (supported_ & (1u << f)) != 0; | 
 |   } | 
 |  | 
 |   static bool IsFoundByRuntimeProbingOnly(CpuFeature f) { | 
 |     ASSERT(initialized_); | 
 |     return (found_by_runtime_probing_only_ & | 
 |             (static_cast<uint64_t>(1) << f)) != 0; | 
 |   } | 
 |  | 
 |   static bool IsSafeForSnapshot(CpuFeature f) { | 
 |     return (IsSupported(f) && | 
 |             (!Serializer::enabled() || !IsFoundByRuntimeProbingOnly(f))); | 
 |   } | 
 |  | 
 |   static unsigned cache_line_size() { return cache_line_size_; } | 
 |  | 
 |  private: | 
 | #ifdef DEBUG | 
 |   static bool initialized_; | 
 | #endif | 
 |   static unsigned supported_; | 
 |   static unsigned found_by_runtime_probing_only_; | 
 |   static unsigned cache_line_size_; | 
 |  | 
 |   friend class ExternalReference; | 
 |   friend class PlatformFeatureScope; | 
 |   DISALLOW_COPY_AND_ASSIGN(CpuFeatures); | 
 | }; | 
 |  | 
 |  | 
 | // 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. | 
 |  | 
 | // Core register | 
 | struct Register { | 
 |   static const int kNumRegisters = 16; | 
 |   static const int kMaxNumAllocatableRegisters = 8; | 
 |   static const int kSizeInBytes = 4; | 
 |  | 
 |   inline static int NumAllocatableRegisters(); | 
 |  | 
 |   static int ToAllocationIndex(Register reg) { | 
 |     ASSERT(reg.code() < kMaxNumAllocatableRegisters); | 
 |     return reg.code(); | 
 |   } | 
 |  | 
 |   static Register FromAllocationIndex(int index) { | 
 |     ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters); | 
 |     return from_code(index); | 
 |   } | 
 |  | 
 |   static const char* AllocationIndexToString(int index) { | 
 |     ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters); | 
 |     const char* const names[] = { | 
 |       "r0", | 
 |       "r1", | 
 |       "r2", | 
 |       "r3", | 
 |       "r4", | 
 |       "r5", | 
 |       "r6", | 
 |       "r7", | 
 |     }; | 
 |     return names[index]; | 
 |   } | 
 |  | 
 |   static Register from_code(int code) { | 
 |     Register r = { code }; | 
 |     return r; | 
 |   } | 
 |  | 
 |   bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; } | 
 |   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_; | 
 |   } | 
 |  | 
 |   void set_code(int code) { | 
 |     code_ = code; | 
 |     ASSERT(is_valid()); | 
 |   } | 
 |  | 
 |   // Unfortunately we can't make this private in a struct. | 
 |   int code_; | 
 | }; | 
 |  | 
 | // These constants are used in several locations, including static initializers | 
 | const int kRegister_no_reg_Code = -1; | 
 | const int kRegister_r0_Code = 0; | 
 | const int kRegister_r1_Code = 1; | 
 | const int kRegister_r2_Code = 2; | 
 | const int kRegister_r3_Code = 3; | 
 | const int kRegister_r4_Code = 4; | 
 | const int kRegister_r5_Code = 5; | 
 | const int kRegister_r6_Code = 6; | 
 | const int kRegister_r7_Code = 7; | 
 | const int kRegister_r8_Code = 8; | 
 | const int kRegister_r9_Code = 9; | 
 | const int kRegister_r10_Code = 10; | 
 | const int kRegister_fp_Code = 11; | 
 | const int kRegister_ip_Code = 12; | 
 | const int kRegister_sp_Code = 13; | 
 | const int kRegister_lr_Code = 14; | 
 | const int kRegister_pc_Code = 15; | 
 |  | 
 | const Register no_reg = { kRegister_no_reg_Code }; | 
 |  | 
 | const Register r0  = { kRegister_r0_Code }; | 
 | const Register r1  = { kRegister_r1_Code }; | 
 | const Register r2  = { kRegister_r2_Code }; | 
 | const Register r3  = { kRegister_r3_Code }; | 
 | const Register r4  = { kRegister_r4_Code }; | 
 | const Register r5  = { kRegister_r5_Code }; | 
 | const Register r6  = { kRegister_r6_Code }; | 
 | const Register r7  = { kRegister_r7_Code }; | 
 | // Used as context register. | 
 | const Register r8  = { kRegister_r8_Code }; | 
 | // Used as lithium codegen scratch register. | 
 | const Register r9  = { kRegister_r9_Code }; | 
 | // Used as roots register. | 
 | const Register r10 = { kRegister_r10_Code }; | 
 | const Register fp  = { kRegister_fp_Code }; | 
 | const Register ip  = { kRegister_ip_Code }; | 
 | const Register sp  = { kRegister_sp_Code }; | 
 | const Register lr  = { kRegister_lr_Code }; | 
 | const Register pc  = { kRegister_pc_Code }; | 
 |  | 
 | // Single word VFP register. | 
 | struct SwVfpRegister { | 
 |   static const int kSizeInBytes = 4; | 
 |   bool is_valid() const { return 0 <= code_ && code_ < 32; } | 
 |   bool is(SwVfpRegister reg) const { return code_ == reg.code_; } | 
 |   int code() const { | 
 |     ASSERT(is_valid()); | 
 |     return code_; | 
 |   } | 
 |   int bit() const { | 
 |     ASSERT(is_valid()); | 
 |     return 1 << code_; | 
 |   } | 
 |   void split_code(int* vm, int* m) const { | 
 |     ASSERT(is_valid()); | 
 |     *m = code_ & 0x1; | 
 |     *vm = code_ >> 1; | 
 |   } | 
 |  | 
 |   int code_; | 
 | }; | 
 |  | 
 |  | 
 | // Double word VFP register. | 
 | struct DwVfpRegister { | 
 |   static const int kMaxNumRegisters = 32; | 
 |   // A few double registers are reserved: one as a scratch register and one to | 
 |   // hold 0.0, that does not fit in the immediate field of vmov instructions. | 
 |   //  d14: 0.0 | 
 |   //  d15: scratch register. | 
 |   static const int kNumReservedRegisters = 2; | 
 |   static const int kMaxNumAllocatableRegisters = kMaxNumRegisters - | 
 |       kNumReservedRegisters; | 
 |   static const int kSizeInBytes = 8; | 
 |  | 
 |   // Note: the number of registers can be different at snapshot and run-time. | 
 |   // Any code included in the snapshot must be able to run both with 16 or 32 | 
 |   // registers. | 
 |   inline static int NumRegisters(); | 
 |   inline static int NumAllocatableRegisters(); | 
 |  | 
 |   inline static int ToAllocationIndex(DwVfpRegister reg); | 
 |   static const char* AllocationIndexToString(int index); | 
 |   inline static DwVfpRegister FromAllocationIndex(int index); | 
 |  | 
 |   static DwVfpRegister from_code(int code) { | 
 |     DwVfpRegister r = { code }; | 
 |     return r; | 
 |   } | 
 |  | 
 |   bool is_valid() const { | 
 |     return 0 <= code_ && code_ < kMaxNumRegisters; | 
 |   } | 
 |   bool is(DwVfpRegister reg) const { return code_ == reg.code_; } | 
 |   int code() const { | 
 |     ASSERT(is_valid()); | 
 |     return code_; | 
 |   } | 
 |   int bit() const { | 
 |     ASSERT(is_valid()); | 
 |     return 1 << code_; | 
 |   } | 
 |   void split_code(int* vm, int* m) const { | 
 |     ASSERT(is_valid()); | 
 |     *m = (code_ & 0x10) >> 4; | 
 |     *vm = code_ & 0x0F; | 
 |   } | 
 |  | 
 |   int code_; | 
 | }; | 
 |  | 
 |  | 
 | typedef DwVfpRegister DoubleRegister; | 
 |  | 
 |  | 
 | // Double word VFP register d0-15. | 
 | struct LowDwVfpRegister { | 
 |  public: | 
 |   static const int kMaxNumLowRegisters = 16; | 
 |   operator DwVfpRegister() const { | 
 |     DwVfpRegister r = { code_ }; | 
 |     return r; | 
 |   } | 
 |   static LowDwVfpRegister from_code(int code) { | 
 |     LowDwVfpRegister r = { code }; | 
 |     return r; | 
 |   } | 
 |  | 
 |   bool is_valid() const { | 
 |     return 0 <= code_ && code_ < kMaxNumLowRegisters; | 
 |   } | 
 |   bool is(DwVfpRegister reg) const { return code_ == reg.code_; } | 
 |   bool is(LowDwVfpRegister reg) const { return code_ == reg.code_; } | 
 |   int code() const { | 
 |     ASSERT(is_valid()); | 
 |     return code_; | 
 |   } | 
 |   SwVfpRegister low() const { | 
 |     SwVfpRegister reg; | 
 |     reg.code_ = code_ * 2; | 
 |  | 
 |     ASSERT(reg.is_valid()); | 
 |     return reg; | 
 |   } | 
 |   SwVfpRegister high() const { | 
 |     SwVfpRegister reg; | 
 |     reg.code_ = (code_ * 2) + 1; | 
 |  | 
 |     ASSERT(reg.is_valid()); | 
 |     return reg; | 
 |   } | 
 |  | 
 |   int code_; | 
 | }; | 
 |  | 
 |  | 
 | // Quad word NEON register. | 
 | struct QwNeonRegister { | 
 |   static const int kMaxNumRegisters = 16; | 
 |  | 
 |   static QwNeonRegister from_code(int code) { | 
 |     QwNeonRegister r = { code }; | 
 |     return r; | 
 |   } | 
 |  | 
 |   bool is_valid() const { | 
 |     return (0 <= code_) && (code_ < kMaxNumRegisters); | 
 |   } | 
 |   bool is(QwNeonRegister reg) const { return code_ == reg.code_; } | 
 |   int code() const { | 
 |     ASSERT(is_valid()); | 
 |     return code_; | 
 |   } | 
 |   void split_code(int* vm, int* m) const { | 
 |     ASSERT(is_valid()); | 
 |     *m = (code_ & 0x10) >> 4; | 
 |     *vm = code_ & 0x0F; | 
 |   } | 
 |  | 
 |   int code_; | 
 | }; | 
 |  | 
 |  | 
 | typedef QwNeonRegister QuadRegister; | 
 |  | 
 |  | 
 | // Support for the VFP registers s0 to s31 (d0 to d15). | 
 | // Note that "s(N):s(N+1)" is the same as "d(N/2)". | 
 | const SwVfpRegister s0  = {  0 }; | 
 | const SwVfpRegister s1  = {  1 }; | 
 | const SwVfpRegister s2  = {  2 }; | 
 | const SwVfpRegister s3  = {  3 }; | 
 | const SwVfpRegister s4  = {  4 }; | 
 | const SwVfpRegister s5  = {  5 }; | 
 | const SwVfpRegister s6  = {  6 }; | 
 | const SwVfpRegister s7  = {  7 }; | 
 | const SwVfpRegister s8  = {  8 }; | 
 | const SwVfpRegister s9  = {  9 }; | 
 | const SwVfpRegister s10 = { 10 }; | 
 | const SwVfpRegister s11 = { 11 }; | 
 | const SwVfpRegister s12 = { 12 }; | 
 | const SwVfpRegister s13 = { 13 }; | 
 | const SwVfpRegister s14 = { 14 }; | 
 | const SwVfpRegister s15 = { 15 }; | 
 | const SwVfpRegister s16 = { 16 }; | 
 | const SwVfpRegister s17 = { 17 }; | 
 | const SwVfpRegister s18 = { 18 }; | 
 | const SwVfpRegister s19 = { 19 }; | 
 | const SwVfpRegister s20 = { 20 }; | 
 | const SwVfpRegister s21 = { 21 }; | 
 | const SwVfpRegister s22 = { 22 }; | 
 | const SwVfpRegister s23 = { 23 }; | 
 | const SwVfpRegister s24 = { 24 }; | 
 | const SwVfpRegister s25 = { 25 }; | 
 | const SwVfpRegister s26 = { 26 }; | 
 | const SwVfpRegister s27 = { 27 }; | 
 | const SwVfpRegister s28 = { 28 }; | 
 | const SwVfpRegister s29 = { 29 }; | 
 | const SwVfpRegister s30 = { 30 }; | 
 | const SwVfpRegister s31 = { 31 }; | 
 |  | 
 | const DwVfpRegister no_dreg = { -1 }; | 
 | const LowDwVfpRegister d0 = { 0 }; | 
 | const LowDwVfpRegister d1 = { 1 }; | 
 | const LowDwVfpRegister d2 = { 2 }; | 
 | const LowDwVfpRegister d3 = { 3 }; | 
 | const LowDwVfpRegister d4 = { 4 }; | 
 | const LowDwVfpRegister d5 = { 5 }; | 
 | const LowDwVfpRegister d6 = { 6 }; | 
 | const LowDwVfpRegister d7 = { 7 }; | 
 | const LowDwVfpRegister d8 = { 8 }; | 
 | const LowDwVfpRegister d9 = { 9 }; | 
 | const LowDwVfpRegister d10 = { 10 }; | 
 | const LowDwVfpRegister d11 = { 11 }; | 
 | const LowDwVfpRegister d12 = { 12 }; | 
 | const LowDwVfpRegister d13 = { 13 }; | 
 | const LowDwVfpRegister d14 = { 14 }; | 
 | const LowDwVfpRegister d15 = { 15 }; | 
 | const DwVfpRegister d16 = { 16 }; | 
 | const DwVfpRegister d17 = { 17 }; | 
 | const DwVfpRegister d18 = { 18 }; | 
 | const DwVfpRegister d19 = { 19 }; | 
 | const DwVfpRegister d20 = { 20 }; | 
 | const DwVfpRegister d21 = { 21 }; | 
 | const DwVfpRegister d22 = { 22 }; | 
 | const DwVfpRegister d23 = { 23 }; | 
 | const DwVfpRegister d24 = { 24 }; | 
 | const DwVfpRegister d25 = { 25 }; | 
 | const DwVfpRegister d26 = { 26 }; | 
 | const DwVfpRegister d27 = { 27 }; | 
 | const DwVfpRegister d28 = { 28 }; | 
 | const DwVfpRegister d29 = { 29 }; | 
 | const DwVfpRegister d30 = { 30 }; | 
 | const DwVfpRegister d31 = { 31 }; | 
 |  | 
 | const QwNeonRegister q0  = {  0 }; | 
 | const QwNeonRegister q1  = {  1 }; | 
 | const QwNeonRegister q2  = {  2 }; | 
 | const QwNeonRegister q3  = {  3 }; | 
 | const QwNeonRegister q4  = {  4 }; | 
 | const QwNeonRegister q5  = {  5 }; | 
 | const QwNeonRegister q6  = {  6 }; | 
 | const QwNeonRegister q7  = {  7 }; | 
 | const QwNeonRegister q8  = {  8 }; | 
 | const QwNeonRegister q9  = {  9 }; | 
 | const QwNeonRegister q10 = { 10 }; | 
 | const QwNeonRegister q11 = { 11 }; | 
 | const QwNeonRegister q12 = { 12 }; | 
 | const QwNeonRegister q13 = { 13 }; | 
 | const QwNeonRegister q14 = { 14 }; | 
 | const QwNeonRegister q15 = { 15 }; | 
 |  | 
 |  | 
 | // Aliases for double registers.  Defined using #define instead of | 
 | // "static const DwVfpRegister&" because Clang complains otherwise when a | 
 | // compilation unit that includes this header doesn't use the variables. | 
 | #define kFirstCalleeSavedDoubleReg d8 | 
 | #define kLastCalleeSavedDoubleReg d15 | 
 | #define kDoubleRegZero d14 | 
 | #define kScratchDoubleReg d15 | 
 |  | 
 |  | 
 | // Coprocessor register | 
 | struct CRegister { | 
 |   bool is_valid() const { return 0 <= code_ && code_ < 16; } | 
 |   bool is(CRegister creg) const { return code_ == creg.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_; | 
 | }; | 
 |  | 
 |  | 
 | const CRegister no_creg = { -1 }; | 
 |  | 
 | const CRegister cr0  = {  0 }; | 
 | const CRegister cr1  = {  1 }; | 
 | const CRegister cr2  = {  2 }; | 
 | const CRegister cr3  = {  3 }; | 
 | const CRegister cr4  = {  4 }; | 
 | const CRegister cr5  = {  5 }; | 
 | const CRegister cr6  = {  6 }; | 
 | const CRegister cr7  = {  7 }; | 
 | const CRegister cr8  = {  8 }; | 
 | const CRegister cr9  = {  9 }; | 
 | const CRegister cr10 = { 10 }; | 
 | const CRegister cr11 = { 11 }; | 
 | const CRegister cr12 = { 12 }; | 
 | const CRegister cr13 = { 13 }; | 
 | const CRegister cr14 = { 14 }; | 
 | const CRegister cr15 = { 15 }; | 
 |  | 
 |  | 
 | // Coprocessor number | 
 | enum Coprocessor { | 
 |   p0  = 0, | 
 |   p1  = 1, | 
 |   p2  = 2, | 
 |   p3  = 3, | 
 |   p4  = 4, | 
 |   p5  = 5, | 
 |   p6  = 6, | 
 |   p7  = 7, | 
 |   p8  = 8, | 
 |   p9  = 9, | 
 |   p10 = 10, | 
 |   p11 = 11, | 
 |   p12 = 12, | 
 |   p13 = 13, | 
 |   p14 = 14, | 
 |   p15 = 15 | 
 | }; | 
 |  | 
 |  | 
 | // ----------------------------------------------------------------------------- | 
 | // Machine instruction Operands | 
 |  | 
 | // Class Operand represents a shifter operand in data processing instructions | 
 | class Operand BASE_EMBEDDED { | 
 |  public: | 
 |   // immediate | 
 |   INLINE(explicit Operand(int32_t immediate, | 
 |          RelocInfo::Mode rmode = RelocInfo::NONE32)); | 
 |   INLINE(static Operand Zero()) { | 
 |     return Operand(static_cast<int32_t>(0)); | 
 |   } | 
 |   INLINE(explicit Operand(const ExternalReference& f)); | 
 |   explicit Operand(Handle<Object> handle); | 
 |   INLINE(explicit Operand(Smi* value)); | 
 |  | 
 |   // rm | 
 |   INLINE(explicit Operand(Register rm)); | 
 |  | 
 |   // rm <shift_op> shift_imm | 
 |   explicit Operand(Register rm, ShiftOp shift_op, int shift_imm); | 
 |   INLINE(static Operand SmiUntag(Register rm)) { | 
 |     return Operand(rm, ASR, kSmiTagSize); | 
 |   } | 
 |   INLINE(static Operand PointerOffsetFromSmiKey(Register key)) { | 
 |     STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | 
 |     return Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize); | 
 |   } | 
 |   INLINE(static Operand DoubleOffsetFromSmiKey(Register key)) { | 
 |     STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kDoubleSizeLog2); | 
 |     return Operand(key, LSL, kDoubleSizeLog2 - kSmiTagSize); | 
 |   } | 
 |  | 
 |   // rm <shift_op> rs | 
 |   explicit Operand(Register rm, ShiftOp shift_op, Register rs); | 
 |  | 
 |   // Return true if this is a register operand. | 
 |   INLINE(bool is_reg() const); | 
 |  | 
 |   // Return true if this operand fits in one instruction so that no | 
 |   // 2-instruction solution with a load into the ip register is necessary. If | 
 |   // the instruction this operand is used for is a MOV or MVN instruction the | 
 |   // actual instruction to use is required for this calculation. For other | 
 |   // instructions instr is ignored. | 
 |   bool is_single_instruction(const Assembler* assembler, Instr instr = 0) const; | 
 |   bool must_output_reloc_info(const Assembler* assembler) const; | 
 |  | 
 |   inline int32_t immediate() const { | 
 |     ASSERT(!rm_.is_valid()); | 
 |     return imm32_; | 
 |   } | 
 |  | 
 |   Register rm() const { return rm_; } | 
 |   Register rs() const { return rs_; } | 
 |   ShiftOp shift_op() const { return shift_op_; } | 
 |  | 
 |  private: | 
 |   Register rm_; | 
 |   Register rs_; | 
 |   ShiftOp shift_op_; | 
 |   int shift_imm_;  // valid if rm_ != no_reg && rs_ == no_reg | 
 |   int32_t imm32_;  // valid if rm_ == no_reg | 
 |   RelocInfo::Mode rmode_; | 
 |  | 
 |   friend class Assembler; | 
 | }; | 
 |  | 
 |  | 
 | // Class MemOperand represents a memory operand in load and store instructions | 
 | class MemOperand BASE_EMBEDDED { | 
 |  public: | 
 |   // [rn +/- offset]      Offset/NegOffset | 
 |   // [rn +/- offset]!     PreIndex/NegPreIndex | 
 |   // [rn], +/- offset     PostIndex/NegPostIndex | 
 |   // offset is any signed 32-bit value; offset is first loaded to register ip if | 
 |   // it does not fit the addressing mode (12-bit unsigned and sign bit) | 
 |   explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset); | 
 |  | 
 |   // [rn +/- rm]          Offset/NegOffset | 
 |   // [rn +/- rm]!         PreIndex/NegPreIndex | 
 |   // [rn], +/- rm         PostIndex/NegPostIndex | 
 |   explicit MemOperand(Register rn, Register rm, AddrMode am = Offset); | 
 |  | 
 |   // [rn +/- rm <shift_op> shift_imm]      Offset/NegOffset | 
 |   // [rn +/- rm <shift_op> shift_imm]!     PreIndex/NegPreIndex | 
 |   // [rn], +/- rm <shift_op> shift_imm     PostIndex/NegPostIndex | 
 |   explicit MemOperand(Register rn, Register rm, | 
 |                       ShiftOp shift_op, int shift_imm, AddrMode am = Offset); | 
 |   INLINE(static MemOperand PointerAddressFromSmiKey(Register array, | 
 |                                                     Register key, | 
 |                                                     AddrMode am = Offset)) { | 
 |     STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | 
 |     return MemOperand(array, key, LSL, kPointerSizeLog2 - kSmiTagSize, am); | 
 |   } | 
 |  | 
 |   void set_offset(int32_t offset) { | 
 |       ASSERT(rm_.is(no_reg)); | 
 |       offset_ = offset; | 
 |   } | 
 |  | 
 |   uint32_t offset() const { | 
 |       ASSERT(rm_.is(no_reg)); | 
 |       return offset_; | 
 |   } | 
 |  | 
 |   Register rn() const { return rn_; } | 
 |   Register rm() const { return rm_; } | 
 |   AddrMode am() const { return am_; } | 
 |  | 
 |   bool OffsetIsUint12Encodable() const { | 
 |     return offset_ >= 0 ? is_uint12(offset_) : is_uint12(-offset_); | 
 |   } | 
 |  | 
 |  private: | 
 |   Register rn_;  // base | 
 |   Register rm_;  // register offset | 
 |   int32_t offset_;  // valid if rm_ == no_reg | 
 |   ShiftOp shift_op_; | 
 |   int shift_imm_;  // valid if rm_ != no_reg && rs_ == no_reg | 
 |   AddrMode am_;  // bits P, U, and W | 
 |  | 
 |   friend class Assembler; | 
 | }; | 
 |  | 
 |  | 
 | // Class NeonMemOperand represents a memory operand in load and | 
 | // store NEON instructions | 
 | class NeonMemOperand BASE_EMBEDDED { | 
 |  public: | 
 |   // [rn {:align}]       Offset | 
 |   // [rn {:align}]!      PostIndex | 
 |   explicit NeonMemOperand(Register rn, AddrMode am = Offset, int align = 0); | 
 |  | 
 |   // [rn {:align}], rm   PostIndex | 
 |   explicit NeonMemOperand(Register rn, Register rm, int align = 0); | 
 |  | 
 |   Register rn() const { return rn_; } | 
 |   Register rm() const { return rm_; } | 
 |   int align() const { return align_; } | 
 |  | 
 |  private: | 
 |   void SetAlignment(int align); | 
 |  | 
 |   Register rn_;  // base | 
 |   Register rm_;  // register increment | 
 |   int align_; | 
 | }; | 
 |  | 
 |  | 
 | // Class NeonListOperand represents a list of NEON registers | 
 | class NeonListOperand BASE_EMBEDDED { | 
 |  public: | 
 |   explicit NeonListOperand(DoubleRegister base, int registers_count = 1); | 
 |   DoubleRegister base() const { return base_; } | 
 |   NeonListType type() const { return type_; } | 
 |  private: | 
 |   DoubleRegister base_; | 
 |   NeonListType type_; | 
 | }; | 
 |  | 
 | extern const Instr kMovLrPc; | 
 | extern const Instr kLdrPCMask; | 
 | extern const Instr kLdrPCPattern; | 
 | extern const Instr kBlxRegMask; | 
 | extern const Instr kBlxRegPattern; | 
 | extern const Instr kBlxIp; | 
 |  | 
 | extern const Instr kMovMvnMask; | 
 | extern const Instr kMovMvnPattern; | 
 | extern const Instr kMovMvnFlip; | 
 |  | 
 | extern const Instr kMovLeaveCCMask; | 
 | extern const Instr kMovLeaveCCPattern; | 
 | extern const Instr kMovwMask; | 
 | extern const Instr kMovwPattern; | 
 | extern const Instr kMovwLeaveCCFlip; | 
 |  | 
 | extern const Instr kCmpCmnMask; | 
 | extern const Instr kCmpCmnPattern; | 
 | extern const Instr kCmpCmnFlip; | 
 | extern const Instr kAddSubFlip; | 
 | extern const Instr kAndBicFlip; | 
 |  | 
 | struct VmovIndex { | 
 |   unsigned char index; | 
 | }; | 
 | const VmovIndex VmovIndexLo = { 0 }; | 
 | const VmovIndex VmovIndexHi = { 1 }; | 
 |  | 
 | class Assembler : public AssemblerBase { | 
 |  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(Isolate* isolate, void* buffer, int buffer_size); | 
 |   virtual ~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 in between GetCode() calls. | 
 |   void GetCode(CodeDesc* desc); | 
 |  | 
 |   // Label operations & relative jumps (PPUM Appendix D) | 
 |   // | 
 |   // Takes a branch opcode (cc) and a label (L) and generates | 
 |   // either a backward branch or a forward branch and links it | 
 |   // to the label fixup chain. Usage: | 
 |   // | 
 |   // Label L;    // unbound label | 
 |   // j(cc, &L);  // forward branch to unbound label | 
 |   // bind(&L);   // bind label to the current pc | 
 |   // j(cc, &L);  // backward branch to bound label | 
 |   // bind(&L);   // illegal: a label may be bound only once | 
 |   // | 
 |   // Note: The same Label can be used for forward and backward branches | 
 |   // but it may be bound only once. | 
 |  | 
 |   void bind(Label* L);  // binds an unbound label L to the current code position | 
 |  | 
 |   // Returns the branch offset to the given label from the current code position | 
 |   // Links the label to the current position if it is still unbound | 
 |   // Manages the jump elimination optimization if the second parameter is true. | 
 |   int branch_offset(Label* L, bool jump_elimination_allowed); | 
 |  | 
 |   // Return the address in the constant pool of the code target address used by | 
 |   // the branch/call instruction at pc, or the object in a mov. | 
 |   INLINE(static Address target_pointer_address_at(Address pc)); | 
 |  | 
 |   // Read/Modify the pointer in the branch/call/move instruction at pc. | 
 |   INLINE(static Address target_pointer_at(Address pc)); | 
 |   INLINE(static void set_target_pointer_at(Address pc, Address target)); | 
 |  | 
 |   // Read/Modify the code target address 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)); | 
 |  | 
 |   // Return the code target address at a call site from the return address | 
 |   // of that call in the instruction stream. | 
 |   INLINE(static Address target_address_from_return_address(Address pc)); | 
 |  | 
 |   // Given the address of the beginning of a call, return the address | 
 |   // in the instruction stream that the call will return from. | 
 |   INLINE(static Address return_address_from_call_start(Address pc)); | 
 |  | 
 |   // This sets the branch destination (which is in the constant pool on ARM). | 
 |   // This is for calls and branches within generated code. | 
 |   inline static void deserialization_set_special_target_at( | 
 |       Address constant_pool_entry, Address target); | 
 |  | 
 |   // This sets the branch destination (which is in the constant pool on ARM). | 
 |   // This is for calls and branches to runtime code. | 
 |   inline static void set_external_target_at(Address constant_pool_entry, | 
 |                                             Address target); | 
 |  | 
 |   // Here we are patching the address in the constant pool, not the actual call | 
 |   // instruction.  The address in the constant pool is the same size as a | 
 |   // pointer. | 
 |   static const int kSpecialTargetSize = kPointerSize; | 
 |  | 
 |   // Size of an instruction. | 
 |   static const int kInstrSize = sizeof(Instr); | 
 |  | 
 |   // Distance between start of patched return sequence and the emitted address | 
 |   // to jump to. | 
 |   // Patched return sequence is: | 
 |   //  ldr  ip, [pc, #0]   @ emited address and start | 
 |   //  blx  ip | 
 |   static const int kPatchReturnSequenceAddressOffset =  0 * kInstrSize; | 
 |  | 
 |   // Distance between start of patched debug break slot and the emitted address | 
 |   // to jump to. | 
 |   // Patched debug break slot code is: | 
 |   //  ldr  ip, [pc, #0]   @ emited address and start | 
 |   //  blx  ip | 
 |   static const int kPatchDebugBreakSlotAddressOffset =  0 * kInstrSize; | 
 |  | 
 |   static const int kPatchDebugBreakSlotReturnOffset = 2 * kInstrSize; | 
 |  | 
 |   // Difference between address of current opcode and value read from pc | 
 |   // register. | 
 |   static const int kPcLoadDelta = 8; | 
 |  | 
 |   static const int kJSReturnSequenceInstructions = 4; | 
 |   static const int kDebugBreakSlotInstructions = 3; | 
 |   static const int kDebugBreakSlotLength = | 
 |       kDebugBreakSlotInstructions * kInstrSize; | 
 |  | 
 |   // --------------------------------------------------------------------------- | 
 |   // Code generation | 
 |  | 
 |   // Insert the smallest number of nop instructions | 
 |   // possible to align the pc offset to a multiple | 
 |   // of m. m must be a power of 2 (>= 4). | 
 |   void Align(int m); | 
 |   // Aligns code to something that's optimal for a jump target for the platform. | 
 |   void CodeTargetAlign(); | 
 |  | 
 |   // Branch instructions | 
 |   void b(int branch_offset, Condition cond = al); | 
 |   void bl(int branch_offset, Condition cond = al); | 
 |   void blx(int branch_offset);  // v5 and above | 
 |   void blx(Register target, Condition cond = al);  // v5 and above | 
 |   void bx(Register target, Condition cond = al);  // v5 and above, plus v4t | 
 |  | 
 |   // Convenience branch instructions using labels | 
 |   void b(Label* L, Condition cond = al)  { | 
 |     b(branch_offset(L, cond == al), cond); | 
 |   } | 
 |   void b(Condition cond, Label* L)  { b(branch_offset(L, cond == al), cond); } | 
 |   void bl(Label* L, Condition cond = al)  { bl(branch_offset(L, false), cond); } | 
 |   void bl(Condition cond, Label* L)  { bl(branch_offset(L, false), cond); } | 
 |   void blx(Label* L)  { blx(branch_offset(L, false)); }  // v5 and above | 
 |  | 
 |   // Data-processing instructions | 
 |  | 
 |   void and_(Register dst, Register src1, const Operand& src2, | 
 |             SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void eor(Register dst, Register src1, const Operand& src2, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void sub(Register dst, Register src1, const Operand& src2, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |   void sub(Register dst, Register src1, Register src2, | 
 |            SBit s = LeaveCC, Condition cond = al) { | 
 |     sub(dst, src1, Operand(src2), s, cond); | 
 |   } | 
 |  | 
 |   void rsb(Register dst, Register src1, const Operand& src2, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void add(Register dst, Register src1, const Operand& src2, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |   void add(Register dst, Register src1, Register src2, | 
 |            SBit s = LeaveCC, Condition cond = al) { | 
 |     add(dst, src1, Operand(src2), s, cond); | 
 |   } | 
 |  | 
 |   void adc(Register dst, Register src1, const Operand& src2, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void sbc(Register dst, Register src1, const Operand& src2, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void rsc(Register dst, Register src1, const Operand& src2, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void tst(Register src1, const Operand& src2, Condition cond = al); | 
 |   void tst(Register src1, Register src2, Condition cond = al) { | 
 |     tst(src1, Operand(src2), cond); | 
 |   } | 
 |  | 
 |   void teq(Register src1, const Operand& src2, Condition cond = al); | 
 |  | 
 |   void cmp(Register src1, const Operand& src2, Condition cond = al); | 
 |   void cmp(Register src1, Register src2, Condition cond = al) { | 
 |     cmp(src1, Operand(src2), cond); | 
 |   } | 
 |   void cmp_raw_immediate(Register src1, int raw_immediate, Condition cond = al); | 
 |  | 
 |   void cmn(Register src1, const Operand& src2, Condition cond = al); | 
 |  | 
 |   void orr(Register dst, Register src1, const Operand& src2, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |   void orr(Register dst, Register src1, Register src2, | 
 |            SBit s = LeaveCC, Condition cond = al) { | 
 |     orr(dst, src1, Operand(src2), s, cond); | 
 |   } | 
 |  | 
 |   void mov(Register dst, const Operand& src, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |   void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) { | 
 |     mov(dst, Operand(src), s, cond); | 
 |   } | 
 |  | 
 |   // Load the position of the label relative to the generated code object | 
 |   // pointer in a register. | 
 |   void mov_label_offset(Register dst, Label* label); | 
 |  | 
 |   // ARMv7 instructions for loading a 32 bit immediate in two instructions. | 
 |   // This may actually emit a different mov instruction, but on an ARMv7 it | 
 |   // is guaranteed to only emit one instruction. | 
 |   void movw(Register reg, uint32_t immediate, Condition cond = al); | 
 |   // The constant for movt should be in the range 0-0xffff. | 
 |   void movt(Register reg, uint32_t immediate, Condition cond = al); | 
 |  | 
 |   void bic(Register dst, Register src1, const Operand& src2, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void mvn(Register dst, const Operand& src, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   // Multiply instructions | 
 |  | 
 |   void mla(Register dst, Register src1, Register src2, Register srcA, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void mls(Register dst, Register src1, Register src2, Register srcA, | 
 |            Condition cond = al); | 
 |  | 
 |   void sdiv(Register dst, Register src1, Register src2, | 
 |             Condition cond = al); | 
 |  | 
 |   void mul(Register dst, Register src1, Register src2, | 
 |            SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void smlal(Register dstL, Register dstH, Register src1, Register src2, | 
 |              SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void smull(Register dstL, Register dstH, Register src1, Register src2, | 
 |              SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void umlal(Register dstL, Register dstH, Register src1, Register src2, | 
 |              SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   void umull(Register dstL, Register dstH, Register src1, Register src2, | 
 |              SBit s = LeaveCC, Condition cond = al); | 
 |  | 
 |   // Miscellaneous arithmetic instructions | 
 |  | 
 |   void clz(Register dst, Register src, Condition cond = al);  // v5 and above | 
 |  | 
 |   // Saturating instructions. v6 and above. | 
 |  | 
 |   // Unsigned saturate. | 
 |   // | 
 |   // Saturate an optionally shifted signed value to an unsigned range. | 
 |   // | 
 |   //   usat dst, #satpos, src | 
 |   //   usat dst, #satpos, src, lsl #sh | 
 |   //   usat dst, #satpos, src, asr #sh | 
 |   // | 
 |   // Register dst will contain: | 
 |   // | 
 |   //   0,                 if s < 0 | 
 |   //   (1 << satpos) - 1, if s > ((1 << satpos) - 1) | 
 |   //   s,                 otherwise | 
 |   // | 
 |   // where s is the contents of src after shifting (if used.) | 
 |   void usat(Register dst, int satpos, const Operand& src, Condition cond = al); | 
 |  | 
 |   // Bitfield manipulation instructions. v7 and above. | 
 |  | 
 |   void ubfx(Register dst, Register src, int lsb, int width, | 
 |             Condition cond = al); | 
 |  | 
 |   void sbfx(Register dst, Register src, int lsb, int width, | 
 |             Condition cond = al); | 
 |  | 
 |   void bfc(Register dst, int lsb, int width, Condition cond = al); | 
 |  | 
 |   void bfi(Register dst, Register src, int lsb, int width, | 
 |            Condition cond = al); | 
 |  | 
 |   void pkhbt(Register dst, Register src1, const Operand& src2, | 
 |              Condition cond = al); | 
 |  | 
 |   void pkhtb(Register dst, Register src1, const Operand& src2, | 
 |              Condition cond = al); | 
 |  | 
 |   void uxtb(Register dst, const Operand& src, Condition cond = al); | 
 |  | 
 |   void uxtab(Register dst, Register src1, const Operand& src2, | 
 |              Condition cond = al); | 
 |  | 
 |   void uxtb16(Register dst, const Operand& src, Condition cond = al); | 
 |  | 
 |   // Status register access instructions | 
 |  | 
 |   void mrs(Register dst, SRegister s, Condition cond = al); | 
 |   void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al); | 
 |  | 
 |   // Load/Store instructions | 
 |   void ldr(Register dst, const MemOperand& src, Condition cond = al); | 
 |   void str(Register src, const MemOperand& dst, Condition cond = al); | 
 |   void ldrb(Register dst, const MemOperand& src, Condition cond = al); | 
 |   void strb(Register src, const MemOperand& dst, Condition cond = al); | 
 |   void ldrh(Register dst, const MemOperand& src, Condition cond = al); | 
 |   void strh(Register src, const MemOperand& dst, Condition cond = al); | 
 |   void ldrsb(Register dst, const MemOperand& src, Condition cond = al); | 
 |   void ldrsh(Register dst, const MemOperand& src, Condition cond = al); | 
 |   void ldrd(Register dst1, | 
 |             Register dst2, | 
 |             const MemOperand& src, Condition cond = al); | 
 |   void strd(Register src1, | 
 |             Register src2, | 
 |             const MemOperand& dst, Condition cond = al); | 
 |  | 
 |   // Preload instructions | 
 |   void pld(const MemOperand& address); | 
 |  | 
 |   // Load/Store multiple instructions | 
 |   void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al); | 
 |   void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al); | 
 |  | 
 |   // Exception-generating instructions and debugging support | 
 |   void stop(const char* msg, | 
 |             Condition cond = al, | 
 |             int32_t code = kDefaultStopCode); | 
 |  | 
 |   void bkpt(uint32_t imm16);  // v5 and above | 
 |   void svc(uint32_t imm24, Condition cond = al); | 
 |  | 
 |   // Coprocessor instructions | 
 |  | 
 |   void cdp(Coprocessor coproc, int opcode_1, | 
 |            CRegister crd, CRegister crn, CRegister crm, | 
 |            int opcode_2, Condition cond = al); | 
 |  | 
 |   void cdp2(Coprocessor coproc, int opcode_1, | 
 |             CRegister crd, CRegister crn, CRegister crm, | 
 |             int opcode_2);  // v5 and above | 
 |  | 
 |   void mcr(Coprocessor coproc, int opcode_1, | 
 |            Register rd, CRegister crn, CRegister crm, | 
 |            int opcode_2 = 0, Condition cond = al); | 
 |  | 
 |   void mcr2(Coprocessor coproc, int opcode_1, | 
 |             Register rd, CRegister crn, CRegister crm, | 
 |             int opcode_2 = 0);  // v5 and above | 
 |  | 
 |   void mrc(Coprocessor coproc, int opcode_1, | 
 |            Register rd, CRegister crn, CRegister crm, | 
 |            int opcode_2 = 0, Condition cond = al); | 
 |  | 
 |   void mrc2(Coprocessor coproc, int opcode_1, | 
 |             Register rd, CRegister crn, CRegister crm, | 
 |             int opcode_2 = 0);  // v5 and above | 
 |  | 
 |   void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src, | 
 |            LFlag l = Short, Condition cond = al); | 
 |   void ldc(Coprocessor coproc, CRegister crd, Register base, int option, | 
 |            LFlag l = Short, Condition cond = al); | 
 |  | 
 |   void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src, | 
 |             LFlag l = Short);  // v5 and above | 
 |   void ldc2(Coprocessor coproc, CRegister crd, Register base, int option, | 
 |             LFlag l = Short);  // v5 and above | 
 |  | 
 |   // Support for VFP. | 
 |   // All these APIs support S0 to S31 and D0 to D31. | 
 |  | 
 |   void vldr(const DwVfpRegister dst, | 
 |             const Register base, | 
 |             int offset, | 
 |             const Condition cond = al); | 
 |   void vldr(const DwVfpRegister dst, | 
 |             const MemOperand& src, | 
 |             const Condition cond = al); | 
 |  | 
 |   void vldr(const SwVfpRegister dst, | 
 |             const Register base, | 
 |             int offset, | 
 |             const Condition cond = al); | 
 |   void vldr(const SwVfpRegister dst, | 
 |             const MemOperand& src, | 
 |             const Condition cond = al); | 
 |  | 
 |   void vstr(const DwVfpRegister src, | 
 |             const Register base, | 
 |             int offset, | 
 |             const Condition cond = al); | 
 |   void vstr(const DwVfpRegister src, | 
 |             const MemOperand& dst, | 
 |             const Condition cond = al); | 
 |  | 
 |   void vstr(const SwVfpRegister src, | 
 |             const Register base, | 
 |             int offset, | 
 |             const Condition cond = al); | 
 |   void vstr(const SwVfpRegister src, | 
 |             const MemOperand& dst, | 
 |             const Condition cond = al); | 
 |  | 
 |   void vldm(BlockAddrMode am, | 
 |             Register base, | 
 |             DwVfpRegister first, | 
 |             DwVfpRegister last, | 
 |             Condition cond = al); | 
 |  | 
 |   void vstm(BlockAddrMode am, | 
 |             Register base, | 
 |             DwVfpRegister first, | 
 |             DwVfpRegister last, | 
 |             Condition cond = al); | 
 |  | 
 |   void vldm(BlockAddrMode am, | 
 |             Register base, | 
 |             SwVfpRegister first, | 
 |             SwVfpRegister last, | 
 |             Condition cond = al); | 
 |  | 
 |   void vstm(BlockAddrMode am, | 
 |             Register base, | 
 |             SwVfpRegister first, | 
 |             SwVfpRegister last, | 
 |             Condition cond = al); | 
 |  | 
 |   void vmov(const DwVfpRegister dst, | 
 |             double imm, | 
 |             const Register scratch = no_reg); | 
 |   void vmov(const SwVfpRegister dst, | 
 |             const SwVfpRegister src, | 
 |             const Condition cond = al); | 
 |   void vmov(const DwVfpRegister dst, | 
 |             const DwVfpRegister src, | 
 |             const Condition cond = al); | 
 |   void vmov(const DwVfpRegister dst, | 
 |             const VmovIndex index, | 
 |             const Register src, | 
 |             const Condition cond = al); | 
 |   void vmov(const Register dst, | 
 |             const VmovIndex index, | 
 |             const DwVfpRegister src, | 
 |             const Condition cond = al); | 
 |   void vmov(const DwVfpRegister dst, | 
 |             const Register src1, | 
 |             const Register src2, | 
 |             const Condition cond = al); | 
 |   void vmov(const Register dst1, | 
 |             const Register dst2, | 
 |             const DwVfpRegister src, | 
 |             const Condition cond = al); | 
 |   void vmov(const SwVfpRegister dst, | 
 |             const Register src, | 
 |             const Condition cond = al); | 
 |   void vmov(const Register dst, | 
 |             const SwVfpRegister src, | 
 |             const Condition cond = al); | 
 |   void vcvt_f64_s32(const DwVfpRegister dst, | 
 |                     const SwVfpRegister src, | 
 |                     VFPConversionMode mode = kDefaultRoundToZero, | 
 |                     const Condition cond = al); | 
 |   void vcvt_f32_s32(const SwVfpRegister dst, | 
 |                     const SwVfpRegister src, | 
 |                     VFPConversionMode mode = kDefaultRoundToZero, | 
 |                     const Condition cond = al); | 
 |   void vcvt_f64_u32(const DwVfpRegister dst, | 
 |                     const SwVfpRegister src, | 
 |                     VFPConversionMode mode = kDefaultRoundToZero, | 
 |                     const Condition cond = al); | 
 |   void vcvt_s32_f64(const SwVfpRegister dst, | 
 |                     const DwVfpRegister src, | 
 |                     VFPConversionMode mode = kDefaultRoundToZero, | 
 |                     const Condition cond = al); | 
 |   void vcvt_u32_f64(const SwVfpRegister dst, | 
 |                     const DwVfpRegister src, | 
 |                     VFPConversionMode mode = kDefaultRoundToZero, | 
 |                     const Condition cond = al); | 
 |   void vcvt_f64_f32(const DwVfpRegister dst, | 
 |                     const SwVfpRegister src, | 
 |                     VFPConversionMode mode = kDefaultRoundToZero, | 
 |                     const Condition cond = al); | 
 |   void vcvt_f32_f64(const SwVfpRegister dst, | 
 |                     const DwVfpRegister src, | 
 |                     VFPConversionMode mode = kDefaultRoundToZero, | 
 |                     const Condition cond = al); | 
 |   void vcvt_f64_s32(const DwVfpRegister dst, | 
 |                     int fraction_bits, | 
 |                     const Condition cond = al); | 
 |  | 
 |   void vneg(const DwVfpRegister dst, | 
 |             const DwVfpRegister src, | 
 |             const Condition cond = al); | 
 |   void vabs(const DwVfpRegister dst, | 
 |             const DwVfpRegister src, | 
 |             const Condition cond = al); | 
 |   void vadd(const DwVfpRegister dst, | 
 |             const DwVfpRegister src1, | 
 |             const DwVfpRegister src2, | 
 |             const Condition cond = al); | 
 |   void vsub(const DwVfpRegister dst, | 
 |             const DwVfpRegister src1, | 
 |             const DwVfpRegister src2, | 
 |             const Condition cond = al); | 
 |   void vmul(const DwVfpRegister dst, | 
 |             const DwVfpRegister src1, | 
 |             const DwVfpRegister src2, | 
 |             const Condition cond = al); | 
 |   void vmla(const DwVfpRegister dst, | 
 |             const DwVfpRegister src1, | 
 |             const DwVfpRegister src2, | 
 |             const Condition cond = al); | 
 |   void vmls(const DwVfpRegister dst, | 
 |             const DwVfpRegister src1, | 
 |             const DwVfpRegister src2, | 
 |             const Condition cond = al); | 
 |   void vdiv(const DwVfpRegister dst, | 
 |             const DwVfpRegister src1, | 
 |             const DwVfpRegister src2, | 
 |             const Condition cond = al); | 
 |   void vcmp(const DwVfpRegister src1, | 
 |             const DwVfpRegister src2, | 
 |             const Condition cond = al); | 
 |   void vcmp(const DwVfpRegister src1, | 
 |             const double src2, | 
 |             const Condition cond = al); | 
 |   void vmrs(const Register dst, | 
 |             const Condition cond = al); | 
 |   void vmsr(const Register dst, | 
 |             const Condition cond = al); | 
 |   void vsqrt(const DwVfpRegister dst, | 
 |              const DwVfpRegister src, | 
 |              const Condition cond = al); | 
 |  | 
 |   // Support for NEON. | 
 |   // All these APIs support D0 to D31 and Q0 to Q15. | 
 |  | 
 |   void vld1(NeonSize size, | 
 |             const NeonListOperand& dst, | 
 |             const NeonMemOperand& src); | 
 |   void vst1(NeonSize size, | 
 |             const NeonListOperand& src, | 
 |             const NeonMemOperand& dst); | 
 |   void vmovl(NeonDataType dt, QwNeonRegister dst, DwVfpRegister src); | 
 |  | 
 |   // Pseudo instructions | 
 |  | 
 |   // Different nop operations are used by the code generator to detect certain | 
 |   // states of the generated code. | 
 |   enum NopMarkerTypes { | 
 |     NON_MARKING_NOP = 0, | 
 |     DEBUG_BREAK_NOP, | 
 |     // IC markers. | 
 |     PROPERTY_ACCESS_INLINED, | 
 |     PROPERTY_ACCESS_INLINED_CONTEXT, | 
 |     PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE, | 
 |     // Helper values. | 
 |     LAST_CODE_MARKER, | 
 |     FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED | 
 |   }; | 
 |  | 
 |   void nop(int type = 0);   // 0 is the default non-marking type. | 
 |  | 
 |   void push(Register src, Condition cond = al) { | 
 |     str(src, MemOperand(sp, 4, NegPreIndex), cond); | 
 |   } | 
 |  | 
 |   void pop(Register dst, Condition cond = al) { | 
 |     ldr(dst, MemOperand(sp, 4, PostIndex), cond); | 
 |   } | 
 |  | 
 |   void pop() { | 
 |     add(sp, sp, Operand(kPointerSize)); | 
 |   } | 
 |  | 
 |   // Jump unconditionally to given label. | 
 |   void jmp(Label* L) { b(L, al); } | 
 |  | 
 |   static bool use_immediate_embedded_pointer_loads( | 
 |       const Assembler* assembler) { | 
 |     return CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) && | 
 |         (assembler == NULL || !assembler->predictable_code_size()); | 
 |   } | 
 |  | 
 |   // Check the code size generated from label to here. | 
 |   int SizeOfCodeGeneratedSince(Label* label) { | 
 |     return pc_offset() - label->pos(); | 
 |   } | 
 |  | 
 |   // Check the number of instructions generated from label to here. | 
 |   int InstructionsGeneratedSince(Label* label) { | 
 |     return SizeOfCodeGeneratedSince(label) / kInstrSize; | 
 |   } | 
 |  | 
 |   // Check whether an immediate fits an addressing mode 1 instruction. | 
 |   bool ImmediateFitsAddrMode1Instruction(int32_t imm32); | 
 |  | 
 |   // Class for scoping postponing the constant pool generation. | 
 |   class BlockConstPoolScope { | 
 |    public: | 
 |     explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) { | 
 |       assem_->StartBlockConstPool(); | 
 |     } | 
 |     ~BlockConstPoolScope() { | 
 |       assem_->EndBlockConstPool(); | 
 |     } | 
 |  | 
 |    private: | 
 |     Assembler* assem_; | 
 |  | 
 |     DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope); | 
 |   }; | 
 |  | 
 |   // Debugging | 
 |  | 
 |   // Mark address of the ExitJSFrame code. | 
 |   void RecordJSReturn(); | 
 |  | 
 |   // Mark address of a debug break slot. | 
 |   void RecordDebugBreakSlot(); | 
 |  | 
 |   // Record the AST id of the CallIC being compiled, so that it can be placed | 
 |   // in the relocation information. | 
 |   void SetRecordedAstId(TypeFeedbackId ast_id) { | 
 |     ASSERT(recorded_ast_id_.IsNone()); | 
 |     recorded_ast_id_ = ast_id; | 
 |   } | 
 |  | 
 |   TypeFeedbackId RecordedAstId() { | 
 |     ASSERT(!recorded_ast_id_.IsNone()); | 
 |     return recorded_ast_id_; | 
 |   } | 
 |  | 
 |   void ClearRecordedAstId() { recorded_ast_id_ = TypeFeedbackId::None(); } | 
 |  | 
 |   // Record a comment relocation entry that can be used by a disassembler. | 
 |   // Use --code-comments to enable. | 
 |   void RecordComment(const char* msg); | 
 |  | 
 |   // Record the emission of a constant pool. | 
 |   // | 
 |   // The emission of constant pool depends on the size of the code generated and | 
 |   // the number of RelocInfo recorded. | 
 |   // The Debug mechanism needs to map code offsets between two versions of a | 
 |   // function, compiled with and without debugger support (see for example | 
 |   // Debug::PrepareForBreakPoints()). | 
 |   // Compiling functions with debugger support generates additional code | 
 |   // (Debug::GenerateSlot()). This may affect the emission of the constant | 
 |   // pools and cause the version of the code with debugger support to have | 
 |   // constant pools generated in different places. | 
 |   // Recording the position and size of emitted constant pools allows to | 
 |   // correctly compute the offset mappings between the different versions of a | 
 |   // function in all situations. | 
 |   // | 
 |   // The parameter indicates the size of the constant pool (in bytes), including | 
 |   // the marker and branch over the data. | 
 |   void RecordConstPool(int size); | 
 |  | 
 |   // Writes a single byte or word of data in the code stream.  Used | 
 |   // for inline tables, e.g., jump-tables. The constant pool should be | 
 |   // emitted before any use of db and dd to ensure that constant pools | 
 |   // are not emitted as part of the tables generated. | 
 |   void db(uint8_t data); | 
 |   void dd(uint32_t data); | 
 |  | 
 |   PositionsRecorder* positions_recorder() { return &positions_recorder_; } | 
 |  | 
 |   // Read/patch instructions | 
 |   Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); } | 
 |   void instr_at_put(int pos, Instr instr) { | 
 |     *reinterpret_cast<Instr*>(buffer_ + pos) = instr; | 
 |   } | 
 |   static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); } | 
 |   static void instr_at_put(byte* pc, Instr instr) { | 
 |     *reinterpret_cast<Instr*>(pc) = instr; | 
 |   } | 
 |   static Condition GetCondition(Instr instr); | 
 |   static bool IsBranch(Instr instr); | 
 |   static int GetBranchOffset(Instr instr); | 
 |   static bool IsLdrRegisterImmediate(Instr instr); | 
 |   static bool IsVldrDRegisterImmediate(Instr instr); | 
 |   static int GetLdrRegisterImmediateOffset(Instr instr); | 
 |   static int GetVldrDRegisterImmediateOffset(Instr instr); | 
 |   static Instr SetLdrRegisterImmediateOffset(Instr instr, int offset); | 
 |   static Instr SetVldrDRegisterImmediateOffset(Instr instr, int offset); | 
 |   static bool IsStrRegisterImmediate(Instr instr); | 
 |   static Instr SetStrRegisterImmediateOffset(Instr instr, int offset); | 
 |   static bool IsAddRegisterImmediate(Instr instr); | 
 |   static Instr SetAddRegisterImmediateOffset(Instr instr, int offset); | 
 |   static Register GetRd(Instr instr); | 
 |   static Register GetRn(Instr instr); | 
 |   static Register GetRm(Instr instr); | 
 |   static bool IsPush(Instr instr); | 
 |   static bool IsPop(Instr instr); | 
 |   static bool IsStrRegFpOffset(Instr instr); | 
 |   static bool IsLdrRegFpOffset(Instr instr); | 
 |   static bool IsStrRegFpNegOffset(Instr instr); | 
 |   static bool IsLdrRegFpNegOffset(Instr instr); | 
 |   static bool IsLdrPcImmediateOffset(Instr instr); | 
 |   static bool IsVldrDPcImmediateOffset(Instr instr); | 
 |   static bool IsTstImmediate(Instr instr); | 
 |   static bool IsCmpRegister(Instr instr); | 
 |   static bool IsCmpImmediate(Instr instr); | 
 |   static Register GetCmpImmediateRegister(Instr instr); | 
 |   static int GetCmpImmediateRawImmediate(Instr instr); | 
 |   static bool IsNop(Instr instr, int type = NON_MARKING_NOP); | 
 |   static bool IsMovT(Instr instr); | 
 |   static bool IsMovW(Instr instr); | 
 |  | 
 |   // Constants in pools are accessed via pc relative addressing, which can | 
 |   // reach +/-4KB for integer PC-relative loads and +/-1KB for floating-point | 
 |   // PC-relative loads, thereby defining a maximum distance between the | 
 |   // instruction and the accessed constant. | 
 |   static const int kMaxDistToIntPool = 4*KB; | 
 |   static const int kMaxDistToFPPool = 1*KB; | 
 |   // All relocations could be integer, it therefore acts as the limit. | 
 |   static const int kMaxNumPendingRelocInfo = kMaxDistToIntPool/kInstrSize; | 
 |  | 
 |   // Postpone the generation of the constant pool for the specified number of | 
 |   // instructions. | 
 |   void BlockConstPoolFor(int instructions); | 
 |  | 
 |   // Check if is time to emit a constant pool. | 
 |   void CheckConstPool(bool force_emit, bool require_jump); | 
 |  | 
 |  protected: | 
 |   // Relocation for a type-recording IC has the AST id added to it.  This | 
 |   // member variable is a way to pass the information from the call site to | 
 |   // the relocation info. | 
 |   TypeFeedbackId recorded_ast_id_; | 
 |  | 
 |   int buffer_space() const { return reloc_info_writer.pos() - pc_; } | 
 |  | 
 |   // Decode branch instruction at pos and return branch target pos | 
 |   int target_at(int pos); | 
 |  | 
 |   // Patch branch instruction at pos to branch to given branch target pos | 
 |   void target_at_put(int pos, int target_pos); | 
 |  | 
 |   // Prevent contant pool emission until EndBlockConstPool is called. | 
 |   // Call to this function can be nested but must be followed by an equal | 
 |   // number of call to EndBlockConstpool. | 
 |   void StartBlockConstPool() { | 
 |     if (const_pool_blocked_nesting_++ == 0) { | 
 |       // Prevent constant pool checks happening by setting the next check to | 
 |       // the biggest possible offset. | 
 |       next_buffer_check_ = kMaxInt; | 
 |     } | 
 |   } | 
 |  | 
 |   // Resume constant pool emission. Need to be called as many time as | 
 |   // StartBlockConstPool to have an effect. | 
 |   void EndBlockConstPool() { | 
 |     if (--const_pool_blocked_nesting_ == 0) { | 
 |       // Check the constant pool hasn't been blocked for too long. | 
 |       ASSERT((num_pending_reloc_info_ == 0) || | 
 |              (pc_offset() < (first_const_pool_use_ + kMaxDistToIntPool))); | 
 |       ASSERT((num_pending_64_bit_reloc_info_ == 0) || | 
 |              (pc_offset() < (first_const_pool_use_ + kMaxDistToFPPool))); | 
 |       // Two cases: | 
 |       //  * no_const_pool_before_ >= next_buffer_check_ and the emission is | 
 |       //    still blocked | 
 |       //  * no_const_pool_before_ < next_buffer_check_ and the next emit will | 
 |       //    trigger a check. | 
 |       next_buffer_check_ = no_const_pool_before_; | 
 |     } | 
 |   } | 
 |  | 
 |   bool is_const_pool_blocked() const { | 
 |     return (const_pool_blocked_nesting_ > 0) || | 
 |            (pc_offset() < no_const_pool_before_); | 
 |   } | 
 |  | 
 |  private: | 
 |   int next_buffer_check_;  // pc offset of next buffer check | 
 |  | 
 |   // Code generation | 
 |   // The relocation writer's position is at least kGap bytes below the end of | 
 |   // the generated instructions. This is so that multi-instruction sequences do | 
 |   // not have to check for overflow. The same is true for writes of large | 
 |   // relocation info entries. | 
 |   static const int kGap = 32; | 
 |  | 
 |   // Constant pool generation | 
 |   // Pools are emitted in the instruction stream, preferably after unconditional | 
 |   // jumps or after returns from functions (in dead code locations). | 
 |   // If a long code sequence does not contain unconditional jumps, it is | 
 |   // necessary to emit the constant pool before the pool gets too far from the | 
 |   // location it is accessed from. In this case, we emit a jump over the emitted | 
 |   // constant pool. | 
 |   // Constants in the pool may be addresses of functions that gets relocated; | 
 |   // if so, a relocation info entry is associated to the constant pool entry. | 
 |  | 
 |   // Repeated checking whether the constant pool should be emitted is rather | 
 |   // expensive. By default we only check again once a number of instructions | 
 |   // has been generated. That also means that the sizing of the buffers is not | 
 |   // an exact science, and that we rely on some slop to not overrun buffers. | 
 |   static const int kCheckPoolIntervalInst = 32; | 
 |   static const int kCheckPoolInterval = kCheckPoolIntervalInst * kInstrSize; | 
 |  | 
 |  | 
 |   // Emission of the constant pool may be blocked in some code sequences. | 
 |   int const_pool_blocked_nesting_;  // Block emission if this is not zero. | 
 |   int no_const_pool_before_;  // Block emission before this pc offset. | 
 |  | 
 |   // Keep track of the first instruction requiring a constant pool entry | 
 |   // since the previous constant pool was emitted. | 
 |   int first_const_pool_use_; | 
 |  | 
 |   // Relocation info generation | 
 |   // Each relocation is encoded as a variable size value | 
 |   static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; | 
 |   RelocInfoWriter reloc_info_writer; | 
 |  | 
 |   // Relocation info records are also used during code generation as temporary | 
 |   // containers for constants and code target addresses until they are emitted | 
 |   // to the constant pool. These pending relocation info records are temporarily | 
 |   // stored in a separate buffer until a constant pool is emitted. | 
 |   // If every instruction in a long sequence is accessing the pool, we need one | 
 |   // pending relocation entry per instruction. | 
 |  | 
 |   // the buffer of pending relocation info | 
 |   RelocInfo pending_reloc_info_[kMaxNumPendingRelocInfo]; | 
 |   // number of pending reloc info entries in the buffer | 
 |   int num_pending_reloc_info_; | 
 |   // Number of pending reloc info entries included above which also happen to | 
 |   // be 64-bit. | 
 |   int num_pending_64_bit_reloc_info_; | 
 |  | 
 |   // The bound position, before this we cannot do instruction elimination. | 
 |   int last_bound_pos_; | 
 |  | 
 |   // Code emission | 
 |   inline void CheckBuffer(); | 
 |   void GrowBuffer(); | 
 |   inline void emit(Instr x); | 
 |  | 
 |   // 32-bit immediate values | 
 |   void move_32_bit_immediate(Condition cond, | 
 |                              Register rd, | 
 |                              SBit s, | 
 |                              const Operand& x); | 
 |  | 
 |   // Instruction generation | 
 |   void addrmod1(Instr instr, Register rn, Register rd, const Operand& x); | 
 |   void addrmod2(Instr instr, Register rd, const MemOperand& x); | 
 |   void addrmod3(Instr instr, Register rd, const MemOperand& x); | 
 |   void addrmod4(Instr instr, Register rn, RegList rl); | 
 |   void addrmod5(Instr instr, CRegister crd, const MemOperand& x); | 
 |  | 
 |   // Labels | 
 |   void print(Label* L); | 
 |   void bind_to(Label* L, int pos); | 
 |   void next(Label* L); | 
 |  | 
 |   enum UseConstantPoolMode { | 
 |     USE_CONSTANT_POOL, | 
 |     DONT_USE_CONSTANT_POOL | 
 |   }; | 
 |  | 
 |   // Record reloc info for current pc_ | 
 |   void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0, | 
 |                        UseConstantPoolMode mode = USE_CONSTANT_POOL); | 
 |   void RecordRelocInfo(double data); | 
 |   void RecordRelocInfoConstantPoolEntryHelper(const RelocInfo& rinfo); | 
 |  | 
 |   friend class RelocInfo; | 
 |   friend class CodePatcher; | 
 |   friend class BlockConstPoolScope; | 
 |  | 
 |   PositionsRecorder positions_recorder_; | 
 |   friend class PositionsRecorder; | 
 |   friend class EnsureSpace; | 
 | }; | 
 |  | 
 |  | 
 | class EnsureSpace BASE_EMBEDDED { | 
 |  public: | 
 |   explicit EnsureSpace(Assembler* assembler) { | 
 |     assembler->CheckBuffer(); | 
 |   } | 
 | }; | 
 |  | 
 |  | 
 | } }  // namespace v8::internal | 
 |  | 
 | #endif  // V8_ARM_ASSEMBLER_ARM_H_ |