code-stubs-arm.h 10.7 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_ARM_CODE_STUBS_ARM_H_
#define V8_ARM_CODE_STUBS_ARM_H_

8 9
#include "src/arm/frames-arm.h"

10 11 12 13
namespace v8 {
namespace internal {


14 15 16
void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);


17 18 19 20 21 22
class StringHelper : public AllStatic {
 public:
  // 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.
23 24 25 26 27 28
  static void GenerateCopyCharacters(MacroAssembler* masm,
                                     Register dest,
                                     Register src,
                                     Register count,
                                     Register scratch,
                                     String::Encoding encoding);
29

30 31 32 33 34 35 36 37
  // Compares two flat one-byte strings and returns result in r0.
  static void GenerateCompareFlatOneByteStrings(
      MacroAssembler* masm, Register left, Register right, Register scratch1,
      Register scratch2, Register scratch3, Register scratch4);

  // Compares two flat one-byte strings for equality and returns result in r0.
  static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
                                              Register left, Register right,
38 39
                                              Register scratch1,
                                              Register scratch2,
40
                                              Register scratch3);
41

42
 private:
43 44 45
  static void GenerateOneByteCharsCompareLoop(
      MacroAssembler* masm, Register left, Register right, Register length,
      Register scratch1, Register scratch2, Label* chars_not_equal);
46 47

  DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
48 49 50
};


51
class RecordWriteStub: public PlatformCodeStub {
52
 public:
53 54
  RecordWriteStub(Isolate* isolate,
                  Register object,
55 56 57 58
                  Register value,
                  Register address,
                  RememberedSetAction remembered_set_action,
                  SaveFPRegsMode fp_mode)
59
      : PlatformCodeStub(isolate),
60 61 62
        regs_(object,   // An input reg.
              address,  // An input reg.
              value) {  // One scratch reg.
63 64 65 66 67
    minor_key_ = ObjectBits::encode(object.code()) |
                 ValueBits::encode(value.code()) |
                 AddressBits::encode(address.code()) |
                 RememberedSetActionBits::encode(remembered_set_action) |
                 SaveFPRegsModeBits::encode(fp_mode);
68 69
  }

70 71 72
  RecordWriteStub(uint32_t key, Isolate* isolate)
      : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}

73 74 75 76 77 78
  enum Mode {
    STORE_BUFFER_ONLY,
    INCREMENTAL,
    INCREMENTAL_COMPACTION
  };

79
  bool SometimesSetsUpAFrame() override { return false; }
80 81 82

  static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
    masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20));
83
    DCHECK(Assembler::IsTstImmediate(masm->instr_at(pos)));
84 85 86 87
  }

  static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
    masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27);
88
    DCHECK(Assembler::IsBranch(masm->instr_at(pos)));
89 90 91 92 93 94 95 96 97 98 99
  }

  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;
    }

100
    DCHECK(Assembler::IsTstImmediate(first_instruction));
101 102 103 104 105

    if (Assembler::IsBranch(second_instruction)) {
      return INCREMENTAL_COMPACTION;
    }

106
    DCHECK(Assembler::IsTstImmediate(second_instruction));
107 108 109 110 111 112 113 114 115 116

    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:
117
        DCHECK(GetMode(stub) == INCREMENTAL ||
118 119 120 121 122
               GetMode(stub) == INCREMENTAL_COMPACTION);
        PatchBranchIntoNop(&masm, 0);
        PatchBranchIntoNop(&masm, Assembler::kInstrSize);
        break;
      case INCREMENTAL:
123
        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
124 125 126
        PatchNopIntoBranch(&masm, 0);
        break;
      case INCREMENTAL_COMPACTION:
127
        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
128 129 130
        PatchNopIntoBranch(&masm, Assembler::kInstrSize);
        break;
    }
131
    DCHECK(GetMode(stub) == mode);
132 133
    Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(),
                           2 * Assembler::kInstrSize);
134 135
  }

136 137
  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();

