1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_MIPS_CODE_STUBS_ARM_H_ 29 #define V8_MIPS_CODE_STUBS_ARM_H_ 30 31 #include "ic-inl.h" 32 33 34 namespace v8 { 35 namespace internal { 36 37 38 // Compute a transcendental math function natively, or call the 39 // TranscendentalCache runtime function. 40 class TranscendentalCacheStub: public CodeStub { 41 public: 42 enum ArgumentType { 43 TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits, 44 UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits 45 }; 46 TranscendentalCacheStub(TranscendentalCache::Type type,ArgumentType argument_type)47 TranscendentalCacheStub(TranscendentalCache::Type type, 48 ArgumentType argument_type) 49 : type_(type), argument_type_(argument_type) { } 50 void Generate(MacroAssembler* masm); 51 private: 52 TranscendentalCache::Type type_; 53 ArgumentType argument_type_; 54 void GenerateCallCFunction(MacroAssembler* masm, Register scratch); 55 MajorKey()56 Major MajorKey() { return TranscendentalCache; } MinorKey()57 int MinorKey() { return type_ | argument_type_; } 58 Runtime::FunctionId RuntimeFunction(); 59 }; 60 61 62 class StoreBufferOverflowStub: public CodeStub { 63 public: StoreBufferOverflowStub(SaveFPRegsMode save_fp)64 explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp) 65 : save_doubles_(save_fp) { } 66 67 void Generate(MacroAssembler* masm); 68 69 virtual bool IsPregenerated(); 70 static void GenerateFixedRegStubsAheadOfTime(); SometimesSetsUpAFrame()71 virtual bool SometimesSetsUpAFrame() { return false; } 72 73 private: 74 SaveFPRegsMode save_doubles_; 75 MajorKey()76 Major MajorKey() { return StoreBufferOverflow; } MinorKey()77 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } 78 }; 79 80 81 class UnaryOpStub: public CodeStub { 82 public: 83 UnaryOpStub(Token::Value op, 84 UnaryOverwriteMode mode, 85 UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED) op_(op)86 : op_(op), 87 mode_(mode), 88 operand_type_(operand_type) { 89 } 90 91 private: 92 Token::Value op_; 93 UnaryOverwriteMode mode_; 94 95 // Operand type information determined at runtime. 96 UnaryOpIC::TypeInfo operand_type_; 97 98 virtual void PrintName(StringStream* stream); 99 100 class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {}; 101 class OpBits: public BitField<Token::Value, 1, 7> {}; 102 class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {}; 103 MajorKey()104 Major MajorKey() { return UnaryOp; } MinorKey()105 int MinorKey() { 106 return ModeBits::encode(mode_) 107 | OpBits::encode(op_) 108 | OperandTypeInfoBits::encode(operand_type_); 109 } 110 111 // Note: A lot of the helper functions below will vanish when we use virtual 112 // function instead of switch more often. 113 void Generate(MacroAssembler* masm); 114 115 void GenerateTypeTransition(MacroAssembler* masm); 116 117 void GenerateSmiStub(MacroAssembler* masm); 118 void GenerateSmiStubSub(MacroAssembler* masm); 119 void GenerateSmiStubBitNot(MacroAssembler* masm); 120 void GenerateSmiCodeSub(MacroAssembler* masm, Label* non_smi, Label* slow); 121 void GenerateSmiCodeBitNot(MacroAssembler* masm, Label* slow); 122 123 void GenerateHeapNumberStub(MacroAssembler* masm); 124 void GenerateHeapNumberStubSub(MacroAssembler* masm); 125 void GenerateHeapNumberStubBitNot(MacroAssembler* masm); 126 void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow); 127 void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow); 128 129 void GenerateGenericStub(MacroAssembler* masm); 130 void GenerateGenericStubSub(MacroAssembler* masm); 131 void GenerateGenericStubBitNot(MacroAssembler* masm); 132 void GenerateGenericCodeFallback(MacroAssembler* masm); 133 GetCodeKind()134 virtual int GetCodeKind() { return Code::UNARY_OP_IC; } 135 GetICState()136 virtual InlineCacheState GetICState() { 137 return UnaryOpIC::ToState(operand_type_); 138 } 139 FinishCode(Handle<Code> code)140 virtual void FinishCode(Handle<Code> code) { 141 code->set_unary_op_type(operand_type_); 142 } 143 }; 144 145 146 class BinaryOpStub: public CodeStub { 147 public: BinaryOpStub(Token::Value op,OverwriteMode mode)148 BinaryOpStub(Token::Value op, OverwriteMode mode) 149 : op_(op), 150 mode_(mode), 151 operands_type_(BinaryOpIC::UNINITIALIZED), 152 result_type_(BinaryOpIC::UNINITIALIZED) { 153 use_fpu_ = CpuFeatures::IsSupported(FPU); 154 ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); 155 } 156 157 BinaryOpStub( 158 int key, 159 BinaryOpIC::TypeInfo operands_type, 160 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED) op_(OpBits::decode (key))161 : op_(OpBits::decode(key)), 162 mode_(ModeBits::decode(key)), 163 use_fpu_(FPUBits::decode(key)), 164 operands_type_(operands_type), 165 result_type_(result_type) { } 166 167 private: 168 enum SmiCodeGenerateHeapNumberResults { 169 ALLOW_HEAPNUMBER_RESULTS, 170 NO_HEAPNUMBER_RESULTS 171 }; 172 173 Token::Value op_; 174 OverwriteMode mode_; 175 bool use_fpu_; 176 177 // Operand type information determined at runtime. 178 BinaryOpIC::TypeInfo operands_type_; 179 BinaryOpIC::TypeInfo result_type_; 180 181 virtual void PrintName(StringStream* stream); 182 183 // Minor key encoding in 16 bits RRRTTTVOOOOOOOMM. 184 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; 185 class OpBits: public BitField<Token::Value, 2, 7> {}; 186 class FPUBits: public BitField<bool, 9, 1> {}; 187 class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {}; 188 class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {}; 189 MajorKey()190 Major MajorKey() { return BinaryOp; } MinorKey()191 int MinorKey() { 192 return OpBits::encode(op_) 193 | ModeBits::encode(mode_) 194 | FPUBits::encode(use_fpu_) 195 | OperandTypeInfoBits::encode(operands_type_) 196 | ResultTypeInfoBits::encode(result_type_); 197 } 198 199 void Generate(MacroAssembler* masm); 200 void GenerateGeneric(MacroAssembler* masm); 201 void GenerateSmiSmiOperation(MacroAssembler* masm); 202 void GenerateFPOperation(MacroAssembler* masm, 203 bool smi_operands, 204 Label* not_numbers, 205 Label* gc_required); 206 void GenerateSmiCode(MacroAssembler* masm, 207 Label* use_runtime, 208 Label* gc_required, 209 SmiCodeGenerateHeapNumberResults heapnumber_results); 210 void GenerateLoadArguments(MacroAssembler* masm); 211 void GenerateReturn(MacroAssembler* masm); 212 void GenerateUninitializedStub(MacroAssembler* masm); 213 void GenerateSmiStub(MacroAssembler* masm); 214 void GenerateInt32Stub(MacroAssembler* masm); 215 void GenerateHeapNumberStub(MacroAssembler* masm); 216 void GenerateOddballStub(MacroAssembler* masm); 217 void GenerateStringStub(MacroAssembler* masm); 218 void GenerateBothStringStub(MacroAssembler* masm); 219 void GenerateGenericStub(MacroAssembler* masm); 220 void GenerateAddStrings(MacroAssembler* masm); 221 void GenerateCallRuntime(MacroAssembler* masm); 222 223 void GenerateHeapResultAllocation(MacroAssembler* masm, 224 Register result, 225 Register heap_number_map, 226 Register scratch1, 227 Register scratch2, 228 Label* gc_required); 229 void GenerateRegisterArgsPush(MacroAssembler* masm); 230 void GenerateTypeTransition(MacroAssembler* masm); 231 void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); 232 GetCodeKind()233 virtual int GetCodeKind() { return Code::BINARY_OP_IC; } 234 GetICState()235 virtual InlineCacheState GetICState() { 236 return BinaryOpIC::ToState(operands_type_); 237 } 238 FinishCode(Handle<Code> code)239 virtual void FinishCode(Handle<Code> code) { 240 code->set_binary_op_type(operands_type_); 241 code->set_binary_op_result_type(result_type_); 242 } 243 244 friend class CodeGenerator; 245 }; 246 247 248 class StringHelper : public AllStatic { 249 public: 250 // Generate code for copying characters using a simple loop. This should only 251 // be used in places where the number of characters is small and the 252 // additional setup and checking in GenerateCopyCharactersLong adds too much 253 // overhead. Copying of overlapping regions is not supported. 254 // Dest register ends at the position after the last character written. 255 static void GenerateCopyCharacters(MacroAssembler* masm, 256 Register dest, 257 Register src, 258 Register count, 259 Register scratch, 260 bool ascii); 261 262 // Generate code for copying a large number of characters. This function 263 // is allowed to spend extra time setting up conditions to make copying 264 // faster. Copying of overlapping regions is not supported. 265 // Dest register ends at the position after the last character written. 266 static void GenerateCopyCharactersLong(MacroAssembler* masm, 267 Register dest, 268 Register src, 269 Register count, 270 Register scratch1, 271 Register scratch2, 272 Register scratch3, 273 Register scratch4, 274 Register scratch5, 275 int flags); 276 277 278 // Probe the symbol table for a two character string. If the string is 279 // not found by probing a jump to the label not_found is performed. This jump 280 // does not guarantee that the string is not in the symbol table. If the 281 // string is found the code falls through with the string in register r0. 282 // Contents of both c1 and c2 registers are modified. At the exit c1 is 283 // guaranteed to contain halfword with low and high bytes equal to 284 // initial contents of c1 and c2 respectively. 285 static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, 286 Register c1, 287 Register c2, 288 Register scratch1, 289 Register scratch2, 290 Register scratch3, 291 Register scratch4, 292 Register scratch5, 293 Label* not_found); 294 295 // Generate string hash. 296 static void GenerateHashInit(MacroAssembler* masm, 297 Register hash, 298 Register character); 299 300 static void GenerateHashAddCharacter(MacroAssembler* masm, 301 Register hash, 302 Register character); 303 304 static void GenerateHashGetHash(MacroAssembler* masm, 305 Register hash); 306 307 private: 308 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); 309 }; 310 311 312 // Flag that indicates how to generate code for the stub StringAddStub. 313 enum StringAddFlags { 314 NO_STRING_ADD_FLAGS = 0, 315 // Omit left string check in stub (left is definitely a string). 316 NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0, 317 // Omit right string check in stub (right is definitely a string). 318 NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1, 319 // Omit both string checks in stub. 320 NO_STRING_CHECK_IN_STUB = 321 NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB 322 }; 323 324 325 class StringAddStub: public CodeStub { 326 public: StringAddStub(StringAddFlags flags)327 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} 328 329 private: MajorKey()330 Major MajorKey() { return StringAdd; } MinorKey()331 int MinorKey() { return flags_; } 332 333 void Generate(MacroAssembler* masm); 334 335 void GenerateConvertArgument(MacroAssembler* masm, 336 int stack_offset, 337 Register arg, 338 Register scratch1, 339 Register scratch2, 340 Register scratch3, 341 Register scratch4, 342 Label* slow); 343 344 const StringAddFlags flags_; 345 }; 346 347 348 class SubStringStub: public CodeStub { 349 public: SubStringStub()350 SubStringStub() {} 351 352 private: MajorKey()353 Major MajorKey() { return SubString; } MinorKey()354 int MinorKey() { return 0; } 355 356 void Generate(MacroAssembler* masm); 357 }; 358 359 360 class StringCompareStub: public CodeStub { 361 public: StringCompareStub()362 StringCompareStub() { } 363 364 // Compare two flat ASCII strings and returns result in v0. 365 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 366 Register left, 367 Register right, 368 Register scratch1, 369 Register scratch2, 370 Register scratch3, 371 Register scratch4); 372 373 // Compares two flat ASCII strings for equality and returns result 374 // in v0. 375 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm, 376 Register left, 377 Register right, 378 Register scratch1, 379 Register scratch2, 380 Register scratch3); 381 382 private: MajorKey()383 virtual Major MajorKey() { return StringCompare; } MinorKey()384 virtual int MinorKey() { return 0; } 385 virtual void Generate(MacroAssembler* masm); 386 387 static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm, 388 Register left, 389 Register right, 390 Register length, 391 Register scratch1, 392 Register scratch2, 393 Register scratch3, 394 Label* chars_not_equal); 395 }; 396 397 398 // This stub can convert a signed int32 to a heap number (double). It does 399 // not work for int32s that are in Smi range! No GC occurs during this stub 400 // so you don't have to set up the frame. 401 class WriteInt32ToHeapNumberStub : public CodeStub { 402 public: WriteInt32ToHeapNumberStub(Register the_int,Register the_heap_number,Register scratch,Register scratch2)403 WriteInt32ToHeapNumberStub(Register the_int, 404 Register the_heap_number, 405 Register scratch, 406 Register scratch2) 407 : the_int_(the_int), 408 the_heap_number_(the_heap_number), 409 scratch_(scratch), 410 sign_(scratch2) { 411 ASSERT(IntRegisterBits::is_valid(the_int_.code())); 412 ASSERT(HeapNumberRegisterBits::is_valid(the_heap_number_.code())); 413 ASSERT(ScratchRegisterBits::is_valid(scratch_.code())); 414 ASSERT(SignRegisterBits::is_valid(sign_.code())); 415 } 416 417 bool IsPregenerated(); 418 static void GenerateFixedRegStubsAheadOfTime(); 419 420 private: 421 Register the_int_; 422 Register the_heap_number_; 423 Register scratch_; 424 Register sign_; 425 426 // Minor key encoding in 16 bits. 427 class IntRegisterBits: public BitField<int, 0, 4> {}; 428 class HeapNumberRegisterBits: public BitField<int, 4, 4> {}; 429 class ScratchRegisterBits: public BitField<int, 8, 4> {}; 430 class SignRegisterBits: public BitField<int, 12, 4> {}; 431 MajorKey()432 Major MajorKey() { return WriteInt32ToHeapNumber; } MinorKey()433 int MinorKey() { 434 // Encode the parameters in a unique 16 bit value. 435 return IntRegisterBits::encode(the_int_.code()) 436 | HeapNumberRegisterBits::encode(the_heap_number_.code()) 437 | ScratchRegisterBits::encode(scratch_.code()) 438 | SignRegisterBits::encode(sign_.code()); 439 } 440 441 void Generate(MacroAssembler* masm); 442 }; 443 444 445 class NumberToStringStub: public CodeStub { 446 public: NumberToStringStub()447 NumberToStringStub() { } 448 449 // Generate code to do a lookup in the number string cache. If the number in 450 // the register object is found in the cache the generated code falls through 451 // with the result in the result register. The object and the result register 452 // can be the same. If the number is not found in the cache the code jumps to 453 // the label not_found with only the content of register object unchanged. 454 static void GenerateLookupNumberStringCache(MacroAssembler* masm, 455 Register object, 456 Register result, 457 Register scratch1, 458 Register scratch2, 459 Register scratch3, 460 bool object_is_smi, 461 Label* not_found); 462 463 private: MajorKey()464 Major MajorKey() { return NumberToString; } MinorKey()465 int MinorKey() { return 0; } 466 467 void Generate(MacroAssembler* masm); 468 }; 469 470 471 class RecordWriteStub: public CodeStub { 472 public: RecordWriteStub(Register object,Register value,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)473 RecordWriteStub(Register object, 474 Register value, 475 Register address, 476 RememberedSetAction remembered_set_action, 477 SaveFPRegsMode fp_mode) 478 : object_(object), 479 value_(value), 480 address_(address), 481 remembered_set_action_(remembered_set_action), 482 save_fp_regs_mode_(fp_mode), 483 regs_(object, // An input reg. 484 address, // An input reg. 485 value) { // One scratch reg. 486 } 487 488 enum Mode { 489 STORE_BUFFER_ONLY, 490 INCREMENTAL, 491 INCREMENTAL_COMPACTION 492 }; 493 494 virtual bool IsPregenerated(); 495 static void GenerateFixedRegStubsAheadOfTime(); SometimesSetsUpAFrame()496 virtual bool SometimesSetsUpAFrame() { return false; } 497 PatchBranchIntoNop(MacroAssembler * masm,int pos)498 static void PatchBranchIntoNop(MacroAssembler* masm, int pos) { 499 const unsigned offset = masm->instr_at(pos) & kImm16Mask; 500 masm->instr_at_put(pos, BNE | (zero_reg.code() << kRsShift) | 501 (zero_reg.code() << kRtShift) | (offset & kImm16Mask)); 502 ASSERT(Assembler::IsBne(masm->instr_at(pos))); 503 } 504 PatchNopIntoBranch(MacroAssembler * masm,int pos)505 static void PatchNopIntoBranch(MacroAssembler* masm, int pos) { 506 const unsigned offset = masm->instr_at(pos) & kImm16Mask; 507 masm->instr_at_put(pos, BEQ | (zero_reg.code() << kRsShift) | 508 (zero_reg.code() << kRtShift) | (offset & kImm16Mask)); 509 ASSERT(Assembler::IsBeq(masm->instr_at(pos))); 510 } 511 GetMode(Code * stub)512 static Mode GetMode(Code* stub) { 513 Instr first_instruction = Assembler::instr_at(stub->instruction_start()); 514 Instr second_instruction = Assembler::instr_at(stub->instruction_start() + 515 2 * Assembler::kInstrSize); 516 517 if (Assembler::IsBeq(first_instruction)) { 518 return INCREMENTAL; 519 } 520 521 ASSERT(Assembler::IsBne(first_instruction)); 522 523 if (Assembler::IsBeq(second_instruction)) { 524 return INCREMENTAL_COMPACTION; 525 } 526 527 ASSERT(Assembler::IsBne(second_instruction)); 528 529 return STORE_BUFFER_ONLY; 530 } 531 Patch(Code * stub,Mode mode)532 static void Patch(Code* stub, Mode mode) { 533 MacroAssembler masm(NULL, 534 stub->instruction_start(), 535 stub->instruction_size()); 536 switch (mode) { 537 case STORE_BUFFER_ONLY: 538 ASSERT(GetMode(stub) == INCREMENTAL || 539 GetMode(stub) == INCREMENTAL_COMPACTION); 540 PatchBranchIntoNop(&masm, 0); 541 PatchBranchIntoNop(&masm, 2 * Assembler::kInstrSize); 542 break; 543 case INCREMENTAL: 544 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY); 545 PatchNopIntoBranch(&masm, 0); 546 break; 547 case INCREMENTAL_COMPACTION: 548 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY); 549 PatchNopIntoBranch(&masm, 2 * Assembler::kInstrSize); 550 break; 551 } 552 ASSERT(GetMode(stub) == mode); 553 CPU::FlushICache(stub->instruction_start(), 4 * Assembler::kInstrSize); 554 } 555 556 private: 557 // This is a helper class for freeing up 3 scratch registers. The input is 558 // two registers that must be preserved and one scratch register provided by 559 // the caller. 560 class RegisterAllocation { 561 public: RegisterAllocation(Register object,Register address,Register scratch0)562 RegisterAllocation(Register object, 563 Register address, 564 Register scratch0) 565 : object_(object), 566 address_(address), 567 scratch0_(scratch0) { 568 ASSERT(!AreAliased(scratch0, object, address, no_reg)); 569 scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_); 570 } 571 Save(MacroAssembler * masm)572 void Save(MacroAssembler* masm) { 573 ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_)); 574 // We don't have to save scratch0_ because it was given to us as 575 // a scratch register. 576 masm->push(scratch1_); 577 } 578 Restore(MacroAssembler * masm)579 void Restore(MacroAssembler* masm) { 580 masm->pop(scratch1_); 581 } 582 583 // If we have to call into C then we need to save and restore all caller- 584 // saved registers that were not already preserved. The scratch registers 585 // will be restored by other means so we don't bother pushing them here. SaveCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)586 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { 587 masm->MultiPush((kJSCallerSaved | ra.bit()) & ~scratch1_.bit()); 588 if (mode == kSaveFPRegs) { 589 CpuFeatures::Scope scope(FPU); 590 masm->MultiPushFPU(kCallerSavedFPU); 591 } 592 } 593 RestoreCallerSaveRegisters(MacroAssembler * masm,SaveFPRegsMode mode)594 inline void RestoreCallerSaveRegisters(MacroAssembler*masm, 595 SaveFPRegsMode mode) { 596 if (mode == kSaveFPRegs) { 597 CpuFeatures::Scope scope(FPU); 598 masm->MultiPopFPU(kCallerSavedFPU); 599 } 600 masm->MultiPop((kJSCallerSaved | ra.bit()) & ~scratch1_.bit()); 601 } 602 object()603 inline Register object() { return object_; } address()604 inline Register address() { return address_; } scratch0()605 inline Register scratch0() { return scratch0_; } scratch1()606 inline Register scratch1() { return scratch1_; } 607 608 private: 609 Register object_; 610 Register address_; 611 Register scratch0_; 612 Register scratch1_; 613 GetRegThatIsNotOneOf(Register r1,Register r2,Register r3)614 Register GetRegThatIsNotOneOf(Register r1, 615 Register r2, 616 Register r3) { 617 for (int i = 0; i < Register::kNumAllocatableRegisters; i++) { 618 Register candidate = Register::FromAllocationIndex(i); 619 if (candidate.is(r1)) continue; 620 if (candidate.is(r2)) continue; 621 if (candidate.is(r3)) continue; 622 return candidate; 623 } 624 UNREACHABLE(); 625 return no_reg; 626 } 627 friend class RecordWriteStub; 628 }; 629 630 enum OnNoNeedToInformIncrementalMarker { 631 kReturnOnNoNeedToInformIncrementalMarker, 632 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker 633 }; 634 635 void Generate(MacroAssembler* masm); 636 void GenerateIncremental(MacroAssembler* masm, Mode mode); 637 void CheckNeedsToInformIncrementalMarker( 638 MacroAssembler* masm, 639 OnNoNeedToInformIncrementalMarker on_no_need, 640 Mode mode); 641 void InformIncrementalMarker(MacroAssembler* masm, Mode mode); 642 MajorKey()643 Major MajorKey() { return RecordWrite; } 644 MinorKey()645 int MinorKey() { 646 return ObjectBits::encode(object_.code()) | 647 ValueBits::encode(value_.code()) | 648 AddressBits::encode(address_.code()) | 649 RememberedSetActionBits::encode(remembered_set_action_) | 650 SaveFPRegsModeBits::encode(save_fp_regs_mode_); 651 } 652 Activate(Code * code)653 void Activate(Code* code) { 654 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); 655 } 656 657 class ObjectBits: public BitField<int, 0, 5> {}; 658 class ValueBits: public BitField<int, 5, 5> {}; 659 class AddressBits: public BitField<int, 10, 5> {}; 660 class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {}; 661 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {}; 662 663 Register object_; 664 Register value_; 665 Register address_; 666 RememberedSetAction remembered_set_action_; 667 SaveFPRegsMode save_fp_regs_mode_; 668 Label slow_; 669 RegisterAllocation regs_; 670 }; 671 672 673 // Enter C code from generated RegExp code in a way that allows 674 // the C code to fix the return address in case of a GC. 675 // Currently only needed on ARM and MIPS. 676 class RegExpCEntryStub: public CodeStub { 677 public: RegExpCEntryStub()678 RegExpCEntryStub() {} ~RegExpCEntryStub()679 virtual ~RegExpCEntryStub() {} 680 void Generate(MacroAssembler* masm); 681 682 private: MajorKey()683 Major MajorKey() { return RegExpCEntry; } MinorKey()684 int MinorKey() { return 0; } 685 NeedsImmovableCode()686 bool NeedsImmovableCode() { return true; } 687 }; 688 689 // Trampoline stub to call into native code. To call safely into native code 690 // in the presence of compacting GC (which can move code objects) we need to 691 // keep the code which called into native pinned in the memory. Currently the 692 // simplest approach is to generate such stub early enough so it can never be 693 // moved by GC 694 class DirectCEntryStub: public CodeStub { 695 public: DirectCEntryStub()696 DirectCEntryStub() {} 697 void Generate(MacroAssembler* masm); 698 void GenerateCall(MacroAssembler* masm, 699 ExternalReference function); 700 void GenerateCall(MacroAssembler* masm, Register target); 701 702 private: MajorKey()703 Major MajorKey() { return DirectCEntry; } MinorKey()704 int MinorKey() { return 0; } 705 NeedsImmovableCode()706 bool NeedsImmovableCode() { return true; } 707 }; 708 709 class FloatingPointHelper : public AllStatic { 710 public: 711 enum Destination { 712 kFPURegisters, 713 kCoreRegisters 714 }; 715 716 717 // Loads smis from a0 and a1 (right and left in binary operations) into 718 // floating point registers. Depending on the destination the values ends up 719 // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination 720 // is floating point registers FPU must be supported. If core registers are 721 // requested when FPU is supported f12 and f14 will be scratched. 722 static void LoadSmis(MacroAssembler* masm, 723 Destination destination, 724 Register scratch1, 725 Register scratch2); 726 727 // Loads objects from a0 and a1 (right and left in binary operations) into 728 // floating point registers. Depending on the destination the values ends up 729 // either f14 and f12 or in a2/a3 and a0/a1 respectively. If the destination 730 // is floating point registers FPU must be supported. If core registers are 731 // requested when FPU is supported f12 and f14 will still be scratched. If 732 // either a0 or a1 is not a number (not smi and not heap number object) the 733 // not_number label is jumped to with a0 and a1 intact. 734 static void LoadOperands(MacroAssembler* masm, 735 FloatingPointHelper::Destination destination, 736 Register heap_number_map, 737 Register scratch1, 738 Register scratch2, 739 Label* not_number); 740 741 // Convert the smi or heap number in object to an int32 using the rules 742 // for ToInt32 as described in ECMAScript 9.5.: the value is truncated 743 // and brought into the range -2^31 .. +2^31 - 1. 744 static void ConvertNumberToInt32(MacroAssembler* masm, 745 Register object, 746 Register dst, 747 Register heap_number_map, 748 Register scratch1, 749 Register scratch2, 750 Register scratch3, 751 FPURegister double_scratch, 752 Label* not_int32); 753 754 // Converts the integer (untagged smi) in |int_scratch| to a double, storing 755 // the result either in |double_dst| or |dst2:dst1|, depending on 756 // |destination|. 757 // Warning: The value in |int_scratch| will be changed in the process! 758 static void ConvertIntToDouble(MacroAssembler* masm, 759 Register int_scratch, 760 Destination destination, 761 FPURegister double_dst, 762 Register dst1, 763 Register dst2, 764 Register scratch2, 765 FPURegister single_scratch); 766 767 // Load the number from object into double_dst in the double format. 768 // Control will jump to not_int32 if the value cannot be exactly represented 769 // by a 32-bit integer. 770 // Floating point value in the 32-bit integer range that are not exact integer 771 // won't be loaded. 772 static void LoadNumberAsInt32Double(MacroAssembler* masm, 773 Register object, 774 Destination destination, 775 FPURegister double_dst, 776 Register dst1, 777 Register dst2, 778 Register heap_number_map, 779 Register scratch1, 780 Register scratch2, 781 FPURegister single_scratch, 782 Label* not_int32); 783 784 // Loads the number from object into dst as a 32-bit integer. 785 // Control will jump to not_int32 if the object cannot be exactly represented 786 // by a 32-bit integer. 787 // Floating point value in the 32-bit integer range that are not exact integer 788 // won't be converted. 789 // scratch3 is not used when FPU is supported. 790 static void LoadNumberAsInt32(MacroAssembler* masm, 791 Register object, 792 Register dst, 793 Register heap_number_map, 794 Register scratch1, 795 Register scratch2, 796 Register scratch3, 797 FPURegister double_scratch, 798 Label* not_int32); 799 800 // Generate non FPU code to check if a double can be exactly represented by a 801 // 32-bit integer. This does not check for 0 or -0, which need 802 // to be checked for separately. 803 // Control jumps to not_int32 if the value is not a 32-bit integer, and falls 804 // through otherwise. 805 // src1 and src2 will be cloberred. 806 // 807 // Expected input: 808 // - src1: higher (exponent) part of the double value. 809 // - src2: lower (mantissa) part of the double value. 810 // Output status: 811 // - dst: 32 higher bits of the mantissa. (mantissa[51:20]) 812 // - src2: contains 1. 813 // - other registers are clobbered. 814 static void DoubleIs32BitInteger(MacroAssembler* masm, 815 Register src1, 816 Register src2, 817 Register dst, 818 Register scratch, 819 Label* not_int32); 820 821 // Generates code to call a C function to do a double operation using core 822 // registers. (Used when FPU is not supported.) 823 // This code never falls through, but returns with a heap number containing 824 // the result in v0. 825 // Register heapnumber_result must be a heap number in which the 826 // result of the operation will be stored. 827 // Requires the following layout on entry: 828 // a0: Left value (least significant part of mantissa). 829 // a1: Left value (sign, exponent, top of mantissa). 830 // a2: Right value (least significant part of mantissa). 831 // a3: Right value (sign, exponent, top of mantissa). 832 static void CallCCodeForDoubleOperation(MacroAssembler* masm, 833 Token::Value op, 834 Register heap_number_result, 835 Register scratch); 836 837 private: 838 static void LoadNumber(MacroAssembler* masm, 839 FloatingPointHelper::Destination destination, 840 Register object, 841 FPURegister dst, 842 Register dst1, 843 Register dst2, 844 Register heap_number_map, 845 Register scratch1, 846 Register scratch2, 847 Label* not_number); 848 }; 849 850 851 class StringDictionaryLookupStub: public CodeStub { 852 public: 853 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP }; 854 StringDictionaryLookupStub(LookupMode mode)855 explicit StringDictionaryLookupStub(LookupMode mode) : mode_(mode) { } 856 857 void Generate(MacroAssembler* masm); 858 859 static void GenerateNegativeLookup(MacroAssembler* masm, 860 Label* miss, 861 Label* done, 862 Register receiver, 863 Register properties, 864 Handle<String> name, 865 Register scratch0); 866 867 static void GeneratePositiveLookup(MacroAssembler* masm, 868 Label* miss, 869 Label* done, 870 Register elements, 871 Register name, 872 Register r0, 873 Register r1); 874 SometimesSetsUpAFrame()875 virtual bool SometimesSetsUpAFrame() { return false; } 876 877 private: 878 static const int kInlinedProbes = 4; 879 static const int kTotalProbes = 20; 880 881 static const int kCapacityOffset = 882 StringDictionary::kHeaderSize + 883 StringDictionary::kCapacityIndex * kPointerSize; 884 885 static const int kElementsStartOffset = 886 StringDictionary::kHeaderSize + 887 StringDictionary::kElementsStartIndex * kPointerSize; 888 MajorKey()889 Major MajorKey() { return StringDictionaryLookup; } 890 MinorKey()891 int MinorKey() { 892 return LookupModeBits::encode(mode_); 893 } 894 895 class LookupModeBits: public BitField<LookupMode, 0, 1> {}; 896 897 LookupMode mode_; 898 }; 899 900 901 } } // namespace v8::internal 902 903 #endif // V8_MIPS_CODE_STUBS_ARM_H_ 904