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_X87_CODE_STUBS_X87_H_ 6 #define V8_X87_CODE_STUBS_X87_H_ 7 8 namespace v8 { 9 namespace internal { 10 11 12 void ArrayNativeCode(MacroAssembler* masm, 13 bool construct_call, 14 Label* call_generic_code); 15 16 17 class StringHelper : public AllStatic { 18 public: 19 // Generate code for copying characters using the rep movs instruction. 20 // Copies ecx characters from esi to edi. Copying of overlapping regions is 21 // not supported. 22 static void GenerateCopyCharacters(MacroAssembler* masm, 23 Register dest, 24 Register src, 25 Register count, 26 Register scratch, 27 String::Encoding encoding); 28 29 // Compares two flat one byte strings and returns result in eax. 30 static void GenerateCompareFlatOneByteStrings(MacroAssembler* masm, 31 Register left, Register right, 32 Register scratch1, 33 Register scratch2, 34 Register scratch3); 35 36 // Compares two flat one byte strings for equality and returns result in eax. 37 static void GenerateFlatOneByteStringEquals(MacroAssembler* masm, 38 Register left, Register right, 39 Register scratch1, 40 Register scratch2); 41 42 private: 43 static void GenerateOneByteCharsCompareLoop( 44 MacroAssembler* masm, Register left, Register right, Register length, 45 Register scratch, Label* chars_not_equal, 46 Label::Distance chars_not_equal_near = Label::kFar); 47 48 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); 49 }; 50 51 52 class NameDictionaryLookupStub: public PlatformCodeStub { 53 public: 54 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP }; 55 NameDictionaryLookupStub(Isolate * isolate,Register dictionary,Register result,Register index,LookupMode mode)56 NameDictionaryLookupStub(Isolate* isolate, Register dictionary, 57 Register result, Register index, LookupMode mode) 58 : PlatformCodeStub(isolate) { 59 minor_key_ = DictionaryBits::encode(dictionary.code()) | 60 ResultBits::encode(result.code()) | 61 IndexBits::encode(index.code()) | LookupModeBits::encode(mode); 62 } 63 64 static void GenerateNegativeLookup(MacroAssembler* masm, 65 Label* miss, 66 Label* done, 67 Register properties, 68 Handle<Name> name, 69 Register r0); 70 71 static void GeneratePositiveLookup(MacroAssembler* masm, 72 Label* miss, 73 Label* done, 74 Register elements, 75 Register name, 76 Register r0, 77 Register r1); 78 SometimesSetsUpAFrame()79 bool SometimesSetsUpAFrame() override { return false; } 80 81 private: 82 static const int kInlinedProbes = 4; 83 static const int kTotalProbes = 20; 84 85 static const int kCapacityOffset = 86 NameDictionary::kHeaderSize + 87 NameDictionary::kCapacityIndex * kPointerSize; 88 89 static const int kElementsStartOffset = 90 NameDictionary::kHeaderSize + 91 NameDictionary::kElementsStartIndex * kPointerSize; 92 dictionary()93 Register dictionary() const { 94 return Register::from_code(DictionaryBits::decode(minor_key_)); 95 } 96 result()97 Register result() const { 98 return Register::from_code(ResultBits::decode(minor_key_)); 99 } 100 index()101 Register index() const { 102 return Register::from_code(IndexBits::decode(minor_key_)); 103 } 104 mode()105 LookupMode mode() const { return LookupModeBits::decode(minor_key_); } 106 107 class DictionaryBits: public BitField<int, 0, 3> {}; 108 class ResultBits: public BitField<int, 3, 3> {}; 109 class IndexBits: public BitField<int, 6, 3> {}; 110 class LookupModeBits: public BitField<LookupMode, 9, 1> {}; 111 112 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 113 DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub); 114 }; 115 116 117 class RecordWriteStub: public PlatformCodeStub { 118 public: RecordWriteStub(Isolate * isolate,Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)119 RecordWriteStub(Isolate* isolate, Register object, Register value, 120 Register address, RememberedSetAction remembered_set_action, 121 SaveFPRegsMode fp_mode) 122 : PlatformCodeStub(isolate), 123 regs_(object, // An input reg. 124 address, // An input reg. 125 value) { // One scratch reg. 126 minor_key_ = ObjectBits::encode(object.code()) | 127 ValueBits::encode(value.code()) | 128 AddressBits::encode(address.code()) | 129 RememberedSetActionBits::encode(remembered_set_action) | 130 SaveFPRegsModeBits::encode(fp_mode); 131 } 132 RecordWriteStub(uint32_t key,Isolate * isolate)133 RecordWriteStub(uint32_t key, Isolate* isolate) 134 : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {} 135 136 enum Mode { 137 STORE_BUFFER_ONLY, 138 INCREMENTAL, 139 INCREMENTAL_COMPACTION 140 }; 141 SometimesSetsUpAFrame()142 bool SometimesSetsUpAFrame() override { return false; } 143 144 static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8. 145 static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8. 146 147 static const byte kFiveByteNopInstruction = 0x3d; // Cmpl eax, #imm32. 148 static const byte kFiveByteJumpInstruction = 0xe9; // Jmp #imm32. 149 GetMode(Code * stub)150 static Mode GetMode(Code* stub) { 151 byte first_instruction = stub->instruction_start()[0]; 152 byte second_instruction = stub->instruction_start()[2]; 153 154 if (first_instruction == kTwoByteJumpInstruction) { 155 return INCREMENTAL; 156 } 157 158 DCHECK(first_instruction == kTwoByteNopInstruction); 159 160 if (second_instruction == kFiveByteJumpInstruction) { 161 return INCREMENTAL_COMPACTION; 162 } 163 164 DCHECK(second_instruction == kFiveByteNopInstruction); 165 166 return STORE_BUFFER_ONLY; 167 } 168 Patch(Code * stub,Mode mode)169 static void Patch(Code* stub, Mode mode) { 170 switch (mode) { 171 case STORE_BUFFER_ONLY: 172 DCHECK(GetMode(stub) == INCREMENTAL || 173 GetMode(stub) == INCREMENTAL_COMPACTION); 174 stub->instruction_start()[0] = kTwoByteNopInstruction; 175 stub->instruction_start()[2] = kFiveByteNopInstruction; 176 break; 177 case INCREMENTAL: 178 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY); 179 stub->instruction_start()[0] = kTwoByteJumpInstruction; 180 break; 181 case INCREMENTAL_COMPACTION: 182 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY); 183 stub->instruction_start()[0] = kTwoByteNopInstruction; 184 stub->instruction_start()[2] = kFiveByteJumpInstruction; 185 break; 186 } 187 DCHECK(GetMode(stub) == mode); 188 Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(), 7); 189 } 190 191 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 192 193 private: 194 // This is a helper class for freeing up 3 scratch registers, where the third 195 // is always ecx (needed for shift operations). The input is two registers 196 // that must be preserved and one scratch register provided by the caller. 197 class RegisterAllocation { 198 public: RegisterAllocation(Register object,Register address,Register scratch0)199 RegisterAllocation(Register object, 200 Register address, 201 Register scratch0) 202 : object_orig_(object), 203 address_orig_(address), 204 scratch0_orig_(scratch0), 205 object_(object), 206 address_(address), 207 scratch0_(scratch0) { 208 DCHECK(!AreAliased(scratch0, object, address, no_reg)); 209 scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_); 210 if (scratch0.is(ecx)) { 211 scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_); 212 } 213 if (object.is(ecx)) { 214 object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_); 215 } 216 if (address.is(ecx)) { 217 address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_); 218 } 219 DCHECK(!AreAliased(scratch0_, object_, address_, ecx)); 220 } 221 Save(MacroAssembler * masm)222 void Save(MacroAssembler* masm) { 223 DCHECK(!address_orig_.is(object_)); 224 DCHECK(object_.is(object_orig_) || address_.is(address_orig_)); 225 DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_)); 226 DCHECK(!AreAliased(object_orig_, address_, scratch1_, scratch0_)); 227 DCHECK(!AreAliased(object_, address_orig_, scratch1_, scratch0_)); 228 // We don't have to save scratch0_orig_ because it was given to us as 229 // a scratch register. But if we had to switch to a different reg then 230 // we should save the new scratch0_. 231 if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_); 232 if (!ecx.is(scratch0_orig_) && 233 !ecx.is(object_orig_) && 234 !ecx.is(address_orig_)) { 235 masm->push(ecx); 236 } 237 masm->push(scratch1_); 238 if (!address_.is(address_orig_)) { 239 masm->push(address_); 240 masm->mov(address_, address_orig_); 241 } 242 if (!object_.is(object_orig_)) { 243 masm->push(object_); 244 masm->mov(object_, object_orig_); 245 } 246 } 247 Restore(MacroAssembler * masm)248 void Restore(MacroAssembler* masm) { 249 // These will have been preserved the entire time, so we just need to move 250 // them back. Only in one case is the orig_ reg different from the plain 251 // one, since only one of them can alias with ecx. 252 if (!object_.is(object_orig_)) { 253 masm->mov(object_orig_, object_); 254 masm->pop(object_); 255 } 256 if (!address_.is(address_orig_)) { 257 masm->mov(address_orig_, address_); 258 masm->pop(address_); 259 } 260 masm->pop(scratch1_); 261 if (!ecx.is(scratch0_orig_) && 262 !ecx.is(object_orig_) && 263 !ecx.is(address_orig_)) { 264 masm->pop(ecx); 265 } 266 if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_); 267 } 268 269 // If we have to call into C then we need to save and restore all caller- 270 // saved registers that were not already preserved. The caller saved 271 // registers are eax, ecx and edx. The three scratch registers (incl. ecx) 272 // will be restored by other means so we don't bother pushing them here. SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)273 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { 274 if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax); 275 if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx); 276 if (mode == kSaveFPRegs) { 277 // Save FPU state in m108byte. 278 masm->sub(esp, Immediate(108)); 279 masm->fnsave(Operand(esp, 0)); 280 } 281 } 282 RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)283 inline void RestoreCallerSaveRegisters(MacroAssembler* masm, 284 SaveFPRegsMode mode) { 285 if (mode == kSaveFPRegs) { 286 // Restore FPU state in m108byte. 287 masm->frstor(Operand(esp, 0)); 288 masm->add(esp, Immediate(108)); 289 } 290 if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx); 291 if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax); 292 } 293 object()294 inline Register object() { return object_; } address()295 inline Register address() { return address_; } scratch0()296 inline Register scratch0() { return scratch0_; } scratch1()297 inline Register scratch1() { return scratch1_; } 298 299 private: 300 Register object_orig_; 301 Register address_orig_; 302 Register scratch0_orig_; 303 Register object_; 304 Register address_; 305 Register scratch0_; 306 Register scratch1_; 307 // Third scratch register is always ecx. 308 GetRegThatIsNotEcxOr(Register r1,Register r2,Register r3)309 Register GetRegThatIsNotEcxOr(Register r1, 310 Register r2, 311 Register r3) { 312 for (int i = 0; i < Register::kNumRegisters; i++) { 313 Register candidate = Register::from_code(i); 314 if (candidate.IsAllocatable()) { 315 if (candidate.is(ecx)) continue; 316 if (candidate.is(r1)) continue; 317 if (candidate.is(r2)) continue; 318 if (candidate.is(r3)) continue; 319 return candidate; 320 } 321 } 322 UNREACHABLE(); 323 return no_reg; 324 } 325 friend class RecordWriteStub; 326 }; 327 328 enum OnNoNeedToInformIncrementalMarker { 329 kReturnOnNoNeedToInformIncrementalMarker, 330 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker 331 }; 332 MajorKey()333 inline Major MajorKey() const final { return RecordWrite; } 334 335 void Generate(MacroAssembler* masm) override; 336 void GenerateIncremental(MacroAssembler* masm, Mode mode); 337 void CheckNeedsToInformIncrementalMarker( 338 MacroAssembler* masm, 339 OnNoNeedToInformIncrementalMarker on_no_need, 340 Mode mode); 341 void InformIncrementalMarker(MacroAssembler* masm); 342 Activate(Code * code)343 void Activate(Code* code) override { 344 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); 345 } 346 object()347 Register object() const { 348 return Register::from_code(ObjectBits::decode(minor_key_)); 349 } 350 value()351 Register value() const { 352 return Register::from_code(ValueBits::decode(minor_key_)); 353 } 354 address()355 Register address() const { 356 return Register::from_code(AddressBits::decode(minor_key_)); 357 } 358 remembered_set_action()359 RememberedSetAction remembered_set_action() const { 360 return RememberedSetActionBits::decode(minor_key_); 361 } 362 save_fp_regs_mode()363 SaveFPRegsMode save_fp_regs_mode() const { 364 return SaveFPRegsModeBits::decode(minor_key_); 365 } 366 367 class ObjectBits: public BitField<int, 0, 3> {}; 368 class ValueBits: public BitField<int, 3, 3> {}; 369 class AddressBits: public BitField<int, 6, 3> {}; 370 class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {}; 371 class SaveFPRegsModeBits : public BitField<SaveFPRegsMode, 10, 1> {}; 372 373 RegisterAllocation regs_; 374 375 DISALLOW_COPY_AND_ASSIGN(RecordWriteStub); 376 }; 377 378 379 } // namespace internal 380 } // namespace v8 381 382 #endif // V8_X87_CODE_STUBS_X87_H_ 383