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