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