| // Copyright 2012 the V8 project authors. 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. | 
 | //     * Redistributions 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 Google Inc. nor the names of its | 
 | //       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. | 
 |  | 
 | #ifndef V8_ARM_CODE_STUBS_ARM_H_ | 
 | #define V8_ARM_CODE_STUBS_ARM_H_ | 
 |  | 
 | #include "ic-inl.h" | 
 |  | 
 | namespace v8 { | 
 | namespace internal { | 
 |  | 
 |  | 
 | void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code); | 
 |  | 
 |  | 
 | // Compute a transcendental math function natively, or call the | 
 | // TranscendentalCache runtime function. | 
 | class TranscendentalCacheStub: public PlatformCodeStub { | 
 |  public: | 
 |   enum ArgumentType { | 
 |     TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits, | 
 |     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits | 
 |   }; | 
 |  | 
 |   TranscendentalCacheStub(TranscendentalCache::Type type, | 
 |                           ArgumentType argument_type) | 
 |       : type_(type), argument_type_(argument_type) { } | 
 |   void Generate(MacroAssembler* masm); | 
 |  private: | 
 |   TranscendentalCache::Type type_; | 
 |   ArgumentType argument_type_; | 
 |   void GenerateCallCFunction(MacroAssembler* masm, Register scratch); | 
 |  | 
 |   Major MajorKey() { return TranscendentalCache; } | 
 |   int MinorKey() { return type_ | argument_type_; } | 
 |   Runtime::FunctionId RuntimeFunction(); | 
 | }; | 
 |  | 
 |  | 
 | class StoreBufferOverflowStub: public PlatformCodeStub { | 
 |  public: | 
 |   explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp) | 
 |       : save_doubles_(save_fp) {} | 
 |  | 
 |   void Generate(MacroAssembler* masm); | 
 |  | 
 |   virtual bool IsPregenerated() { return true; } | 
 |   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate); | 
 |   virtual bool SometimesSetsUpAFrame() { return false; } | 
 |  | 
 |  private: | 
 |   SaveFPRegsMode save_doubles_; | 
 |  | 
 |   Major MajorKey() { return StoreBufferOverflow; } | 
 |   int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } | 
 | }; | 
 |  | 
 |  | 
 | class StringHelper : public AllStatic { | 
 |  public: | 
 |   // Generate code for copying characters using a simple loop. This should only | 
 |   // be used in places where the number of characters is small and the | 
 |   // additional setup and checking in GenerateCopyCharactersLong adds too much | 
 |   // overhead. Copying of overlapping regions is not supported. | 
 |   // Dest register ends at the position after the last character written. | 
 |   static void GenerateCopyCharacters(MacroAssembler* masm, | 
 |                                      Register dest, | 
 |                                      Register src, | 
 |                                      Register count, | 
 |                                      Register scratch, | 
 |                                      bool ascii); | 
 |  | 
 |   // Generate code for copying a large number of characters. This function | 
 |   // is allowed to spend extra time setting up conditions to make copying | 
 |   // faster. Copying of overlapping regions is not supported. | 
 |   // Dest register ends at the position after the last character written. | 
 |   static void GenerateCopyCharactersLong(MacroAssembler* masm, | 
 |                                          Register dest, | 
 |                                          Register src, | 
 |                                          Register count, | 
 |                                          Register scratch1, | 
 |                                          Register scratch2, | 
 |                                          Register scratch3, | 
 |                                          Register scratch4, | 
 |                                          Register scratch5, | 
 |                                          int flags); | 
 |  | 
 |  | 
 |   // Probe the string table for a two character string. If the string is | 
 |   // not found by probing a jump to the label not_found is performed. This jump | 
 |   // does not guarantee that the string is not in the string table. If the | 
 |   // string is found the code falls through with the string in register r0. | 
 |   // Contents of both c1 and c2 registers are modified. At the exit c1 is | 
 |   // guaranteed to contain halfword with low and high bytes equal to | 
 |   // initial contents of c1 and c2 respectively. | 
 |   static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, | 
 |                                                    Register c1, | 
 |                                                    Register c2, | 
 |                                                    Register scratch1, | 
 |                                                    Register scratch2, | 
 |                                                    Register scratch3, | 
 |                                                    Register scratch4, | 
 |                                                    Register scratch5, | 
 |                                                    Label* not_found); | 
 |  | 
 |   // Generate string hash. | 
 |   static void GenerateHashInit(MacroAssembler* masm, | 
 |                                Register hash, | 
 |                                Register character); | 
 |  | 
 |   static void GenerateHashAddCharacter(MacroAssembler* masm, | 
 |                                        Register hash, | 
 |                                        Register character); | 
 |  | 
 |   static void GenerateHashGetHash(MacroAssembler* masm, | 
 |                                   Register hash); | 
 |  | 
 |  private: | 
 |   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); | 
 | }; | 
 |  | 
 |  | 
 | class StringAddStub: public PlatformCodeStub { | 
 |  public: | 
 |   explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} | 
 |  | 
 |  private: | 
 |   Major MajorKey() { return StringAdd; } | 
 |   int MinorKey() { return flags_; } | 
 |  | 
 |   void Generate(MacroAssembler* masm); | 
 |  | 
 |   void GenerateConvertArgument(MacroAssembler* masm, | 
 |                                int stack_offset, | 
 |                                Register arg, | 
 |                                Register scratch1, | 
 |                                Register scratch2, | 
 |                                Register scratch3, | 
 |                                Register scratch4, | 
 |                                Label* slow); | 
 |  | 
 |   void GenerateRegisterArgsPush(MacroAssembler* masm); | 
 |   void GenerateRegisterArgsPop(MacroAssembler* masm); | 
 |  | 
 |   const StringAddFlags flags_; | 
 | }; | 
 |  | 
 |  | 
 | class SubStringStub: public PlatformCodeStub { | 
 |  public: | 
 |   SubStringStub() {} | 
 |  | 
 |  private: | 
 |   Major MajorKey() { return SubString; } | 
 |   int MinorKey() { return 0; } | 
 |  | 
 |   void Generate(MacroAssembler* masm); | 
 | }; | 
 |  | 
 |  | 
 |  | 
 | class StringCompareStub: public PlatformCodeStub { | 
 |  public: | 
 |   StringCompareStub() { } | 
 |  | 
 |   // Compares two flat ASCII strings and returns result in r0. | 
 |   static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 
 |                                               Register left, | 
 |                                               Register right, | 
 |                                               Register scratch1, | 
 |                                               Register scratch2, | 
 |                                               Register scratch3, | 
 |                                               Register scratch4); | 
 |  | 
 |   // Compares two flat ASCII strings for equality and returns result | 
 |   // in r0. | 
 |   static void GenerateFlatAsciiStringEquals(MacroAssembler* masm, | 
 |                                             Register left, | 
 |                                             Register right, | 
 |                                             Register scratch1, | 
 |                                             Register scratch2, | 
 |                                             Register scratch3); | 
 |  | 
 |  private: | 
 |   virtual Major MajorKey() { return StringCompare; } | 
 |   virtual int MinorKey() { return 0; } | 
 |   virtual void Generate(MacroAssembler* masm); | 
 |  | 
 |   static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm, | 
 |                                             Register left, | 
 |                                             Register right, | 
 |                                             Register length, | 
 |                                             Register scratch1, | 
 |                                             Register scratch2, | 
 |                                             Label* chars_not_equal); | 
 | }; | 
 |  | 
 |  | 
 | // This stub can convert a signed int32 to a heap number (double).  It does | 
 | // not work for int32s that are in Smi range!  No GC occurs during this stub | 
 | // so you don't have to set up the frame. | 
 | class WriteInt32ToHeapNumberStub : public PlatformCodeStub { | 
 |  public: | 
 |   WriteInt32ToHeapNumberStub(Register the_int, | 
 |                              Register the_heap_number, | 
 |                              Register scratch) | 
 |       : the_int_(the_int), | 
 |         the_heap_number_(the_heap_number), | 
 |         scratch_(scratch) { } | 
 |  | 
 |   bool IsPregenerated(); | 
 |   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate); | 
 |  | 
 |  private: | 
 |   Register the_int_; | 
 |   Register the_heap_number_; | 
 |   Register scratch_; | 
 |  | 
 |   // Minor key encoding in 16 bits. | 
 |   class IntRegisterBits: public BitField<int, 0, 4> {}; | 
 |   class HeapNumberRegisterBits: public BitField<int, 4, 4> {}; | 
 |   class ScratchRegisterBits: public BitField<int, 8, 4> {}; | 
 |  | 
 |   Major MajorKey() { return WriteInt32ToHeapNumber; } | 
 |   int MinorKey() { | 
 |     // Encode the parameters in a unique 16 bit value. | 
 |     return IntRegisterBits::encode(the_int_.code()) | 
 |            | HeapNumberRegisterBits::encode(the_heap_number_.code()) | 
 |            | ScratchRegisterBits::encode(scratch_.code()); | 
 |   } | 
 |  | 
 |   void Generate(MacroAssembler* masm); | 
 | }; | 
 |  | 
 |  | 
 | class NumberToStringStub: public PlatformCodeStub { | 
 |  public: | 
 |   NumberToStringStub() { } | 
 |  | 
 |   // Generate code to do a lookup in the number string cache. If the number in | 
 |   // the register object is found in the cache the generated code falls through | 
 |   // with the result in the result register. The object and the result register | 
 |   // can be the same. If the number is not found in the cache the code jumps to | 
 |   // the label not_found with only the content of register object unchanged. | 
 |   static void GenerateLookupNumberStringCache(MacroAssembler* masm, | 
 |                                               Register object, | 
 |                                               Register result, | 
 |                                               Register scratch1, | 
 |                                               Register scratch2, | 
 |                                               Register scratch3, | 
 |                                               Label* not_found); | 
 |  | 
 |  private: | 
 |   Major MajorKey() { return NumberToString; } | 
 |   int MinorKey() { return 0; } | 
 |  | 
 |   void Generate(MacroAssembler* masm); | 
 | }; | 
 |  | 
 |  | 
 | class RecordWriteStub: public PlatformCodeStub { | 
 |  public: | 
 |   RecordWriteStub(Register object, | 
 |                   Register value, | 
 |                   Register address, | 
 |                   RememberedSetAction remembered_set_action, | 
 |                   SaveFPRegsMode fp_mode) | 
 |       : object_(object), | 
 |         value_(value), | 
 |         address_(address), | 
 |         remembered_set_action_(remembered_set_action), | 
 |         save_fp_regs_mode_(fp_mode), | 
 |         regs_(object,   // An input reg. | 
 |               address,  // An input reg. | 
 |               value) {  // One scratch reg. | 
 |   } | 
 |  | 
 |   enum Mode { | 
 |     STORE_BUFFER_ONLY, | 
 |     INCREMENTAL, | 
 |     INCREMENTAL_COMPACTION | 
 |   }; | 
 |  | 
 |   virtual bool IsPregenerated(); | 
 |   static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate); | 
 |   virtual bool SometimesSetsUpAFrame() { return false; } | 
 |  | 
 |   static void PatchBranchIntoNop(MacroAssembler* masm, int pos) { | 
 |     masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20)); | 
 |     ASSERT(Assembler::IsTstImmediate(masm->instr_at(pos))); | 
 |   } | 
 |  | 
 |   static void PatchNopIntoBranch(MacroAssembler* masm, int pos) { | 
 |     masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27); | 
 |     ASSERT(Assembler::IsBranch(masm->instr_at(pos))); | 
 |   } | 
 |  | 
 |   static Mode GetMode(Code* stub) { | 
 |     Instr first_instruction = Assembler::instr_at(stub->instruction_start()); | 
 |     Instr second_instruction = Assembler::instr_at(stub->instruction_start() + | 
 |                                                    Assembler::kInstrSize); | 
 |  | 
 |     if (Assembler::IsBranch(first_instruction)) { | 
 |       return INCREMENTAL; | 
 |     } | 
 |  | 
 |     ASSERT(Assembler::IsTstImmediate(first_instruction)); | 
 |  | 
 |     if (Assembler::IsBranch(second_instruction)) { | 
 |       return INCREMENTAL_COMPACTION; | 
 |     } | 
 |  | 
 |     ASSERT(Assembler::IsTstImmediate(second_instruction)); | 
 |  | 
 |     return STORE_BUFFER_ONLY; | 
 |   } | 
 |  | 
 |   static void Patch(Code* stub, Mode mode) { | 
 |     MacroAssembler masm(NULL, | 
 |                         stub->instruction_start(), | 
 |                         stub->instruction_size()); | 
 |     switch (mode) { | 
 |       case STORE_BUFFER_ONLY: | 
 |         ASSERT(GetMode(stub) == INCREMENTAL || | 
 |                GetMode(stub) == INCREMENTAL_COMPACTION); | 
 |         PatchBranchIntoNop(&masm, 0); | 
 |         PatchBranchIntoNop(&masm, Assembler::kInstrSize); | 
 |         break; | 
 |       case INCREMENTAL: | 
 |         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY); | 
 |         PatchNopIntoBranch(&masm, 0); | 
 |         break; | 
 |       case INCREMENTAL_COMPACTION: | 
 |         ASSERT(GetMode(stub) == STORE_BUFFER_ONLY); | 
 |         PatchNopIntoBranch(&masm, Assembler::kInstrSize); | 
 |         break; | 
 |     } | 
 |     ASSERT(GetMode(stub) == mode); | 
 |     CPU::FlushICache(stub->instruction_start(), 2 * Assembler::kInstrSize); | 
 |   } | 
 |  | 
 |  private: | 
 |   // This is a helper class for freeing up 3 scratch registers.  The input is | 
 |   // two registers that must be preserved and one scratch register provided by | 
 |   // the caller. | 
 |   class RegisterAllocation { | 
 |    public: | 
 |     RegisterAllocation(Register object, | 
 |                        Register address, | 
 |                        Register scratch0) | 
 |         : object_(object), | 
 |           address_(address), | 
 |           scratch0_(scratch0) { | 
 |       ASSERT(!AreAliased(scratch0, object, address, no_reg)); | 
 |       scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_); | 
 |     } | 
 |  | 
 |     void Save(MacroAssembler* masm) { | 
 |       ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_)); | 
 |       // We don't have to save scratch0_ because it was given to us as | 
 |       // a scratch register. | 
 |       masm->push(scratch1_); | 
 |     } | 
 |  | 
 |     void Restore(MacroAssembler* masm) { | 
 |       masm->pop(scratch1_); | 
 |     } | 
 |  | 
 |     // If we have to call into C then we need to save and restore all caller- | 
 |     // saved registers that were not already preserved.  The scratch registers | 
 |     // will be restored by other means so we don't bother pushing them here. | 
 |     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { | 
 |       masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit()); | 
 |       if (mode == kSaveFPRegs) { | 
 |         masm->SaveFPRegs(sp, scratch0_); | 
 |       } | 
 |     } | 
 |  | 
 |     inline void RestoreCallerSaveRegisters(MacroAssembler*masm, | 
 |                                            SaveFPRegsMode mode) { | 
 |       if (mode == kSaveFPRegs) { | 
 |         masm->RestoreFPRegs(sp, scratch0_); | 
 |       } | 
 |       masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit()); | 
 |     } | 
 |  | 
 |     inline Register object() { return object_; } | 
 |     inline Register address() { return address_; } | 
 |     inline Register scratch0() { return scratch0_; } | 
 |     inline Register scratch1() { return scratch1_; } | 
 |  | 
 |    private: | 
 |     Register object_; | 
 |     Register address_; | 
 |     Register scratch0_; | 
 |     Register scratch1_; | 
 |  | 
 |     Register GetRegThatIsNotOneOf(Register r1, | 
 |                                   Register r2, | 
 |                                   Register r3) { | 
 |       for (int i = 0; i < Register::NumAllocatableRegisters(); i++) { | 
 |         Register candidate = Register::FromAllocationIndex(i); | 
 |         if (candidate.is(r1)) continue; | 
 |         if (candidate.is(r2)) continue; | 
 |         if (candidate.is(r3)) continue; | 
 |         return candidate; | 
 |       } | 
 |       UNREACHABLE(); | 
 |       return no_reg; | 
 |     } | 
 |     friend class RecordWriteStub; | 
 |   }; | 
 |  | 
 |   enum OnNoNeedToInformIncrementalMarker { | 
 |     kReturnOnNoNeedToInformIncrementalMarker, | 
 |     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker | 
 |   }; | 
 |  | 
 |   void Generate(MacroAssembler* masm); | 
 |   void GenerateIncremental(MacroAssembler* masm, Mode mode); | 
 |   void CheckNeedsToInformIncrementalMarker( | 
 |       MacroAssembler* masm, | 
 |       OnNoNeedToInformIncrementalMarker on_no_need, | 
 |       Mode mode); | 
 |   void InformIncrementalMarker(MacroAssembler* masm, Mode mode); | 
 |  | 
 |   Major MajorKey() { return RecordWrite; } | 
 |  | 
 |   int MinorKey() { | 
 |     return ObjectBits::encode(object_.code()) | | 
 |         ValueBits::encode(value_.code()) | | 
 |         AddressBits::encode(address_.code()) | | 
 |         RememberedSetActionBits::encode(remembered_set_action_) | | 
 |         SaveFPRegsModeBits::encode(save_fp_regs_mode_); | 
 |   } | 
 |  | 
 |   void Activate(Code* code) { | 
 |     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); | 
 |   } | 
 |  | 
 |   class ObjectBits: public BitField<int, 0, 4> {}; | 
 |   class ValueBits: public BitField<int, 4, 4> {}; | 
 |   class AddressBits: public BitField<int, 8, 4> {}; | 
 |   class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {}; | 
 |   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {}; | 
 |  | 
 |   Register object_; | 
 |   Register value_; | 
 |   Register address_; | 
 |   RememberedSetAction remembered_set_action_; | 
 |   SaveFPRegsMode save_fp_regs_mode_; | 
 |   Label slow_; | 
 |   RegisterAllocation regs_; | 
 | }; | 
 |  | 
 |  | 
 | // Enter C code from generated RegExp code in a way that allows | 
 | // the C code to fix the return address in case of a GC. | 
 | // Currently only needed on ARM. | 
 | class RegExpCEntryStub: public PlatformCodeStub { | 
 |  public: | 
 |   RegExpCEntryStub() {} | 
 |   virtual ~RegExpCEntryStub() {} | 
 |   void Generate(MacroAssembler* masm); | 
 |  | 
 |  private: | 
 |   Major MajorKey() { return RegExpCEntry; } | 
 |   int MinorKey() { return 0; } | 
 |  | 
 |   bool NeedsImmovableCode() { return true; } | 
 | }; | 
 |  | 
 |  | 
 | // Trampoline stub to call into native code. To call safely into native code | 
 | // in the presence of compacting GC (which can move code objects) we need to | 
 | // keep the code which called into native pinned in the memory. Currently the | 
 | // simplest approach is to generate such stub early enough so it can never be | 
 | // moved by GC | 
 | class DirectCEntryStub: public PlatformCodeStub { | 
 |  public: | 
 |   DirectCEntryStub() {} | 
 |   void Generate(MacroAssembler* masm); | 
 |   void GenerateCall(MacroAssembler* masm, Register target); | 
 |  | 
 |  private: | 
 |   Major MajorKey() { return DirectCEntry; } | 
 |   int MinorKey() { return 0; } | 
 |  | 
 |   bool NeedsImmovableCode() { return true; } | 
 | }; | 
 |  | 
 |  | 
 | class NameDictionaryLookupStub: public PlatformCodeStub { | 
 |  public: | 
 |   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP }; | 
 |  | 
 |   explicit NameDictionaryLookupStub(LookupMode mode) : mode_(mode) { } | 
 |  | 
 |   void Generate(MacroAssembler* masm); | 
 |  | 
 |   static void GenerateNegativeLookup(MacroAssembler* masm, | 
 |                                      Label* miss, | 
 |                                      Label* done, | 
 |                                      Register receiver, | 
 |                                      Register properties, | 
 |                                      Handle<Name> name, | 
 |                                      Register scratch0); | 
 |  | 
 |   static void GeneratePositiveLookup(MacroAssembler* masm, | 
 |                                      Label* miss, | 
 |                                      Label* done, | 
 |                                      Register elements, | 
 |                                      Register name, | 
 |                                      Register r0, | 
 |                                      Register r1); | 
 |  | 
 |   virtual bool SometimesSetsUpAFrame() { return false; } | 
 |  | 
 |  private: | 
 |   static const int kInlinedProbes = 4; | 
 |   static const int kTotalProbes = 20; | 
 |  | 
 |   static const int kCapacityOffset = | 
 |       NameDictionary::kHeaderSize + | 
 |       NameDictionary::kCapacityIndex * kPointerSize; | 
 |  | 
 |   static const int kElementsStartOffset = | 
 |       NameDictionary::kHeaderSize + | 
 |       NameDictionary::kElementsStartIndex * kPointerSize; | 
 |  | 
 |   Major MajorKey() { return NameDictionaryLookup; } | 
 |  | 
 |   int MinorKey() { | 
 |     return LookupModeBits::encode(mode_); | 
 |   } | 
 |  | 
 |   class LookupModeBits: public BitField<LookupMode, 0, 1> {}; | 
 |  | 
 |   LookupMode mode_; | 
 | }; | 
 |  | 
 |  | 
 | } }  // namespace v8::internal | 
 |  | 
 | #endif  // V8_ARM_CODE_STUBS_ARM_H_ |