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