15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2011 the V8 project authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef V8_IA32_CODE_STUBS_IA32_H_ 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define V8_IA32_CODE_STUBS_IA32_H_ 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace v8 { 9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace internal { 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ArrayNativeCode(MacroAssembler* masm, 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool construct_call, 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Label* call_generic_code); 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class StringHelper : public AllStatic { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Generate code for copying characters using the rep movs instruction. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copies ecx characters from esi to edi. Copying of overlapping regions is 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not supported. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void GenerateCopyCharacters(MacroAssembler* masm, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register dest, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register src, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register count, 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register scratch, 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) String::Encoding encoding); 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Compares two flat one byte strings and returns result in eax. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void GenerateCompareFlatOneByteStrings(MacroAssembler* masm, 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Register left, Register right, 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Register scratch1, 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Register scratch2, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register scratch3); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Compares two flat one byte strings for equality and returns result in eax. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void GenerateFlatOneByteStringEquals(MacroAssembler* masm, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register left, Register right, 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register scratch1, 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register scratch2); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void GenerateOneByteCharsCompareLoop( 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MacroAssembler* masm, Register left, Register right, Register length, 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register scratch, Label* chars_not_equal, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Label::Distance chars_not_equal_near = Label::kFar); 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NameDictionaryLookupStub: public PlatformCodeStub { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP }; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NameDictionaryLookupStub(Isolate* isolate, Register dictionary, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register result, Register index, LookupMode mode) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : PlatformCodeStub(isolate) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minor_key_ = DictionaryBits::encode(dictionary.code()) | 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResultBits::encode(result.code()) | 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IndexBits::encode(index.code()) | LookupModeBits::encode(mode); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void GenerateNegativeLookup(MacroAssembler* masm, 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Label* miss, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Label* done, 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register properties, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 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 79 virtual bool SometimesSetsUpAFrame() { 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 93 Register dictionary() const { 94 return Register::from_code(DictionaryBits::decode(minor_key_)); 95 } 96 97 Register result() const { 98 return Register::from_code(ResultBits::decode(minor_key_)); 99 } 100 101 Register index() const { 102 return Register::from_code(IndexBits::decode(minor_key_)); 103 } 104 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 117class RecordWriteStub: public PlatformCodeStub { 118 public: 119 RecordWriteStub(Isolate* isolate, 120 Register object, 121 Register value, 122 Register address, 123 RememberedSetAction remembered_set_action, 124 SaveFPRegsMode fp_mode) 125 : PlatformCodeStub(isolate), 126 regs_(object, // An input reg. 127 address, // An input reg. 128 value) { // One scratch reg. 129 minor_key_ = ObjectBits::encode(object.code()) | 130 ValueBits::encode(value.code()) | 131 AddressBits::encode(address.code()) | 132 RememberedSetActionBits::encode(remembered_set_action) | 133 SaveFPRegsModeBits::encode(fp_mode); 134 } 135 136 RecordWriteStub(uint32_t key, Isolate* isolate) 137 : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {} 138 139 enum Mode { 140 STORE_BUFFER_ONLY, 141 INCREMENTAL, 142 INCREMENTAL_COMPACTION 143 }; 144 145 virtual bool SometimesSetsUpAFrame() { return false; } 146 147 static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8. 148 static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8. 149 150 static const byte kFiveByteNopInstruction = 0x3d; // Cmpl eax, #imm32. 151 static const byte kFiveByteJumpInstruction = 0xe9; // Jmp #imm32. 152 153 static Mode GetMode(Code* stub) { 154 byte first_instruction = stub->instruction_start()[0]; 155 byte second_instruction = stub->instruction_start()[2]; 156 157 if (first_instruction == kTwoByteJumpInstruction) { 158 return INCREMENTAL; 159 } 160 161 DCHECK(first_instruction == kTwoByteNopInstruction); 162 163 if (second_instruction == kFiveByteJumpInstruction) { 164 return INCREMENTAL_COMPACTION; 165 } 166 167 DCHECK(second_instruction == kFiveByteNopInstruction); 168 169 return STORE_BUFFER_ONLY; 170 } 171 172 static void Patch(Code* stub, Mode mode) { 173 switch (mode) { 174 case STORE_BUFFER_ONLY: 175 DCHECK(GetMode(stub) == INCREMENTAL || 176 GetMode(stub) == INCREMENTAL_COMPACTION); 177 stub->instruction_start()[0] = kTwoByteNopInstruction; 178 stub->instruction_start()[2] = kFiveByteNopInstruction; 179 break; 180 case INCREMENTAL: 181 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY); 182 stub->instruction_start()[0] = kTwoByteJumpInstruction; 183 break; 184 case INCREMENTAL_COMPACTION: 185 DCHECK(GetMode(stub) == STORE_BUFFER_ONLY); 186 stub->instruction_start()[0] = kTwoByteNopInstruction; 187 stub->instruction_start()[2] = kFiveByteJumpInstruction; 188 break; 189 } 190 DCHECK(GetMode(stub) == mode); 191 CpuFeatures::FlushICache(stub->instruction_start(), 7); 192 } 193 194 DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); 195 196 private: 197 // This is a helper class for freeing up 3 scratch registers, where the third 198 // is always ecx (needed for shift operations). The input is two registers 199 // that must be preserved and one scratch register provided by the caller. 200 class RegisterAllocation { 201 public: 202 RegisterAllocation(Register object, 203 Register address, 204 Register scratch0) 205 : object_orig_(object), 206 address_orig_(address), 207 scratch0_orig_(scratch0), 208 object_(object), 209 address_(address), 210 scratch0_(scratch0) { 211 DCHECK(!AreAliased(scratch0, object, address, no_reg)); 212 scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_); 213 if (scratch0.is(ecx)) { 214 scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_); 215 } 216 if (object.is(ecx)) { 217 object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_); 218 } 219 if (address.is(ecx)) { 220 address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_); 221 } 222 DCHECK(!AreAliased(scratch0_, object_, address_, ecx)); 223 } 224 225 void Save(MacroAssembler* masm) { 226 DCHECK(!address_orig_.is(object_)); 227 DCHECK(object_.is(object_orig_) || address_.is(address_orig_)); 228 DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_)); 229 DCHECK(!AreAliased(object_orig_, address_, scratch1_, scratch0_)); 230 DCHECK(!AreAliased(object_, address_orig_, scratch1_, scratch0_)); 231 // We don't have to save scratch0_orig_ because it was given to us as 232 // a scratch register. But if we had to switch to a different reg then 233 // we should save the new scratch0_. 234 if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_); 235 if (!ecx.is(scratch0_orig_) && 236 !ecx.is(object_orig_) && 237 !ecx.is(address_orig_)) { 238 masm->push(ecx); 239 } 240 masm->push(scratch1_); 241 if (!address_.is(address_orig_)) { 242 masm->push(address_); 243 masm->mov(address_, address_orig_); 244 } 245 if (!object_.is(object_orig_)) { 246 masm->push(object_); 247 masm->mov(object_, object_orig_); 248 } 249 } 250 251 void Restore(MacroAssembler* masm) { 252 // These will have been preserved the entire time, so we just need to move 253 // them back. Only in one case is the orig_ reg different from the plain 254 // one, since only one of them can alias with ecx. 255 if (!object_.is(object_orig_)) { 256 masm->mov(object_orig_, object_); 257 masm->pop(object_); 258 } 259 if (!address_.is(address_orig_)) { 260 masm->mov(address_orig_, address_); 261 masm->pop(address_); 262 } 263 masm->pop(scratch1_); 264 if (!ecx.is(scratch0_orig_) && 265 !ecx.is(object_orig_) && 266 !ecx.is(address_orig_)) { 267 masm->pop(ecx); 268 } 269 if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_); 270 } 271 272 // If we have to call into C then we need to save and restore all caller- 273 // saved registers that were not already preserved. The caller saved 274 // registers are eax, ecx and edx. The three scratch registers (incl. ecx) 275 // will be restored by other means so we don't bother pushing them here. 276 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { 277 if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax); 278 if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx); 279 if (mode == kSaveFPRegs) { 280 masm->sub(esp, 281 Immediate(kDoubleSize * (XMMRegister::kMaxNumRegisters - 1))); 282 // Save all XMM registers except XMM0. 283 for (int i = XMMRegister::kMaxNumRegisters - 1; i > 0; i--) { 284 XMMRegister reg = XMMRegister::from_code(i); 285 masm->movsd(Operand(esp, (i - 1) * kDoubleSize), reg); 286 } 287 } 288 } 289 290 inline void RestoreCallerSaveRegisters(MacroAssembler*masm, 291 SaveFPRegsMode mode) { 292 if (mode == kSaveFPRegs) { 293 // Restore all XMM registers except XMM0. 294 for (int i = XMMRegister::kMaxNumRegisters - 1; i > 0; i--) { 295 XMMRegister reg = XMMRegister::from_code(i); 296 masm->movsd(reg, Operand(esp, (i - 1) * kDoubleSize)); 297 } 298 masm->add(esp, 299 Immediate(kDoubleSize * (XMMRegister::kMaxNumRegisters - 1))); 300 } 301 if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx); 302 if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax); 303 } 304 305 inline Register object() { return object_; } 306 inline Register address() { return address_; } 307 inline Register scratch0() { return scratch0_; } 308 inline Register scratch1() { return scratch1_; } 309 310 private: 311 Register object_orig_; 312 Register address_orig_; 313 Register scratch0_orig_; 314 Register object_; 315 Register address_; 316 Register scratch0_; 317 Register scratch1_; 318 // Third scratch register is always ecx. 319 320 Register GetRegThatIsNotEcxOr(Register r1, 321 Register r2, 322 Register r3) { 323 for (int i = 0; i < Register::NumAllocatableRegisters(); i++) { 324 Register candidate = Register::FromAllocationIndex(i); 325 if (candidate.is(ecx)) continue; 326 if (candidate.is(r1)) continue; 327 if (candidate.is(r2)) continue; 328 if (candidate.is(r3)) continue; 329 return candidate; 330 } 331 UNREACHABLE(); 332 return no_reg; 333 } 334 friend class RecordWriteStub; 335 }; 336 337 enum OnNoNeedToInformIncrementalMarker { 338 kReturnOnNoNeedToInformIncrementalMarker, 339 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker 340 }; 341 342 virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; } 343 344 virtual void Generate(MacroAssembler* masm) OVERRIDE; 345 void GenerateIncremental(MacroAssembler* masm, Mode mode); 346 void CheckNeedsToInformIncrementalMarker( 347 MacroAssembler* masm, 348 OnNoNeedToInformIncrementalMarker on_no_need, 349 Mode mode); 350 void InformIncrementalMarker(MacroAssembler* masm); 351 352 void Activate(Code* code) { 353 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); 354 } 355 356 Register object() const { 357 return Register::from_code(ObjectBits::decode(minor_key_)); 358 } 359 360 Register value() const { 361 return Register::from_code(ValueBits::decode(minor_key_)); 362 } 363 364 Register address() const { 365 return Register::from_code(AddressBits::decode(minor_key_)); 366 } 367 368 RememberedSetAction remembered_set_action() const { 369 return RememberedSetActionBits::decode(minor_key_); 370 } 371 372 SaveFPRegsMode save_fp_regs_mode() const { 373 return SaveFPRegsModeBits::decode(minor_key_); 374 } 375 376 class ObjectBits: public BitField<int, 0, 3> {}; 377 class ValueBits: public BitField<int, 3, 3> {}; 378 class AddressBits: public BitField<int, 6, 3> {}; 379 class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {}; 380 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 10, 1> {}; 381 382 RegisterAllocation regs_; 383 384 DISALLOW_COPY_AND_ASSIGN(RecordWriteStub); 385}; 386 387 388} } // namespace v8::internal 389 390#endif // V8_IA32_CODE_STUBS_IA32_H_ 391