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