• 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   // 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 
42 class StoreRegistersStateStub: public PlatformCodeStub {
43  public:
StoreRegistersStateStub(Isolate * isolate)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 
55 class RestoreRegistersStateStub: public PlatformCodeStub {
56  public:
RestoreRegistersStateStub(Isolate * isolate)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 
68 class RecordWriteStub: public PlatformCodeStub {
69  public:
RecordWriteStub(Isolate * isolate,Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)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 
RecordWriteStub(uint32_t key,Isolate * isolate)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 
SometimesSetsUpAFrame()96   bool SometimesSetsUpAFrame() override { return false; }
97 
PatchBranchIntoNop(MacroAssembler * masm,int pos)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 
PatchNopIntoBranch(MacroAssembler * masm,int pos)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 
GetMode(Code * stub)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 
Patch(Code * stub,Mode mode)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:
RegisterAllocation(Register object,Register address,Register scratch0)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 
Save(MacroAssembler * masm)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 
Restore(MacroAssembler * masm)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.
SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)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 
RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)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 
object()203     inline Register object() { return object_; }
address()204     inline Register address() { return address_; }
scratch0()205     inline Register scratch0() { return scratch0_; }
scratch1()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 
MajorKey()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 
Activate(Code * code)232   void Activate(Code* code) override {
233     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
234   }
235 
object()236   Register object() const {
237     return Register::from_code(ObjectBits::decode(minor_key_));
238   }
239 
value()240   Register value() const {
241     return Register::from_code(ValueBits::decode(minor_key_));
242   }
243 
address()244   Register address() const {
245     return Register::from_code(AddressBits::decode(minor_key_));
246   }
247 
remembered_set_action()248   RememberedSetAction remembered_set_action() const {
249     return RememberedSetActionBits::decode(minor_key_);
250   }
251 
save_fp_regs_mode()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
274 class DirectCEntryStub: public PlatformCodeStub {
275  public:
DirectCEntryStub(Isolate * isolate)276   explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
277   void GenerateCall(MacroAssembler* masm, Register target);
278 
279  private:
NeedsImmovableCode()280   bool NeedsImmovableCode() override { return true; }
281 
282   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
283   DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
284 };
285 
286 
287 class NameDictionaryLookupStub: public PlatformCodeStub {
288  public:
289   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
290 
NameDictionaryLookupStub(Isolate * isolate,LookupMode mode)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 
SometimesSetsUpAFrame()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 
mode()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