138 139 140 141 142 143 144 145 146 147 148 149
 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) {
150
      DCHECK(!AreAliased(scratch0, object, address, no_reg));
151
      scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
152 153 154
    }

    void Save(MacroAssembler* masm) {
155
      DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
      // 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) {
171
        masm->SaveFPRegs(sp, scratch0_);
172 173 174 175 176 177
      }
    }

    inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
                                           SaveFPRegsMode mode) {
      if (mode == kSaveFPRegs) {
178
        masm->RestoreFPRegs(sp, scratch0_);
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
      }
      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_;

    friend class RecordWriteStub;
  };

  enum OnNoNeedToInformIncrementalMarker {
    kReturnOnNoNeedToInformIncrementalMarker,
    kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
  };

202
  inline Major MajorKey() const final { return RecordWrite; }
203

204
  void Generate(MacroAssembler* masm) override;
205 206 207 208 209
  void GenerateIncremental(MacroAssembler* masm, Mode mode);
  void CheckNeedsToInformIncrementalMarker(
      MacroAssembler* masm,
      OnNoNeedToInformIncrementalMarker on_no_need,
      Mode mode);
210
  void InformIncrementalMarker(MacroAssembler* masm);
211

212
  void Activate(Code* code) override {
213 214
    code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
  }
215

216 217
  Register object() const {
    return Register::from_code(ObjectBits::decode(minor_key_));
218 219
  }

220 221 222 223 224 225 226 227 228 229 230 231 232 233
  Register value() const {
    return Register::from_code(ValueBits::decode(minor_key_));
  }

  Register address() const {
    return Register::from_code(AddressBits::decode(minor_key_));
  }

  RememberedSetAction remembered_set_action() const {
    return RememberedSetActionBits::decode(minor_key_);
  }

  SaveFPRegsMode save_fp_regs_mode() const {
    return SaveFPRegsModeBits::decode(minor_key_);
234 235 236 237 238 239 240 241 242 243
  }

  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> {};

  Label slow_;
  RegisterAllocation regs_;
244 245

  DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
246 247 248
};


249 250 251 252 253
// 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
254
class DirectCEntryStub: public PlatformCodeStub {
255
 public:
256
  explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
257
  void GenerateCall(MacroAssembler* masm, Register target);
258 259

 private:
260
  bool NeedsImmovableCode() override { return true; }
261

262
  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
263
  DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
264 265 266
};


267
class NameDictionaryLookupStub: public PlatformCodeStub {
268 269 270
 public:
  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };

271
  NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
272 273 274
      : PlatformCodeStub(isolate) {
    minor_key_ = LookupModeBits::encode(mode);
  }
275

276 277 278 279 280
  static void GenerateNegativeLookup(MacroAssembler* masm,
                                     Label* miss,
                                     Label* done,
                                     Register receiver,
                                     Register properties,
281
                                     Handle<Name> name,
282 283
                                     Register scratch0);

284 285 286 287 288 289 290 291
  static void GeneratePositiveLookup(MacroAssembler* masm,
                                     Label* miss,
                                     Label* done,
                                     Register elements,
                                     Register name,
                                     Register r0,
                                     Register r1);

292
  bool SometimesSetsUpAFrame() override { return false; }
293

294 295 296 297 298
 private:
  static const int kInlinedProbes = 4;
  static const int kTotalProbes = 20;

  static const int kCapacityOffset =
299 300
      NameDictionary::kHeaderSize +
      NameDictionary::kCapacityIndex * kPointerSize;
301 302

  static const int kElementsStartOffset =
303 304
      NameDictionary::kHeaderSize +
      NameDictionary::kElementsStartIndex * kPointerSize;
305

306
  LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
307 308 309

  class LookupModeBits: public BitField<LookupMode, 0, 1> {};

310
  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
311
  DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
312 313
};

314 315
}  // namespace internal
}  // namespace v8
316 317

#endif  // V8_ARM_CODE_STUBS_ARM_H_