1// Copyright 2012 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_MIPS_MACRO_ASSEMBLER_MIPS_H_ 6#define V8_MIPS_MACRO_ASSEMBLER_MIPS_H_ 7 8#include "src/assembler.h" 9#include "src/globals.h" 10#include "src/mips/assembler-mips.h" 11 12namespace v8 { 13namespace internal { 14 15// Give alias names to registers for calling conventions. 16const Register kReturnRegister0 = {Register::kCode_v0}; 17const Register kReturnRegister1 = {Register::kCode_v1}; 18const Register kReturnRegister2 = {Register::kCode_a0}; 19const Register kJSFunctionRegister = {Register::kCode_a1}; 20const Register kContextRegister = {Register::kCpRegister}; 21const Register kAllocateSizeRegister = {Register::kCode_a0}; 22const Register kInterpreterAccumulatorRegister = {Register::kCode_v0}; 23const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_t4}; 24const Register kInterpreterBytecodeArrayRegister = {Register::kCode_t5}; 25const Register kInterpreterDispatchTableRegister = {Register::kCode_t6}; 26const Register kJavaScriptCallArgCountRegister = {Register::kCode_a0}; 27const Register kJavaScriptCallNewTargetRegister = {Register::kCode_a3}; 28const Register kRuntimeCallFunctionRegister = {Register::kCode_a1}; 29const Register kRuntimeCallArgCountRegister = {Register::kCode_a0}; 30 31// Forward declaration. 32class JumpTarget; 33 34// Reserved Register Usage Summary. 35// 36// Registers t8, t9, and at are reserved for use by the MacroAssembler. 37// 38// The programmer should know that the MacroAssembler may clobber these three, 39// but won't touch other registers except in special cases. 40// 41// Per the MIPS ABI, register t9 must be used for indirect function call 42// via 'jalr t9' or 'jr t9' instructions. This is relied upon by gcc when 43// trying to update gp register for position-independent-code. Whenever 44// MIPS generated code calls C code, it must be via t9 register. 45 46 47// Flags used for LeaveExitFrame function. 48enum LeaveExitFrameMode { 49 EMIT_RETURN = true, 50 NO_EMIT_RETURN = false 51}; 52 53// Flags used for AllocateHeapNumber 54enum TaggingMode { 55 // Tag the result. 56 TAG_RESULT, 57 // Don't tag 58 DONT_TAG_RESULT 59}; 60 61// Flags used for the ObjectToDoubleFPURegister function. 62enum ObjectToDoubleFlags { 63 // No special flags. 64 NO_OBJECT_TO_DOUBLE_FLAGS = 0, 65 // Object is known to be a non smi. 66 OBJECT_NOT_SMI = 1 << 0, 67 // Don't load NaNs or infinities, branch to the non number case instead. 68 AVOID_NANS_AND_INFINITIES = 1 << 1 69}; 70 71// Allow programmer to use Branch Delay Slot of Branches, Jumps, Calls. 72enum BranchDelaySlot { 73 USE_DELAY_SLOT, 74 PROTECT 75}; 76 77// Flags used for the li macro-assembler function. 78enum LiFlags { 79 // If the constant value can be represented in just 16 bits, then 80 // optimize the li to use a single instruction, rather than lui/ori pair. 81 OPTIMIZE_SIZE = 0, 82 // Always use 2 instructions (lui/ori pair), even if the constant could 83 // be loaded with just one, so that this value is patchable later. 84 CONSTANT_SIZE = 1 85}; 86 87 88enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; 89enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; 90enum PointersToHereCheck { 91 kPointersToHereMaybeInteresting, 92 kPointersToHereAreAlwaysInteresting 93}; 94enum RAStatus { kRAHasNotBeenSaved, kRAHasBeenSaved }; 95 96Register GetRegisterThatIsNotOneOf(Register reg1, 97 Register reg2 = no_reg, 98 Register reg3 = no_reg, 99 Register reg4 = no_reg, 100 Register reg5 = no_reg, 101 Register reg6 = no_reg); 102 103bool AreAliased(Register reg1, Register reg2, Register reg3 = no_reg, 104 Register reg4 = no_reg, Register reg5 = no_reg, 105 Register reg6 = no_reg, Register reg7 = no_reg, 106 Register reg8 = no_reg, Register reg9 = no_reg, 107 Register reg10 = no_reg); 108 109 110// ----------------------------------------------------------------------------- 111// Static helper functions. 112 113inline MemOperand ContextMemOperand(Register context, int index) { 114 return MemOperand(context, Context::SlotOffset(index)); 115} 116 117 118inline MemOperand NativeContextMemOperand() { 119 return ContextMemOperand(cp, Context::NATIVE_CONTEXT_INDEX); 120} 121 122 123// Generate a MemOperand for loading a field from an object. 124inline MemOperand FieldMemOperand(Register object, int offset) { 125 return MemOperand(object, offset - kHeapObjectTag); 126} 127 128 129// Generate a MemOperand for storing arguments 5..N on the stack 130// when calling CallCFunction(). 131inline MemOperand CFunctionArgumentOperand(int index) { 132 DCHECK(index > kCArgSlotCount); 133 // Argument 5 takes the slot just past the four Arg-slots. 134 int offset = (index - 5) * kPointerSize + kCArgsSlotsSize; 135 return MemOperand(sp, offset); 136} 137 138 139// MacroAssembler implements a collection of frequently used macros. 140class MacroAssembler: public Assembler { 141 public: 142 MacroAssembler(Isolate* isolate, void* buffer, int size, 143 CodeObjectRequired create_code_object); 144 145 // Arguments macros. 146#define COND_TYPED_ARGS Condition cond, Register r1, const Operand& r2 147#define COND_ARGS cond, r1, r2 148 149 // Cases when relocation is not needed. 150#define DECLARE_NORELOC_PROTOTYPE(Name, target_type) \ 151 void Name(target_type target, BranchDelaySlot bd = PROTECT); \ 152 inline void Name(BranchDelaySlot bd, target_type target) { \ 153 Name(target, bd); \ 154 } \ 155 void Name(target_type target, \ 156 COND_TYPED_ARGS, \ 157 BranchDelaySlot bd = PROTECT); \ 158 inline void Name(BranchDelaySlot bd, \ 159 target_type target, \ 160 COND_TYPED_ARGS) { \ 161 Name(target, COND_ARGS, bd); \ 162 } 163 164#define DECLARE_BRANCH_PROTOTYPES(Name) \ 165 DECLARE_NORELOC_PROTOTYPE(Name, Label*) \ 166 DECLARE_NORELOC_PROTOTYPE(Name, int32_t) 167 168 DECLARE_BRANCH_PROTOTYPES(Branch) 169 DECLARE_BRANCH_PROTOTYPES(BranchAndLink) 170 DECLARE_BRANCH_PROTOTYPES(BranchShort) 171 172#undef DECLARE_BRANCH_PROTOTYPES 173#undef COND_TYPED_ARGS 174#undef COND_ARGS 175 176 177 // Jump, Call, and Ret pseudo instructions implementing inter-working. 178#define COND_ARGS Condition cond = al, Register rs = zero_reg, \ 179 const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT 180 181 void Jump(Register target, COND_ARGS); 182 void Jump(intptr_t target, RelocInfo::Mode rmode, COND_ARGS); 183 void Jump(Address target, RelocInfo::Mode rmode, COND_ARGS); 184 void Jump(Handle<Code> code, RelocInfo::Mode rmode, COND_ARGS); 185 static int CallSize(Register target, COND_ARGS); 186 void Call(Register target, COND_ARGS); 187 static int CallSize(Address target, RelocInfo::Mode rmode, COND_ARGS); 188 void Call(Address target, RelocInfo::Mode rmode, COND_ARGS); 189 int CallSize(Handle<Code> code, 190 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 191 TypeFeedbackId ast_id = TypeFeedbackId::None(), 192 COND_ARGS); 193 void Call(Handle<Code> code, 194 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 195 TypeFeedbackId ast_id = TypeFeedbackId::None(), 196 COND_ARGS); 197 void Ret(COND_ARGS); 198 inline void Ret(BranchDelaySlot bd, Condition cond = al, 199 Register rs = zero_reg, const Operand& rt = Operand(zero_reg)) { 200 Ret(cond, rs, rt, bd); 201 } 202 203 bool IsNear(Label* L, Condition cond, int rs_reg); 204 205 void Branch(Label* L, 206 Condition cond, 207 Register rs, 208 Heap::RootListIndex index, 209 BranchDelaySlot bdslot = PROTECT); 210 211 // GetLabelFunction must be lambda '[](size_t index) -> Label*' or a 212 // functor/function with 'Label *func(size_t index)' declaration. 213 template <typename Func> 214 void GenerateSwitchTable(Register index, size_t case_count, 215 Func GetLabelFunction); 216#undef COND_ARGS 217 218 // Emit code to discard a non-negative number of pointer-sized elements 219 // from the stack, clobbering only the sp register. 220 void Drop(int count, 221 Condition cond = cc_always, 222 Register reg = no_reg, 223 const Operand& op = Operand(no_reg)); 224 225 // Trivial case of DropAndRet that utilizes the delay slot and only emits 226 // 2 instructions. 227 void DropAndRet(int drop); 228 229 void DropAndRet(int drop, 230 Condition cond, 231 Register reg, 232 const Operand& op); 233 234 // Swap two registers. If the scratch register is omitted then a slightly 235 // less efficient form using xor instead of mov is emitted. 236 void Swap(Register reg1, Register reg2, Register scratch = no_reg); 237 238 void Call(Label* target); 239 240 inline void Move(Register dst, Handle<Object> handle) { li(dst, handle); } 241 inline void Move(Register dst, Smi* smi) { li(dst, Operand(smi)); } 242 243 inline void Move(Register dst, Register src) { 244 if (!dst.is(src)) { 245 mov(dst, src); 246 } 247 } 248 249 inline void Move_d(FPURegister dst, FPURegister src) { 250 if (!dst.is(src)) { 251 mov_d(dst, src); 252 } 253 } 254 255 inline void Move_s(FPURegister dst, FPURegister src) { 256 if (!dst.is(src)) { 257 mov_s(dst, src); 258 } 259 } 260 261 inline void Move(FPURegister dst, FPURegister src) { Move_d(dst, src); } 262 263 inline void Move(Register dst_low, Register dst_high, FPURegister src) { 264 mfc1(dst_low, src); 265 Mfhc1(dst_high, src); 266 } 267 268 inline void FmoveHigh(Register dst_high, FPURegister src) { 269 Mfhc1(dst_high, src); 270 } 271 272 inline void FmoveHigh(FPURegister dst, Register src_high) { 273 Mthc1(src_high, dst); 274 } 275 276 inline void FmoveLow(Register dst_low, FPURegister src) { 277 mfc1(dst_low, src); 278 } 279 280 void FmoveLow(FPURegister dst, Register src_low); 281 282 inline void Move(FPURegister dst, Register src_low, Register src_high) { 283 mtc1(src_low, dst); 284 Mthc1(src_high, dst); 285 } 286 287 void Move(FPURegister dst, float imm); 288 void Move(FPURegister dst, double imm); 289 290 // Conditional move. 291 void Movz(Register rd, Register rs, Register rt); 292 void Movn(Register rd, Register rs, Register rt); 293 void Movt(Register rd, Register rs, uint16_t cc = 0); 294 void Movf(Register rd, Register rs, uint16_t cc = 0); 295 296 // Min, Max macros. 297 // On pre-r6 these functions may modify at and t8 registers. 298 void MinNaNCheck_d(FPURegister dst, FPURegister src1, FPURegister src2, 299 Label* nan = nullptr); 300 void MaxNaNCheck_d(FPURegister dst, FPURegister src1, FPURegister src2, 301 Label* nan = nullptr); 302 void MinNaNCheck_s(FPURegister dst, FPURegister src1, FPURegister src2, 303 Label* nan = nullptr); 304 void MaxNaNCheck_s(FPURegister dst, FPURegister src1, FPURegister src2, 305 Label* nan = nullptr); 306 307 void Clz(Register rd, Register rs); 308 309 // Jump unconditionally to given label. 310 // We NEED a nop in the branch delay slot, as it used by v8, for example in 311 // CodeGenerator::ProcessDeferred(). 312 // Currently the branch delay slot is filled by the MacroAssembler. 313 // Use rather b(Label) for code generation. 314 void jmp(Label* L) { 315 Branch(L); 316 } 317 318 void Load(Register dst, const MemOperand& src, Representation r); 319 void Store(Register src, const MemOperand& dst, Representation r); 320 321 void PushRoot(Heap::RootListIndex index) { 322 LoadRoot(at, index); 323 Push(at); 324 } 325 326 // Compare the object in a register to a value and jump if they are equal. 327 void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal) { 328 LoadRoot(at, index); 329 Branch(if_equal, eq, with, Operand(at)); 330 } 331 332 // Compare the object in a register to a value and jump if they are not equal. 333 void JumpIfNotRoot(Register with, Heap::RootListIndex index, 334 Label* if_not_equal) { 335 LoadRoot(at, index); 336 Branch(if_not_equal, ne, with, Operand(at)); 337 } 338 339 // Load an object from the root table. 340 void LoadRoot(Register destination, 341 Heap::RootListIndex index); 342 void LoadRoot(Register destination, 343 Heap::RootListIndex index, 344 Condition cond, Register src1, const Operand& src2); 345 346 // Store an object to the root table. 347 void StoreRoot(Register source, 348 Heap::RootListIndex index); 349 void StoreRoot(Register source, 350 Heap::RootListIndex index, 351 Condition cond, Register src1, const Operand& src2); 352 353 // --------------------------------------------------------------------------- 354 // GC Support 355 356 void IncrementalMarkingRecordWriteHelper(Register object, 357 Register value, 358 Register address); 359 360 enum RememberedSetFinalAction { 361 kReturnAtEnd, 362 kFallThroughAtEnd 363 }; 364 365 366 // Record in the remembered set the fact that we have a pointer to new space 367 // at the address pointed to by the addr register. Only works if addr is not 368 // in new space. 369 void RememberedSetHelper(Register object, // Used for debug code. 370 Register addr, 371 Register scratch, 372 SaveFPRegsMode save_fp, 373 RememberedSetFinalAction and_then); 374 375 void CheckPageFlag(Register object, 376 Register scratch, 377 int mask, 378 Condition cc, 379 Label* condition_met); 380 381 // Check if object is in new space. Jumps if the object is not in new space. 382 // The register scratch can be object itself, but it will be clobbered. 383 void JumpIfNotInNewSpace(Register object, 384 Register scratch, 385 Label* branch) { 386 InNewSpace(object, scratch, eq, branch); 387 } 388 389 // Check if object is in new space. Jumps if the object is in new space. 390 // The register scratch can be object itself, but scratch will be clobbered. 391 void JumpIfInNewSpace(Register object, 392 Register scratch, 393 Label* branch) { 394 InNewSpace(object, scratch, ne, branch); 395 } 396 397 // Check if an object has a given incremental marking color. 398 void HasColor(Register object, 399 Register scratch0, 400 Register scratch1, 401 Label* has_color, 402 int first_bit, 403 int second_bit); 404 405 void JumpIfBlack(Register object, 406 Register scratch0, 407 Register scratch1, 408 Label* on_black); 409 410 // Checks the color of an object. If the object is white we jump to the 411 // incremental marker. 412 void JumpIfWhite(Register value, Register scratch1, Register scratch2, 413 Register scratch3, Label* value_is_white); 414 415 // Notify the garbage collector that we wrote a pointer into an object. 416 // |object| is the object being stored into, |value| is the object being 417 // stored. value and scratch registers are clobbered by the operation. 418 // The offset is the offset from the start of the object, not the offset from 419 // the tagged HeapObject pointer. For use with FieldOperand(reg, off). 420 void RecordWriteField( 421 Register object, 422 int offset, 423 Register value, 424 Register scratch, 425 RAStatus ra_status, 426 SaveFPRegsMode save_fp, 427 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 428 SmiCheck smi_check = INLINE_SMI_CHECK, 429 PointersToHereCheck pointers_to_here_check_for_value = 430 kPointersToHereMaybeInteresting); 431 432 // As above, but the offset has the tag presubtracted. For use with 433 // MemOperand(reg, off). 434 inline void RecordWriteContextSlot( 435 Register context, 436 int offset, 437 Register value, 438 Register scratch, 439 RAStatus ra_status, 440 SaveFPRegsMode save_fp, 441 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 442 SmiCheck smi_check = INLINE_SMI_CHECK, 443 PointersToHereCheck pointers_to_here_check_for_value = 444 kPointersToHereMaybeInteresting) { 445 RecordWriteField(context, 446 offset + kHeapObjectTag, 447 value, 448 scratch, 449 ra_status, 450 save_fp, 451 remembered_set_action, 452 smi_check, 453 pointers_to_here_check_for_value); 454 } 455 456 // Notify the garbage collector that we wrote a code entry into a 457 // JSFunction. Only scratch is clobbered by the operation. 458 void RecordWriteCodeEntryField(Register js_function, Register code_entry, 459 Register scratch); 460 461 void RecordWriteForMap( 462 Register object, 463 Register map, 464 Register dst, 465 RAStatus ra_status, 466 SaveFPRegsMode save_fp); 467 468 // For a given |object| notify the garbage collector that the slot |address| 469 // has been written. |value| is the object being stored. The value and 470 // address registers are clobbered by the operation. 471 void RecordWrite( 472 Register object, 473 Register address, 474 Register value, 475 RAStatus ra_status, 476 SaveFPRegsMode save_fp, 477 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, 478 SmiCheck smi_check = INLINE_SMI_CHECK, 479 PointersToHereCheck pointers_to_here_check_for_value = 480 kPointersToHereMaybeInteresting); 481 482 483 // --------------------------------------------------------------------------- 484 // Inline caching support. 485 486 // Generate code for checking access rights - used for security checks 487 // on access to global objects across environments. The holder register 488 // is left untouched, whereas both scratch registers are clobbered. 489 void CheckAccessGlobalProxy(Register holder_reg, 490 Register scratch, 491 Label* miss); 492 493 void GetNumberHash(Register reg0, Register scratch); 494 495 void LoadFromNumberDictionary(Label* miss, 496 Register elements, 497 Register key, 498 Register result, 499 Register reg0, 500 Register reg1, 501 Register reg2); 502 503 504 inline void MarkCode(NopMarkerTypes type) { 505 nop(type); 506 } 507 508 // Check if the given instruction is a 'type' marker. 509 // i.e. check if it is a sll zero_reg, zero_reg, <type> (referenced as 510 // nop(type)). These instructions are generated to mark special location in 511 // the code, like some special IC code. 512 static inline bool IsMarkedCode(Instr instr, int type) { 513 DCHECK((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)); 514 return IsNop(instr, type); 515 } 516 517 518 static inline int GetCodeMarker(Instr instr) { 519 uint32_t opcode = ((instr & kOpcodeMask)); 520 uint32_t rt = ((instr & kRtFieldMask) >> kRtShift); 521 uint32_t rs = ((instr & kRsFieldMask) >> kRsShift); 522 uint32_t sa = ((instr & kSaFieldMask) >> kSaShift); 523 524 // Return <n> if we have a sll zero_reg, zero_reg, n 525 // else return -1. 526 bool sllzz = (opcode == SLL && 527 rt == static_cast<uint32_t>(ToNumber(zero_reg)) && 528 rs == static_cast<uint32_t>(ToNumber(zero_reg))); 529 int type = 530 (sllzz && FIRST_IC_MARKER <= sa && sa < LAST_CODE_MARKER) ? sa : -1; 531 DCHECK((type == -1) || 532 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER))); 533 return type; 534 } 535 536 537 538 // --------------------------------------------------------------------------- 539 // Allocation support. 540 541 // Allocate an object in new space or old space. The object_size is 542 // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS 543 // is passed. If the space is exhausted control continues at the gc_required 544 // label. The allocated object is returned in result. If the flag 545 // tag_allocated_object is true the result is tagged as as a heap object. 546 // All registers are clobbered also when control continues at the gc_required 547 // label. 548 void Allocate(int object_size, 549 Register result, 550 Register scratch1, 551 Register scratch2, 552 Label* gc_required, 553 AllocationFlags flags); 554 555 void Allocate(Register object_size, Register result, Register result_new, 556 Register scratch, Label* gc_required, AllocationFlags flags); 557 558 // FastAllocate is right now only used for folded allocations. It just 559 // increments the top pointer without checking against limit. This can only 560 // be done if it was proved earlier that the allocation will succeed. 561 void FastAllocate(int object_size, Register result, Register scratch1, 562 Register scratch2, AllocationFlags flags); 563 564 void FastAllocate(Register object_size, Register result, Register result_new, 565 Register scratch, AllocationFlags flags); 566 567 void AllocateTwoByteString(Register result, 568 Register length, 569 Register scratch1, 570 Register scratch2, 571 Register scratch3, 572 Label* gc_required); 573 void AllocateOneByteString(Register result, Register length, 574 Register scratch1, Register scratch2, 575 Register scratch3, Label* gc_required); 576 void AllocateTwoByteConsString(Register result, 577 Register length, 578 Register scratch1, 579 Register scratch2, 580 Label* gc_required); 581 void AllocateOneByteConsString(Register result, Register length, 582 Register scratch1, Register scratch2, 583 Label* gc_required); 584 void AllocateTwoByteSlicedString(Register result, 585 Register length, 586 Register scratch1, 587 Register scratch2, 588 Label* gc_required); 589 void AllocateOneByteSlicedString(Register result, Register length, 590 Register scratch1, Register scratch2, 591 Label* gc_required); 592 593 // Allocates a heap number or jumps to the gc_required label if the young 594 // space is full and a scavenge is needed. All registers are clobbered also 595 // when control continues at the gc_required label. 596 void AllocateHeapNumber(Register result, 597 Register scratch1, 598 Register scratch2, 599 Register heap_number_map, 600 Label* gc_required, 601 MutableMode mode = IMMUTABLE); 602 void AllocateHeapNumberWithValue(Register result, 603 FPURegister value, 604 Register scratch1, 605 Register scratch2, 606 Label* gc_required); 607 608 // Allocate and initialize a JSValue wrapper with the specified {constructor} 609 // and {value}. 610 void AllocateJSValue(Register result, Register constructor, Register value, 611 Register scratch1, Register scratch2, 612 Label* gc_required); 613 614 // --------------------------------------------------------------------------- 615 // Instruction macros. 616 617#define DEFINE_INSTRUCTION(instr) \ 618 void instr(Register rd, Register rs, const Operand& rt); \ 619 void instr(Register rd, Register rs, Register rt) { \ 620 instr(rd, rs, Operand(rt)); \ 621 } \ 622 void instr(Register rs, Register rt, int32_t j) { \ 623 instr(rs, rt, Operand(j)); \ 624 } 625 626#define DEFINE_INSTRUCTION2(instr) \ 627 void instr(Register rs, const Operand& rt); \ 628 void instr(Register rs, Register rt) { \ 629 instr(rs, Operand(rt)); \ 630 } \ 631 void instr(Register rs, int32_t j) { \ 632 instr(rs, Operand(j)); \ 633 } 634 635#define DEFINE_INSTRUCTION3(instr) \ 636 void instr(Register rd_hi, Register rd_lo, Register rs, const Operand& rt); \ 637 void instr(Register rd_hi, Register rd_lo, Register rs, Register rt) { \ 638 instr(rd_hi, rd_lo, rs, Operand(rt)); \ 639 } \ 640 void instr(Register rd_hi, Register rd_lo, Register rs, int32_t j) { \ 641 instr(rd_hi, rd_lo, rs, Operand(j)); \ 642 } 643 644 DEFINE_INSTRUCTION(Addu); 645 DEFINE_INSTRUCTION(Subu); 646 DEFINE_INSTRUCTION(Mul); 647 DEFINE_INSTRUCTION(Div); 648 DEFINE_INSTRUCTION(Divu); 649 DEFINE_INSTRUCTION(Mod); 650 DEFINE_INSTRUCTION(Modu); 651 DEFINE_INSTRUCTION(Mulh); 652 DEFINE_INSTRUCTION2(Mult); 653 DEFINE_INSTRUCTION(Mulhu); 654 DEFINE_INSTRUCTION2(Multu); 655 DEFINE_INSTRUCTION2(Div); 656 DEFINE_INSTRUCTION2(Divu); 657 658 DEFINE_INSTRUCTION3(Div); 659 DEFINE_INSTRUCTION3(Mul); 660 DEFINE_INSTRUCTION3(Mulu); 661 662 DEFINE_INSTRUCTION(And); 663 DEFINE_INSTRUCTION(Or); 664 DEFINE_INSTRUCTION(Xor); 665 DEFINE_INSTRUCTION(Nor); 666 DEFINE_INSTRUCTION2(Neg); 667 668 DEFINE_INSTRUCTION(Slt); 669 DEFINE_INSTRUCTION(Sltu); 670 671 // MIPS32 R2 instruction macro. 672 DEFINE_INSTRUCTION(Ror); 673 674#undef DEFINE_INSTRUCTION 675#undef DEFINE_INSTRUCTION2 676#undef DEFINE_INSTRUCTION3 677 678 // Load Scaled Address instructions. Parameter sa (shift argument) must be 679 // between [1, 31] (inclusive). On pre-r6 architectures the scratch register 680 // may be clobbered. 681 void Lsa(Register rd, Register rs, Register rt, uint8_t sa, 682 Register scratch = at); 683 684 void Pref(int32_t hint, const MemOperand& rs); 685 686 687 // --------------------------------------------------------------------------- 688 // Pseudo-instructions. 689 690 // Change endianness 691 void ByteSwapSigned(Register reg, int operand_size); 692 void ByteSwapUnsigned(Register reg, int operand_size); 693 694 void mov(Register rd, Register rt) { or_(rd, rt, zero_reg); } 695 696 void Ulh(Register rd, const MemOperand& rs); 697 void Ulhu(Register rd, const MemOperand& rs); 698 void Ush(Register rd, const MemOperand& rs, Register scratch); 699 700 void Ulw(Register rd, const MemOperand& rs); 701 void Usw(Register rd, const MemOperand& rs); 702 703 void Ulwc1(FPURegister fd, const MemOperand& rs, Register scratch); 704 void Uswc1(FPURegister fd, const MemOperand& rs, Register scratch); 705 706 void Uldc1(FPURegister fd, const MemOperand& rs, Register scratch); 707 void Usdc1(FPURegister fd, const MemOperand& rs, Register scratch); 708 709 // Load int32 in the rd register. 710 void li(Register rd, Operand j, LiFlags mode = OPTIMIZE_SIZE); 711 inline void li(Register rd, int32_t j, LiFlags mode = OPTIMIZE_SIZE) { 712 li(rd, Operand(j), mode); 713 } 714 void li(Register dst, Handle<Object> value, LiFlags mode = OPTIMIZE_SIZE); 715 716 // Push multiple registers on the stack. 717 // Registers are saved in numerical order, with higher numbered registers 718 // saved in higher memory addresses. 719 void MultiPush(RegList regs); 720 void MultiPushReversed(RegList regs); 721 722 void MultiPushFPU(RegList regs); 723 void MultiPushReversedFPU(RegList regs); 724 725 void push(Register src) { 726 Addu(sp, sp, Operand(-kPointerSize)); 727 sw(src, MemOperand(sp, 0)); 728 } 729 void Push(Register src) { push(src); } 730 731 // Push a handle. 732 void Push(Handle<Object> handle); 733 void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); } 734 735 // Push two registers. Pushes leftmost register first (to highest address). 736 void Push(Register src1, Register src2) { 737 Subu(sp, sp, Operand(2 * kPointerSize)); 738 sw(src1, MemOperand(sp, 1 * kPointerSize)); 739 sw(src2, MemOperand(sp, 0 * kPointerSize)); 740 } 741 742 // Push three registers. Pushes leftmost register first (to highest address). 743 void Push(Register src1, Register src2, Register src3) { 744 Subu(sp, sp, Operand(3 * kPointerSize)); 745 sw(src1, MemOperand(sp, 2 * kPointerSize)); 746 sw(src2, MemOperand(sp, 1 * kPointerSize)); 747 sw(src3, MemOperand(sp, 0 * kPointerSize)); 748 } 749 750 // Push four registers. Pushes leftmost register first (to highest address). 751 void Push(Register src1, Register src2, Register src3, Register src4) { 752 Subu(sp, sp, Operand(4 * kPointerSize)); 753 sw(src1, MemOperand(sp, 3 * kPointerSize)); 754 sw(src2, MemOperand(sp, 2 * kPointerSize)); 755 sw(src3, MemOperand(sp, 1 * kPointerSize)); 756 sw(src4, MemOperand(sp, 0 * kPointerSize)); 757 } 758 759 // Push five registers. Pushes leftmost register first (to highest address). 760 void Push(Register src1, Register src2, Register src3, Register src4, 761 Register src5) { 762 Subu(sp, sp, Operand(5 * kPointerSize)); 763 sw(src1, MemOperand(sp, 4 * kPointerSize)); 764 sw(src2, MemOperand(sp, 3 * kPointerSize)); 765 sw(src3, MemOperand(sp, 2 * kPointerSize)); 766 sw(src4, MemOperand(sp, 1 * kPointerSize)); 767 sw(src5, MemOperand(sp, 0 * kPointerSize)); 768 } 769 770 void Push(Register src, Condition cond, Register tst1, Register tst2) { 771 // Since we don't have conditional execution we use a Branch. 772 Branch(3, cond, tst1, Operand(tst2)); 773 Subu(sp, sp, Operand(kPointerSize)); 774 sw(src, MemOperand(sp, 0)); 775 } 776 777 // Pops multiple values from the stack and load them in the 778 // registers specified in regs. Pop order is the opposite as in MultiPush. 779 void MultiPop(RegList regs); 780 void MultiPopReversed(RegList regs); 781 782 void MultiPopFPU(RegList regs); 783 void MultiPopReversedFPU(RegList regs); 784 785 void pop(Register dst) { 786 lw(dst, MemOperand(sp, 0)); 787 Addu(sp, sp, Operand(kPointerSize)); 788 } 789 void Pop(Register dst) { pop(dst); } 790 791 // Pop two registers. Pops rightmost register first (from lower address). 792 void Pop(Register src1, Register src2) { 793 DCHECK(!src1.is(src2)); 794 lw(src2, MemOperand(sp, 0 * kPointerSize)); 795 lw(src1, MemOperand(sp, 1 * kPointerSize)); 796 Addu(sp, sp, 2 * kPointerSize); 797 } 798 799 // Pop three registers. Pops rightmost register first (from lower address). 800 void Pop(Register src1, Register src2, Register src3) { 801 lw(src3, MemOperand(sp, 0 * kPointerSize)); 802 lw(src2, MemOperand(sp, 1 * kPointerSize)); 803 lw(src1, MemOperand(sp, 2 * kPointerSize)); 804 Addu(sp, sp, 3 * kPointerSize); 805 } 806 807 void Pop(uint32_t count = 1) { 808 Addu(sp, sp, Operand(count * kPointerSize)); 809 } 810 811 // Push a fixed frame, consisting of ra, fp. 812 void PushCommonFrame(Register marker_reg = no_reg); 813 814 // Push a standard frame, consisting of ra, fp, context and JS function. 815 void PushStandardFrame(Register function_reg); 816 817 void PopCommonFrame(Register marker_reg = no_reg); 818 819 // Push and pop the registers that can hold pointers, as defined by the 820 // RegList constant kSafepointSavedRegisters. 821 void PushSafepointRegisters(); 822 void PopSafepointRegisters(); 823 // Store value in register src in the safepoint stack slot for 824 // register dst. 825 void StoreToSafepointRegisterSlot(Register src, Register dst); 826 // Load the value of the src register from its safepoint stack slot 827 // into register dst. 828 void LoadFromSafepointRegisterSlot(Register dst, Register src); 829 830 // MIPS32 R2 instruction macro. 831 void Ins(Register rt, Register rs, uint16_t pos, uint16_t size); 832 void Ext(Register rt, Register rs, uint16_t pos, uint16_t size); 833 834 // Int64Lowering instructions 835 void AddPair(Register dst_low, Register dst_high, Register left_low, 836 Register left_high, Register right_low, Register right_high); 837 838 void SubPair(Register dst_low, Register dst_high, Register left_low, 839 Register left_high, Register right_low, Register right_high); 840 841 void ShlPair(Register dst_low, Register dst_high, Register src_low, 842 Register src_high, Register shift); 843 844 void ShlPair(Register dst_low, Register dst_high, Register src_low, 845 Register src_high, uint32_t shift); 846 847 void ShrPair(Register dst_low, Register dst_high, Register src_low, 848 Register src_high, Register shift); 849 850 void ShrPair(Register dst_low, Register dst_high, Register src_low, 851 Register src_high, uint32_t shift); 852 853 void SarPair(Register dst_low, Register dst_high, Register src_low, 854 Register src_high, Register shift); 855 856 void SarPair(Register dst_low, Register dst_high, Register src_low, 857 Register src_high, uint32_t shift); 858 859 // --------------------------------------------------------------------------- 860 // FPU macros. These do not handle special cases like NaN or +- inf. 861 862 // Convert unsigned word to double. 863 void Cvt_d_uw(FPURegister fd, Register rs, FPURegister scratch); 864 865 // Convert single to unsigned word. 866 void Trunc_uw_s(FPURegister fd, FPURegister fs, FPURegister scratch); 867 void Trunc_uw_s(FPURegister fd, Register rs, FPURegister scratch); 868 869 // Convert double to unsigned word. 870 void Trunc_uw_d(FPURegister fd, FPURegister fs, FPURegister scratch); 871 void Trunc_uw_d(FPURegister fd, Register rs, FPURegister scratch); 872 873 void Trunc_w_d(FPURegister fd, FPURegister fs); 874 void Round_w_d(FPURegister fd, FPURegister fs); 875 void Floor_w_d(FPURegister fd, FPURegister fs); 876 void Ceil_w_d(FPURegister fd, FPURegister fs); 877 878 // Preserve value of a NaN operand 879 void SubNanPreservePayloadAndSign_s(FPURegister fd, FPURegister fs, 880 FPURegister ft); 881 void SubNanPreservePayloadAndSign_d(FPURegister fd, FPURegister fs, 882 FPURegister ft); 883 884 // FP32 mode: Move the general purpose register into 885 // the high part of the double-register pair. 886 // FP64 mode: Move the general-purpose register into 887 // the higher 32 bits of the 64-bit coprocessor register, 888 // while leaving the low bits unchanged. 889 void Mthc1(Register rt, FPURegister fs); 890 891 // FP32 mode: move the high part of the double-register pair into 892 // general purpose register. 893 // FP64 mode: Move the higher 32 bits of the 64-bit coprocessor register into 894 // general-purpose register. 895 void Mfhc1(Register rt, FPURegister fs); 896 897 // Wrapper functions for the different cmp/branch types. 898 inline void BranchF32(Label* target, Label* nan, Condition cc, 899 FPURegister cmp1, FPURegister cmp2, 900 BranchDelaySlot bd = PROTECT) { 901 BranchFCommon(S, target, nan, cc, cmp1, cmp2, bd); 902 } 903 904 inline void BranchF64(Label* target, Label* nan, Condition cc, 905 FPURegister cmp1, FPURegister cmp2, 906 BranchDelaySlot bd = PROTECT) { 907 BranchFCommon(D, target, nan, cc, cmp1, cmp2, bd); 908 } 909 910 // Alternate (inline) version for better readability with USE_DELAY_SLOT. 911 inline void BranchF64(BranchDelaySlot bd, Label* target, Label* nan, 912 Condition cc, FPURegister cmp1, FPURegister cmp2) { 913 BranchF64(target, nan, cc, cmp1, cmp2, bd); 914 } 915 916 inline void BranchF32(BranchDelaySlot bd, Label* target, Label* nan, 917 Condition cc, FPURegister cmp1, FPURegister cmp2) { 918 BranchF32(target, nan, cc, cmp1, cmp2, bd); 919 } 920 921 // Alias functions for backward compatibility. 922 inline void BranchF(Label* target, Label* nan, Condition cc, FPURegister cmp1, 923 FPURegister cmp2, BranchDelaySlot bd = PROTECT) { 924 BranchF64(target, nan, cc, cmp1, cmp2, bd); 925 } 926 927 inline void BranchF(BranchDelaySlot bd, Label* target, Label* nan, 928 Condition cc, FPURegister cmp1, FPURegister cmp2) { 929 BranchF64(bd, target, nan, cc, cmp1, cmp2); 930 } 931 932 // Truncates a double using a specific rounding mode, and writes the value 933 // to the result register. 934 // The except_flag will contain any exceptions caused by the instruction. 935 // If check_inexact is kDontCheckForInexactConversion, then the inexact 936 // exception is masked. 937 void EmitFPUTruncate(FPURoundingMode rounding_mode, 938 Register result, 939 DoubleRegister double_input, 940 Register scratch, 941 DoubleRegister double_scratch, 942 Register except_flag, 943 CheckForInexactConversion check_inexact 944 = kDontCheckForInexactConversion); 945 946 // Performs a truncating conversion of a floating point number as used by 947 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it 948 // succeeds, otherwise falls through if result is saturated. On return 949 // 'result' either holds answer, or is clobbered on fall through. 950 // 951 // Only public for the test code in test-code-stubs-arm.cc. 952 void TryInlineTruncateDoubleToI(Register result, 953 DoubleRegister input, 954 Label* done); 955 956 // Performs a truncating conversion of a floating point number as used by 957 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 958 // Exits with 'result' holding the answer. 959 void TruncateDoubleToI(Register result, DoubleRegister double_input); 960 961 // Performs a truncating conversion of a heap number as used by 962 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input' 963 // must be different registers. Exits with 'result' holding the answer. 964 void TruncateHeapNumberToI(Register result, Register object); 965 966 // Converts the smi or heap number in object to an int32 using the rules 967 // for ToInt32 as described in ECMAScript 9.5.: the value is truncated 968 // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be 969 // different registers. 970 void TruncateNumberToI(Register object, 971 Register result, 972 Register heap_number_map, 973 Register scratch, 974 Label* not_int32); 975 976 // Loads the number from object into dst register. 977 // If |object| is neither smi nor heap number, |not_number| is jumped to 978 // with |object| still intact. 979 void LoadNumber(Register object, 980 FPURegister dst, 981 Register heap_number_map, 982 Register scratch, 983 Label* not_number); 984 985 // Loads the number from object into double_dst in the double format. 986 // Control will jump to not_int32 if the value cannot be exactly represented 987 // by a 32-bit integer. 988 // Floating point value in the 32-bit integer range that are not exact integer 989 // won't be loaded. 990 void LoadNumberAsInt32Double(Register object, 991 DoubleRegister double_dst, 992 Register heap_number_map, 993 Register scratch1, 994 Register scratch2, 995 FPURegister double_scratch, 996 Label* not_int32); 997 998 // Loads the number from object into dst as a 32-bit integer. 999 // Control will jump to not_int32 if the object cannot be exactly represented 1000 // by a 32-bit integer. 1001 // Floating point value in the 32-bit integer range that are not exact integer 1002 // won't be converted. 1003 void LoadNumberAsInt32(Register object, 1004 Register dst, 1005 Register heap_number_map, 1006 Register scratch1, 1007 Register scratch2, 1008 FPURegister double_scratch0, 1009 FPURegister double_scratch1, 1010 Label* not_int32); 1011 1012 // Enter exit frame. 1013 // argc - argument count to be dropped by LeaveExitFrame. 1014 // save_doubles - saves FPU registers on stack, currently disabled. 1015 // stack_space - extra stack space. 1016 void EnterExitFrame(bool save_doubles, 1017 int stack_space = 0); 1018 1019 // Leave the current exit frame. 1020 void LeaveExitFrame(bool save_doubles, Register arg_count, 1021 bool restore_context, bool do_return = NO_EMIT_RETURN, 1022 bool argument_count_is_length = false); 1023 1024 // Get the actual activation frame alignment for target environment. 1025 static int ActivationFrameAlignment(); 1026 1027 // Make sure the stack is aligned. Only emits code in debug mode. 1028 void AssertStackIsAligned(); 1029 1030 void LoadContext(Register dst, int context_chain_length); 1031 1032 // Load the global object from the current context. 1033 void LoadGlobalObject(Register dst) { 1034 LoadNativeContextSlot(Context::EXTENSION_INDEX, dst); 1035 } 1036 1037 // Load the global proxy from the current context. 1038 void LoadGlobalProxy(Register dst) { 1039 LoadNativeContextSlot(Context::GLOBAL_PROXY_INDEX, dst); 1040 } 1041 1042 // Conditionally load the cached Array transitioned map of type 1043 // transitioned_kind from the native context if the map in register 1044 // map_in_out is the cached Array map in the native context of 1045 // expected_kind. 1046 void LoadTransitionedArrayMapConditional( 1047 ElementsKind expected_kind, 1048 ElementsKind transitioned_kind, 1049 Register map_in_out, 1050 Register scratch, 1051 Label* no_map_match); 1052 1053 void LoadNativeContextSlot(int index, Register dst); 1054 1055 // Load the initial map from the global function. The registers 1056 // function and map can be the same, function is then overwritten. 1057 void LoadGlobalFunctionInitialMap(Register function, 1058 Register map, 1059 Register scratch); 1060 1061 void InitializeRootRegister() { 1062 ExternalReference roots_array_start = 1063 ExternalReference::roots_array_start(isolate()); 1064 li(kRootRegister, Operand(roots_array_start)); 1065 } 1066 1067 // ------------------------------------------------------------------------- 1068 // JavaScript invokes. 1069 1070 // Removes current frame and its arguments from the stack preserving 1071 // the arguments and a return address pushed to the stack for the next call. 1072 // Both |callee_args_count| and |caller_args_count_reg| do not include 1073 // receiver. |callee_args_count| is not modified, |caller_args_count_reg| 1074 // is trashed. 1075 void PrepareForTailCall(const ParameterCount& callee_args_count, 1076 Register caller_args_count_reg, Register scratch0, 1077 Register scratch1); 1078 1079 // Invoke the JavaScript function code by either calling or jumping. 1080 void InvokeFunctionCode(Register function, Register new_target, 1081 const ParameterCount& expected, 1082 const ParameterCount& actual, InvokeFlag flag, 1083 const CallWrapper& call_wrapper); 1084 1085 void FloodFunctionIfStepping(Register fun, Register new_target, 1086 const ParameterCount& expected, 1087 const ParameterCount& actual); 1088 1089 // Invoke the JavaScript function in the given register. Changes the 1090 // current context to the context in the function before invoking. 1091 void InvokeFunction(Register function, 1092 Register new_target, 1093 const ParameterCount& actual, 1094 InvokeFlag flag, 1095 const CallWrapper& call_wrapper); 1096 1097 void InvokeFunction(Register function, 1098 const ParameterCount& expected, 1099 const ParameterCount& actual, 1100 InvokeFlag flag, 1101 const CallWrapper& call_wrapper); 1102 1103 void InvokeFunction(Handle<JSFunction> function, 1104 const ParameterCount& expected, 1105 const ParameterCount& actual, 1106 InvokeFlag flag, 1107 const CallWrapper& call_wrapper); 1108 1109 void IsObjectJSStringType(Register object, 1110 Register scratch, 1111 Label* fail); 1112 1113 void IsObjectNameType(Register object, 1114 Register scratch, 1115 Label* fail); 1116 1117 // ------------------------------------------------------------------------- 1118 // Debugger Support. 1119 1120 void DebugBreak(); 1121 1122 // ------------------------------------------------------------------------- 1123 // Exception handling. 1124 1125 // Push a new stack handler and link into stack handler chain. 1126 void PushStackHandler(); 1127 1128 // Unlink the stack handler on top of the stack from the stack handler chain. 1129 // Must preserve the result register. 1130 void PopStackHandler(); 1131 1132 // Copies a number of bytes from src to dst. All registers are clobbered. On 1133 // exit src and dst will point to the place just after where the last byte was 1134 // read or written and length will be zero. 1135 void CopyBytes(Register src, 1136 Register dst, 1137 Register length, 1138 Register scratch); 1139 1140 // Initialize fields with filler values. Fields starting at |current_address| 1141 // not including |end_address| are overwritten with the value in |filler|. At 1142 // the end the loop, |current_address| takes the value of |end_address|. 1143 void InitializeFieldsWithFiller(Register current_address, 1144 Register end_address, Register filler); 1145 1146 // ------------------------------------------------------------------------- 1147 // Support functions. 1148 1149 // Machine code version of Map::GetConstructor(). 1150 // |temp| holds |result|'s map when done, and |temp2| its instance type. 1151 void GetMapConstructor(Register result, Register map, Register temp, 1152 Register temp2); 1153 1154 // Try to get function prototype of a function and puts the value in 1155 // the result register. Checks that the function really is a 1156 // function and jumps to the miss label if the fast checks fail. The 1157 // function register will be untouched; the other registers may be 1158 // clobbered. 1159 void TryGetFunctionPrototype(Register function, Register result, 1160 Register scratch, Label* miss); 1161 1162 void GetObjectType(Register function, 1163 Register map, 1164 Register type_reg); 1165 1166 void GetInstanceType(Register object_map, Register object_instance_type) { 1167 lbu(object_instance_type, 1168 FieldMemOperand(object_map, Map::kInstanceTypeOffset)); 1169 } 1170 1171 // Check if a map for a JSObject indicates that the object has fast elements. 1172 // Jump to the specified label if it does not. 1173 void CheckFastElements(Register map, 1174 Register scratch, 1175 Label* fail); 1176 1177 // Check if a map for a JSObject indicates that the object can have both smi 1178 // and HeapObject elements. Jump to the specified label if it does not. 1179 void CheckFastObjectElements(Register map, 1180 Register scratch, 1181 Label* fail); 1182 1183 // Check if a map for a JSObject indicates that the object has fast smi only 1184 // elements. Jump to the specified label if it does not. 1185 void CheckFastSmiElements(Register map, 1186 Register scratch, 1187 Label* fail); 1188 1189 // Check to see if maybe_number can be stored as a double in 1190 // FastDoubleElements. If it can, store it at the index specified by key in 1191 // the FastDoubleElements array elements. Otherwise jump to fail. 1192 void StoreNumberToDoubleElements(Register value_reg, 1193 Register key_reg, 1194 Register elements_reg, 1195 Register scratch1, 1196 Register scratch2, 1197 Register scratch3, 1198 Label* fail, 1199 int elements_offset = 0); 1200 1201 // Compare an object's map with the specified map and its transitioned 1202 // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Jumps to 1203 // "branch_to" if the result of the comparison is "cond". If multiple map 1204 // compares are required, the compare sequences branches to early_success. 1205 void CompareMapAndBranch(Register obj, 1206 Register scratch, 1207 Handle<Map> map, 1208 Label* early_success, 1209 Condition cond, 1210 Label* branch_to); 1211 1212 // As above, but the map of the object is already loaded into the register 1213 // which is preserved by the code generated. 1214 void CompareMapAndBranch(Register obj_map, 1215 Handle<Map> map, 1216 Label* early_success, 1217 Condition cond, 1218 Label* branch_to); 1219 1220 // Check if the map of an object is equal to a specified map and branch to 1221 // label if not. Skip the smi check if not required (object is known to be a 1222 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match 1223 // against maps that are ElementsKind transition maps of the specificed map. 1224 void CheckMap(Register obj, 1225 Register scratch, 1226 Handle<Map> map, 1227 Label* fail, 1228 SmiCheckType smi_check_type); 1229 1230 1231 void CheckMap(Register obj, 1232 Register scratch, 1233 Heap::RootListIndex index, 1234 Label* fail, 1235 SmiCheckType smi_check_type); 1236 1237 // Check if the map of an object is equal to a specified weak map and branch 1238 // to a specified target if equal. Skip the smi check if not required 1239 // (object is known to be a heap object) 1240 void DispatchWeakMap(Register obj, Register scratch1, Register scratch2, 1241 Handle<WeakCell> cell, Handle<Code> success, 1242 SmiCheckType smi_check_type); 1243 1244 // If the value is a NaN, canonicalize the value else, do nothing. 1245 void FPUCanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src); 1246 1247 // Get value of the weak cell. 1248 void GetWeakValue(Register value, Handle<WeakCell> cell); 1249 1250 // Load the value of the weak cell in the value register. Branch to the 1251 // given miss label is the weak cell was cleared. 1252 void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss); 1253 1254 // Load and check the instance type of an object for being a string. 1255 // Loads the type into the second argument register. 1256 // Returns a condition that will be enabled if the object was a string. 1257 Condition IsObjectStringType(Register obj, 1258 Register type, 1259 Register result) { 1260 lw(type, FieldMemOperand(obj, HeapObject::kMapOffset)); 1261 lbu(type, FieldMemOperand(type, Map::kInstanceTypeOffset)); 1262 And(type, type, Operand(kIsNotStringMask)); 1263 DCHECK_EQ(0u, kStringTag); 1264 return eq; 1265 } 1266 1267 1268 // Picks out an array index from the hash field. 1269 // Register use: 1270 // hash - holds the index's hash. Clobbered. 1271 // index - holds the overwritten index on exit. 1272 void IndexFromHash(Register hash, Register index); 1273 1274 // Get the number of least significant bits from a register. 1275 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits); 1276 void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits); 1277 1278 // Load the value of a number object into a FPU double register. If the 1279 // object is not a number a jump to the label not_number is performed 1280 // and the FPU double register is unchanged. 1281 void ObjectToDoubleFPURegister( 1282 Register object, 1283 FPURegister value, 1284 Register scratch1, 1285 Register scratch2, 1286 Register heap_number_map, 1287 Label* not_number, 1288 ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS); 1289 1290 // Load the value of a smi object into a FPU double register. The register 1291 // scratch1 can be the same register as smi in which case smi will hold the 1292 // untagged value afterwards. 1293 void SmiToDoubleFPURegister(Register smi, 1294 FPURegister value, 1295 Register scratch1); 1296 1297 // ------------------------------------------------------------------------- 1298 // Overflow handling functions. 1299 // Usage: first call the appropriate arithmetic function, then call one of the 1300 // jump functions with the overflow_dst register as the second parameter. 1301 1302 inline void AddBranchOvf(Register dst, Register left, const Operand& right, 1303 Label* overflow_label, Register scratch = at) { 1304 AddBranchOvf(dst, left, right, overflow_label, nullptr, scratch); 1305 } 1306 1307 inline void AddBranchNoOvf(Register dst, Register left, const Operand& right, 1308 Label* no_overflow_label, Register scratch = at) { 1309 AddBranchOvf(dst, left, right, nullptr, no_overflow_label, scratch); 1310 } 1311 1312 void AddBranchOvf(Register dst, Register left, const Operand& right, 1313 Label* overflow_label, Label* no_overflow_label, 1314 Register scratch = at); 1315 1316 void AddBranchOvf(Register dst, Register left, Register right, 1317 Label* overflow_label, Label* no_overflow_label, 1318 Register scratch = at); 1319 1320 1321 inline void SubBranchOvf(Register dst, Register left, const Operand& right, 1322 Label* overflow_label, Register scratch = at) { 1323 SubBranchOvf(dst, left, right, overflow_label, nullptr, scratch); 1324 } 1325 1326 inline void SubBranchNoOvf(Register dst, Register left, const Operand& right, 1327 Label* no_overflow_label, Register scratch = at) { 1328 SubBranchOvf(dst, left, right, nullptr, no_overflow_label, scratch); 1329 } 1330 1331 void SubBranchOvf(Register dst, Register left, const Operand& right, 1332 Label* overflow_label, Label* no_overflow_label, 1333 Register scratch = at); 1334 1335 void SubBranchOvf(Register dst, Register left, Register right, 1336 Label* overflow_label, Label* no_overflow_label, 1337 Register scratch = at); 1338 1339 // ------------------------------------------------------------------------- 1340 // Runtime calls. 1341 1342 // See comments at the beginning of CEntryStub::Generate. 1343 inline void PrepareCEntryArgs(int num_args) { li(a0, num_args); } 1344 1345 inline void PrepareCEntryFunction(const ExternalReference& ref) { 1346 li(a1, Operand(ref)); 1347 } 1348 1349#define COND_ARGS Condition cond = al, Register rs = zero_reg, \ 1350const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT 1351 1352 // Call a code stub. 1353 void CallStub(CodeStub* stub, 1354 TypeFeedbackId ast_id = TypeFeedbackId::None(), 1355 COND_ARGS); 1356 1357 // Tail call a code stub (jump). 1358 void TailCallStub(CodeStub* stub, COND_ARGS); 1359 1360#undef COND_ARGS 1361 1362 void CallJSExitStub(CodeStub* stub); 1363 1364 // Call a runtime routine. 1365 void CallRuntime(const Runtime::Function* f, int num_arguments, 1366 SaveFPRegsMode save_doubles = kDontSaveFPRegs, 1367 BranchDelaySlot bd = PROTECT); 1368 void CallRuntimeSaveDoubles(Runtime::FunctionId id) { 1369 const Runtime::Function* function = Runtime::FunctionForId(id); 1370 CallRuntime(function, function->nargs, kSaveFPRegs); 1371 } 1372 1373 // Convenience function: Same as above, but takes the fid instead. 1374 void CallRuntime(Runtime::FunctionId fid, 1375 SaveFPRegsMode save_doubles = kDontSaveFPRegs, 1376 BranchDelaySlot bd = PROTECT) { 1377 const Runtime::Function* function = Runtime::FunctionForId(fid); 1378 CallRuntime(function, function->nargs, save_doubles, bd); 1379 } 1380 1381 // Convenience function: Same as above, but takes the fid instead. 1382 void CallRuntime(Runtime::FunctionId id, int num_arguments, 1383 SaveFPRegsMode save_doubles = kDontSaveFPRegs, 1384 BranchDelaySlot bd = PROTECT) { 1385 CallRuntime(Runtime::FunctionForId(id), num_arguments, save_doubles, bd); 1386 } 1387 1388 // Convenience function: call an external reference. 1389 void CallExternalReference(const ExternalReference& ext, 1390 int num_arguments, 1391 BranchDelaySlot bd = PROTECT); 1392 1393 1394 // Convenience function: tail call a runtime routine (jump). 1395 void TailCallRuntime(Runtime::FunctionId fid); 1396 1397 int CalculateStackPassedWords(int num_reg_arguments, 1398 int num_double_arguments); 1399 1400 // Before calling a C-function from generated code, align arguments on stack 1401 // and add space for the four mips argument slots. 1402 // After aligning the frame, non-register arguments must be stored on the 1403 // stack, after the argument-slots using helper: CFunctionArgumentOperand(). 1404 // The argument count assumes all arguments are word sized. 1405 // Some compilers/platforms require the stack to be aligned when calling 1406 // C++ code. 1407 // Needs a scratch register to do some arithmetic. This register will be 1408 // trashed. 1409 void PrepareCallCFunction(int num_reg_arguments, 1410 int num_double_registers, 1411 Register scratch); 1412 void PrepareCallCFunction(int num_reg_arguments, 1413 Register scratch); 1414 1415 // Arguments 1-4 are placed in registers a0 thru a3 respectively. 1416 // Arguments 5..n are stored to stack using following: 1417 // sw(t0, CFunctionArgumentOperand(5)); 1418 1419 // Calls a C function and cleans up the space for arguments allocated 1420 // by PrepareCallCFunction. The called function is not allowed to trigger a 1421 // garbage collection, since that might move the code and invalidate the 1422 // return address (unless this is somehow accounted for by the called 1423 // function). 1424 void CallCFunction(ExternalReference function, int num_arguments); 1425 void CallCFunction(Register function, int num_arguments); 1426 void CallCFunction(ExternalReference function, 1427 int num_reg_arguments, 1428 int num_double_arguments); 1429 void CallCFunction(Register function, 1430 int num_reg_arguments, 1431 int num_double_arguments); 1432 void MovFromFloatResult(DoubleRegister dst); 1433 void MovFromFloatParameter(DoubleRegister dst); 1434 1435 // There are two ways of passing double arguments on MIPS, depending on 1436 // whether soft or hard floating point ABI is used. These functions 1437 // abstract parameter passing for the three different ways we call 1438 // C functions from generated code. 1439 void MovToFloatParameter(DoubleRegister src); 1440 void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2); 1441 void MovToFloatResult(DoubleRegister src); 1442 1443 // Jump to the builtin routine. 1444 void JumpToExternalReference(const ExternalReference& builtin, 1445 BranchDelaySlot bd = PROTECT); 1446 1447 struct Unresolved { 1448 int pc; 1449 uint32_t flags; // See Bootstrapper::FixupFlags decoders/encoders. 1450 const char* name; 1451 }; 1452 1453 Handle<Object> CodeObject() { 1454 DCHECK(!code_object_.is_null()); 1455 return code_object_; 1456 } 1457 1458 // Emit code for a truncating division by a constant. The dividend register is 1459 // unchanged and at gets clobbered. Dividend and result must be different. 1460 void TruncatingDiv(Register result, Register dividend, int32_t divisor); 1461 1462 // ------------------------------------------------------------------------- 1463 // StatsCounter support. 1464 1465 void SetCounter(StatsCounter* counter, int value, 1466 Register scratch1, Register scratch2); 1467 void IncrementCounter(StatsCounter* counter, int value, 1468 Register scratch1, Register scratch2); 1469 void DecrementCounter(StatsCounter* counter, int value, 1470 Register scratch1, Register scratch2); 1471 1472 1473 // ------------------------------------------------------------------------- 1474 // Debugging. 1475 1476 // Calls Abort(msg) if the condition cc is not satisfied. 1477 // Use --debug_code to enable. 1478 void Assert(Condition cc, BailoutReason reason, Register rs, Operand rt); 1479 void AssertFastElements(Register elements); 1480 1481 // Like Assert(), but always enabled. 1482 void Check(Condition cc, BailoutReason reason, Register rs, Operand rt); 1483 1484 // Print a message to stdout and abort execution. 1485 void Abort(BailoutReason msg); 1486 1487 // Verify restrictions about code generated in stubs. 1488 void set_generating_stub(bool value) { generating_stub_ = value; } 1489 bool generating_stub() { return generating_stub_; } 1490 void set_has_frame(bool value) { has_frame_ = value; } 1491 bool has_frame() { return has_frame_; } 1492 inline bool AllowThisStubCall(CodeStub* stub); 1493 1494 // --------------------------------------------------------------------------- 1495 // Number utilities. 1496 1497 // Check whether the value of reg is a power of two and not zero. If not 1498 // control continues at the label not_power_of_two. If reg is a power of two 1499 // the register scratch contains the value of (reg - 1) when control falls 1500 // through. 1501 void JumpIfNotPowerOfTwoOrZero(Register reg, 1502 Register scratch, 1503 Label* not_power_of_two_or_zero); 1504 1505 // ------------------------------------------------------------------------- 1506 // Smi utilities. 1507 1508 void SmiTag(Register reg) { 1509 Addu(reg, reg, reg); 1510 } 1511 1512 void SmiTag(Register dst, Register src) { Addu(dst, src, src); } 1513 1514 // Test for overflow < 0: use BranchOnOverflow() or BranchOnNoOverflow(). 1515 void SmiTagCheckOverflow(Register reg, Register overflow); 1516 void SmiTagCheckOverflow(Register dst, Register src, Register overflow); 1517 1518 void BranchOnOverflow(Label* label, Register overflow_check, 1519 BranchDelaySlot bd = PROTECT) { 1520 Branch(label, lt, overflow_check, Operand(zero_reg), bd); 1521 } 1522 1523 void BranchOnNoOverflow(Label* label, Register overflow_check, 1524 BranchDelaySlot bd = PROTECT) { 1525 Branch(label, ge, overflow_check, Operand(zero_reg), bd); 1526 } 1527 1528 1529 // Try to convert int32 to smi. If the value is to large, preserve 1530 // the original value and jump to not_a_smi. Destroys scratch and 1531 // sets flags. 1532 void TrySmiTag(Register reg, Register scratch, Label* not_a_smi) { 1533 TrySmiTag(reg, reg, scratch, not_a_smi); 1534 } 1535 void TrySmiTag(Register dst, 1536 Register src, 1537 Register scratch, 1538 Label* not_a_smi) { 1539 SmiTagCheckOverflow(at, src, scratch); 1540 BranchOnOverflow(not_a_smi, scratch); 1541 mov(dst, at); 1542 } 1543 1544 void SmiUntag(Register reg) { 1545 sra(reg, reg, kSmiTagSize); 1546 } 1547 1548 void SmiUntag(Register dst, Register src) { 1549 sra(dst, src, kSmiTagSize); 1550 } 1551 1552 // Test if the register contains a smi. 1553 inline void SmiTst(Register value, Register scratch) { 1554 And(scratch, value, Operand(kSmiTagMask)); 1555 } 1556 inline void NonNegativeSmiTst(Register value, Register scratch) { 1557 And(scratch, value, Operand(kSmiTagMask | kSmiSignMask)); 1558 } 1559 1560 // Untag the source value into destination and jump if source is a smi. 1561 // Souce and destination can be the same register. 1562 void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case); 1563 1564 // Untag the source value into destination and jump if source is not a smi. 1565 // Souce and destination can be the same register. 1566 void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case); 1567 1568 // Jump the register contains a smi. 1569 void JumpIfSmi(Register value, 1570 Label* smi_label, 1571 Register scratch = at, 1572 BranchDelaySlot bd = PROTECT); 1573 1574 // Jump if the register contains a non-smi. 1575 void JumpIfNotSmi(Register value, 1576 Label* not_smi_label, 1577 Register scratch = at, 1578 BranchDelaySlot bd = PROTECT); 1579 1580 // Jump if either of the registers contain a non-smi. 1581 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi); 1582 // Jump if either of the registers contain a smi. 1583 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi); 1584 1585 // Abort execution if argument is a number, enabled via --debug-code. 1586 void AssertNotNumber(Register object); 1587 1588 // Abort execution if argument is a smi, enabled via --debug-code. 1589 void AssertNotSmi(Register object); 1590 void AssertSmi(Register object); 1591 1592 // Abort execution if argument is not a string, enabled via --debug-code. 1593 void AssertString(Register object); 1594 1595 // Abort execution if argument is not a name, enabled via --debug-code. 1596 void AssertName(Register object); 1597 1598 // Abort execution if argument is not a JSFunction, enabled via --debug-code. 1599 void AssertFunction(Register object); 1600 1601 // Abort execution if argument is not a JSBoundFunction, 1602 // enabled via --debug-code. 1603 void AssertBoundFunction(Register object); 1604 1605 // Abort execution if argument is not a JSGeneratorObject, 1606 // enabled via --debug-code. 1607 void AssertGeneratorObject(Register object); 1608 1609 // Abort execution if argument is not a JSReceiver, enabled via --debug-code. 1610 void AssertReceiver(Register object); 1611 1612 // Abort execution if argument is not undefined or an AllocationSite, enabled 1613 // via --debug-code. 1614 void AssertUndefinedOrAllocationSite(Register object, Register scratch); 1615 1616 // Abort execution if reg is not the root value with the given index, 1617 // enabled via --debug-code. 1618 void AssertIsRoot(Register reg, Heap::RootListIndex index); 1619 1620 // --------------------------------------------------------------------------- 1621 // HeapNumber utilities. 1622 1623 void JumpIfNotHeapNumber(Register object, 1624 Register heap_number_map, 1625 Register scratch, 1626 Label* on_not_heap_number); 1627 1628 // ------------------------------------------------------------------------- 1629 // String utilities. 1630 1631 // Checks if both instance types are sequential ASCII strings and jumps to 1632 // label if either is not. 1633 void JumpIfBothInstanceTypesAreNotSequentialOneByte( 1634 Register first_object_instance_type, Register second_object_instance_type, 1635 Register scratch1, Register scratch2, Label* failure); 1636 1637 // Check if instance type is sequential one-byte string and jump to label if 1638 // it is not. 1639 void JumpIfInstanceTypeIsNotSequentialOneByte(Register type, Register scratch, 1640 Label* failure); 1641 1642 void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name); 1643 1644 void EmitSeqStringSetCharCheck(Register string, 1645 Register index, 1646 Register value, 1647 Register scratch, 1648 uint32_t encoding_mask); 1649 1650 // Checks if both objects are sequential one-byte strings and jumps to label 1651 // if either is not. Assumes that neither object is a smi. 1652 void JumpIfNonSmisNotBothSequentialOneByteStrings(Register first, 1653 Register second, 1654 Register scratch1, 1655 Register scratch2, 1656 Label* failure); 1657 1658 // Checks if both objects are sequential one-byte strings and jumps to label 1659 // if either is not. 1660 void JumpIfNotBothSequentialOneByteStrings(Register first, Register second, 1661 Register scratch1, 1662 Register scratch2, 1663 Label* not_flat_one_byte_strings); 1664 1665 void ClampUint8(Register output_reg, Register input_reg); 1666 1667 void ClampDoubleToUint8(Register result_reg, 1668 DoubleRegister input_reg, 1669 DoubleRegister temp_double_reg); 1670 1671 1672 void LoadInstanceDescriptors(Register map, Register descriptors); 1673 void EnumLength(Register dst, Register map); 1674 void NumberOfOwnDescriptors(Register dst, Register map); 1675 void LoadAccessor(Register dst, Register holder, int accessor_index, 1676 AccessorComponent accessor); 1677 1678 template<typename Field> 1679 void DecodeField(Register dst, Register src) { 1680 Ext(dst, src, Field::kShift, Field::kSize); 1681 } 1682 1683 template<typename Field> 1684 void DecodeField(Register reg) { 1685 DecodeField<Field>(reg, reg); 1686 } 1687 1688 template<typename Field> 1689 void DecodeFieldToSmi(Register dst, Register src) { 1690 static const int shift = Field::kShift; 1691 static const int mask = Field::kMask >> shift << kSmiTagSize; 1692 STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0); 1693 STATIC_ASSERT(kSmiTag == 0); 1694 if (shift < kSmiTagSize) { 1695 sll(dst, src, kSmiTagSize - shift); 1696 And(dst, dst, Operand(mask)); 1697 } else if (shift > kSmiTagSize) { 1698 srl(dst, src, shift - kSmiTagSize); 1699 And(dst, dst, Operand(mask)); 1700 } else { 1701 And(dst, src, Operand(mask)); 1702 } 1703 } 1704 1705 template<typename Field> 1706 void DecodeFieldToSmi(Register reg) { 1707 DecodeField<Field>(reg, reg); 1708 } 1709 1710 // Generates function and stub prologue code. 1711 void StubPrologue(StackFrame::Type type); 1712 void Prologue(bool code_pre_aging); 1713 1714 // Load the type feedback vector from a JavaScript frame. 1715 void EmitLoadTypeFeedbackVector(Register vector); 1716 1717 // Activation support. 1718 void EnterFrame(StackFrame::Type type); 1719 void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg); 1720 void LeaveFrame(StackFrame::Type type); 1721 1722 // Expects object in a0 and returns map with validated enum cache 1723 // in a0. Assumes that any other register can be used as a scratch. 1724 void CheckEnumCache(Label* call_runtime); 1725 1726 // AllocationMemento support. Arrays may have an associated AllocationMemento 1727 // object that can be checked for in order to pretransition to another type. 1728 // On entry, receiver_reg should point to the array object. scratch_reg gets 1729 // clobbered. If no info is present jump to no_memento_found, otherwise fall 1730 // through. 1731 void TestJSArrayForAllocationMemento(Register receiver_reg, 1732 Register scratch_reg, 1733 Label* no_memento_found); 1734 1735 void JumpIfJSArrayHasAllocationMemento(Register receiver_reg, 1736 Register scratch_reg, 1737 Label* memento_found) { 1738 Label no_memento_found; 1739 TestJSArrayForAllocationMemento(receiver_reg, scratch_reg, 1740 &no_memento_found); 1741 Branch(memento_found); 1742 bind(&no_memento_found); 1743 } 1744 1745 // Jumps to found label if a prototype map has dictionary elements. 1746 void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0, 1747 Register scratch1, Label* found); 1748 1749 bool IsDoubleZeroRegSet() { return has_double_zero_reg_set_; } 1750 1751 private: 1752 void CallCFunctionHelper(Register function, 1753 int num_reg_arguments, 1754 int num_double_arguments); 1755 1756 inline Register GetRtAsRegisterHelper(const Operand& rt, Register scratch); 1757 inline int32_t GetOffset(int32_t offset, Label* L, OffsetSize bits); 1758 void BranchShortHelperR6(int32_t offset, Label* L); 1759 void BranchShortHelper(int16_t offset, Label* L, BranchDelaySlot bdslot); 1760 bool BranchShortHelperR6(int32_t offset, Label* L, Condition cond, 1761 Register rs, const Operand& rt); 1762 bool BranchShortHelper(int16_t offset, Label* L, Condition cond, Register rs, 1763 const Operand& rt, BranchDelaySlot bdslot); 1764 bool BranchShortCheck(int32_t offset, Label* L, Condition cond, Register rs, 1765 const Operand& rt, BranchDelaySlot bdslot); 1766 1767 void BranchAndLinkShortHelperR6(int32_t offset, Label* L); 1768 void BranchAndLinkShortHelper(int16_t offset, Label* L, 1769 BranchDelaySlot bdslot); 1770 void BranchAndLinkShort(int32_t offset, BranchDelaySlot bdslot = PROTECT); 1771 void BranchAndLinkShort(Label* L, BranchDelaySlot bdslot = PROTECT); 1772 bool BranchAndLinkShortHelperR6(int32_t offset, Label* L, Condition cond, 1773 Register rs, const Operand& rt); 1774 bool BranchAndLinkShortHelper(int16_t offset, Label* L, Condition cond, 1775 Register rs, const Operand& rt, 1776 BranchDelaySlot bdslot); 1777 bool BranchAndLinkShortCheck(int32_t offset, Label* L, Condition cond, 1778 Register rs, const Operand& rt, 1779 BranchDelaySlot bdslot); 1780 void BranchLong(Label* L, BranchDelaySlot bdslot); 1781 void BranchAndLinkLong(Label* L, BranchDelaySlot bdslot); 1782 1783 // Common implementation of BranchF functions for the different formats. 1784 void BranchFCommon(SecondaryField sizeField, Label* target, Label* nan, 1785 Condition cc, FPURegister cmp1, FPURegister cmp2, 1786 BranchDelaySlot bd = PROTECT); 1787 1788 void BranchShortF(SecondaryField sizeField, Label* target, Condition cc, 1789 FPURegister cmp1, FPURegister cmp2, 1790 BranchDelaySlot bd = PROTECT); 1791 1792 // Helper functions for generating invokes. 1793 void InvokePrologue(const ParameterCount& expected, 1794 const ParameterCount& actual, 1795 Label* done, 1796 bool* definitely_mismatches, 1797 InvokeFlag flag, 1798 const CallWrapper& call_wrapper); 1799 1800 void InitializeNewString(Register string, 1801 Register length, 1802 Heap::RootListIndex map_index, 1803 Register scratch1, 1804 Register scratch2); 1805 1806 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace. 1807 void InNewSpace(Register object, Register scratch, 1808 Condition cond, // ne for new space, eq otherwise. 1809 Label* branch); 1810 1811 // Helper for finding the mark bits for an address. Afterwards, the 1812 // bitmap register points at the word with the mark bits and the mask 1813 // the position of the first bit. Leaves addr_reg unchanged. 1814 inline void GetMarkBits(Register addr_reg, 1815 Register bitmap_reg, 1816 Register mask_reg); 1817 1818 // Compute memory operands for safepoint stack slots. 1819 static int SafepointRegisterStackIndex(int reg_code); 1820 MemOperand SafepointRegisterSlot(Register reg); 1821 MemOperand SafepointRegistersAndDoublesSlot(Register reg); 1822 1823 bool generating_stub_; 1824 bool has_frame_; 1825 bool has_double_zero_reg_set_; 1826 // This handle will be patched with the code object on installation. 1827 Handle<Object> code_object_; 1828 1829 // Needs access to SafepointRegisterStackIndex for compiled frame 1830 // traversal. 1831 friend class StandardFrame; 1832}; 1833 1834 1835// The code patcher is used to patch (typically) small parts of code e.g. for 1836// debugging and other types of instrumentation. When using the code patcher 1837// the exact number of bytes specified must be emitted. It is not legal to emit 1838// relocation information. If any of these constraints are violated it causes 1839// an assertion to fail. 1840class CodePatcher { 1841 public: 1842 enum FlushICache { 1843 FLUSH, 1844 DONT_FLUSH 1845 }; 1846 1847 CodePatcher(Isolate* isolate, byte* address, int instructions, 1848 FlushICache flush_cache = FLUSH); 1849 ~CodePatcher(); 1850 1851 // Macro assembler to emit code. 1852 MacroAssembler* masm() { return &masm_; } 1853 1854 // Emit an instruction directly. 1855 void Emit(Instr instr); 1856 1857 // Emit an address directly. 1858 void Emit(Address addr); 1859 1860 // Change the condition part of an instruction leaving the rest of the current 1861 // instruction unchanged. 1862 void ChangeBranchCondition(Instr current_instr, uint32_t new_opcode); 1863 1864 private: 1865 byte* address_; // The address of the code being patched. 1866 int size_; // Number of bytes of the expected patch size. 1867 MacroAssembler masm_; // Macro assembler used to generate the code. 1868 FlushICache flush_cache_; // Whether to flush the I cache after patching. 1869}; 1870 1871template <typename Func> 1872void MacroAssembler::GenerateSwitchTable(Register index, size_t case_count, 1873 Func GetLabelFunction) { 1874 if (kArchVariant >= kMips32r6) { 1875 BlockTrampolinePoolFor(case_count + 5); 1876 addiupc(at, 5); 1877 Lsa(at, at, index, kPointerSizeLog2); 1878 lw(at, MemOperand(at)); 1879 } else { 1880 Label here; 1881 BlockTrampolinePoolFor(case_count + 10); 1882 push(ra); 1883 bal(&here); 1884 sll(at, index, kPointerSizeLog2); // Branch delay slot. 1885 bind(&here); 1886 addu(at, at, ra); 1887 pop(ra); 1888 lw(at, MemOperand(at, 6 * v8::internal::Assembler::kInstrSize)); 1889 } 1890 jr(at); 1891 nop(); // Branch delay slot nop. 1892 for (size_t index = 0; index < case_count; ++index) { 1893 dd(GetLabelFunction(index)); 1894 } 1895} 1896 1897#ifdef GENERATED_CODE_COVERAGE 1898#define CODE_COVERAGE_STRINGIFY(x) #x 1899#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) 1900#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__) 1901#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm-> 1902#else 1903#define ACCESS_MASM(masm) masm-> 1904#endif 1905 1906} // namespace internal 1907} // namespace v8 1908 1909#endif // V8_MIPS_MACRO_ASSEMBLER_MIPS_H_ 1910