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