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