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 // 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 43 class StoreRegistersStateStub : public PlatformCodeStub { 44 public: StoreRegistersStateStub(Isolate * isolate)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 56 class RestoreRegistersStateStub : public PlatformCodeStub { 57 public: RestoreRegistersStateStub(Isolate * isolate)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 69 class RecordWriteStub : public PlatformCodeStub { 70 public: RecordWriteStub(Isolate * isolate,Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)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 RecordWriteStub(uint32_t key,Isolate * isolate)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 SometimesSetsUpAFrame()90 bool SometimesSetsUpAFrame() override { return false; } 91 PatchBranchIntoNop(MacroAssembler * masm,int pos)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 PatchNopIntoBranch(MacroAssembler * masm,int pos)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 GetMode(Code * stub)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 Patch(Code * stub,Mode mode)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: RegisterAllocation(Register object,Register address,Register scratch0)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 Save(MacroAssembler * masm)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 Restore(MacroAssembler * masm)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. SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)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 RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)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 object()193 inline Register object() { return object_; } address()194 inline Register address() { return address_; } scratch0()195 inline Register scratch0() { return scratch0_; } scratch1()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 MajorKey()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 Activate(Code * code)221 void Activate(Code* code) override { 222 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); 223 } 224 object()225 Register object() const { 226 return Register::from_code(ObjectBits::decode(minor_key_)); 227 } 228 value()229 Register value() const { 230 return Register::from_code(ValueBits::decode(minor_key_)); 231 } 232 address()233 Register address() const { 234 return Register::from_code(AddressBits::decode(minor_key_)); 235 } 236 remembered_set_action()237 RememberedSetAction remembered_set_action() const { 238 return RememberedSetActionBits::decode(minor_key_); 239 } 240 save_fp_regs_mode()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 264 class DirectCEntryStub : public PlatformCodeStub { 265 public: DirectCEntryStub(Isolate * isolate)266 explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {} 267 void GenerateCall(MacroAssembler* masm, Register target); 268 269 private: NeedsImmovableCode()270 bool NeedsImmovableCode() override { return true; } 271 272 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 273 DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub); 274 }; 275 276 277 class NameDictionaryLookupStub : public PlatformCodeStub { 278 public: 279 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP }; 280 NameDictionaryLookupStub(Isolate * isolate,LookupMode mode)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 SometimesSetsUpAFrame()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 mode()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