[presubmit] Enable readability/namespace linter checking.
[platform/upstream/v8.git] / src / arm64 / code-stubs-arm64.h
1 // Copyright 2013 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_ARM64_CODE_STUBS_ARM64_H_
6 #define V8_ARM64_CODE_STUBS_ARM64_H_
7
8 namespace v8 {
9 namespace internal {
10
11
12 void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
13
14
15 class StringHelper : public AllStatic {
16  public:
17   // Compares two flat one-byte strings and returns result in x0.
18   static void GenerateCompareFlatOneByteStrings(
19       MacroAssembler* masm, Register left, Register right, Register scratch1,
20       Register scratch2, Register scratch3, Register scratch4);
21
22   // Compare two flat one-byte strings for equality and returns result in x0.
23   static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
24                                               Register left, Register right,
25                                               Register scratch1,
26                                               Register scratch2,
27                                               Register scratch3);
28
29  private:
30   static void GenerateOneByteCharsCompareLoop(
31       MacroAssembler* masm, Register left, Register right, Register length,
32       Register scratch1, Register scratch2, Label* chars_not_equal);
33
34   DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
35 };
36
37
38 class StoreRegistersStateStub: public PlatformCodeStub {
39  public:
40   explicit StoreRegistersStateStub(Isolate* isolate)
41       : PlatformCodeStub(isolate) {}
42
43   static Register to_be_pushed_lr() { return ip0; }
44
45   static void GenerateAheadOfTime(Isolate* isolate);
46
47  private:
48   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
49   DEFINE_PLATFORM_CODE_STUB(StoreRegistersState, PlatformCodeStub);
50 };
51
52
53 class RestoreRegistersStateStub: public PlatformCodeStub {
54  public:
55   explicit RestoreRegistersStateStub(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(RestoreRegistersState, PlatformCodeStub);
63 };
64
65
66 class RecordWriteStub: public PlatformCodeStub {
67  public:
68   // Stub to record the write of 'value' at 'address' in 'object'.
69   // Typically 'address' = 'object' + <some offset>.
70   // See MacroAssembler::RecordWriteField() for example.
71   RecordWriteStub(Isolate* isolate,
72                   Register object,
73                   Register value,
74                   Register address,
75                   RememberedSetAction remembered_set_action,
76                   SaveFPRegsMode fp_mode)
77       : PlatformCodeStub(isolate),
78         regs_(object,   // An input reg.
79               address,  // An input reg.
80               value) {  // One scratch reg.
81     DCHECK(object.Is64Bits());
82     DCHECK(value.Is64Bits());
83     DCHECK(address.Is64Bits());
84     minor_key_ = ObjectBits::encode(object.code()) |
85                  ValueBits::encode(value.code()) |
86                  AddressBits::encode(address.code()) |
87                  RememberedSetActionBits::encode(remembered_set_action) |
88                  SaveFPRegsModeBits::encode(fp_mode);
89   }
90
91   RecordWriteStub(uint32_t key, Isolate* isolate)
92       : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
93
94   enum Mode {
95     STORE_BUFFER_ONLY,
96     INCREMENTAL,
97     INCREMENTAL_COMPACTION
98   };
99
100   bool SometimesSetsUpAFrame() override { return false; }
101
102   static Mode GetMode(Code* stub) {
103     // Find the mode depending on the first two instructions.
104     Instruction* instr1 =
105       reinterpret_cast<Instruction*>(stub->instruction_start());
106     Instruction* instr2 = instr1->following();
107
108     if (instr1->IsUncondBranchImm()) {
109       DCHECK(instr2->IsPCRelAddressing() && (instr2->Rd() == xzr.code()));
110       return INCREMENTAL;
111     }
112
113     DCHECK(instr1->IsPCRelAddressing() && (instr1->Rd() == xzr.code()));
114
115     if (instr2->IsUncondBranchImm()) {
116       return INCREMENTAL_COMPACTION;
117     }
118
119     DCHECK(instr2->IsPCRelAddressing());
120
121     return STORE_BUFFER_ONLY;
122   }
123
124   // We patch the two first instructions of the stub back and forth between an
125   // adr and branch when we start and stop incremental heap marking.
126   // The branch is
127   //   b label
128   // The adr is
129   //   adr xzr label
130   // so effectively a nop.
131   static void Patch(Code* stub, Mode mode) {
132     // We are going to patch the two first instructions of the stub.
133     PatchingAssembler patcher(
134         reinterpret_cast<Instruction*>(stub->instruction_start()), 2);
135     Instruction* instr1 = patcher.InstructionAt(0);
136     Instruction* instr2 = patcher.InstructionAt(kInstructionSize);
137     // Instructions must be either 'adr' or 'b'.
138     DCHECK(instr1->IsPCRelAddressing() || instr1->IsUncondBranchImm());
139     DCHECK(instr2->IsPCRelAddressing() || instr2->IsUncondBranchImm());
140     // Retrieve the offsets to the labels.
141     auto offset_to_incremental_noncompacting =
142         static_cast<int32_t>(instr1->ImmPCOffset());
143     auto offset_to_incremental_compacting =
144         static_cast<int32_t>(instr2->ImmPCOffset());
145
146     switch (mode) {
147       case STORE_BUFFER_ONLY:
148         DCHECK(GetMode(stub) == INCREMENTAL ||
149                GetMode(stub) == INCREMENTAL_COMPACTION);
150         patcher.adr(xzr, offset_to_incremental_noncompacting);
151         patcher.adr(xzr, offset_to_incremental_compacting);
152         break;
153       case INCREMENTAL:
154         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
155         patcher.b(offset_to_incremental_noncompacting >> kInstructionSizeLog2);
156         patcher.adr(xzr, offset_to_incremental_compacting);
157         break;
158       case INCREMENTAL_COMPACTION:
159         DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
160         patcher.adr(xzr, offset_to_incremental_noncompacting);
161         patcher.b(offset_to_incremental_compacting >> kInstructionSizeLog2);
162         break;
163     }
164     DCHECK(GetMode(stub) == mode);
165   }
166
167   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
168
169  private:
170   // This is a helper class to manage the registers associated with the stub.
171   // The 'object' and 'address' registers must be preserved.
172   class RegisterAllocation {
173    public:
174     RegisterAllocation(Register object,
175                        Register address,
176                        Register scratch)
177         : object_(object),
178           address_(address),
179           scratch0_(scratch),
180           saved_regs_(kCallerSaved),
181           saved_fp_regs_(kCallerSavedFP) {
182       DCHECK(!AreAliased(scratch, object, address));
183
184       // The SaveCallerSaveRegisters method needs to save caller-saved
185       // registers, but we don't bother saving MacroAssembler scratch registers.
186       saved_regs_.Remove(MacroAssembler::DefaultTmpList());
187       saved_fp_regs_.Remove(MacroAssembler::DefaultFPTmpList());
188
189       // We would like to require more scratch registers for this stub,
190       // but the number of registers comes down to the ones used in
191       // FullCodeGen::SetVar(), which is architecture independent.
192       // We allocate 2 extra scratch registers that we'll save on the stack.
193       CPURegList pool_available = GetValidRegistersForAllocation();
194       CPURegList used_regs(object, address, scratch);
195       pool_available.Remove(used_regs);
196       scratch1_ = Register(pool_available.PopLowestIndex());
197       scratch2_ = Register(pool_available.PopLowestIndex());
198
199       // The scratch registers will be restored by other means so we don't need
200       // to save them with the other caller saved registers.
201       saved_regs_.Remove(scratch0_);
202       saved_regs_.Remove(scratch1_);
203       saved_regs_.Remove(scratch2_);
204     }
205
206     void Save(MacroAssembler* masm) {
207       // We don't have to save scratch0_ because it was given to us as
208       // a scratch register.
209       masm->Push(scratch1_, scratch2_);
210     }
211
212     void Restore(MacroAssembler* masm) {
213       masm->Pop(scratch2_, scratch1_);
214     }
215
216     // If we have to call into C then we need to save and restore all caller-
217     // saved registers that were not already preserved.
218     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
219       // TODO(all): This can be very expensive, and it is likely that not every
220       // register will need to be preserved. Can we improve this?
221       masm->PushCPURegList(saved_regs_);
222       if (mode == kSaveFPRegs) {
223         masm->PushCPURegList(saved_fp_regs_);
224       }
225     }
226
227     void RestoreCallerSaveRegisters(MacroAssembler*masm, SaveFPRegsMode mode) {
228       // TODO(all): This can be very expensive, and it is likely that not every
229       // register will need to be preserved. Can we improve this?
230       if (mode == kSaveFPRegs) {
231         masm->PopCPURegList(saved_fp_regs_);
232       }
233       masm->PopCPURegList(saved_regs_);
234     }
235
236     Register object() { return object_; }
237     Register address() { return address_; }
238     Register scratch0() { return scratch0_; }
239     Register scratch1() { return scratch1_; }
240     Register scratch2() { return scratch2_; }
241
242    private:
243     Register object_;
244     Register address_;
245     Register scratch0_;
246     Register scratch1_;
247     Register scratch2_;
248     CPURegList saved_regs_;
249     CPURegList saved_fp_regs_;
250
251     // TODO(all): We should consider moving this somewhere else.
252     static CPURegList GetValidRegistersForAllocation() {
253       // The list of valid registers for allocation is defined as all the
254       // registers without those with a special meaning.
255       //
256       // The default list excludes registers x26 to x31 because they are
257       // reserved for the following purpose:
258       //  - x26 root register
259       //  - x27 context pointer register
260       //  - x28 jssp
261       //  - x29 frame pointer
262       //  - x30 link register(lr)
263       //  - x31 xzr/stack pointer
264       CPURegList list(CPURegister::kRegister, kXRegSizeInBits, 0, 25);
265
266       // We also remove MacroAssembler's scratch registers.
267       list.Remove(MacroAssembler::DefaultTmpList());
268
269       return list;
270     }
271
272     friend class RecordWriteStub;
273   };
274
275   enum OnNoNeedToInformIncrementalMarker {
276     kReturnOnNoNeedToInformIncrementalMarker,
277     kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
278   };
279
280   inline Major MajorKey() const final { return RecordWrite; }
281
282   void Generate(MacroAssembler* masm) override;
283   void GenerateIncremental(MacroAssembler* masm, Mode mode);
284   void CheckNeedsToInformIncrementalMarker(
285       MacroAssembler* masm,
286       OnNoNeedToInformIncrementalMarker on_no_need,
287       Mode mode);
288   void InformIncrementalMarker(MacroAssembler* masm);
289
290   void Activate(Code* code) override {
291     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
292   }
293
294   Register object() const {
295     return Register::from_code(ObjectBits::decode(minor_key_));
296   }
297
298   Register value() const {
299     return Register::from_code(ValueBits::decode(minor_key_));
300   }
301
302   Register address() const {
303     return Register::from_code(AddressBits::decode(minor_key_));
304   }
305
306   RememberedSetAction remembered_set_action() const {
307     return RememberedSetActionBits::decode(minor_key_);
308   }
309
310   SaveFPRegsMode save_fp_regs_mode() const {
311     return SaveFPRegsModeBits::decode(minor_key_);
312   }
313
314   class ObjectBits: public BitField<int, 0, 5> {};
315   class ValueBits: public BitField<int, 5, 5> {};
316   class AddressBits: public BitField<int, 10, 5> {};
317   class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
318   class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
319
320   Label slow_;
321   RegisterAllocation regs_;
322 };
323
324
325 // Helper to call C++ functions from generated code. The caller must prepare
326 // the exit frame before doing the call with GenerateCall.
327 class DirectCEntryStub: public PlatformCodeStub {
328  public:
329   explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
330   void GenerateCall(MacroAssembler* masm, Register target);
331
332  private:
333   bool NeedsImmovableCode() override { return true; }
334
335   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
336   DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
337 };
338
339
340 class NameDictionaryLookupStub: public PlatformCodeStub {
341  public:
342   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
343
344   NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
345       : PlatformCodeStub(isolate) {
346     minor_key_ = LookupModeBits::encode(mode);
347   }
348
349   static void GenerateNegativeLookup(MacroAssembler* masm,
350                                      Label* miss,
351                                      Label* done,
352                                      Register receiver,
353                                      Register properties,
354                                      Handle<Name> name,
355                                      Register scratch0);
356
357   static void GeneratePositiveLookup(MacroAssembler* masm,
358                                      Label* miss,
359                                      Label* done,
360                                      Register elements,
361                                      Register name,
362                                      Register scratch1,
363                                      Register scratch2);
364
365   bool SometimesSetsUpAFrame() override { return false; }
366
367  private:
368   static const int kInlinedProbes = 4;
369   static const int kTotalProbes = 20;
370
371   static const int kCapacityOffset =
372       NameDictionary::kHeaderSize +
373       NameDictionary::kCapacityIndex * kPointerSize;
374
375   static const int kElementsStartOffset =
376       NameDictionary::kHeaderSize +
377       NameDictionary::kElementsStartIndex * kPointerSize;
378
379   LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
380
381   class LookupModeBits: public BitField<LookupMode, 0, 1> {};
382
383   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
384   DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
385 };
386
387 }  // namespace internal
388 }  // namespace v8
389
390 #endif  // V8_ARM64_CODE_STUBS_ARM64_H_