Home | History | Annotate | Download | only in arm
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_ARM_CODEGEN_ARM_H_
     29 #define V8_ARM_CODEGEN_ARM_H_
     30 
     31 namespace v8 {
     32 namespace internal {
     33 
     34 // Forward declarations
     35 class CompilationInfo;
     36 class DeferredCode;
     37 class RegisterAllocator;
     38 class RegisterFile;
     39 
     40 enum InitState { CONST_INIT, NOT_CONST_INIT };
     41 enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
     42 
     43 
     44 // -------------------------------------------------------------------------
     45 // Reference support
     46 
     47 // A reference is a C++ stack-allocated object that puts a
     48 // reference on the virtual frame.  The reference may be consumed
     49 // by GetValue, TakeValue, SetValue, and Codegen::UnloadReference.
     50 // When the lifetime (scope) of a valid reference ends, it must have
     51 // been consumed, and be in state UNLOADED.
     52 class Reference BASE_EMBEDDED {
     53  public:
     54   // The values of the types is important, see size().
     55   enum Type { UNLOADED = -2, ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
     56   Reference(CodeGenerator* cgen,
     57             Expression* expression,
     58             bool persist_after_get = false);
     59   ~Reference();
     60 
     61   Expression* expression() const { return expression_; }
     62   Type type() const { return type_; }
     63   void set_type(Type value) {
     64     ASSERT_EQ(ILLEGAL, type_);
     65     type_ = value;
     66   }
     67 
     68   void set_unloaded() {
     69     ASSERT_NE(ILLEGAL, type_);
     70     ASSERT_NE(UNLOADED, type_);
     71     type_ = UNLOADED;
     72   }
     73   // The size the reference takes up on the stack.
     74   int size() const {
     75     return (type_ < SLOT) ? 0 : type_;
     76   }
     77 
     78   bool is_illegal() const { return type_ == ILLEGAL; }
     79   bool is_slot() const { return type_ == SLOT; }
     80   bool is_property() const { return type_ == NAMED || type_ == KEYED; }
     81   bool is_unloaded() const { return type_ == UNLOADED; }
     82 
     83   // Return the name.  Only valid for named property references.
     84   Handle<String> GetName();
     85 
     86   // Generate code to push the value of the reference on top of the
     87   // expression stack.  The reference is expected to be already on top of
     88   // the expression stack, and it is consumed by the call unless the
     89   // reference is for a compound assignment.
     90   // If the reference is not consumed, it is left in place under its value.
     91   void GetValue();
     92 
     93   // Generate code to pop a reference, push the value of the reference,
     94   // and then spill the stack frame.
     95   inline void GetValueAndSpill();
     96 
     97   // Generate code to store the value on top of the expression stack in the
     98   // reference.  The reference is expected to be immediately below the value
     99   // on the expression stack.  The  value is stored in the location specified
    100   // by the reference, and is left on top of the stack, after the reference
    101   // is popped from beneath it (unloaded).
    102   void SetValue(InitState init_state);
    103 
    104  private:
    105   CodeGenerator* cgen_;
    106   Expression* expression_;
    107   Type type_;
    108   // Keep the reference on the stack after get, so it can be used by set later.
    109   bool persist_after_get_;
    110 };
    111 
    112 
    113 // -------------------------------------------------------------------------
    114 // Code generation state
    115 
    116 // The state is passed down the AST by the code generator (and back up, in
    117 // the form of the state of the label pair).  It is threaded through the
    118 // call stack.  Constructing a state implicitly pushes it on the owning code
    119 // generator's stack of states, and destroying one implicitly pops it.
    120 
    121 class CodeGenState BASE_EMBEDDED {
    122  public:
    123   // Create an initial code generator state.  Destroying the initial state
    124   // leaves the code generator with a NULL state.
    125   explicit CodeGenState(CodeGenerator* owner);
    126 
    127   // Create a code generator state based on a code generator's current
    128   // state.  The new state has its own pair of branch labels.
    129   CodeGenState(CodeGenerator* owner,
    130                JumpTarget* true_target,
    131                JumpTarget* false_target);
    132 
    133   // Destroy a code generator state and restore the owning code generator's
    134   // previous state.
    135   ~CodeGenState();
    136 
    137   JumpTarget* true_target() const { return true_target_; }
    138   JumpTarget* false_target() const { return false_target_; }
    139 
    140  private:
    141   CodeGenerator* owner_;
    142   JumpTarget* true_target_;
    143   JumpTarget* false_target_;
    144   CodeGenState* previous_;
    145 };
    146 
    147 
    148 // -------------------------------------------------------------------------
    149 // CodeGenerator
    150 
    151 class CodeGenerator: public AstVisitor {
    152  public:
    153   // Takes a function literal, generates code for it. This function should only
    154   // be called by compiler.cc.
    155   static Handle<Code> MakeCode(CompilationInfo* info);
    156 
    157   // Printing of AST, etc. as requested by flags.
    158   static void MakeCodePrologue(CompilationInfo* info);
    159 
    160   // Allocate and install the code.
    161   static Handle<Code> MakeCodeEpilogue(MacroAssembler* masm,
    162                                        Code::Flags flags,
    163                                        CompilationInfo* info);
    164 
    165 #ifdef ENABLE_LOGGING_AND_PROFILING
    166   static bool ShouldGenerateLog(Expression* type);
    167 #endif
    168 
    169   static void SetFunctionInfo(Handle<JSFunction> fun,
    170                               FunctionLiteral* lit,
    171                               bool is_toplevel,
    172                               Handle<Script> script);
    173 
    174   static void RecordPositions(MacroAssembler* masm, int pos);
    175 
    176   // Accessors
    177   MacroAssembler* masm() { return masm_; }
    178   VirtualFrame* frame() const { return frame_; }
    179   inline Handle<Script> script();
    180 
    181   bool has_valid_frame() const { return frame_ != NULL; }
    182 
    183   // Set the virtual frame to be new_frame, with non-frame register
    184   // reference counts given by non_frame_registers.  The non-frame
    185   // register reference counts of the old frame are returned in
    186   // non_frame_registers.
    187   void SetFrame(VirtualFrame* new_frame, RegisterFile* non_frame_registers);
    188 
    189   void DeleteFrame();
    190 
    191   RegisterAllocator* allocator() const { return allocator_; }
    192 
    193   CodeGenState* state() { return state_; }
    194   void set_state(CodeGenState* state) { state_ = state; }
    195 
    196   void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
    197 
    198   static const int kUnknownIntValue = -1;
    199 
    200  private:
    201   // Construction/Destruction
    202   explicit CodeGenerator(MacroAssembler* masm);
    203 
    204   // Accessors
    205   inline bool is_eval();
    206   Scope* scope();
    207 
    208   // Generating deferred code.
    209   void ProcessDeferred();
    210 
    211   // State
    212   bool has_cc() const  { return cc_reg_ != al; }
    213   JumpTarget* true_target() const  { return state_->true_target(); }
    214   JumpTarget* false_target() const  { return state_->false_target(); }
    215 
    216   // We don't track loop nesting level on ARM yet.
    217   int loop_nesting() const { return 0; }
    218 
    219   // Node visitors.
    220   void VisitStatements(ZoneList<Statement*>* statements);
    221 
    222 #define DEF_VISIT(type) \
    223   void Visit##type(type* node);
    224   AST_NODE_LIST(DEF_VISIT)
    225 #undef DEF_VISIT
    226 
    227   // Visit a statement and then spill the virtual frame if control flow can
    228   // reach the end of the statement (ie, it does not exit via break,
    229   // continue, return, or throw).  This function is used temporarily while
    230   // the code generator is being transformed.
    231   inline void VisitAndSpill(Statement* statement);
    232 
    233   // Visit a list of statements and then spill the virtual frame if control
    234   // flow can reach the end of the list.
    235   inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
    236 
    237   // Main code generation function
    238   void Generate(CompilationInfo* info);
    239 
    240   // The following are used by class Reference.
    241   void LoadReference(Reference* ref);
    242   void UnloadReference(Reference* ref);
    243 
    244   static MemOperand ContextOperand(Register context, int index) {
    245     return MemOperand(context, Context::SlotOffset(index));
    246   }
    247 
    248   MemOperand SlotOperand(Slot* slot, Register tmp);
    249 
    250   MemOperand ContextSlotOperandCheckExtensions(Slot* slot,
    251                                                Register tmp,
    252                                                Register tmp2,
    253                                                JumpTarget* slow);
    254 
    255   // Expressions
    256   static MemOperand GlobalObject()  {
    257     return ContextOperand(cp, Context::GLOBAL_INDEX);
    258   }
    259 
    260   void LoadCondition(Expression* x,
    261                      JumpTarget* true_target,
    262                      JumpTarget* false_target,
    263                      bool force_cc);
    264   void Load(Expression* expr);
    265   void LoadGlobal();
    266   void LoadGlobalReceiver(Register scratch);
    267 
    268   // Generate code to push the value of an expression on top of the frame
    269   // and then spill the frame fully to memory.  This function is used
    270   // temporarily while the code generator is being transformed.
    271   inline void LoadAndSpill(Expression* expression);
    272 
    273   // Call LoadCondition and then spill the virtual frame unless control flow
    274   // cannot reach the end of the expression (ie, by emitting only
    275   // unconditional jumps to the control targets).
    276   inline void LoadConditionAndSpill(Expression* expression,
    277                                     JumpTarget* true_target,
    278                                     JumpTarget* false_target,
    279                                     bool force_control);
    280 
    281   // Read a value from a slot and leave it on top of the expression stack.
    282   void LoadFromSlot(Slot* slot, TypeofState typeof_state);
    283   // Store the value on top of the stack to a slot.
    284   void StoreToSlot(Slot* slot, InitState init_state);
    285   // Load a keyed property, leaving it in r0.  The receiver and key are
    286   // passed on the stack, and remain there.
    287   void EmitKeyedLoad(bool is_global);
    288 
    289   void LoadFromGlobalSlotCheckExtensions(Slot* slot,
    290                                          TypeofState typeof_state,
    291                                          Register tmp,
    292                                          Register tmp2,
    293                                          JumpTarget* slow);
    294 
    295   // Special code for typeof expressions: Unfortunately, we must
    296   // be careful when loading the expression in 'typeof'
    297   // expressions. We are not allowed to throw reference errors for
    298   // non-existing properties of the global object, so we must make it
    299   // look like an explicit property access, instead of an access
    300   // through the context chain.
    301   void LoadTypeofExpression(Expression* x);
    302 
    303   void ToBoolean(JumpTarget* true_target, JumpTarget* false_target);
    304 
    305   void GenericBinaryOperation(Token::Value op,
    306                               OverwriteMode overwrite_mode,
    307                               int known_rhs = kUnknownIntValue);
    308   void Comparison(Condition cc,
    309                   Expression* left,
    310                   Expression* right,
    311                   bool strict = false);
    312 
    313   void SmiOperation(Token::Value op,
    314                     Handle<Object> value,
    315                     bool reversed,
    316                     OverwriteMode mode);
    317 
    318   void CallWithArguments(ZoneList<Expression*>* arguments,
    319                          CallFunctionFlags flags,
    320                          int position);
    321 
    322   // Control flow
    323   void Branch(bool if_true, JumpTarget* target);
    324   void CheckStack();
    325 
    326   struct InlineRuntimeLUT {
    327     void (CodeGenerator::*method)(ZoneList<Expression*>*);
    328     const char* name;
    329   };
    330 
    331   static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
    332   bool CheckForInlineRuntimeCall(CallRuntime* node);
    333   static bool PatchInlineRuntimeEntry(Handle<String> name,
    334                                       const InlineRuntimeLUT& new_entry,
    335                                       InlineRuntimeLUT* old_entry);
    336 
    337   static Handle<Code> ComputeLazyCompile(int argc);
    338   void ProcessDeclarations(ZoneList<Declaration*>* declarations);
    339 
    340   static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
    341 
    342   // Declare global variables and functions in the given array of
    343   // name/value pairs.
    344   void DeclareGlobals(Handle<FixedArray> pairs);
    345 
    346   // Instantiate the function boilerplate.
    347   void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
    348 
    349   // Support for type checks.
    350   void GenerateIsSmi(ZoneList<Expression*>* args);
    351   void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
    352   void GenerateIsArray(ZoneList<Expression*>* args);
    353   void GenerateIsRegExp(ZoneList<Expression*>* args);
    354   void GenerateIsObject(ZoneList<Expression*>* args);
    355   void GenerateIsFunction(ZoneList<Expression*>* args);
    356   void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
    357 
    358   // Support for construct call checks.
    359   void GenerateIsConstructCall(ZoneList<Expression*>* args);
    360 
    361   // Support for arguments.length and arguments[?].
    362   void GenerateArgumentsLength(ZoneList<Expression*>* args);
    363   void GenerateArgumentsAccess(ZoneList<Expression*>* args);
    364 
    365   // Support for accessing the class and value fields of an object.
    366   void GenerateClassOf(ZoneList<Expression*>* args);
    367   void GenerateValueOf(ZoneList<Expression*>* args);
    368   void GenerateSetValueOf(ZoneList<Expression*>* args);
    369 
    370   // Fast support for charCodeAt(n).
    371   void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
    372 
    373   // Fast support for object equality testing.
    374   void GenerateObjectEquals(ZoneList<Expression*>* args);
    375 
    376   void GenerateLog(ZoneList<Expression*>* args);
    377 
    378   // Fast support for Math.random().
    379   void GenerateRandomPositiveSmi(ZoneList<Expression*>* args);
    380 
    381   // Fast support for StringAdd.
    382   void GenerateStringAdd(ZoneList<Expression*>* args);
    383 
    384   // Fast support for SubString.
    385   void GenerateSubString(ZoneList<Expression*>* args);
    386 
    387   // Fast support for StringCompare.
    388   void GenerateStringCompare(ZoneList<Expression*>* args);
    389 
    390   // Support for direct calls from JavaScript to native RegExp code.
    391   void GenerateRegExpExec(ZoneList<Expression*>* args);
    392 
    393   // Fast support for number to string.
    394   void GenerateNumberToString(ZoneList<Expression*>* args);
    395 
    396   // Fast call to sine function.
    397   void GenerateMathSin(ZoneList<Expression*>* args);
    398   void GenerateMathCos(ZoneList<Expression*>* args);
    399 
    400   // Simple condition analysis.
    401   enum ConditionAnalysis {
    402     ALWAYS_TRUE,
    403     ALWAYS_FALSE,
    404     DONT_KNOW
    405   };
    406   ConditionAnalysis AnalyzeCondition(Expression* cond);
    407 
    408   // Methods used to indicate which source code is generated for. Source
    409   // positions are collected by the assembler and emitted with the relocation
    410   // information.
    411   void CodeForFunctionPosition(FunctionLiteral* fun);
    412   void CodeForReturnPosition(FunctionLiteral* fun);
    413   void CodeForStatementPosition(Statement* node);
    414   void CodeForDoWhileConditionPosition(DoWhileStatement* stmt);
    415   void CodeForSourcePosition(int pos);
    416 
    417 #ifdef DEBUG
    418   // True if the registers are valid for entry to a block.
    419   bool HasValidEntryRegisters();
    420 #endif
    421 
    422   List<DeferredCode*> deferred_;
    423 
    424   // Assembler
    425   MacroAssembler* masm_;  // to generate code
    426 
    427   CompilationInfo* info_;
    428 
    429   // Code generation state
    430   VirtualFrame* frame_;
    431   RegisterAllocator* allocator_;
    432   Condition cc_reg_;
    433   CodeGenState* state_;
    434 
    435   // Jump targets
    436   BreakTarget function_return_;
    437 
    438   // True if the function return is shadowed (ie, jumping to the target
    439   // function_return_ does not jump to the true function return, but rather
    440   // to some unlinking code).
    441   bool function_return_is_shadowed_;
    442 
    443   static InlineRuntimeLUT kInlineRuntimeLUT[];
    444 
    445   friend class VirtualFrame;
    446   friend class JumpTarget;
    447   friend class Reference;
    448   friend class FastCodeGenerator;
    449   friend class FullCodeGenerator;
    450   friend class FullCodeGenSyntaxChecker;
    451 
    452   DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
    453 };
    454 
    455 
    456 class GenericBinaryOpStub : public CodeStub {
    457  public:
    458   GenericBinaryOpStub(Token::Value op,
    459                       OverwriteMode mode,
    460                       int constant_rhs = CodeGenerator::kUnknownIntValue)
    461       : op_(op),
    462         mode_(mode),
    463         constant_rhs_(constant_rhs),
    464         specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)),
    465         name_(NULL) { }
    466 
    467  private:
    468   Token::Value op_;
    469   OverwriteMode mode_;
    470   int constant_rhs_;
    471   bool specialized_on_rhs_;
    472   char* name_;
    473 
    474   static const int kMaxKnownRhs = 0x40000000;
    475 
    476   // Minor key encoding in 16 bits.
    477   class ModeBits: public BitField<OverwriteMode, 0, 2> {};
    478   class OpBits: public BitField<Token::Value, 2, 6> {};
    479   class KnownIntBits: public BitField<int, 8, 8> {};
    480 
    481   Major MajorKey() { return GenericBinaryOp; }
    482   int MinorKey() {
    483     // Encode the parameters in a unique 16 bit value.
    484     return OpBits::encode(op_)
    485            | ModeBits::encode(mode_)
    486            | KnownIntBits::encode(MinorKeyForKnownInt());
    487   }
    488 
    489   void Generate(MacroAssembler* masm);
    490   void HandleNonSmiBitwiseOp(MacroAssembler* masm);
    491 
    492   static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) {
    493     if (constant_rhs == CodeGenerator::kUnknownIntValue) return false;
    494     if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3;
    495     if (op == Token::MOD) {
    496       if (constant_rhs <= 1) return false;
    497       if (constant_rhs <= 10) return true;
    498       if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true;
    499       return false;
    500     }
    501     return false;
    502   }
    503 
    504   int MinorKeyForKnownInt() {
    505     if (!specialized_on_rhs_) return 0;
    506     if (constant_rhs_ <= 10) return constant_rhs_ + 1;
    507     ASSERT(IsPowerOf2(constant_rhs_));
    508     int key = 12;
    509     int d = constant_rhs_;
    510     while ((d & 1) == 0) {
    511       key++;
    512       d >>= 1;
    513     }
    514     return key;
    515   }
    516 
    517   const char* GetName();
    518 
    519 #ifdef DEBUG
    520   void Print() {
    521     if (!specialized_on_rhs_) {
    522       PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_));
    523     } else {
    524       PrintF("GenericBinaryOpStub (%s by %d)\n",
    525              Token::String(op_),
    526              constant_rhs_);
    527     }
    528   }
    529 #endif
    530 };
    531 
    532 
    533 class StringStubBase: public CodeStub {
    534  public:
    535   // Generate code for copying characters using a simple loop. This should only
    536   // be used in places where the number of characters is small and the
    537   // additional setup and checking in GenerateCopyCharactersLong adds too much
    538   // overhead. Copying of overlapping regions is not supported.
    539   // Dest register ends at the position after the last character written.
    540   void GenerateCopyCharacters(MacroAssembler* masm,
    541                               Register dest,
    542                               Register src,
    543                               Register count,
    544                               Register scratch,
    545                               bool ascii);
    546 
    547   // Generate code for copying a large number of characters. This function
    548   // is allowed to spend extra time setting up conditions to make copying
    549   // faster. Copying of overlapping regions is not supported.
    550   // Dest register ends at the position after the last character written.
    551   void GenerateCopyCharactersLong(MacroAssembler* masm,
    552                                   Register dest,
    553                                   Register src,
    554                                   Register count,
    555                                   Register scratch1,
    556                                   Register scratch2,
    557                                   Register scratch3,
    558                                   Register scratch4,
    559                                   Register scratch5,
    560                                   int flags);
    561 };
    562 
    563 
    564 // Flag that indicates how to generate code for the stub StringAddStub.
    565 enum StringAddFlags {
    566   NO_STRING_ADD_FLAGS = 0,
    567   NO_STRING_CHECK_IN_STUB = 1 << 0  // Omit string check in stub.
    568 };
    569 
    570 
    571 class StringAddStub: public StringStubBase {
    572  public:
    573   explicit StringAddStub(StringAddFlags flags) {
    574     string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0);
    575   }
    576 
    577  private:
    578   Major MajorKey() { return StringAdd; }
    579   int MinorKey() { return string_check_ ? 0 : 1; }
    580 
    581   void Generate(MacroAssembler* masm);
    582 
    583   // Should the stub check whether arguments are strings?
    584   bool string_check_;
    585 };
    586 
    587 
    588 class SubStringStub: public StringStubBase {
    589  public:
    590   SubStringStub() {}
    591 
    592  private:
    593   Major MajorKey() { return SubString; }
    594   int MinorKey() { return 0; }
    595 
    596   void Generate(MacroAssembler* masm);
    597 };
    598 
    599 
    600 
    601 class StringCompareStub: public CodeStub {
    602  public:
    603   StringCompareStub() { }
    604 
    605   // Compare two flat ASCII strings and returns result in r0.
    606   // Does not use the stack.
    607   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
    608                                               Register left,
    609                                               Register right,
    610                                               Register scratch1,
    611                                               Register scratch2,
    612                                               Register scratch3,
    613                                               Register scratch4);
    614 
    615  private:
    616   Major MajorKey() { return StringCompare; }
    617   int MinorKey() { return 0; }
    618 
    619   void Generate(MacroAssembler* masm);
    620 };
    621 
    622 
    623 } }  // namespace v8::internal
    624 
    625 #endif  // V8_ARM_CODEGEN_ARM_H_
    626