| Index: src/arm/code-stubs-arm.h
 | 
| ===================================================================
 | 
| --- src/arm/code-stubs-arm.h	(revision 9531)
 | 
| +++ src/arm/code-stubs-arm.h	(working copy)
 | 
| @@ -58,6 +58,25 @@
 | 
|  };
 | 
|  
 | 
|  
 | 
| +class StoreBufferOverflowStub: public CodeStub {
 | 
| + public:
 | 
| +  explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp)
 | 
| +      : save_doubles_(save_fp) { }
 | 
| +
 | 
| +  void Generate(MacroAssembler* masm);
 | 
| +
 | 
| +  virtual bool IsPregenerated();
 | 
| +  static void GenerateFixedRegStubsAheadOfTime();
 | 
| +  virtual bool SometimesSetsUpAFrame() { return false; }
 | 
| +
 | 
| + private:
 | 
| +  SaveFPRegsMode save_doubles_;
 | 
| +
 | 
| +  Major MajorKey() { return StoreBufferOverflow; }
 | 
| +  int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; }
 | 
| +};
 | 
| +
 | 
| +
 | 
|  class UnaryOpStub: public CodeStub {
 | 
|   public:
 | 
|    UnaryOpStub(Token::Value op,
 | 
| @@ -323,6 +342,9 @@
 | 
|          the_heap_number_(the_heap_number),
 | 
|          scratch_(scratch) { }
 | 
|  
 | 
| +  bool IsPregenerated();
 | 
| +  static void GenerateFixedRegStubsAheadOfTime();
 | 
| +
 | 
|   private:
 | 
|    Register the_int_;
 | 
|    Register the_heap_number_;
 | 
| @@ -371,6 +393,225 @@
 | 
|  };
 | 
|  
 | 
|  
 | 
| +class RecordWriteStub: public CodeStub {
 | 
| + 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();
 | 
| +  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) {
 | 
| +        CpuFeatures::Scope scope(VFP3);
 | 
| +        masm->sub(sp,
 | 
| +                  sp,
 | 
| +                  Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1)));
 | 
| +        // Save all VFP registers except d0.
 | 
| +        for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) {
 | 
| +          DwVfpRegister reg = DwVfpRegister::from_code(i);
 | 
| +          masm->vstr(reg, MemOperand(sp, (i - 1) * kDoubleSize));
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
 | 
| +                                           SaveFPRegsMode mode) {
 | 
| +      if (mode == kSaveFPRegs) {
 | 
| +        CpuFeatures::Scope scope(VFP3);
 | 
| +        // Restore all VFP registers except d0.
 | 
| +        for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) {
 | 
| +          DwVfpRegister reg = DwVfpRegister::from_code(i);
 | 
| +          masm->vldr(reg, MemOperand(sp, (i - 1) * kDoubleSize));
 | 
| +        }
 | 
| +        masm->add(sp,
 | 
| +                  sp,
 | 
| +                  Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1)));
 | 
| +      }
 | 
| +      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::kNumAllocatableRegisters; 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_);
 | 
| +  }
 | 
| +
 | 
| +  bool MustBeInStubCache() {
 | 
| +    // All stubs must be registered in the stub cache
 | 
| +    // otherwise IncrementalMarker would not be able to find
 | 
| +    // and patch it.
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  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.
 | 
| @@ -575,6 +816,8 @@
 | 
|                                       Register r0,
 | 
|                                       Register r1);
 | 
|  
 | 
| +  virtual bool SometimesSetsUpAFrame() { return false; }
 | 
| +
 | 
|   private:
 | 
|    static const int kInlinedProbes = 4;
 | 
|    static const int kTotalProbes = 20;
 | 
| @@ -587,7 +830,7 @@
 | 
|        StringDictionary::kHeaderSize +
 | 
|        StringDictionary::kElementsStartIndex * kPointerSize;
 | 
|  
 | 
| -  Major MajorKey() { return StringDictionaryNegativeLookup; }
 | 
| +  Major MajorKey() { return StringDictionaryLookup; }
 | 
|  
 | 
|    int MinorKey() {
 | 
|      return LookupModeBits::encode(mode_);
 | 
| 
 |