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 
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, 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 
52 class StoreRegistersStateStub : public PlatformCodeStub {
53  public:
StoreRegistersStateStub(Isolate * isolate)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 
65 class RestoreRegistersStateStub : public PlatformCodeStub {
66  public:
RestoreRegistersStateStub(Isolate * isolate)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 
78 class RecordWriteStub : public PlatformCodeStub {
79  public:
RecordWriteStub(Isolate * isolate,Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)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 
RecordWriteStub(uint32_t key,Isolate * isolate)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 
SometimesSetsUpAFrame()99   bool SometimesSetsUpAFrame() override { return false; }
100 
PatchBranchIntoNop(MacroAssembler * masm,int pos)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 
PatchNopIntoBranch(MacroAssembler * masm,int pos)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 
GetMode(Code * stub)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 
Patch(Code * stub,Mode mode)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:
RegisterAllocation(Register object,Register address,Register scratch0)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 
Save(MacroAssembler * masm)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 
Restore(MacroAssembler * masm)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.
SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)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 
RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)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 
object()202     inline Register object() { return object_; }
address()203     inline Register address() { return address_; }
scratch0()204     inline Register scratch0() { return scratch0_; }
scratch1()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 
MajorKey()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 
Activate(Code * code)230   void Activate(Code* code) override {
231     code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
232   }
233 
object()234   Register object() const {
235     return Register::from_code(ObjectBits::decode(minor_key_));
236   }
237 
value()238   Register value() const {
239     return Register::from_code(ValueBits::decode(minor_key_));
240   }
241 
address()242   Register address() const {
243     return Register::from_code(AddressBits::decode(minor_key_));
244   }
245 
remembered_set_action()246   RememberedSetAction remembered_set_action() const {
247     return RememberedSetActionBits::decode(minor_key_);
248   }
249 
save_fp_regs_mode()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
273 class DirectCEntryStub : public PlatformCodeStub {
274  public:
DirectCEntryStub(Isolate * isolate)275   explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
276   void GenerateCall(MacroAssembler* masm, Register target);
277 
278  private:
NeedsImmovableCode()279   bool NeedsImmovableCode() override { return true; }
280 
281   DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
282   DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
283 };
284 
285 
286 class NameDictionaryLookupStub : public PlatformCodeStub {
287  public:
288   enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
289 
NameDictionaryLookupStub(Isolate * isolate,LookupMode mode)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 
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 }  // namespace internal
326 }  // namespace v8
327 
328 #endif  // V8_PPC_CODE_STUBS_PPC_H_
329