1// Copyright 2011 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_MIPS_CODE_STUBS_MIPS64_H_
6#define V8_MIPS_CODE_STUBS_MIPS64_H_
7
8#include "src/mips64/frames-mips64.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 v0.
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 v0.
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, Register scratch3,
35      Label* chars_not_equal);
36
37 private:
38  DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
39};
40
41
42class StoreRegistersStateStub: public PlatformCodeStub {
43 public:
44  explicit StoreRegistersStateStub(Isolate* isolate)
45      : PlatformCodeStub(isolate) {}
46
47  static void GenerateAheadOfTime(Isolate* isolate);
48
49 private:
50  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
51  DEFINE_PLATFORM_CODE_STUB(StoreRegistersState, PlatformCodeStub);
52};
53
54
55class RestoreRegistersStateStub: public PlatformCodeStub {
56 public:
57  explicit RestoreRegistersStateStub(Isolate* isolate)
58      : PlatformCodeStub(isolate) {}
59
60  static void GenerateAheadOfTime(Isolate* isolate);
61
62 private:
63  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
64  DEFINE_PLATFORM_CODE_STUB(RestoreRegistersState, PlatformCodeStub);
65};
66
67
68class RecordWriteStub: public PlatformCodeStub {
69 public:
70  RecordWriteStub(Isolate* isolate,
71                  Register object,
72                  Register value,
73                  Register address,
74                  RememberedSetAction remembered_set_action,
75                  SaveFPRegsMode fp_mode)
76      : PlatformCodeStub(isolate),
77        regs_(object,   // An input reg.
78              address,  // An input reg.
79              value) {  // One scratch reg.
80    minor_key_ = ObjectBits::encode(object.code()) |
81                 ValueBits::encode(value.code()) |
82                 AddressBits::encode(address.code()) |
83                 RememberedSetActionBits::encode(remembered_set_action) |
84                 SaveFPRegsModeBits::encode(fp_mode);
85  }
86
87  RecordWriteStub(uint32_t key, Isolate* isolate)
88      : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
89
90  enum Mode {
91    STORE_BUFFER_ONLY,
92    INCREMENTAL,
93    INCREMENTAL_COMPACTION
94  };
95
96  bool SometimesSetsUpAFrame() override { return false; }
97
98  static void PatchBranchIntoNop(MacroAssembler* masm, int pos) {
99    const unsigned offset = masm->instr_at(pos) & kImm16Mask;
100    masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) |
101        (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
102    DCHECK(Assembler::IsBne(masm->instr_at(pos)));
103  }
104
105  static void PatchNopIntoBranch(MacroAssembler* masm, int pos) {
106    const unsigned offset = masm->instr_at(pos) & kImm16Mask;
107    masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) |
108        (zero_reg.code() << kRtShift) | (offset & kImm16Mask));
109    DCHECK(Assembler::IsBeq(masm->instr_at(pos)));
110  }
111
112  static Mode GetMode(Code* stub) {
113    Instr first_instruction = Assembler::instr_at(stub->instruction_start());
114    Instr second_instruction = Assembler::instr_at(stub->instruction_start() +
115                                                   2 * Assembler::kInstrSize);
116
117    if (Assembler::IsBeq(first_instruction)) {
118      return INCREMENTAL;
119    }
120
121    DCHECK(Assembler::IsBne(first_instruction));
122
123    if (Assembler::IsBeq(second_instruction)) {
124      return INCREMENTAL_COMPACTION;
125    }
126
127    DCHECK(Assembler::IsBne(second_instruction));
128
129    return STORE_BUFFER_ONLY;
130  }
131
132  static void Patch(Code* stub, Mode mode) {
133    MacroAssembler masm(stub->GetIsolate(), stub->instruction_start(),
134                        stub->instruction_size(), CodeObjectRequired::kNo);
135    switch (mode) {
136      case STORE_BUFFER_ONLY:
137        DCHECK(GetMode(stub) == INCREMENTAL ||
138               GetMode(stub) == INCREMENTAL_COMPACTION);
139        PatchBranchIntoNop(&masm, 0);
140        PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize);
141        break;
142      case INCREMENTAL:
143        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
144        PatchNopIntoBranch(&masm, 0);
145        break;
146      case INCREMENTAL_COMPACTION:
147        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
148        PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize);
149        break;
150    }
151    DCHECK(GetMode(stub) == mode);
152    Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(),
153                           4 * Assembler::kInstrSize);
154  }
155
156  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
157
158 private:
159  // This is a helper class for freeing up 3 scratch registers.  The input is
160  // two registers that must be preserved and one scratch register provided by
161  // the caller.
162  class RegisterAllocation {
163   public:
164    RegisterAllocation(Register object,
165                       Register address,
166                       Register scratch0)
167        : object_(object),
168          address_(address),
169          scratch0_(scratch0) {
170      DCHECK(!AreAliased(scratch0, object, address, no_reg));
171      scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_);
172    }
173
174    void Save(MacroAssembler* masm) {
175      DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_));
176      // We don't have to save scratch0_ because it was given to us as
177      // a scratch register.
178      masm->push(scratch1_);
179    }
180
181    void Restore(MacroAssembler* masm) {
182      masm->pop(scratch1_);
183    }
184
185    // If we have to call into C then we need to save and restore all caller-
186    // saved registers that were not already preserved.  The scratch registers
187    // will be restored by other means so we don't bother pushing them here.
188    void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
189      masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
190      if (mode == kSaveFPRegs) {
191        masm->MultiPushFPU(kCallerSavedFPU);
192      }
193    }
194
195    inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
196                                           SaveFPRegsMode mode) {
197      if (mode == kSaveFPRegs) {
198        masm->MultiPopFPU(kCallerSavedFPU);
199      }
200      masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit());
201    }
202
203    inline Register object() { return object_; }
204    inline Register address() { return address_; }
205    inline Register scratch0() { return scratch0_; }
206    inline Register scratch1() { return scratch1_; }
207
208   private:
209    Register object_;
210    Register address_;
211    Register scratch0_;
212    Register scratch1_;
213
214    friend class RecordWriteStub;
215  };
216
217  enum OnNoNeedToInformIncrementalMarker {
218    kReturnOnNoNeedToInformIncrementalMarker,
219    kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
220  };
221
222  inline Major MajorKey() const final { return RecordWrite; }
223
224  void Generate(MacroAssembler* masm) override;
225  void GenerateIncremental(MacroAssembler* masm, Mode mode);
226  void CheckNeedsToInformIncrementalMarker(
227      MacroAssembler* masm,
228      OnNoNeedToInformIncrementalMarker on_no_need,
229      Mode mode);
230  void InformIncrementalMarker(MacroAssembler* masm);
231
232  void Activate(Code* code) override {
233    code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
234  }
235
236  Register object() const {
237    return Register::from_code(ObjectBits::decode(minor_key_));
238  }
239
240  Register value() const {
241    return Register::from_code(ValueBits::decode(minor_key_));
242  }
243
244  Register address() const {
245    return Register::from_code(AddressBits::decode(minor_key_));
246  }
247
248  RememberedSetAction remembered_set_action() const {
249    return RememberedSetActionBits::decode(minor_key_);
250  }
251
252  SaveFPRegsMode save_fp_regs_mode() const {
253    return SaveFPRegsModeBits::decode(minor_key_);
254  }
255
256  class ObjectBits: public BitField<int, 0, 5> {};
257  class ValueBits: public BitField<int, 5, 5> {};
258  class AddressBits: public BitField<int, 10, 5> {};
259  class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
260  class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
261
262  Label slow_;
263  RegisterAllocation regs_;
264
265  DISALLOW_COPY_AND_ASSIGN(RecordWriteStub);
266};
267
268
269// Trampoline stub to call into native code. To call safely into native code
270// in the presence of compacting GC (which can move code objects) we need to
271// keep the code which called into native pinned in the memory. Currently the
272// simplest approach is to generate such stub early enough so it can never be
273// moved by GC
274class DirectCEntryStub: public PlatformCodeStub {
275 public:
276  explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
277  void GenerateCall(MacroAssembler* masm, Register target);
278
279 private:
280  bool NeedsImmovableCode() override { return true; }
281
282  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
283  DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
284};
285
286
287class NameDictionaryLookupStub: public PlatformCodeStub {
288 public:
289  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
290
291  NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
292      : PlatformCodeStub(isolate) {
293    minor_key_ = LookupModeBits::encode(mode);
294  }
295
296  static void GenerateNegativeLookup(MacroAssembler* masm,
297                                     Label* miss,
298                                     Label* done,
299                                     Register receiver,
300                                     Register properties,
301                                     Handle<Name> name,
302                                     Register scratch0);
303
304  bool SometimesSetsUpAFrame() override { return false; }
305
306 private:
307  static const int kInlinedProbes = 4;
308  static const int kTotalProbes = 20;
309
310  static const int kCapacityOffset =
311      NameDictionary::kHeaderSize +
312      NameDictionary::kCapacityIndex * kPointerSize;
313
314  static const int kElementsStartOffset =
315      NameDictionary::kHeaderSize +
316      NameDictionary::kElementsStartIndex * kPointerSize;
317
318  LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
319
320  class LookupModeBits: public BitField<LookupMode, 0, 1> {};
321
322  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
323  DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
324};
325
326
327}  // namespace internal
328}  // namespace v8
329
330#endif  // V8_MIPS_CODE_STUBS_MIPS64_H_
331