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