1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_ARM_CODE_STUBS_ARM_H_
6#define V8_ARM_CODE_STUBS_ARM_H_
7
8#include "src/arm/frames-arm.h"
9
10namespace v8 {
11namespace internal {
12
13
14void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
15
16
17class StringHelper : public AllStatic {
18 public:
19  // Compares two flat one-byte strings and returns result in r0.
20  static void GenerateCompareFlatOneByteStrings(
21      MacroAssembler* masm, Register left, Register right, Register scratch1,
22      Register scratch2, Register scratch3, Register scratch4);
23
24  // Compares two flat one-byte strings for equality and returns result in r0.
25  static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
26                                              Register left, Register right,
27                                              Register scratch1,
28                                              Register scratch2,
29                                              Register scratch3);
30
31 private:
32  static void GenerateOneByteCharsCompareLoop(
33      MacroAssembler* masm, Register left, Register right, Register length,
34      Register scratch1, Register scratch2, Label* chars_not_equal);
35
36  DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
37};
38
39
40class RecordWriteStub: public PlatformCodeStub {
41 public:
42  RecordWriteStub(Isolate* isolate,
43                  Register object,
44                  Register value,
45                  Register address,
46                  RememberedSetAction remembered_set_action,
47                  SaveFPRegsMode fp_mode)
48      : PlatformCodeStub(isolate),
49        regs_(object,   // An input reg.
50              address,  // An input reg.
51              value) {  // One scratch reg.
52    minor_key_ = ObjectBits::encode(object.code()) |
53                 ValueBits::encode(value.code()) |
54                 AddressBits::encode(address.code()) |
55                 RememberedSetActionBits::encode(remembered_set_action) |
56                 SaveFPRegsModeBits::encode(fp_mode);
57  }
58
59  RecordWriteStub(uint32_t key, Isolate* isolate)
60      : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
61
62  enum Mode {
63    STORE_BUFFER_ONLY,
64    INCREMENTAL,
65    INCREMENTAL_COMPACTION
66  };
67
68  bool SometimesSetsUpAFrame() override { return false; }
69
70  static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
71    masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20));
72    DCHECK(Assembler::IsTstImmediate(masm->instr_at(pos)));
73  }
74
75  static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
76    masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27);
77    DCHECK(Assembler::IsBranch(masm->instr_at(pos)));
78  }
79
80  static Mode GetMode(Code* stub) {
81    Instr first_instruction = Assembler::instr_at(stub->instruction_start());
82    Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
83                                                   Assembler::kInstrSize);
84
85    if (Assembler::IsBranch(first_instruction)) {
86      return INCREMENTAL;
87    }
88
89    DCHECK(Assembler::IsTstImmediate(first_instruction));
90
91    if (Assembler::IsBranch(second_instruction)) {
92      return INCREMENTAL_COMPACTION;
93    }
94
95    DCHECK(Assembler::IsTstImmediate(second_instruction));
96
97    return STORE_BUFFER_ONLY;
98  }
99
100  static void Patch(Code* stub, Mode mode) {
101    MacroAssembler masm(stub->GetIsolate(), stub->instruction_start(),
102                        stub->instruction_size(), CodeObjectRequired::kNo);
103    switch (mode) {
104      case STORE_BUFFER_ONLY:
105        DCHECK(GetMode(stub) == INCREMENTAL ||
106               GetMode(stub) == INCREMENTAL_COMPACTION);
107        PatchBranchIntoNop(&masm, 0);
108        PatchBranchIntoNop(&masm, Assembler::kInstrSize);
109        break;
110      case INCREMENTAL:
111        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
112        PatchNopIntoBranch(&masm, 0);
113        break;
114      case INCREMENTAL_COMPACTION:
115        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
116        PatchNopIntoBranch(&masm, Assembler::kInstrSize);
117        break;
118    }
119    DCHECK(GetMode(stub) == mode);
120    Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(),
121                           2 * Assembler::kInstrSize);
122  }
123
124  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
125
126 private:
127  // This is a helper class for freeing up 3 scratch registers.  The input is
128  // two registers that must be preserved and one scratch register provided by
129  // the caller.
130  class RegisterAllocation {
131   public:
132    RegisterAllocation(Register object,
133                       Register address,
134                       Register scratch0)
135        : object_(object),
136          address_(address),
137          scratch0_(scratch0) {
138      DCHECK(!AreAliased(scratch0, object, address, no_reg));
139      scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
140    }
141
142    void Save(MacroAssembler* masm) {
143      DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
144      // We don't have to save scratch0_ because it was given to us as
145      // a scratch register.
146      masm->push(scratch1_);
147    }
148
149    void Restore(MacroAssembler* masm) {
150      masm->pop(scratch1_);
151    }
152
153    // If we have to call into C then we need to save and restore all caller-
154    // saved registers that were not already preserved.  The scratch registers
155    // will be restored by other means so we don't bother pushing them here.
156    void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
157      masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
158      if (mode == kSaveFPRegs) {
159        masm->SaveFPRegs(sp, scratch0_);
160      }
161    }
162
163    inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
164                                           SaveFPRegsMode mode) {
165      if (mode == kSaveFPRegs) {
166        masm->RestoreFPRegs(sp, scratch0_);
167      }
168      masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
169    }
170
171    inline Register object() { return object_; }
172    inline Register address() { return address_; }
173    inline Register scratch0() { return scratch0_; }
174    inline Register scratch1() { return scratch1_; }
175
176   private:
177    Register object_;
178    Register address_;
179    Register scratch0_;
180    Register scratch1_;
181
182    friend class RecordWriteStub;
183  };
184
185  enum OnNoNeedToInformIncrementalMarker {
186    kReturnOnNoNeedToInformIncrementalMarker,
187    kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
188  };
189
190  inline Major MajorKey() const final { return RecordWrite; }
191
192  void Generate(MacroAssembler* masm) override;
193  void GenerateIncremental(MacroAssembler* masm, Mode mode);
194  void CheckNeedsToInformIncrementalMarker(
195      MacroAssembler* masm,
196      OnNoNeedToInformIncrementalMarker on_no_need,
197      Mode mode);
198  void InformIncrementalMarker(MacroAssembler* masm);
199
200  void Activate(Code* code) override {
201    code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
202  }
203
204  Register object() const {
205    return Register::from_code(ObjectBits::decode(minor_key_));
206  }
207
208  Register value() const {
209    return Register::from_code(ValueBits::decode(minor_key_));
210  }
211
212  Register address() const {
213    return Register::from_code(AddressBits::decode(minor_key_));
214  }
215
216  RememberedSetAction remembered_set_action() const {
217    return RememberedSetActionBits::decode(minor_key_);
218  }
219
220  SaveFPRegsMode save_fp_regs_mode() const {
221    return SaveFPRegsModeBits::decode(minor_key_);
222  }
223
224  class ObjectBits: public BitField<int, 0, 4> {};
225  class ValueBits: public BitField<int, 4, 4> {};
226  class AddressBits: public BitField<int, 8, 4> {};
227  class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {};
228  class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {};
229
230  Label slow_;
231  RegisterAllocation regs_;
232
233  DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
234};
235
236
237// Trampoline stub to call into native code. To call safely into native code
238// in the presence of compacting GC (which can move code objects) we need to
239// keep the code which called into native pinned in the memory. Currently the
240// simplest approach is to generate such stub early enough so it can never be
241// moved by GC
242class DirectCEntryStub: public PlatformCodeStub {
243 public:
244  explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
245  void GenerateCall(MacroAssembler* masm, Register target);
246
247 private:
248  bool NeedsImmovableCode() override { return true; }
249
250  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
251  DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
252};
253
254
255class NameDictionaryLookupStub: public PlatformCodeStub {
256 public:
257  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
258
259  NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
260      : PlatformCodeStub(isolate) {
261    minor_key_ = LookupModeBits::encode(mode);
262  }
263
264  static void GenerateNegativeLookup(MacroAssembler* masm,
265                                     Label* miss,
266                                     Label* done,
267                                     Register receiver,
268                                     Register properties,
269                                     Handle<Name> name,
270                                     Register scratch0);
271
272  bool SometimesSetsUpAFrame() override { return false; }
273
274 private:
275  static const int kInlinedProbes = 4;
276  static const int kTotalProbes = 20;
277
278  static const int kCapacityOffset =
279      NameDictionary::kHeaderSize +
280      NameDictionary::kCapacityIndex * kPointerSize;
281
282  static const int kElementsStartOffset =
283      NameDictionary::kHeaderSize +
284      NameDictionary::kElementsStartIndex * kPointerSize;
285
286  LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
287
288  class LookupModeBits: public BitField<LookupMode, 0, 1> {};
289
290  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
291  DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
292};
293
294}  // namespace internal
295}  // namespace v8
296
297#endif  // V8_ARM_CODE_STUBS_ARM_H_
298