1 // Copyright 2014 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 #include <assert.h> // For assert 6 #include <limits.h> // For LONG_MIN, LONG_MAX. 7 8 #if V8_TARGET_ARCH_PPC 9 10 #include "src/base/bits.h" 11 #include "src/base/division-by-constant.h" 12 #include "src/bootstrapper.h" 13 #include "src/codegen.h" 14 #include "src/debug/debug.h" 15 #include "src/register-configuration.h" 16 #include "src/runtime/runtime.h" 17 18 #include "src/ppc/macro-assembler-ppc.h" 19 20 namespace v8 { 21 namespace internal { 22 23 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size, 24 CodeObjectRequired create_code_object) 25 : Assembler(arg_isolate, buffer, size), 26 generating_stub_(false), 27 has_frame_(false) { 28 if (create_code_object == CodeObjectRequired::kYes) { 29 code_object_ = 30 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate()); 31 } 32 } 33 34 35 void MacroAssembler::Jump(Register target) { 36 mtctr(target); 37 bctr(); 38 } 39 40 41 void MacroAssembler::JumpToJSEntry(Register target) { 42 Move(ip, target); 43 Jump(ip); 44 } 45 46 47 void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode, 48 Condition cond, CRegister cr) { 49 Label skip; 50 51 if (cond != al) b(NegateCondition(cond), &skip, cr); 52 53 DCHECK(rmode == RelocInfo::CODE_TARGET || rmode == RelocInfo::RUNTIME_ENTRY); 54 55 mov(ip, Operand(target, rmode)); 56 mtctr(ip); 57 bctr(); 58 59 bind(&skip); 60 } 61 62 63 void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond, 64 CRegister cr) { 65 DCHECK(!RelocInfo::IsCodeTarget(rmode)); 66 Jump(reinterpret_cast<intptr_t>(target), rmode, cond, cr); 67 } 68 69 70 void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode, 71 Condition cond) { 72 DCHECK(RelocInfo::IsCodeTarget(rmode)); 73 // 'code' is always generated ppc code, never THUMB code 74 AllowDeferredHandleDereference embedding_raw_address; 75 Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond); 76 } 77 78 79 int MacroAssembler::CallSize(Register target) { return 2 * kInstrSize; } 80 81 82 void MacroAssembler::Call(Register target) { 83 BlockTrampolinePoolScope block_trampoline_pool(this); 84 Label start; 85 bind(&start); 86 87 // Statement positions are expected to be recorded when the target 88 // address is loaded. 89 positions_recorder()->WriteRecordedPositions(); 90 91 // branch via link register and set LK bit for return point 92 mtctr(target); 93 bctrl(); 94 95 DCHECK_EQ(CallSize(target), SizeOfCodeGeneratedSince(&start)); 96 } 97 98 99 void MacroAssembler::CallJSEntry(Register target) { 100 DCHECK(target.is(ip)); 101 Call(target); 102 } 103 104 105 int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode, 106 Condition cond) { 107 Operand mov_operand = Operand(reinterpret_cast<intptr_t>(target), rmode); 108 return (2 + instructions_required_for_mov(ip, mov_operand)) * kInstrSize; 109 } 110 111 112 int MacroAssembler::CallSizeNotPredictableCodeSize(Address target, 113 RelocInfo::Mode rmode, 114 Condition cond) { 115 return (2 + kMovInstructionsNoConstantPool) * kInstrSize; 116 } 117 118 119 void MacroAssembler::Call(Address target, RelocInfo::Mode rmode, 120 Condition cond) { 121 BlockTrampolinePoolScope block_trampoline_pool(this); 122 DCHECK(cond == al); 123 124 #ifdef DEBUG 125 // Check the expected size before generating code to ensure we assume the same 126 // constant pool availability (e.g., whether constant pool is full or not). 127 int expected_size = CallSize(target, rmode, cond); 128 Label start; 129 bind(&start); 130 #endif 131 132 // Statement positions are expected to be recorded when the target 133 // address is loaded. 134 positions_recorder()->WriteRecordedPositions(); 135 136 // This can likely be optimized to make use of bc() with 24bit relative 137 // 138 // RecordRelocInfo(x.rmode_, x.imm_); 139 // bc( BA, .... offset, LKset); 140 // 141 142 mov(ip, Operand(reinterpret_cast<intptr_t>(target), rmode)); 143 mtctr(ip); 144 bctrl(); 145 146 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start)); 147 } 148 149 150 int MacroAssembler::CallSize(Handle<Code> code, RelocInfo::Mode rmode, 151 TypeFeedbackId ast_id, Condition cond) { 152 AllowDeferredHandleDereference using_raw_address; 153 return CallSize(reinterpret_cast<Address>(code.location()), rmode, cond); 154 } 155 156 157 void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode, 158 TypeFeedbackId ast_id, Condition cond) { 159 BlockTrampolinePoolScope block_trampoline_pool(this); 160 DCHECK(RelocInfo::IsCodeTarget(rmode)); 161 162 #ifdef DEBUG 163 // Check the expected size before generating code to ensure we assume the same 164 // constant pool availability (e.g., whether constant pool is full or not). 165 int expected_size = CallSize(code, rmode, ast_id, cond); 166 Label start; 167 bind(&start); 168 #endif 169 170 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) { 171 SetRecordedAstId(ast_id); 172 rmode = RelocInfo::CODE_TARGET_WITH_ID; 173 } 174 AllowDeferredHandleDereference using_raw_address; 175 Call(reinterpret_cast<Address>(code.location()), rmode, cond); 176 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start)); 177 } 178 179 180 void MacroAssembler::Drop(int count) { 181 if (count > 0) { 182 Add(sp, sp, count * kPointerSize, r0); 183 } 184 } 185 186 187 void MacroAssembler::Call(Label* target) { b(target, SetLK); } 188 189 190 void MacroAssembler::Push(Handle<Object> handle) { 191 mov(r0, Operand(handle)); 192 push(r0); 193 } 194 195 196 void MacroAssembler::Move(Register dst, Handle<Object> value) { 197 AllowDeferredHandleDereference smi_check; 198 if (value->IsSmi()) { 199 LoadSmiLiteral(dst, reinterpret_cast<Smi*>(*value)); 200 } else { 201 DCHECK(value->IsHeapObject()); 202 if (isolate()->heap()->InNewSpace(*value)) { 203 Handle<Cell> cell = isolate()->factory()->NewCell(value); 204 mov(dst, Operand(cell)); 205 LoadP(dst, FieldMemOperand(dst, Cell::kValueOffset)); 206 } else { 207 mov(dst, Operand(value)); 208 } 209 } 210 } 211 212 213 void MacroAssembler::Move(Register dst, Register src, Condition cond) { 214 DCHECK(cond == al); 215 if (!dst.is(src)) { 216 mr(dst, src); 217 } 218 } 219 220 221 void MacroAssembler::Move(DoubleRegister dst, DoubleRegister src) { 222 if (!dst.is(src)) { 223 fmr(dst, src); 224 } 225 } 226 227 228 void MacroAssembler::MultiPush(RegList regs, Register location) { 229 int16_t num_to_push = NumberOfBitsSet(regs); 230 int16_t stack_offset = num_to_push * kPointerSize; 231 232 subi(location, location, Operand(stack_offset)); 233 for (int16_t i = Register::kNumRegisters - 1; i >= 0; i--) { 234 if ((regs & (1 << i)) != 0) { 235 stack_offset -= kPointerSize; 236 StoreP(ToRegister(i), MemOperand(location, stack_offset)); 237 } 238 } 239 } 240 241 242 void MacroAssembler::MultiPop(RegList regs, Register location) { 243 int16_t stack_offset = 0; 244 245 for (int16_t i = 0; i < Register::kNumRegisters; i++) { 246 if ((regs & (1 << i)) != 0) { 247 LoadP(ToRegister(i), MemOperand(location, stack_offset)); 248 stack_offset += kPointerSize; 249 } 250 } 251 addi(location, location, Operand(stack_offset)); 252 } 253 254 255 void MacroAssembler::MultiPushDoubles(RegList dregs, Register location) { 256 int16_t num_to_push = NumberOfBitsSet(dregs); 257 int16_t stack_offset = num_to_push * kDoubleSize; 258 259 subi(location, location, Operand(stack_offset)); 260 for (int16_t i = DoubleRegister::kNumRegisters - 1; i >= 0; i--) { 261 if ((dregs & (1 << i)) != 0) { 262 DoubleRegister dreg = DoubleRegister::from_code(i); 263 stack_offset -= kDoubleSize; 264 stfd(dreg, MemOperand(location, stack_offset)); 265 } 266 } 267 } 268 269 270 void MacroAssembler::MultiPopDoubles(RegList dregs, Register location) { 271 int16_t stack_offset = 0; 272 273 for (int16_t i = 0; i < DoubleRegister::kNumRegisters; i++) { 274 if ((dregs & (1 << i)) != 0) { 275 DoubleRegister dreg = DoubleRegister::from_code(i); 276 lfd(dreg, MemOperand(location, stack_offset)); 277 stack_offset += kDoubleSize; 278 } 279 } 280 addi(location, location, Operand(stack_offset)); 281 } 282 283 284 void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index, 285 Condition cond) { 286 DCHECK(cond == al); 287 LoadP(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), r0); 288 } 289 290 291 void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index, 292 Condition cond) { 293 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); 294 DCHECK(cond == al); 295 StoreP(source, MemOperand(kRootRegister, index << kPointerSizeLog2), r0); 296 } 297 298 299 void MacroAssembler::InNewSpace(Register object, Register scratch, 300 Condition cond, Label* branch) { 301 // N.B. scratch may be same register as object 302 DCHECK(cond == eq || cond == ne); 303 mov(r0, Operand(ExternalReference::new_space_mask(isolate()))); 304 and_(scratch, object, r0); 305 mov(r0, Operand(ExternalReference::new_space_start(isolate()))); 306 cmp(scratch, r0); 307 b(cond, branch); 308 } 309 310 311 void MacroAssembler::RecordWriteField( 312 Register object, int offset, Register value, Register dst, 313 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp, 314 RememberedSetAction remembered_set_action, SmiCheck smi_check, 315 PointersToHereCheck pointers_to_here_check_for_value) { 316 // First, check if a write barrier is even needed. The tests below 317 // catch stores of Smis. 318 Label done; 319 320 // Skip barrier if writing a smi. 321 if (smi_check == INLINE_SMI_CHECK) { 322 JumpIfSmi(value, &done); 323 } 324 325 // Although the object register is tagged, the offset is relative to the start 326 // of the object, so so offset must be a multiple of kPointerSize. 327 DCHECK(IsAligned(offset, kPointerSize)); 328 329 Add(dst, object, offset - kHeapObjectTag, r0); 330 if (emit_debug_code()) { 331 Label ok; 332 andi(r0, dst, Operand((1 << kPointerSizeLog2) - 1)); 333 beq(&ok, cr0); 334 stop("Unaligned cell in write barrier"); 335 bind(&ok); 336 } 337 338 RecordWrite(object, dst, value, lr_status, save_fp, remembered_set_action, 339 OMIT_SMI_CHECK, pointers_to_here_check_for_value); 340 341 bind(&done); 342 343 // Clobber clobbered input registers when running with the debug-code flag 344 // turned on to provoke errors. 345 if (emit_debug_code()) { 346 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 4))); 347 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 8))); 348 } 349 } 350 351 352 // Will clobber 4 registers: object, map, dst, ip. The 353 // register 'object' contains a heap object pointer. 354 void MacroAssembler::RecordWriteForMap(Register object, Register map, 355 Register dst, 356 LinkRegisterStatus lr_status, 357 SaveFPRegsMode fp_mode) { 358 if (emit_debug_code()) { 359 LoadP(dst, FieldMemOperand(map, HeapObject::kMapOffset)); 360 Cmpi(dst, Operand(isolate()->factory()->meta_map()), r0); 361 Check(eq, kWrongAddressOrValuePassedToRecordWrite); 362 } 363 364 if (!FLAG_incremental_marking) { 365 return; 366 } 367 368 if (emit_debug_code()) { 369 LoadP(ip, FieldMemOperand(object, HeapObject::kMapOffset)); 370 cmp(ip, map); 371 Check(eq, kWrongAddressOrValuePassedToRecordWrite); 372 } 373 374 Label done; 375 376 // A single check of the map's pages interesting flag suffices, since it is 377 // only set during incremental collection, and then it's also guaranteed that 378 // the from object's page's interesting flag is also set. This optimization 379 // relies on the fact that maps can never be in new space. 380 CheckPageFlag(map, 381 map, // Used as scratch. 382 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done); 383 384 addi(dst, object, Operand(HeapObject::kMapOffset - kHeapObjectTag)); 385 if (emit_debug_code()) { 386 Label ok; 387 andi(r0, dst, Operand((1 << kPointerSizeLog2) - 1)); 388 beq(&ok, cr0); 389 stop("Unaligned cell in write barrier"); 390 bind(&ok); 391 } 392 393 // Record the actual write. 394 if (lr_status == kLRHasNotBeenSaved) { 395 mflr(r0); 396 push(r0); 397 } 398 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET, 399 fp_mode); 400 CallStub(&stub); 401 if (lr_status == kLRHasNotBeenSaved) { 402 pop(r0); 403 mtlr(r0); 404 } 405 406 bind(&done); 407 408 // Count number of write barriers in generated code. 409 isolate()->counters()->write_barriers_static()->Increment(); 410 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, dst); 411 412 // Clobber clobbered registers when running with the debug-code flag 413 // turned on to provoke errors. 414 if (emit_debug_code()) { 415 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 12))); 416 mov(map, Operand(bit_cast<intptr_t>(kZapValue + 16))); 417 } 418 } 419 420 421 // Will clobber 4 registers: object, address, scratch, ip. The 422 // register 'object' contains a heap object pointer. The heap object 423 // tag is shifted away. 424 void MacroAssembler::RecordWrite( 425 Register object, Register address, Register value, 426 LinkRegisterStatus lr_status, SaveFPRegsMode fp_mode, 427 RememberedSetAction remembered_set_action, SmiCheck smi_check, 428 PointersToHereCheck pointers_to_here_check_for_value) { 429 DCHECK(!object.is(value)); 430 if (emit_debug_code()) { 431 LoadP(r0, MemOperand(address)); 432 cmp(r0, value); 433 Check(eq, kWrongAddressOrValuePassedToRecordWrite); 434 } 435 436 if (remembered_set_action == OMIT_REMEMBERED_SET && 437 !FLAG_incremental_marking) { 438 return; 439 } 440 441 // First, check if a write barrier is even needed. The tests below 442 // catch stores of smis and stores into the young generation. 443 Label done; 444 445 if (smi_check == INLINE_SMI_CHECK) { 446 JumpIfSmi(value, &done); 447 } 448 449 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { 450 CheckPageFlag(value, 451 value, // Used as scratch. 452 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done); 453 } 454 CheckPageFlag(object, 455 value, // Used as scratch. 456 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done); 457 458 // Record the actual write. 459 if (lr_status == kLRHasNotBeenSaved) { 460 mflr(r0); 461 push(r0); 462 } 463 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, 464 fp_mode); 465 CallStub(&stub); 466 if (lr_status == kLRHasNotBeenSaved) { 467 pop(r0); 468 mtlr(r0); 469 } 470 471 bind(&done); 472 473 // Count number of write barriers in generated code. 474 isolate()->counters()->write_barriers_static()->Increment(); 475 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, 476 value); 477 478 // Clobber clobbered registers when running with the debug-code flag 479 // turned on to provoke errors. 480 if (emit_debug_code()) { 481 mov(address, Operand(bit_cast<intptr_t>(kZapValue + 12))); 482 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 16))); 483 } 484 } 485 486 487 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests. 488 Register address, Register scratch, 489 SaveFPRegsMode fp_mode, 490 RememberedSetFinalAction and_then) { 491 Label done; 492 if (emit_debug_code()) { 493 Label ok; 494 JumpIfNotInNewSpace(object, scratch, &ok); 495 stop("Remembered set pointer is in new space"); 496 bind(&ok); 497 } 498 // Load store buffer top. 499 ExternalReference store_buffer = 500 ExternalReference::store_buffer_top(isolate()); 501 mov(ip, Operand(store_buffer)); 502 LoadP(scratch, MemOperand(ip)); 503 // Store pointer to buffer and increment buffer top. 504 StoreP(address, MemOperand(scratch)); 505 addi(scratch, scratch, Operand(kPointerSize)); 506 // Write back new top of buffer. 507 StoreP(scratch, MemOperand(ip)); 508 // Call stub on end of buffer. 509 // Check for end of buffer. 510 mov(r0, Operand(StoreBuffer::kStoreBufferOverflowBit)); 511 and_(r0, scratch, r0, SetRC); 512 513 if (and_then == kFallThroughAtEnd) { 514 beq(&done, cr0); 515 } else { 516 DCHECK(and_then == kReturnAtEnd); 517 Ret(eq, cr0); 518 } 519 mflr(r0); 520 push(r0); 521 StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode); 522 CallStub(&store_buffer_overflow); 523 pop(r0); 524 mtlr(r0); 525 bind(&done); 526 if (and_then == kReturnAtEnd) { 527 Ret(); 528 } 529 } 530 531 532 void MacroAssembler::PushFixedFrame(Register marker_reg) { 533 mflr(r0); 534 if (FLAG_enable_embedded_constant_pool) { 535 if (marker_reg.is_valid()) { 536 Push(r0, fp, kConstantPoolRegister, cp, marker_reg); 537 } else { 538 Push(r0, fp, kConstantPoolRegister, cp); 539 } 540 } else { 541 if (marker_reg.is_valid()) { 542 Push(r0, fp, cp, marker_reg); 543 } else { 544 Push(r0, fp, cp); 545 } 546 } 547 } 548 549 550 void MacroAssembler::PopFixedFrame(Register marker_reg) { 551 if (FLAG_enable_embedded_constant_pool) { 552 if (marker_reg.is_valid()) { 553 Pop(r0, fp, kConstantPoolRegister, cp, marker_reg); 554 } else { 555 Pop(r0, fp, kConstantPoolRegister, cp); 556 } 557 } else { 558 if (marker_reg.is_valid()) { 559 Pop(r0, fp, cp, marker_reg); 560 } else { 561 Pop(r0, fp, cp); 562 } 563 } 564 mtlr(r0); 565 } 566 567 568 const RegList MacroAssembler::kSafepointSavedRegisters = Register::kAllocatable; 569 const int MacroAssembler::kNumSafepointSavedRegisters = 570 Register::kNumAllocatable; 571 572 // Push and pop all registers that can hold pointers. 573 void MacroAssembler::PushSafepointRegisters() { 574 // Safepoints expect a block of kNumSafepointRegisters values on the 575 // stack, so adjust the stack for unsaved registers. 576 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; 577 DCHECK(num_unsaved >= 0); 578 if (num_unsaved > 0) { 579 subi(sp, sp, Operand(num_unsaved * kPointerSize)); 580 } 581 MultiPush(kSafepointSavedRegisters); 582 } 583 584 585 void MacroAssembler::PopSafepointRegisters() { 586 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; 587 MultiPop(kSafepointSavedRegisters); 588 if (num_unsaved > 0) { 589 addi(sp, sp, Operand(num_unsaved * kPointerSize)); 590 } 591 } 592 593 594 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { 595 StoreP(src, SafepointRegisterSlot(dst)); 596 } 597 598 599 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { 600 LoadP(dst, SafepointRegisterSlot(src)); 601 } 602 603 604 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { 605 // The registers are pushed starting with the highest encoding, 606 // which means that lowest encodings are closest to the stack pointer. 607 RegList regs = kSafepointSavedRegisters; 608 int index = 0; 609 610 DCHECK(reg_code >= 0 && reg_code < kNumRegisters); 611 612 for (int16_t i = 0; i < reg_code; i++) { 613 if ((regs & (1 << i)) != 0) { 614 index++; 615 } 616 } 617 618 return index; 619 } 620 621 622 MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) { 623 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); 624 } 625 626 627 MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) { 628 // General purpose registers are pushed last on the stack. 629 const RegisterConfiguration* config = 630 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT); 631 int doubles_size = config->num_allocatable_double_registers() * kDoubleSize; 632 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize; 633 return MemOperand(sp, doubles_size + register_offset); 634 } 635 636 637 void MacroAssembler::CanonicalizeNaN(const DoubleRegister dst, 638 const DoubleRegister src) { 639 // Turn potential sNaN into qNaN. 640 fsub(dst, src, kDoubleRegZero); 641 } 642 643 644 void MacroAssembler::ConvertIntToDouble(Register src, 645 DoubleRegister double_dst) { 646 MovIntToDouble(double_dst, src, r0); 647 fcfid(double_dst, double_dst); 648 } 649 650 651 void MacroAssembler::ConvertUnsignedIntToDouble(Register src, 652 DoubleRegister double_dst) { 653 MovUnsignedIntToDouble(double_dst, src, r0); 654 fcfid(double_dst, double_dst); 655 } 656 657 658 void MacroAssembler::ConvertIntToFloat(const DoubleRegister dst, 659 const Register src, 660 const Register int_scratch) { 661 MovIntToDouble(dst, src, int_scratch); 662 fcfids(dst, dst); 663 } 664 665 666 #if V8_TARGET_ARCH_PPC64 667 void MacroAssembler::ConvertInt64ToDouble(Register src, 668 DoubleRegister double_dst) { 669 MovInt64ToDouble(double_dst, src); 670 fcfid(double_dst, double_dst); 671 } 672 673 674 void MacroAssembler::ConvertUnsignedInt64ToFloat(Register src, 675 DoubleRegister double_dst) { 676 MovInt64ToDouble(double_dst, src); 677 fcfidus(double_dst, double_dst); 678 } 679 680 681 void MacroAssembler::ConvertUnsignedInt64ToDouble(Register src, 682 DoubleRegister double_dst) { 683 MovInt64ToDouble(double_dst, src); 684 fcfidu(double_dst, double_dst); 685 } 686 687 688 void MacroAssembler::ConvertInt64ToFloat(Register src, 689 DoubleRegister double_dst) { 690 MovInt64ToDouble(double_dst, src); 691 fcfids(double_dst, double_dst); 692 } 693 #endif 694 695 696 void MacroAssembler::ConvertDoubleToInt64(const DoubleRegister double_input, 697 #if !V8_TARGET_ARCH_PPC64 698 const Register dst_hi, 699 #endif 700 const Register dst, 701 const DoubleRegister double_dst, 702 FPRoundingMode rounding_mode) { 703 if (rounding_mode == kRoundToZero) { 704 fctidz(double_dst, double_input); 705 } else { 706 SetRoundingMode(rounding_mode); 707 fctid(double_dst, double_input); 708 ResetRoundingMode(); 709 } 710 711 MovDoubleToInt64( 712 #if !V8_TARGET_ARCH_PPC64 713 dst_hi, 714 #endif 715 dst, double_dst); 716 } 717 718 #if V8_TARGET_ARCH_PPC64 719 void MacroAssembler::ConvertDoubleToUnsignedInt64( 720 const DoubleRegister double_input, const Register dst, 721 const DoubleRegister double_dst, FPRoundingMode rounding_mode) { 722 if (rounding_mode == kRoundToZero) { 723 fctiduz(double_dst, double_input); 724 } else { 725 SetRoundingMode(rounding_mode); 726 fctidu(double_dst, double_input); 727 ResetRoundingMode(); 728 } 729 730 MovDoubleToInt64(dst, double_dst); 731 } 732 #endif 733 734 735 void MacroAssembler::LoadConstantPoolPointerRegisterFromCodeTargetAddress( 736 Register code_target_address) { 737 lwz(kConstantPoolRegister, 738 MemOperand(code_target_address, 739 Code::kConstantPoolOffset - Code::kHeaderSize)); 740 add(kConstantPoolRegister, kConstantPoolRegister, code_target_address); 741 } 742 743 744 void MacroAssembler::LoadConstantPoolPointerRegister(Register base, 745 int code_start_delta) { 746 add_label_offset(kConstantPoolRegister, base, ConstantPoolPosition(), 747 code_start_delta); 748 } 749 750 751 void MacroAssembler::LoadConstantPoolPointerRegister() { 752 mov_label_addr(kConstantPoolRegister, ConstantPoolPosition()); 753 } 754 755 756 void MacroAssembler::StubPrologue(Register base, int prologue_offset) { 757 LoadSmiLiteral(r11, Smi::FromInt(StackFrame::STUB)); 758 PushFixedFrame(r11); 759 // Adjust FP to point to saved FP. 760 addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); 761 if (FLAG_enable_embedded_constant_pool) { 762 if (!base.is(no_reg)) { 763 // base contains prologue address 764 LoadConstantPoolPointerRegister(base, -prologue_offset); 765 } else { 766 LoadConstantPoolPointerRegister(); 767 } 768 set_constant_pool_available(true); 769 } 770 } 771 772 773 void MacroAssembler::Prologue(bool code_pre_aging, Register base, 774 int prologue_offset) { 775 DCHECK(!base.is(no_reg)); 776 { 777 PredictableCodeSizeScope predictible_code_size_scope( 778 this, kNoCodeAgeSequenceLength); 779 Assembler::BlockTrampolinePoolScope block_trampoline_pool(this); 780 // The following instructions must remain together and unmodified 781 // for code aging to work properly. 782 if (code_pre_aging) { 783 // Pre-age the code. 784 // This matches the code found in PatchPlatformCodeAge() 785 Code* stub = Code::GetPreAgedCodeAgeStub(isolate()); 786 intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start()); 787 // Don't use Call -- we need to preserve ip and lr 788 nop(); // marker to detect sequence (see IsOld) 789 mov(r3, Operand(target)); 790 Jump(r3); 791 for (int i = 0; i < kCodeAgingSequenceNops; i++) { 792 nop(); 793 } 794 } else { 795 // This matches the code found in GetNoCodeAgeSequence() 796 PushFixedFrame(r4); 797 // Adjust fp to point to saved fp. 798 addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); 799 for (int i = 0; i < kNoCodeAgeSequenceNops; i++) { 800 nop(); 801 } 802 } 803 } 804 if (FLAG_enable_embedded_constant_pool) { 805 // base contains prologue address 806 LoadConstantPoolPointerRegister(base, -prologue_offset); 807 set_constant_pool_available(true); 808 } 809 } 810 811 812 void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) { 813 LoadP(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 814 LoadP(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset)); 815 LoadP(vector, 816 FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset)); 817 } 818 819 820 void MacroAssembler::EnterFrame(StackFrame::Type type, 821 bool load_constant_pool_pointer_reg) { 822 if (FLAG_enable_embedded_constant_pool && load_constant_pool_pointer_reg) { 823 PushFixedFrame(); 824 // This path should not rely on ip containing code entry. 825 LoadConstantPoolPointerRegister(); 826 LoadSmiLiteral(ip, Smi::FromInt(type)); 827 push(ip); 828 } else { 829 LoadSmiLiteral(ip, Smi::FromInt(type)); 830 PushFixedFrame(ip); 831 } 832 // Adjust FP to point to saved FP. 833 addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); 834 835 mov(r0, Operand(CodeObject())); 836 push(r0); 837 } 838 839 840 int MacroAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) { 841 ConstantPoolUnavailableScope constant_pool_unavailable(this); 842 // r3: preserved 843 // r4: preserved 844 // r5: preserved 845 846 // Drop the execution stack down to the frame pointer and restore 847 // the caller's state. 848 int frame_ends; 849 LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); 850 LoadP(ip, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 851 if (FLAG_enable_embedded_constant_pool) { 852 const int exitOffset = ExitFrameConstants::kConstantPoolOffset; 853 const int standardOffset = StandardFrameConstants::kConstantPoolOffset; 854 const int offset = 855 ((type == StackFrame::EXIT) ? exitOffset : standardOffset); 856 LoadP(kConstantPoolRegister, MemOperand(fp, offset)); 857 } 858 mtlr(r0); 859 frame_ends = pc_offset(); 860 Add(sp, fp, StandardFrameConstants::kCallerSPOffset + stack_adjustment, r0); 861 mr(fp, ip); 862 return frame_ends; 863 } 864 865 866 // ExitFrame layout (probably wrongish.. needs updating) 867 // 868 // SP -> previousSP 869 // LK reserved 870 // code 871 // sp_on_exit (for debug?) 872 // oldSP->prev SP 873 // LK 874 // <parameters on stack> 875 876 // Prior to calling EnterExitFrame, we've got a bunch of parameters 877 // on the stack that we need to wrap a real frame around.. so first 878 // we reserve a slot for LK and push the previous SP which is captured 879 // in the fp register (r31) 880 // Then - we buy a new frame 881 882 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { 883 // Set up the frame structure on the stack. 884 DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); 885 DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); 886 DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); 887 DCHECK(stack_space > 0); 888 889 // This is an opportunity to build a frame to wrap 890 // all of the pushes that have happened inside of V8 891 // since we were called from C code 892 893 // replicate ARM frame - TODO make this more closely follow PPC ABI 894 mflr(r0); 895 Push(r0, fp); 896 mr(fp, sp); 897 // Reserve room for saved entry sp and code object. 898 subi(sp, sp, Operand(ExitFrameConstants::kFrameSize)); 899 900 if (emit_debug_code()) { 901 li(r8, Operand::Zero()); 902 StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset)); 903 } 904 if (FLAG_enable_embedded_constant_pool) { 905 StoreP(kConstantPoolRegister, 906 MemOperand(fp, ExitFrameConstants::kConstantPoolOffset)); 907 } 908 mov(r8, Operand(CodeObject())); 909 StoreP(r8, MemOperand(fp, ExitFrameConstants::kCodeOffset)); 910 911 // Save the frame pointer and the context in top. 912 mov(r8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); 913 StoreP(fp, MemOperand(r8)); 914 mov(r8, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); 915 StoreP(cp, MemOperand(r8)); 916 917 // Optionally save all volatile double registers. 918 if (save_doubles) { 919 MultiPushDoubles(kCallerSavedDoubles); 920 // Note that d0 will be accessible at 921 // fp - ExitFrameConstants::kFrameSize - 922 // kNumCallerSavedDoubles * kDoubleSize, 923 // since the sp slot and code slot were pushed after the fp. 924 } 925 926 addi(sp, sp, Operand(-stack_space * kPointerSize)); 927 928 // Allocate and align the frame preparing for calling the runtime 929 // function. 930 const int frame_alignment = ActivationFrameAlignment(); 931 if (frame_alignment > kPointerSize) { 932 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 933 ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment))); 934 } 935 li(r0, Operand::Zero()); 936 StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize)); 937 938 // Set the exit frame sp value to point just before the return address 939 // location. 940 addi(r8, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize)); 941 StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset)); 942 } 943 944 945 void MacroAssembler::InitializeNewString(Register string, Register length, 946 Heap::RootListIndex map_index, 947 Register scratch1, Register scratch2) { 948 SmiTag(scratch1, length); 949 LoadRoot(scratch2, map_index); 950 StoreP(scratch1, FieldMemOperand(string, String::kLengthOffset), r0); 951 li(scratch1, Operand(String::kEmptyHashField)); 952 StoreP(scratch2, FieldMemOperand(string, HeapObject::kMapOffset), r0); 953 StoreP(scratch1, FieldMemOperand(string, String::kHashFieldSlot), r0); 954 } 955 956 957 int MacroAssembler::ActivationFrameAlignment() { 958 #if !defined(USE_SIMULATOR) 959 // Running on the real platform. Use the alignment as mandated by the local 960 // environment. 961 // Note: This will break if we ever start generating snapshots on one PPC 962 // platform for another PPC platform with a different alignment. 963 return base::OS::ActivationFrameAlignment(); 964 #else // Simulated 965 // If we are using the simulator then we should always align to the expected 966 // alignment. As the simulator is used to generate snapshots we do not know 967 // if the target platform will need alignment, so this is controlled from a 968 // flag. 969 return FLAG_sim_stack_alignment; 970 #endif 971 } 972 973 974 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count, 975 bool restore_context, 976 bool argument_count_is_length) { 977 ConstantPoolUnavailableScope constant_pool_unavailable(this); 978 // Optionally restore all double registers. 979 if (save_doubles) { 980 // Calculate the stack location of the saved doubles and restore them. 981 const int kNumRegs = kNumCallerSavedDoubles; 982 const int offset = 983 (ExitFrameConstants::kFrameSize + kNumRegs * kDoubleSize); 984 addi(r6, fp, Operand(-offset)); 985 MultiPopDoubles(kCallerSavedDoubles, r6); 986 } 987 988 // Clear top frame. 989 li(r6, Operand::Zero()); 990 mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); 991 StoreP(r6, MemOperand(ip)); 992 993 // Restore current context from top and clear it in debug mode. 994 if (restore_context) { 995 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); 996 LoadP(cp, MemOperand(ip)); 997 } 998 #ifdef DEBUG 999 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); 1000 StoreP(r6, MemOperand(ip)); 1001 #endif 1002 1003 // Tear down the exit frame, pop the arguments, and return. 1004 LeaveFrame(StackFrame::EXIT); 1005 1006 if (argument_count.is_valid()) { 1007 if (!argument_count_is_length) { 1008 ShiftLeftImm(argument_count, argument_count, Operand(kPointerSizeLog2)); 1009 } 1010 add(sp, sp, argument_count); 1011 } 1012 } 1013 1014 1015 void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) { 1016 Move(dst, d1); 1017 } 1018 1019 1020 void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) { 1021 Move(dst, d1); 1022 } 1023 1024 1025 void MacroAssembler::InvokePrologue(const ParameterCount& expected, 1026 const ParameterCount& actual, Label* done, 1027 bool* definitely_mismatches, 1028 InvokeFlag flag, 1029 const CallWrapper& call_wrapper) { 1030 bool definitely_matches = false; 1031 *definitely_mismatches = false; 1032 Label regular_invoke; 1033 1034 // Check whether the expected and actual arguments count match. If not, 1035 // setup registers according to contract with ArgumentsAdaptorTrampoline: 1036 // r3: actual arguments count 1037 // r4: function (passed through to callee) 1038 // r5: expected arguments count 1039 1040 // The code below is made a lot easier because the calling code already sets 1041 // up actual and expected registers according to the contract if values are 1042 // passed in registers. 1043 1044 // ARM has some sanity checks as per below, considering add them for PPC 1045 // DCHECK(actual.is_immediate() || actual.reg().is(r3)); 1046 // DCHECK(expected.is_immediate() || expected.reg().is(r5)); 1047 1048 if (expected.is_immediate()) { 1049 DCHECK(actual.is_immediate()); 1050 mov(r3, Operand(actual.immediate())); 1051 if (expected.immediate() == actual.immediate()) { 1052 definitely_matches = true; 1053 } else { 1054 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel; 1055 if (expected.immediate() == sentinel) { 1056 // Don't worry about adapting arguments for builtins that 1057 // don't want that done. Skip adaption code by making it look 1058 // like we have a match between expected and actual number of 1059 // arguments. 1060 definitely_matches = true; 1061 } else { 1062 *definitely_mismatches = true; 1063 mov(r5, Operand(expected.immediate())); 1064 } 1065 } 1066 } else { 1067 if (actual.is_immediate()) { 1068 mov(r3, Operand(actual.immediate())); 1069 cmpi(expected.reg(), Operand(actual.immediate())); 1070 beq(®ular_invoke); 1071 } else { 1072 cmp(expected.reg(), actual.reg()); 1073 beq(®ular_invoke); 1074 } 1075 } 1076 1077 if (!definitely_matches) { 1078 Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline(); 1079 if (flag == CALL_FUNCTION) { 1080 call_wrapper.BeforeCall(CallSize(adaptor)); 1081 Call(adaptor); 1082 call_wrapper.AfterCall(); 1083 if (!*definitely_mismatches) { 1084 b(done); 1085 } 1086 } else { 1087 Jump(adaptor, RelocInfo::CODE_TARGET); 1088 } 1089 bind(®ular_invoke); 1090 } 1091 } 1092 1093 1094 void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target, 1095 const ParameterCount& expected, 1096 const ParameterCount& actual) { 1097 Label skip_flooding; 1098 ExternalReference step_in_enabled = 1099 ExternalReference::debug_step_in_enabled_address(isolate()); 1100 mov(r7, Operand(step_in_enabled)); 1101 lbz(r7, MemOperand(r7)); 1102 cmpi(r7, Operand::Zero()); 1103 beq(&skip_flooding); 1104 { 1105 FrameScope frame(this, 1106 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); 1107 if (expected.is_reg()) { 1108 SmiTag(expected.reg()); 1109 Push(expected.reg()); 1110 } 1111 if (actual.is_reg()) { 1112 SmiTag(actual.reg()); 1113 Push(actual.reg()); 1114 } 1115 if (new_target.is_valid()) { 1116 Push(new_target); 1117 } 1118 Push(fun, fun); 1119 CallRuntime(Runtime::kDebugPrepareStepInIfStepping, 1); 1120 Pop(fun); 1121 if (new_target.is_valid()) { 1122 Pop(new_target); 1123 } 1124 if (actual.is_reg()) { 1125 Pop(actual.reg()); 1126 SmiUntag(actual.reg()); 1127 } 1128 if (expected.is_reg()) { 1129 Pop(expected.reg()); 1130 SmiUntag(expected.reg()); 1131 } 1132 } 1133 bind(&skip_flooding); 1134 } 1135 1136 1137 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, 1138 const ParameterCount& expected, 1139 const ParameterCount& actual, 1140 InvokeFlag flag, 1141 const CallWrapper& call_wrapper) { 1142 // You can't call a function without a valid frame. 1143 DCHECK(flag == JUMP_FUNCTION || has_frame()); 1144 DCHECK(function.is(r4)); 1145 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r6)); 1146 1147 if (call_wrapper.NeedsDebugStepCheck()) { 1148 FloodFunctionIfStepping(function, new_target, expected, actual); 1149 } 1150 1151 // Clear the new.target register if not given. 1152 if (!new_target.is_valid()) { 1153 LoadRoot(r6, Heap::kUndefinedValueRootIndex); 1154 } 1155 1156 Label done; 1157 bool definitely_mismatches = false; 1158 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag, 1159 call_wrapper); 1160 if (!definitely_mismatches) { 1161 // We call indirectly through the code field in the function to 1162 // allow recompilation to take effect without changing any of the 1163 // call sites. 1164 Register code = ip; 1165 LoadP(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); 1166 if (flag == CALL_FUNCTION) { 1167 call_wrapper.BeforeCall(CallSize(code)); 1168 CallJSEntry(code); 1169 call_wrapper.AfterCall(); 1170 } else { 1171 DCHECK(flag == JUMP_FUNCTION); 1172 JumpToJSEntry(code); 1173 } 1174 1175 // Continue here if InvokePrologue does handle the invocation due to 1176 // mismatched parameter counts. 1177 bind(&done); 1178 } 1179 } 1180 1181 1182 void MacroAssembler::InvokeFunction(Register fun, Register new_target, 1183 const ParameterCount& actual, 1184 InvokeFlag flag, 1185 const CallWrapper& call_wrapper) { 1186 // You can't call a function without a valid frame. 1187 DCHECK(flag == JUMP_FUNCTION || has_frame()); 1188 1189 // Contract with called JS functions requires that function is passed in r4. 1190 DCHECK(fun.is(r4)); 1191 1192 Register expected_reg = r5; 1193 Register temp_reg = r7; 1194 1195 LoadP(temp_reg, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); 1196 LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset)); 1197 LoadWordArith(expected_reg, 1198 FieldMemOperand( 1199 temp_reg, SharedFunctionInfo::kFormalParameterCountOffset)); 1200 #if !defined(V8_TARGET_ARCH_PPC64) 1201 SmiUntag(expected_reg); 1202 #endif 1203 1204 ParameterCount expected(expected_reg); 1205 InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper); 1206 } 1207 1208 1209 void MacroAssembler::InvokeFunction(Register function, 1210 const ParameterCount& expected, 1211 const ParameterCount& actual, 1212 InvokeFlag flag, 1213 const CallWrapper& call_wrapper) { 1214 // You can't call a function without a valid frame. 1215 DCHECK(flag == JUMP_FUNCTION || has_frame()); 1216 1217 // Contract with called JS functions requires that function is passed in r4. 1218 DCHECK(function.is(r4)); 1219 1220 // Get the function and setup the context. 1221 LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset)); 1222 1223 InvokeFunctionCode(r4, no_reg, expected, actual, flag, call_wrapper); 1224 } 1225 1226 1227 void MacroAssembler::InvokeFunction(Handle<JSFunction> function, 1228 const ParameterCount& expected, 1229 const ParameterCount& actual, 1230 InvokeFlag flag, 1231 const CallWrapper& call_wrapper) { 1232 Move(r4, function); 1233 InvokeFunction(r4, expected, actual, flag, call_wrapper); 1234 } 1235 1236 1237 void MacroAssembler::IsObjectJSStringType(Register object, Register scratch, 1238 Label* fail) { 1239 DCHECK(kNotStringTag != 0); 1240 1241 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 1242 lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); 1243 andi(r0, scratch, Operand(kIsNotStringMask)); 1244 bne(fail, cr0); 1245 } 1246 1247 1248 void MacroAssembler::IsObjectNameType(Register object, Register scratch, 1249 Label* fail) { 1250 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 1251 lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); 1252 cmpi(scratch, Operand(LAST_NAME_TYPE)); 1253 bgt(fail); 1254 } 1255 1256 1257 void MacroAssembler::DebugBreak() { 1258 li(r3, Operand::Zero()); 1259 mov(r4, 1260 Operand(ExternalReference(Runtime::kHandleDebuggerStatement, isolate()))); 1261 CEntryStub ces(isolate(), 1); 1262 DCHECK(AllowThisStubCall(&ces)); 1263 Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); 1264 } 1265 1266 1267 void MacroAssembler::PushStackHandler() { 1268 // Adjust this code if not the case. 1269 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); 1270 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); 1271 1272 // Link the current handler as the next handler. 1273 // Preserve r3-r7. 1274 mov(r8, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); 1275 LoadP(r0, MemOperand(r8)); 1276 push(r0); 1277 1278 // Set this new handler as the current one. 1279 StoreP(sp, MemOperand(r8)); 1280 } 1281 1282 1283 void MacroAssembler::PopStackHandler() { 1284 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); 1285 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 1286 1287 pop(r4); 1288 mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); 1289 StoreP(r4, MemOperand(ip)); 1290 } 1291 1292 1293 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, 1294 Register scratch, Label* miss) { 1295 Label same_contexts; 1296 1297 DCHECK(!holder_reg.is(scratch)); 1298 DCHECK(!holder_reg.is(ip)); 1299 DCHECK(!scratch.is(ip)); 1300 1301 // Load current lexical context from the stack frame. 1302 LoadP(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); 1303 // In debug mode, make sure the lexical context is set. 1304 #ifdef DEBUG 1305 cmpi(scratch, Operand::Zero()); 1306 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext); 1307 #endif 1308 1309 // Load the native context of the current context. 1310 LoadP(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX)); 1311 1312 // Check the context is a native context. 1313 if (emit_debug_code()) { 1314 // Cannot use ip as a temporary in this verification code. Due to the fact 1315 // that ip is clobbered as part of cmp with an object Operand. 1316 push(holder_reg); // Temporarily save holder on the stack. 1317 // Read the first word and compare to the native_context_map. 1318 LoadP(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); 1319 LoadRoot(ip, Heap::kNativeContextMapRootIndex); 1320 cmp(holder_reg, ip); 1321 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); 1322 pop(holder_reg); // Restore holder. 1323 } 1324 1325 // Check if both contexts are the same. 1326 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); 1327 cmp(scratch, ip); 1328 beq(&same_contexts); 1329 1330 // Check the context is a native context. 1331 if (emit_debug_code()) { 1332 // Cannot use ip as a temporary in this verification code. Due to the fact 1333 // that ip is clobbered as part of cmp with an object Operand. 1334 push(holder_reg); // Temporarily save holder on the stack. 1335 mr(holder_reg, ip); // Move ip to its holding place. 1336 LoadRoot(ip, Heap::kNullValueRootIndex); 1337 cmp(holder_reg, ip); 1338 Check(ne, kJSGlobalProxyContextShouldNotBeNull); 1339 1340 LoadP(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); 1341 LoadRoot(ip, Heap::kNativeContextMapRootIndex); 1342 cmp(holder_reg, ip); 1343 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); 1344 // Restore ip is not needed. ip is reloaded below. 1345 pop(holder_reg); // Restore holder. 1346 // Restore ip to holder's context. 1347 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); 1348 } 1349 1350 // Check that the security token in the calling global object is 1351 // compatible with the security token in the receiving global 1352 // object. 1353 int token_offset = 1354 Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize; 1355 1356 LoadP(scratch, FieldMemOperand(scratch, token_offset)); 1357 LoadP(ip, FieldMemOperand(ip, token_offset)); 1358 cmp(scratch, ip); 1359 bne(miss); 1360 1361 bind(&same_contexts); 1362 } 1363 1364 1365 // Compute the hash code from the untagged key. This must be kept in sync with 1366 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in 1367 // code-stub-hydrogen.cc 1368 void MacroAssembler::GetNumberHash(Register t0, Register scratch) { 1369 // First of all we assign the hash seed to scratch. 1370 LoadRoot(scratch, Heap::kHashSeedRootIndex); 1371 SmiUntag(scratch); 1372 1373 // Xor original key with a seed. 1374 xor_(t0, t0, scratch); 1375 1376 // Compute the hash code from the untagged key. This must be kept in sync 1377 // with ComputeIntegerHash in utils.h. 1378 // 1379 // hash = ~hash + (hash << 15); 1380 notx(scratch, t0); 1381 slwi(t0, t0, Operand(15)); 1382 add(t0, scratch, t0); 1383 // hash = hash ^ (hash >> 12); 1384 srwi(scratch, t0, Operand(12)); 1385 xor_(t0, t0, scratch); 1386 // hash = hash + (hash << 2); 1387 slwi(scratch, t0, Operand(2)); 1388 add(t0, t0, scratch); 1389 // hash = hash ^ (hash >> 4); 1390 srwi(scratch, t0, Operand(4)); 1391 xor_(t0, t0, scratch); 1392 // hash = hash * 2057; 1393 mr(r0, t0); 1394 slwi(scratch, t0, Operand(3)); 1395 add(t0, t0, scratch); 1396 slwi(scratch, r0, Operand(11)); 1397 add(t0, t0, scratch); 1398 // hash = hash ^ (hash >> 16); 1399 srwi(scratch, t0, Operand(16)); 1400 xor_(t0, t0, scratch); 1401 // hash & 0x3fffffff 1402 ExtractBitRange(t0, t0, 29, 0); 1403 } 1404 1405 1406 void MacroAssembler::LoadFromNumberDictionary(Label* miss, Register elements, 1407 Register key, Register result, 1408 Register t0, Register t1, 1409 Register t2) { 1410 // Register use: 1411 // 1412 // elements - holds the slow-case elements of the receiver on entry. 1413 // Unchanged unless 'result' is the same register. 1414 // 1415 // key - holds the smi key on entry. 1416 // Unchanged unless 'result' is the same register. 1417 // 1418 // result - holds the result on exit if the load succeeded. 1419 // Allowed to be the same as 'key' or 'result'. 1420 // Unchanged on bailout so 'key' or 'result' can be used 1421 // in further computation. 1422 // 1423 // Scratch registers: 1424 // 1425 // t0 - holds the untagged key on entry and holds the hash once computed. 1426 // 1427 // t1 - used to hold the capacity mask of the dictionary 1428 // 1429 // t2 - used for the index into the dictionary. 1430 Label done; 1431 1432 GetNumberHash(t0, t1); 1433 1434 // Compute the capacity mask. 1435 LoadP(t1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset)); 1436 SmiUntag(t1); 1437 subi(t1, t1, Operand(1)); 1438 1439 // Generate an unrolled loop that performs a few probes before giving up. 1440 for (int i = 0; i < kNumberDictionaryProbes; i++) { 1441 // Use t2 for index calculations and keep the hash intact in t0. 1442 mr(t2, t0); 1443 // Compute the masked index: (hash + i + i * i) & mask. 1444 if (i > 0) { 1445 addi(t2, t2, Operand(SeededNumberDictionary::GetProbeOffset(i))); 1446 } 1447 and_(t2, t2, t1); 1448 1449 // Scale the index by multiplying by the element size. 1450 DCHECK(SeededNumberDictionary::kEntrySize == 3); 1451 slwi(ip, t2, Operand(1)); 1452 add(t2, t2, ip); // t2 = t2 * 3 1453 1454 // Check if the key is identical to the name. 1455 slwi(t2, t2, Operand(kPointerSizeLog2)); 1456 add(t2, elements, t2); 1457 LoadP(ip, 1458 FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset)); 1459 cmp(key, ip); 1460 if (i != kNumberDictionaryProbes - 1) { 1461 beq(&done); 1462 } else { 1463 bne(miss); 1464 } 1465 } 1466 1467 bind(&done); 1468 // Check that the value is a field property. 1469 // t2: elements + (index * kPointerSize) 1470 const int kDetailsOffset = 1471 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize; 1472 LoadP(t1, FieldMemOperand(t2, kDetailsOffset)); 1473 LoadSmiLiteral(ip, Smi::FromInt(PropertyDetails::TypeField::kMask)); 1474 DCHECK_EQ(DATA, 0); 1475 and_(r0, t1, ip, SetRC); 1476 bne(miss, cr0); 1477 1478 // Get the value at the masked, scaled index and return. 1479 const int kValueOffset = 1480 SeededNumberDictionary::kElementsStartOffset + kPointerSize; 1481 LoadP(result, FieldMemOperand(t2, kValueOffset)); 1482 } 1483 1484 1485 void MacroAssembler::Allocate(int object_size, Register result, 1486 Register scratch1, Register scratch2, 1487 Label* gc_required, AllocationFlags flags) { 1488 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize); 1489 if (!FLAG_inline_new) { 1490 if (emit_debug_code()) { 1491 // Trash the registers to simulate an allocation failure. 1492 li(result, Operand(0x7091)); 1493 li(scratch1, Operand(0x7191)); 1494 li(scratch2, Operand(0x7291)); 1495 } 1496 b(gc_required); 1497 return; 1498 } 1499 1500 DCHECK(!AreAliased(result, scratch1, scratch2, ip)); 1501 1502 // Make object size into bytes. 1503 if ((flags & SIZE_IN_WORDS) != 0) { 1504 object_size *= kPointerSize; 1505 } 1506 DCHECK_EQ(0, static_cast<int>(object_size & kObjectAlignmentMask)); 1507 1508 // Check relative positions of allocation top and limit addresses. 1509 ExternalReference allocation_top = 1510 AllocationUtils::GetAllocationTopReference(isolate(), flags); 1511 ExternalReference allocation_limit = 1512 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 1513 1514 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address()); 1515 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address()); 1516 DCHECK((limit - top) == kPointerSize); 1517 1518 // Set up allocation top address register. 1519 Register top_address = scratch1; 1520 // This code stores a temporary value in ip. This is OK, as the code below 1521 // does not need ip for implicit literal generation. 1522 Register alloc_limit = ip; 1523 Register result_end = scratch2; 1524 mov(top_address, Operand(allocation_top)); 1525 1526 if ((flags & RESULT_CONTAINS_TOP) == 0) { 1527 // Load allocation top into result and allocation limit into ip. 1528 LoadP(result, MemOperand(top_address)); 1529 LoadP(alloc_limit, MemOperand(top_address, kPointerSize)); 1530 } else { 1531 if (emit_debug_code()) { 1532 // Assert that result actually contains top on entry. 1533 LoadP(alloc_limit, MemOperand(top_address)); 1534 cmp(result, alloc_limit); 1535 Check(eq, kUnexpectedAllocationTop); 1536 } 1537 // Load allocation limit. Result already contains allocation top. 1538 LoadP(alloc_limit, MemOperand(top_address, limit - top)); 1539 } 1540 1541 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1542 // Align the next allocation. Storing the filler map without checking top is 1543 // safe in new-space because the limit of the heap is aligned there. 1544 #if V8_TARGET_ARCH_PPC64 1545 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment); 1546 #else 1547 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment); 1548 andi(result_end, result, Operand(kDoubleAlignmentMask)); 1549 Label aligned; 1550 beq(&aligned, cr0); 1551 if ((flags & PRETENURE) != 0) { 1552 cmpl(result, alloc_limit); 1553 bge(gc_required); 1554 } 1555 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); 1556 stw(result_end, MemOperand(result)); 1557 addi(result, result, Operand(kDoubleSize / 2)); 1558 bind(&aligned); 1559 #endif 1560 } 1561 1562 // Calculate new top and bail out if new space is exhausted. Use result 1563 // to calculate the new top. 1564 sub(r0, alloc_limit, result); 1565 if (is_int16(object_size)) { 1566 cmpi(r0, Operand(object_size)); 1567 blt(gc_required); 1568 addi(result_end, result, Operand(object_size)); 1569 } else { 1570 Cmpi(r0, Operand(object_size), result_end); 1571 blt(gc_required); 1572 add(result_end, result, result_end); 1573 } 1574 StoreP(result_end, MemOperand(top_address)); 1575 1576 // Tag object if requested. 1577 if ((flags & TAG_OBJECT) != 0) { 1578 addi(result, result, Operand(kHeapObjectTag)); 1579 } 1580 } 1581 1582 1583 void MacroAssembler::Allocate(Register object_size, Register result, 1584 Register result_end, Register scratch, 1585 Label* gc_required, AllocationFlags flags) { 1586 if (!FLAG_inline_new) { 1587 if (emit_debug_code()) { 1588 // Trash the registers to simulate an allocation failure. 1589 li(result, Operand(0x7091)); 1590 li(scratch, Operand(0x7191)); 1591 li(result_end, Operand(0x7291)); 1592 } 1593 b(gc_required); 1594 return; 1595 } 1596 1597 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag 1598 // is not specified. Other registers must not overlap. 1599 DCHECK(!AreAliased(object_size, result, scratch, ip)); 1600 DCHECK(!AreAliased(result_end, result, scratch, ip)); 1601 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end)); 1602 1603 // Check relative positions of allocation top and limit addresses. 1604 ExternalReference allocation_top = 1605 AllocationUtils::GetAllocationTopReference(isolate(), flags); 1606 ExternalReference allocation_limit = 1607 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 1608 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address()); 1609 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address()); 1610 DCHECK((limit - top) == kPointerSize); 1611 1612 // Set up allocation top address and allocation limit registers. 1613 Register top_address = scratch; 1614 // This code stores a temporary value in ip. This is OK, as the code below 1615 // does not need ip for implicit literal generation. 1616 Register alloc_limit = ip; 1617 mov(top_address, Operand(allocation_top)); 1618 1619 if ((flags & RESULT_CONTAINS_TOP) == 0) { 1620 // Load allocation top into result and allocation limit into alloc_limit.. 1621 LoadP(result, MemOperand(top_address)); 1622 LoadP(alloc_limit, MemOperand(top_address, kPointerSize)); 1623 } else { 1624 if (emit_debug_code()) { 1625 // Assert that result actually contains top on entry. 1626 LoadP(alloc_limit, MemOperand(top_address)); 1627 cmp(result, alloc_limit); 1628 Check(eq, kUnexpectedAllocationTop); 1629 } 1630 // Load allocation limit. Result already contains allocation top. 1631 LoadP(alloc_limit, MemOperand(top_address, limit - top)); 1632 } 1633 1634 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1635 // Align the next allocation. Storing the filler map without checking top is 1636 // safe in new-space because the limit of the heap is aligned there. 1637 #if V8_TARGET_ARCH_PPC64 1638 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment); 1639 #else 1640 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment); 1641 andi(result_end, result, Operand(kDoubleAlignmentMask)); 1642 Label aligned; 1643 beq(&aligned, cr0); 1644 if ((flags & PRETENURE) != 0) { 1645 cmpl(result, alloc_limit); 1646 bge(gc_required); 1647 } 1648 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); 1649 stw(result_end, MemOperand(result)); 1650 addi(result, result, Operand(kDoubleSize / 2)); 1651 bind(&aligned); 1652 #endif 1653 } 1654 1655 // Calculate new top and bail out if new space is exhausted. Use result 1656 // to calculate the new top. Object size may be in words so a shift is 1657 // required to get the number of bytes. 1658 sub(r0, alloc_limit, result); 1659 if ((flags & SIZE_IN_WORDS) != 0) { 1660 ShiftLeftImm(result_end, object_size, Operand(kPointerSizeLog2)); 1661 cmp(r0, result_end); 1662 blt(gc_required); 1663 add(result_end, result, result_end); 1664 } else { 1665 cmp(r0, object_size); 1666 blt(gc_required); 1667 add(result_end, result, object_size); 1668 } 1669 1670 // Update allocation top. result temporarily holds the new top. 1671 if (emit_debug_code()) { 1672 andi(r0, result_end, Operand(kObjectAlignmentMask)); 1673 Check(eq, kUnalignedAllocationInNewSpace, cr0); 1674 } 1675 StoreP(result_end, MemOperand(top_address)); 1676 1677 // Tag object if requested. 1678 if ((flags & TAG_OBJECT) != 0) { 1679 addi(result, result, Operand(kHeapObjectTag)); 1680 } 1681 } 1682 1683 1684 void MacroAssembler::AllocateTwoByteString(Register result, Register length, 1685 Register scratch1, Register scratch2, 1686 Register scratch3, 1687 Label* gc_required) { 1688 // Calculate the number of bytes needed for the characters in the string while 1689 // observing object alignment. 1690 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); 1691 slwi(scratch1, length, Operand(1)); // Length in bytes, not chars. 1692 addi(scratch1, scratch1, 1693 Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize)); 1694 mov(r0, Operand(~kObjectAlignmentMask)); 1695 and_(scratch1, scratch1, r0); 1696 1697 // Allocate two-byte string in new space. 1698 Allocate(scratch1, result, scratch2, scratch3, gc_required, TAG_OBJECT); 1699 1700 // Set the map, length and hash field. 1701 InitializeNewString(result, length, Heap::kStringMapRootIndex, scratch1, 1702 scratch2); 1703 } 1704 1705 1706 void MacroAssembler::AllocateOneByteString(Register result, Register length, 1707 Register scratch1, Register scratch2, 1708 Register scratch3, 1709 Label* gc_required) { 1710 // Calculate the number of bytes needed for the characters in the string while 1711 // observing object alignment. 1712 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); 1713 DCHECK(kCharSize == 1); 1714 addi(scratch1, length, 1715 Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize)); 1716 li(r0, Operand(~kObjectAlignmentMask)); 1717 and_(scratch1, scratch1, r0); 1718 1719 // Allocate one-byte string in new space. 1720 Allocate(scratch1, result, scratch2, scratch3, gc_required, TAG_OBJECT); 1721 1722 // Set the map, length and hash field. 1723 InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex, 1724 scratch1, scratch2); 1725 } 1726 1727 1728 void MacroAssembler::AllocateTwoByteConsString(Register result, Register length, 1729 Register scratch1, 1730 Register scratch2, 1731 Label* gc_required) { 1732 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, 1733 TAG_OBJECT); 1734 1735 InitializeNewString(result, length, Heap::kConsStringMapRootIndex, scratch1, 1736 scratch2); 1737 } 1738 1739 1740 void MacroAssembler::AllocateOneByteConsString(Register result, Register length, 1741 Register scratch1, 1742 Register scratch2, 1743 Label* gc_required) { 1744 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, 1745 TAG_OBJECT); 1746 1747 InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex, 1748 scratch1, scratch2); 1749 } 1750 1751 1752 void MacroAssembler::AllocateTwoByteSlicedString(Register result, 1753 Register length, 1754 Register scratch1, 1755 Register scratch2, 1756 Label* gc_required) { 1757 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, 1758 TAG_OBJECT); 1759 1760 InitializeNewString(result, length, Heap::kSlicedStringMapRootIndex, scratch1, 1761 scratch2); 1762 } 1763 1764 1765 void MacroAssembler::AllocateOneByteSlicedString(Register result, 1766 Register length, 1767 Register scratch1, 1768 Register scratch2, 1769 Label* gc_required) { 1770 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, 1771 TAG_OBJECT); 1772 1773 InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex, 1774 scratch1, scratch2); 1775 } 1776 1777 1778 void MacroAssembler::CompareObjectType(Register object, Register map, 1779 Register type_reg, InstanceType type) { 1780 const Register temp = type_reg.is(no_reg) ? r0 : type_reg; 1781 1782 LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset)); 1783 CompareInstanceType(map, temp, type); 1784 } 1785 1786 1787 void MacroAssembler::CompareInstanceType(Register map, Register type_reg, 1788 InstanceType type) { 1789 STATIC_ASSERT(Map::kInstanceTypeOffset < 4096); 1790 STATIC_ASSERT(LAST_TYPE < 256); 1791 lbz(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); 1792 cmpi(type_reg, Operand(type)); 1793 } 1794 1795 1796 void MacroAssembler::CompareRoot(Register obj, Heap::RootListIndex index) { 1797 DCHECK(!obj.is(r0)); 1798 LoadRoot(r0, index); 1799 cmp(obj, r0); 1800 } 1801 1802 1803 void MacroAssembler::CheckFastElements(Register map, Register scratch, 1804 Label* fail) { 1805 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 1806 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 1807 STATIC_ASSERT(FAST_ELEMENTS == 2); 1808 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); 1809 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset)); 1810 STATIC_ASSERT(Map::kMaximumBitField2FastHoleyElementValue < 0x8000); 1811 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue)); 1812 bgt(fail); 1813 } 1814 1815 1816 void MacroAssembler::CheckFastObjectElements(Register map, Register scratch, 1817 Label* fail) { 1818 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 1819 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 1820 STATIC_ASSERT(FAST_ELEMENTS == 2); 1821 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); 1822 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset)); 1823 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue)); 1824 ble(fail); 1825 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue)); 1826 bgt(fail); 1827 } 1828 1829 1830 void MacroAssembler::CheckFastSmiElements(Register map, Register scratch, 1831 Label* fail) { 1832 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 1833 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 1834 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset)); 1835 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue)); 1836 bgt(fail); 1837 } 1838 1839 1840 void MacroAssembler::StoreNumberToDoubleElements( 1841 Register value_reg, Register key_reg, Register elements_reg, 1842 Register scratch1, DoubleRegister double_scratch, Label* fail, 1843 int elements_offset) { 1844 DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1)); 1845 Label smi_value, store; 1846 1847 // Handle smi values specially. 1848 JumpIfSmi(value_reg, &smi_value); 1849 1850 // Ensure that the object is a heap number 1851 CheckMap(value_reg, scratch1, isolate()->factory()->heap_number_map(), fail, 1852 DONT_DO_SMI_CHECK); 1853 1854 lfd(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); 1855 // Double value, turn potential sNaN into qNaN. 1856 CanonicalizeNaN(double_scratch); 1857 b(&store); 1858 1859 bind(&smi_value); 1860 SmiToDouble(double_scratch, value_reg); 1861 1862 bind(&store); 1863 SmiToDoubleArrayOffset(scratch1, key_reg); 1864 add(scratch1, elements_reg, scratch1); 1865 stfd(double_scratch, FieldMemOperand(scratch1, FixedDoubleArray::kHeaderSize - 1866 elements_offset)); 1867 } 1868 1869 1870 void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left, 1871 Register right, 1872 Register overflow_dst, 1873 Register scratch) { 1874 DCHECK(!dst.is(overflow_dst)); 1875 DCHECK(!dst.is(scratch)); 1876 DCHECK(!overflow_dst.is(scratch)); 1877 DCHECK(!overflow_dst.is(left)); 1878 DCHECK(!overflow_dst.is(right)); 1879 1880 bool left_is_right = left.is(right); 1881 RCBit xorRC = left_is_right ? SetRC : LeaveRC; 1882 1883 // C = A+B; C overflows if A/B have same sign and C has diff sign than A 1884 if (dst.is(left)) { 1885 mr(scratch, left); // Preserve left. 1886 add(dst, left, right); // Left is overwritten. 1887 xor_(overflow_dst, dst, scratch, xorRC); // Original left. 1888 if (!left_is_right) xor_(scratch, dst, right); 1889 } else if (dst.is(right)) { 1890 mr(scratch, right); // Preserve right. 1891 add(dst, left, right); // Right is overwritten. 1892 xor_(overflow_dst, dst, left, xorRC); 1893 if (!left_is_right) xor_(scratch, dst, scratch); // Original right. 1894 } else { 1895 add(dst, left, right); 1896 xor_(overflow_dst, dst, left, xorRC); 1897 if (!left_is_right) xor_(scratch, dst, right); 1898 } 1899 if (!left_is_right) and_(overflow_dst, scratch, overflow_dst, SetRC); 1900 } 1901 1902 1903 void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left, 1904 intptr_t right, 1905 Register overflow_dst, 1906 Register scratch) { 1907 Register original_left = left; 1908 DCHECK(!dst.is(overflow_dst)); 1909 DCHECK(!dst.is(scratch)); 1910 DCHECK(!overflow_dst.is(scratch)); 1911 DCHECK(!overflow_dst.is(left)); 1912 1913 // C = A+B; C overflows if A/B have same sign and C has diff sign than A 1914 if (dst.is(left)) { 1915 // Preserve left. 1916 original_left = overflow_dst; 1917 mr(original_left, left); 1918 } 1919 Add(dst, left, right, scratch); 1920 xor_(overflow_dst, dst, original_left); 1921 if (right >= 0) { 1922 and_(overflow_dst, overflow_dst, dst, SetRC); 1923 } else { 1924 andc(overflow_dst, overflow_dst, dst, SetRC); 1925 } 1926 } 1927 1928 1929 void MacroAssembler::SubAndCheckForOverflow(Register dst, Register left, 1930 Register right, 1931 Register overflow_dst, 1932 Register scratch) { 1933 DCHECK(!dst.is(overflow_dst)); 1934 DCHECK(!dst.is(scratch)); 1935 DCHECK(!overflow_dst.is(scratch)); 1936 DCHECK(!overflow_dst.is(left)); 1937 DCHECK(!overflow_dst.is(right)); 1938 1939 // C = A-B; C overflows if A/B have diff signs and C has diff sign than A 1940 if (dst.is(left)) { 1941 mr(scratch, left); // Preserve left. 1942 sub(dst, left, right); // Left is overwritten. 1943 xor_(overflow_dst, dst, scratch); 1944 xor_(scratch, scratch, right); 1945 and_(overflow_dst, overflow_dst, scratch, SetRC); 1946 } else if (dst.is(right)) { 1947 mr(scratch, right); // Preserve right. 1948 sub(dst, left, right); // Right is overwritten. 1949 xor_(overflow_dst, dst, left); 1950 xor_(scratch, left, scratch); 1951 and_(overflow_dst, overflow_dst, scratch, SetRC); 1952 } else { 1953 sub(dst, left, right); 1954 xor_(overflow_dst, dst, left); 1955 xor_(scratch, left, right); 1956 and_(overflow_dst, scratch, overflow_dst, SetRC); 1957 } 1958 } 1959 1960 1961 void MacroAssembler::CompareMap(Register obj, Register scratch, Handle<Map> map, 1962 Label* early_success) { 1963 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); 1964 CompareMap(scratch, map, early_success); 1965 } 1966 1967 1968 void MacroAssembler::CompareMap(Register obj_map, Handle<Map> map, 1969 Label* early_success) { 1970 mov(r0, Operand(map)); 1971 cmp(obj_map, r0); 1972 } 1973 1974 1975 void MacroAssembler::CheckMap(Register obj, Register scratch, Handle<Map> map, 1976 Label* fail, SmiCheckType smi_check_type) { 1977 if (smi_check_type == DO_SMI_CHECK) { 1978 JumpIfSmi(obj, fail); 1979 } 1980 1981 Label success; 1982 CompareMap(obj, scratch, map, &success); 1983 bne(fail); 1984 bind(&success); 1985 } 1986 1987 1988 void MacroAssembler::CheckMap(Register obj, Register scratch, 1989 Heap::RootListIndex index, Label* fail, 1990 SmiCheckType smi_check_type) { 1991 if (smi_check_type == DO_SMI_CHECK) { 1992 JumpIfSmi(obj, fail); 1993 } 1994 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); 1995 LoadRoot(r0, index); 1996 cmp(scratch, r0); 1997 bne(fail); 1998 } 1999 2000 2001 void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1, 2002 Register scratch2, Handle<WeakCell> cell, 2003 Handle<Code> success, 2004 SmiCheckType smi_check_type) { 2005 Label fail; 2006 if (smi_check_type == DO_SMI_CHECK) { 2007 JumpIfSmi(obj, &fail); 2008 } 2009 LoadP(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset)); 2010 CmpWeakValue(scratch1, cell, scratch2); 2011 Jump(success, RelocInfo::CODE_TARGET, eq); 2012 bind(&fail); 2013 } 2014 2015 2016 void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell, 2017 Register scratch, CRegister cr) { 2018 mov(scratch, Operand(cell)); 2019 LoadP(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset)); 2020 cmp(value, scratch, cr); 2021 } 2022 2023 2024 void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) { 2025 mov(value, Operand(cell)); 2026 LoadP(value, FieldMemOperand(value, WeakCell::kValueOffset)); 2027 } 2028 2029 2030 void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell, 2031 Label* miss) { 2032 GetWeakValue(value, cell); 2033 JumpIfSmi(value, miss); 2034 } 2035 2036 2037 void MacroAssembler::GetMapConstructor(Register result, Register map, 2038 Register temp, Register temp2) { 2039 Label done, loop; 2040 LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); 2041 bind(&loop); 2042 JumpIfSmi(result, &done); 2043 CompareObjectType(result, temp, temp2, MAP_TYPE); 2044 bne(&done); 2045 LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); 2046 b(&loop); 2047 bind(&done); 2048 } 2049 2050 2051 void MacroAssembler::TryGetFunctionPrototype(Register function, Register result, 2052 Register scratch, Label* miss) { 2053 // Get the prototype or initial map from the function. 2054 LoadP(result, 2055 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 2056 2057 // If the prototype or initial map is the hole, don't return it and 2058 // simply miss the cache instead. This will allow us to allocate a 2059 // prototype object on-demand in the runtime system. 2060 LoadRoot(r0, Heap::kTheHoleValueRootIndex); 2061 cmp(result, r0); 2062 beq(miss); 2063 2064 // If the function does not have an initial map, we're done. 2065 Label done; 2066 CompareObjectType(result, scratch, scratch, MAP_TYPE); 2067 bne(&done); 2068 2069 // Get the prototype from the initial map. 2070 LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset)); 2071 2072 // All done. 2073 bind(&done); 2074 } 2075 2076 2077 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id, 2078 Condition cond) { 2079 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. 2080 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond); 2081 } 2082 2083 2084 void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) { 2085 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond); 2086 } 2087 2088 2089 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { 2090 return has_frame_ || !stub->SometimesSetsUpAFrame(); 2091 } 2092 2093 2094 void MacroAssembler::IndexFromHash(Register hash, Register index) { 2095 // If the hash field contains an array index pick it out. The assert checks 2096 // that the constants for the maximum number of digits for an array index 2097 // cached in the hash field and the number of bits reserved for it does not 2098 // conflict. 2099 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < 2100 (1 << String::kArrayIndexValueBits)); 2101 DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash); 2102 } 2103 2104 2105 void MacroAssembler::SmiToDouble(DoubleRegister value, Register smi) { 2106 SmiUntag(ip, smi); 2107 ConvertIntToDouble(ip, value); 2108 } 2109 2110 2111 void MacroAssembler::TestDoubleIsInt32(DoubleRegister double_input, 2112 Register scratch1, Register scratch2, 2113 DoubleRegister double_scratch) { 2114 TryDoubleToInt32Exact(scratch1, double_input, scratch2, double_scratch); 2115 } 2116 2117 2118 void MacroAssembler::TryDoubleToInt32Exact(Register result, 2119 DoubleRegister double_input, 2120 Register scratch, 2121 DoubleRegister double_scratch) { 2122 Label done; 2123 DCHECK(!double_input.is(double_scratch)); 2124 2125 ConvertDoubleToInt64(double_input, 2126 #if !V8_TARGET_ARCH_PPC64 2127 scratch, 2128 #endif 2129 result, double_scratch); 2130 2131 #if V8_TARGET_ARCH_PPC64 2132 TestIfInt32(result, r0); 2133 #else 2134 TestIfInt32(scratch, result, r0); 2135 #endif 2136 bne(&done); 2137 2138 // convert back and compare 2139 fcfid(double_scratch, double_scratch); 2140 fcmpu(double_scratch, double_input); 2141 bind(&done); 2142 } 2143 2144 2145 void MacroAssembler::TryInt32Floor(Register result, DoubleRegister double_input, 2146 Register input_high, Register scratch, 2147 DoubleRegister double_scratch, Label* done, 2148 Label* exact) { 2149 DCHECK(!result.is(input_high)); 2150 DCHECK(!double_input.is(double_scratch)); 2151 Label exception; 2152 2153 MovDoubleHighToInt(input_high, double_input); 2154 2155 // Test for NaN/Inf 2156 ExtractBitMask(result, input_high, HeapNumber::kExponentMask); 2157 cmpli(result, Operand(0x7ff)); 2158 beq(&exception); 2159 2160 // Convert (rounding to -Inf) 2161 ConvertDoubleToInt64(double_input, 2162 #if !V8_TARGET_ARCH_PPC64 2163 scratch, 2164 #endif 2165 result, double_scratch, kRoundToMinusInf); 2166 2167 // Test for overflow 2168 #if V8_TARGET_ARCH_PPC64 2169 TestIfInt32(result, r0); 2170 #else 2171 TestIfInt32(scratch, result, r0); 2172 #endif 2173 bne(&exception); 2174 2175 // Test for exactness 2176 fcfid(double_scratch, double_scratch); 2177 fcmpu(double_scratch, double_input); 2178 beq(exact); 2179 b(done); 2180 2181 bind(&exception); 2182 } 2183 2184 2185 void MacroAssembler::TryInlineTruncateDoubleToI(Register result, 2186 DoubleRegister double_input, 2187 Label* done) { 2188 DoubleRegister double_scratch = kScratchDoubleReg; 2189 #if !V8_TARGET_ARCH_PPC64 2190 Register scratch = ip; 2191 #endif 2192 2193 ConvertDoubleToInt64(double_input, 2194 #if !V8_TARGET_ARCH_PPC64 2195 scratch, 2196 #endif 2197 result, double_scratch); 2198 2199 // Test for overflow 2200 #if V8_TARGET_ARCH_PPC64 2201 TestIfInt32(result, r0); 2202 #else 2203 TestIfInt32(scratch, result, r0); 2204 #endif 2205 beq(done); 2206 } 2207 2208 2209 void MacroAssembler::TruncateDoubleToI(Register result, 2210 DoubleRegister double_input) { 2211 Label done; 2212 2213 TryInlineTruncateDoubleToI(result, double_input, &done); 2214 2215 // If we fell through then inline version didn't succeed - call stub instead. 2216 mflr(r0); 2217 push(r0); 2218 // Put input on stack. 2219 stfdu(double_input, MemOperand(sp, -kDoubleSize)); 2220 2221 DoubleToIStub stub(isolate(), sp, result, 0, true, true); 2222 CallStub(&stub); 2223 2224 addi(sp, sp, Operand(kDoubleSize)); 2225 pop(r0); 2226 mtlr(r0); 2227 2228 bind(&done); 2229 } 2230 2231 2232 void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) { 2233 Label done; 2234 DoubleRegister double_scratch = kScratchDoubleReg; 2235 DCHECK(!result.is(object)); 2236 2237 lfd(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset)); 2238 TryInlineTruncateDoubleToI(result, double_scratch, &done); 2239 2240 // If we fell through then inline version didn't succeed - call stub instead. 2241 mflr(r0); 2242 push(r0); 2243 DoubleToIStub stub(isolate(), object, result, 2244 HeapNumber::kValueOffset - kHeapObjectTag, true, true); 2245 CallStub(&stub); 2246 pop(r0); 2247 mtlr(r0); 2248 2249 bind(&done); 2250 } 2251 2252 2253 void MacroAssembler::TruncateNumberToI(Register object, Register result, 2254 Register heap_number_map, 2255 Register scratch1, Label* not_number) { 2256 Label done; 2257 DCHECK(!result.is(object)); 2258 2259 UntagAndJumpIfSmi(result, object, &done); 2260 JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); 2261 TruncateHeapNumberToI(result, object); 2262 2263 bind(&done); 2264 } 2265 2266 2267 void MacroAssembler::GetLeastBitsFromSmi(Register dst, Register src, 2268 int num_least_bits) { 2269 #if V8_TARGET_ARCH_PPC64 2270 rldicl(dst, src, kBitsPerPointer - kSmiShift, 2271 kBitsPerPointer - num_least_bits); 2272 #else 2273 rlwinm(dst, src, kBitsPerPointer - kSmiShift, 2274 kBitsPerPointer - num_least_bits, 31); 2275 #endif 2276 } 2277 2278 2279 void MacroAssembler::GetLeastBitsFromInt32(Register dst, Register src, 2280 int num_least_bits) { 2281 rlwinm(dst, src, 0, 32 - num_least_bits, 31); 2282 } 2283 2284 2285 void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments, 2286 SaveFPRegsMode save_doubles) { 2287 // All parameters are on the stack. r3 has the return value after call. 2288 2289 // If the expected number of arguments of the runtime function is 2290 // constant, we check that the actual number of arguments match the 2291 // expectation. 2292 CHECK(f->nargs < 0 || f->nargs == num_arguments); 2293 2294 // TODO(1236192): Most runtime routines don't need the number of 2295 // arguments passed in because it is constant. At some point we 2296 // should remove this need and make the runtime routine entry code 2297 // smarter. 2298 mov(r3, Operand(num_arguments)); 2299 mov(r4, Operand(ExternalReference(f, isolate()))); 2300 CEntryStub stub(isolate(), 2301 #if V8_TARGET_ARCH_PPC64 2302 f->result_size, 2303 #else 2304 1, 2305 #endif 2306 save_doubles); 2307 CallStub(&stub); 2308 } 2309 2310 2311 void MacroAssembler::CallExternalReference(const ExternalReference& ext, 2312 int num_arguments) { 2313 mov(r3, Operand(num_arguments)); 2314 mov(r4, Operand(ext)); 2315 2316 CEntryStub stub(isolate(), 1); 2317 CallStub(&stub); 2318 } 2319 2320 2321 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { 2322 const Runtime::Function* function = Runtime::FunctionForId(fid); 2323 DCHECK_EQ(1, function->result_size); 2324 if (function->nargs >= 0) { 2325 mov(r3, Operand(function->nargs)); 2326 } 2327 JumpToExternalReference(ExternalReference(fid, isolate())); 2328 } 2329 2330 2331 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) { 2332 mov(r4, Operand(builtin)); 2333 CEntryStub stub(isolate(), 1); 2334 Jump(stub.GetCode(), RelocInfo::CODE_TARGET); 2335 } 2336 2337 2338 void MacroAssembler::InvokeBuiltin(int native_context_index, InvokeFlag flag, 2339 const CallWrapper& call_wrapper) { 2340 // You can't call a builtin without a valid frame. 2341 DCHECK(flag == JUMP_FUNCTION || has_frame()); 2342 2343 // Fake a parameter count to avoid emitting code to do the check. 2344 ParameterCount expected(0); 2345 LoadNativeContextSlot(native_context_index, r4); 2346 InvokeFunctionCode(r4, no_reg, expected, expected, flag, call_wrapper); 2347 } 2348 2349 2350 void MacroAssembler::SetCounter(StatsCounter* counter, int value, 2351 Register scratch1, Register scratch2) { 2352 if (FLAG_native_code_counters && counter->Enabled()) { 2353 mov(scratch1, Operand(value)); 2354 mov(scratch2, Operand(ExternalReference(counter))); 2355 stw(scratch1, MemOperand(scratch2)); 2356 } 2357 } 2358 2359 2360 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value, 2361 Register scratch1, Register scratch2) { 2362 DCHECK(value > 0); 2363 if (FLAG_native_code_counters && counter->Enabled()) { 2364 mov(scratch2, Operand(ExternalReference(counter))); 2365 lwz(scratch1, MemOperand(scratch2)); 2366 addi(scratch1, scratch1, Operand(value)); 2367 stw(scratch1, MemOperand(scratch2)); 2368 } 2369 } 2370 2371 2372 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, 2373 Register scratch1, Register scratch2) { 2374 DCHECK(value > 0); 2375 if (FLAG_native_code_counters && counter->Enabled()) { 2376 mov(scratch2, Operand(ExternalReference(counter))); 2377 lwz(scratch1, MemOperand(scratch2)); 2378 subi(scratch1, scratch1, Operand(value)); 2379 stw(scratch1, MemOperand(scratch2)); 2380 } 2381 } 2382 2383 2384 void MacroAssembler::Assert(Condition cond, BailoutReason reason, 2385 CRegister cr) { 2386 if (emit_debug_code()) Check(cond, reason, cr); 2387 } 2388 2389 2390 void MacroAssembler::AssertFastElements(Register elements) { 2391 if (emit_debug_code()) { 2392 DCHECK(!elements.is(r0)); 2393 Label ok; 2394 push(elements); 2395 LoadP(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); 2396 LoadRoot(r0, Heap::kFixedArrayMapRootIndex); 2397 cmp(elements, r0); 2398 beq(&ok); 2399 LoadRoot(r0, Heap::kFixedDoubleArrayMapRootIndex); 2400 cmp(elements, r0); 2401 beq(&ok); 2402 LoadRoot(r0, Heap::kFixedCOWArrayMapRootIndex); 2403 cmp(elements, r0); 2404 beq(&ok); 2405 Abort(kJSObjectWithFastElementsMapHasSlowElements); 2406 bind(&ok); 2407 pop(elements); 2408 } 2409 } 2410 2411 2412 void MacroAssembler::Check(Condition cond, BailoutReason reason, CRegister cr) { 2413 Label L; 2414 b(cond, &L, cr); 2415 Abort(reason); 2416 // will not return here 2417 bind(&L); 2418 } 2419 2420 2421 void MacroAssembler::Abort(BailoutReason reason) { 2422 Label abort_start; 2423 bind(&abort_start); 2424 #ifdef DEBUG 2425 const char* msg = GetBailoutReason(reason); 2426 if (msg != NULL) { 2427 RecordComment("Abort message: "); 2428 RecordComment(msg); 2429 } 2430 2431 if (FLAG_trap_on_abort) { 2432 stop(msg); 2433 return; 2434 } 2435 #endif 2436 2437 LoadSmiLiteral(r0, Smi::FromInt(reason)); 2438 push(r0); 2439 // Disable stub call restrictions to always allow calls to abort. 2440 if (!has_frame_) { 2441 // We don't actually want to generate a pile of code for this, so just 2442 // claim there is a stack frame, without generating one. 2443 FrameScope scope(this, StackFrame::NONE); 2444 CallRuntime(Runtime::kAbort, 1); 2445 } else { 2446 CallRuntime(Runtime::kAbort, 1); 2447 } 2448 // will not return here 2449 } 2450 2451 2452 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { 2453 if (context_chain_length > 0) { 2454 // Move up the chain of contexts to the context containing the slot. 2455 LoadP(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX))); 2456 for (int i = 1; i < context_chain_length; i++) { 2457 LoadP(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); 2458 } 2459 } else { 2460 // Slot is in the current function context. Move it into the 2461 // destination register in case we store into it (the write barrier 2462 // cannot be allowed to destroy the context in esi). 2463 mr(dst, cp); 2464 } 2465 } 2466 2467 2468 void MacroAssembler::LoadTransitionedArrayMapConditional( 2469 ElementsKind expected_kind, ElementsKind transitioned_kind, 2470 Register map_in_out, Register scratch, Label* no_map_match) { 2471 DCHECK(IsFastElementsKind(expected_kind)); 2472 DCHECK(IsFastElementsKind(transitioned_kind)); 2473 2474 // Check that the function's map is the same as the expected cached map. 2475 LoadP(scratch, NativeContextMemOperand()); 2476 LoadP(ip, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind))); 2477 cmp(map_in_out, ip); 2478 bne(no_map_match); 2479 2480 // Use the transitioned cached map. 2481 LoadP(map_in_out, 2482 ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind))); 2483 } 2484 2485 2486 void MacroAssembler::LoadNativeContextSlot(int index, Register dst) { 2487 LoadP(dst, NativeContextMemOperand()); 2488 LoadP(dst, ContextMemOperand(dst, index)); 2489 } 2490 2491 2492 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, 2493 Register map, 2494 Register scratch) { 2495 // Load the initial map. The global functions all have initial maps. 2496 LoadP(map, 2497 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 2498 if (emit_debug_code()) { 2499 Label ok, fail; 2500 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); 2501 b(&ok); 2502 bind(&fail); 2503 Abort(kGlobalFunctionsMustHaveInitialMap); 2504 bind(&ok); 2505 } 2506 } 2507 2508 2509 void MacroAssembler::JumpIfNotPowerOfTwoOrZero( 2510 Register reg, Register scratch, Label* not_power_of_two_or_zero) { 2511 subi(scratch, reg, Operand(1)); 2512 cmpi(scratch, Operand::Zero()); 2513 blt(not_power_of_two_or_zero); 2514 and_(r0, scratch, reg, SetRC); 2515 bne(not_power_of_two_or_zero, cr0); 2516 } 2517 2518 2519 void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg, 2520 Register scratch, 2521 Label* zero_and_neg, 2522 Label* not_power_of_two) { 2523 subi(scratch, reg, Operand(1)); 2524 cmpi(scratch, Operand::Zero()); 2525 blt(zero_and_neg); 2526 and_(r0, scratch, reg, SetRC); 2527 bne(not_power_of_two, cr0); 2528 } 2529 2530 #if !V8_TARGET_ARCH_PPC64 2531 void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) { 2532 DCHECK(!reg.is(overflow)); 2533 mr(overflow, reg); // Save original value. 2534 SmiTag(reg); 2535 xor_(overflow, overflow, reg, SetRC); // Overflow if (value ^ 2 * value) < 0. 2536 } 2537 2538 2539 void MacroAssembler::SmiTagCheckOverflow(Register dst, Register src, 2540 Register overflow) { 2541 if (dst.is(src)) { 2542 // Fall back to slower case. 2543 SmiTagCheckOverflow(dst, overflow); 2544 } else { 2545 DCHECK(!dst.is(src)); 2546 DCHECK(!dst.is(overflow)); 2547 DCHECK(!src.is(overflow)); 2548 SmiTag(dst, src); 2549 xor_(overflow, dst, src, SetRC); // Overflow if (value ^ 2 * value) < 0. 2550 } 2551 } 2552 #endif 2553 2554 void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2, 2555 Label* on_not_both_smi) { 2556 STATIC_ASSERT(kSmiTag == 0); 2557 orx(r0, reg1, reg2, LeaveRC); 2558 JumpIfNotSmi(r0, on_not_both_smi); 2559 } 2560 2561 2562 void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src, 2563 Label* smi_case) { 2564 STATIC_ASSERT(kSmiTag == 0); 2565 TestBitRange(src, kSmiTagSize - 1, 0, r0); 2566 SmiUntag(dst, src); 2567 beq(smi_case, cr0); 2568 } 2569 2570 2571 void MacroAssembler::UntagAndJumpIfNotSmi(Register dst, Register src, 2572 Label* non_smi_case) { 2573 STATIC_ASSERT(kSmiTag == 0); 2574 TestBitRange(src, kSmiTagSize - 1, 0, r0); 2575 SmiUntag(dst, src); 2576 bne(non_smi_case, cr0); 2577 } 2578 2579 2580 void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2, 2581 Label* on_either_smi) { 2582 STATIC_ASSERT(kSmiTag == 0); 2583 JumpIfSmi(reg1, on_either_smi); 2584 JumpIfSmi(reg2, on_either_smi); 2585 } 2586 2587 2588 void MacroAssembler::AssertNotSmi(Register object) { 2589 if (emit_debug_code()) { 2590 STATIC_ASSERT(kSmiTag == 0); 2591 TestIfSmi(object, r0); 2592 Check(ne, kOperandIsASmi, cr0); 2593 } 2594 } 2595 2596 2597 void MacroAssembler::AssertSmi(Register object) { 2598 if (emit_debug_code()) { 2599 STATIC_ASSERT(kSmiTag == 0); 2600 TestIfSmi(object, r0); 2601 Check(eq, kOperandIsNotSmi, cr0); 2602 } 2603 } 2604 2605 2606 void MacroAssembler::AssertString(Register object) { 2607 if (emit_debug_code()) { 2608 STATIC_ASSERT(kSmiTag == 0); 2609 TestIfSmi(object, r0); 2610 Check(ne, kOperandIsASmiAndNotAString, cr0); 2611 push(object); 2612 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset)); 2613 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); 2614 pop(object); 2615 Check(lt, kOperandIsNotAString); 2616 } 2617 } 2618 2619 2620 void MacroAssembler::AssertName(Register object) { 2621 if (emit_debug_code()) { 2622 STATIC_ASSERT(kSmiTag == 0); 2623 TestIfSmi(object, r0); 2624 Check(ne, kOperandIsASmiAndNotAName, cr0); 2625 push(object); 2626 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset)); 2627 CompareInstanceType(object, object, LAST_NAME_TYPE); 2628 pop(object); 2629 Check(le, kOperandIsNotAName); 2630 } 2631 } 2632 2633 2634 void MacroAssembler::AssertFunction(Register object) { 2635 if (emit_debug_code()) { 2636 STATIC_ASSERT(kSmiTag == 0); 2637 TestIfSmi(object, r0); 2638 Check(ne, kOperandIsASmiAndNotAFunction, cr0); 2639 push(object); 2640 CompareObjectType(object, object, object, JS_FUNCTION_TYPE); 2641 pop(object); 2642 Check(eq, kOperandIsNotAFunction); 2643 } 2644 } 2645 2646 2647 void MacroAssembler::AssertBoundFunction(Register object) { 2648 if (emit_debug_code()) { 2649 STATIC_ASSERT(kSmiTag == 0); 2650 TestIfSmi(object, r0); 2651 Check(ne, kOperandIsASmiAndNotABoundFunction, cr0); 2652 push(object); 2653 CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE); 2654 pop(object); 2655 Check(eq, kOperandIsNotABoundFunction); 2656 } 2657 } 2658 2659 2660 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object, 2661 Register scratch) { 2662 if (emit_debug_code()) { 2663 Label done_checking; 2664 AssertNotSmi(object); 2665 CompareRoot(object, Heap::kUndefinedValueRootIndex); 2666 beq(&done_checking); 2667 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 2668 CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex); 2669 Assert(eq, kExpectedUndefinedOrCell); 2670 bind(&done_checking); 2671 } 2672 } 2673 2674 2675 void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) { 2676 if (emit_debug_code()) { 2677 CompareRoot(reg, index); 2678 Check(eq, kHeapNumberMapRegisterClobbered); 2679 } 2680 } 2681 2682 2683 void MacroAssembler::JumpIfNotHeapNumber(Register object, 2684 Register heap_number_map, 2685 Register scratch, 2686 Label* on_not_heap_number) { 2687 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 2688 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 2689 cmp(scratch, heap_number_map); 2690 bne(on_not_heap_number); 2691 } 2692 2693 2694 void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings( 2695 Register first, Register second, Register scratch1, Register scratch2, 2696 Label* failure) { 2697 // Test that both first and second are sequential one-byte strings. 2698 // Assume that they are non-smis. 2699 LoadP(scratch1, FieldMemOperand(first, HeapObject::kMapOffset)); 2700 LoadP(scratch2, FieldMemOperand(second, HeapObject::kMapOffset)); 2701 lbz(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); 2702 lbz(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset)); 2703 2704 JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1, 2705 scratch2, failure); 2706 } 2707 2708 void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first, 2709 Register second, 2710 Register scratch1, 2711 Register scratch2, 2712 Label* failure) { 2713 // Check that neither is a smi. 2714 and_(scratch1, first, second); 2715 JumpIfSmi(scratch1, failure); 2716 JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1, 2717 scratch2, failure); 2718 } 2719 2720 2721 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg, 2722 Label* not_unique_name) { 2723 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); 2724 Label succeed; 2725 andi(r0, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask)); 2726 beq(&succeed, cr0); 2727 cmpi(reg, Operand(SYMBOL_TYPE)); 2728 bne(not_unique_name); 2729 2730 bind(&succeed); 2731 } 2732 2733 2734 // Allocates a heap number or jumps to the need_gc label if the young space 2735 // is full and a scavenge is needed. 2736 void MacroAssembler::AllocateHeapNumber(Register result, Register scratch1, 2737 Register scratch2, 2738 Register heap_number_map, 2739 Label* gc_required, 2740 TaggingMode tagging_mode, 2741 MutableMode mode) { 2742 // Allocate an object in the heap for the heap number and tag it as a heap 2743 // object. 2744 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required, 2745 tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS); 2746 2747 Heap::RootListIndex map_index = mode == MUTABLE 2748 ? Heap::kMutableHeapNumberMapRootIndex 2749 : Heap::kHeapNumberMapRootIndex; 2750 AssertIsRoot(heap_number_map, map_index); 2751 2752 // Store heap number map in the allocated object. 2753 if (tagging_mode == TAG_RESULT) { 2754 StoreP(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset), 2755 r0); 2756 } else { 2757 StoreP(heap_number_map, MemOperand(result, HeapObject::kMapOffset)); 2758 } 2759 } 2760 2761 2762 void MacroAssembler::AllocateHeapNumberWithValue( 2763 Register result, DoubleRegister value, Register scratch1, Register scratch2, 2764 Register heap_number_map, Label* gc_required) { 2765 AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required); 2766 stfd(value, FieldMemOperand(result, HeapNumber::kValueOffset)); 2767 } 2768 2769 2770 void MacroAssembler::AllocateJSValue(Register result, Register constructor, 2771 Register value, Register scratch1, 2772 Register scratch2, Label* gc_required) { 2773 DCHECK(!result.is(constructor)); 2774 DCHECK(!result.is(scratch1)); 2775 DCHECK(!result.is(scratch2)); 2776 DCHECK(!result.is(value)); 2777 2778 // Allocate JSValue in new space. 2779 Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT); 2780 2781 // Initialize the JSValue. 2782 LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2); 2783 StoreP(scratch1, FieldMemOperand(result, HeapObject::kMapOffset), r0); 2784 LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex); 2785 StoreP(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset), r0); 2786 StoreP(scratch1, FieldMemOperand(result, JSObject::kElementsOffset), r0); 2787 StoreP(value, FieldMemOperand(result, JSValue::kValueOffset), r0); 2788 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); 2789 } 2790 2791 2792 void MacroAssembler::CopyBytes(Register src, Register dst, Register length, 2793 Register scratch) { 2794 Label align_loop, aligned, word_loop, byte_loop, byte_loop_1, done; 2795 2796 DCHECK(!scratch.is(r0)); 2797 2798 cmpi(length, Operand::Zero()); 2799 beq(&done); 2800 2801 // Check src alignment and length to see whether word_loop is possible 2802 andi(scratch, src, Operand(kPointerSize - 1)); 2803 beq(&aligned, cr0); 2804 subfic(scratch, scratch, Operand(kPointerSize * 2)); 2805 cmp(length, scratch); 2806 blt(&byte_loop); 2807 2808 // Align src before copying in word size chunks. 2809 subi(scratch, scratch, Operand(kPointerSize)); 2810 mtctr(scratch); 2811 bind(&align_loop); 2812 lbz(scratch, MemOperand(src)); 2813 addi(src, src, Operand(1)); 2814 subi(length, length, Operand(1)); 2815 stb(scratch, MemOperand(dst)); 2816 addi(dst, dst, Operand(1)); 2817 bdnz(&align_loop); 2818 2819 bind(&aligned); 2820 2821 // Copy bytes in word size chunks. 2822 if (emit_debug_code()) { 2823 andi(r0, src, Operand(kPointerSize - 1)); 2824 Assert(eq, kExpectingAlignmentForCopyBytes, cr0); 2825 } 2826 2827 ShiftRightImm(scratch, length, Operand(kPointerSizeLog2)); 2828 cmpi(scratch, Operand::Zero()); 2829 beq(&byte_loop); 2830 2831 mtctr(scratch); 2832 bind(&word_loop); 2833 LoadP(scratch, MemOperand(src)); 2834 addi(src, src, Operand(kPointerSize)); 2835 subi(length, length, Operand(kPointerSize)); 2836 if (CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) { 2837 // currently false for PPC - but possible future opt 2838 StoreP(scratch, MemOperand(dst)); 2839 addi(dst, dst, Operand(kPointerSize)); 2840 } else { 2841 #if V8_TARGET_LITTLE_ENDIAN 2842 stb(scratch, MemOperand(dst, 0)); 2843 ShiftRightImm(scratch, scratch, Operand(8)); 2844 stb(scratch, MemOperand(dst, 1)); 2845 ShiftRightImm(scratch, scratch, Operand(8)); 2846 stb(scratch, MemOperand(dst, 2)); 2847 ShiftRightImm(scratch, scratch, Operand(8)); 2848 stb(scratch, MemOperand(dst, 3)); 2849 #if V8_TARGET_ARCH_PPC64 2850 ShiftRightImm(scratch, scratch, Operand(8)); 2851 stb(scratch, MemOperand(dst, 4)); 2852 ShiftRightImm(scratch, scratch, Operand(8)); 2853 stb(scratch, MemOperand(dst, 5)); 2854 ShiftRightImm(scratch, scratch, Operand(8)); 2855 stb(scratch, MemOperand(dst, 6)); 2856 ShiftRightImm(scratch, scratch, Operand(8)); 2857 stb(scratch, MemOperand(dst, 7)); 2858 #endif 2859 #else 2860 #if V8_TARGET_ARCH_PPC64 2861 stb(scratch, MemOperand(dst, 7)); 2862 ShiftRightImm(scratch, scratch, Operand(8)); 2863 stb(scratch, MemOperand(dst, 6)); 2864 ShiftRightImm(scratch, scratch, Operand(8)); 2865 stb(scratch, MemOperand(dst, 5)); 2866 ShiftRightImm(scratch, scratch, Operand(8)); 2867 stb(scratch, MemOperand(dst, 4)); 2868 ShiftRightImm(scratch, scratch, Operand(8)); 2869 #endif 2870 stb(scratch, MemOperand(dst, 3)); 2871 ShiftRightImm(scratch, scratch, Operand(8)); 2872 stb(scratch, MemOperand(dst, 2)); 2873 ShiftRightImm(scratch, scratch, Operand(8)); 2874 stb(scratch, MemOperand(dst, 1)); 2875 ShiftRightImm(scratch, scratch, Operand(8)); 2876 stb(scratch, MemOperand(dst, 0)); 2877 #endif 2878 addi(dst, dst, Operand(kPointerSize)); 2879 } 2880 bdnz(&word_loop); 2881 2882 // Copy the last bytes if any left. 2883 cmpi(length, Operand::Zero()); 2884 beq(&done); 2885 2886 bind(&byte_loop); 2887 mtctr(length); 2888 bind(&byte_loop_1); 2889 lbz(scratch, MemOperand(src)); 2890 addi(src, src, Operand(1)); 2891 stb(scratch, MemOperand(dst)); 2892 addi(dst, dst, Operand(1)); 2893 bdnz(&byte_loop_1); 2894 2895 bind(&done); 2896 } 2897 2898 2899 void MacroAssembler::InitializeNFieldsWithFiller(Register current_address, 2900 Register count, 2901 Register filler) { 2902 Label loop; 2903 mtctr(count); 2904 bind(&loop); 2905 StoreP(filler, MemOperand(current_address)); 2906 addi(current_address, current_address, Operand(kPointerSize)); 2907 bdnz(&loop); 2908 } 2909 2910 void MacroAssembler::InitializeFieldsWithFiller(Register current_address, 2911 Register end_address, 2912 Register filler) { 2913 Label done; 2914 sub(r0, end_address, current_address, LeaveOE, SetRC); 2915 beq(&done, cr0); 2916 ShiftRightImm(r0, r0, Operand(kPointerSizeLog2)); 2917 InitializeNFieldsWithFiller(current_address, r0, filler); 2918 bind(&done); 2919 } 2920 2921 2922 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte( 2923 Register first, Register second, Register scratch1, Register scratch2, 2924 Label* failure) { 2925 const int kFlatOneByteStringMask = 2926 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; 2927 const int kFlatOneByteStringTag = 2928 kStringTag | kOneByteStringTag | kSeqStringTag; 2929 andi(scratch1, first, Operand(kFlatOneByteStringMask)); 2930 andi(scratch2, second, Operand(kFlatOneByteStringMask)); 2931 cmpi(scratch1, Operand(kFlatOneByteStringTag)); 2932 bne(failure); 2933 cmpi(scratch2, Operand(kFlatOneByteStringTag)); 2934 bne(failure); 2935 } 2936 2937 2938 void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type, 2939 Register scratch, 2940 Label* failure) { 2941 const int kFlatOneByteStringMask = 2942 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; 2943 const int kFlatOneByteStringTag = 2944 kStringTag | kOneByteStringTag | kSeqStringTag; 2945 andi(scratch, type, Operand(kFlatOneByteStringMask)); 2946 cmpi(scratch, Operand(kFlatOneByteStringTag)); 2947 bne(failure); 2948 } 2949 2950 static const int kRegisterPassedArguments = 8; 2951 2952 2953 int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments, 2954 int num_double_arguments) { 2955 int stack_passed_words = 0; 2956 if (num_double_arguments > DoubleRegister::kNumRegisters) { 2957 stack_passed_words += 2958 2 * (num_double_arguments - DoubleRegister::kNumRegisters); 2959 } 2960 // Up to 8 simple arguments are passed in registers r3..r10. 2961 if (num_reg_arguments > kRegisterPassedArguments) { 2962 stack_passed_words += num_reg_arguments - kRegisterPassedArguments; 2963 } 2964 return stack_passed_words; 2965 } 2966 2967 2968 void MacroAssembler::EmitSeqStringSetCharCheck(Register string, Register index, 2969 Register value, 2970 uint32_t encoding_mask) { 2971 Label is_object; 2972 TestIfSmi(string, r0); 2973 Check(ne, kNonObject, cr0); 2974 2975 LoadP(ip, FieldMemOperand(string, HeapObject::kMapOffset)); 2976 lbz(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset)); 2977 2978 andi(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask)); 2979 cmpi(ip, Operand(encoding_mask)); 2980 Check(eq, kUnexpectedStringType); 2981 2982 // The index is assumed to be untagged coming in, tag it to compare with the 2983 // string length without using a temp register, it is restored at the end of 2984 // this function. 2985 #if !V8_TARGET_ARCH_PPC64 2986 Label index_tag_ok, index_tag_bad; 2987 JumpIfNotSmiCandidate(index, r0, &index_tag_bad); 2988 #endif 2989 SmiTag(index, index); 2990 #if !V8_TARGET_ARCH_PPC64 2991 b(&index_tag_ok); 2992 bind(&index_tag_bad); 2993 Abort(kIndexIsTooLarge); 2994 bind(&index_tag_ok); 2995 #endif 2996 2997 LoadP(ip, FieldMemOperand(string, String::kLengthOffset)); 2998 cmp(index, ip); 2999 Check(lt, kIndexIsTooLarge); 3000 3001 DCHECK(Smi::FromInt(0) == 0); 3002 cmpi(index, Operand::Zero()); 3003 Check(ge, kIndexIsNegative); 3004 3005 SmiUntag(index, index); 3006 } 3007 3008 3009 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, 3010 int num_double_arguments, 3011 Register scratch) { 3012 int frame_alignment = ActivationFrameAlignment(); 3013 int stack_passed_arguments = 3014 CalculateStackPassedWords(num_reg_arguments, num_double_arguments); 3015 int stack_space = kNumRequiredStackFrameSlots; 3016 3017 if (frame_alignment > kPointerSize) { 3018 // Make stack end at alignment and make room for stack arguments 3019 // -- preserving original value of sp. 3020 mr(scratch, sp); 3021 addi(sp, sp, Operand(-(stack_passed_arguments + 1) * kPointerSize)); 3022 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 3023 ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment))); 3024 StoreP(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); 3025 } else { 3026 // Make room for stack arguments 3027 stack_space += stack_passed_arguments; 3028 } 3029 3030 // Allocate frame with required slots to make ABI work. 3031 li(r0, Operand::Zero()); 3032 StorePU(r0, MemOperand(sp, -stack_space * kPointerSize)); 3033 } 3034 3035 3036 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, 3037 Register scratch) { 3038 PrepareCallCFunction(num_reg_arguments, 0, scratch); 3039 } 3040 3041 3042 void MacroAssembler::MovToFloatParameter(DoubleRegister src) { Move(d1, src); } 3043 3044 3045 void MacroAssembler::MovToFloatResult(DoubleRegister src) { Move(d1, src); } 3046 3047 3048 void MacroAssembler::MovToFloatParameters(DoubleRegister src1, 3049 DoubleRegister src2) { 3050 if (src2.is(d1)) { 3051 DCHECK(!src1.is(d2)); 3052 Move(d2, src2); 3053 Move(d1, src1); 3054 } else { 3055 Move(d1, src1); 3056 Move(d2, src2); 3057 } 3058 } 3059 3060 3061 void MacroAssembler::CallCFunction(ExternalReference function, 3062 int num_reg_arguments, 3063 int num_double_arguments) { 3064 mov(ip, Operand(function)); 3065 CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments); 3066 } 3067 3068 3069 void MacroAssembler::CallCFunction(Register function, int num_reg_arguments, 3070 int num_double_arguments) { 3071 CallCFunctionHelper(function, num_reg_arguments, num_double_arguments); 3072 } 3073 3074 3075 void MacroAssembler::CallCFunction(ExternalReference function, 3076 int num_arguments) { 3077 CallCFunction(function, num_arguments, 0); 3078 } 3079 3080 3081 void MacroAssembler::CallCFunction(Register function, int num_arguments) { 3082 CallCFunction(function, num_arguments, 0); 3083 } 3084 3085 3086 void MacroAssembler::CallCFunctionHelper(Register function, 3087 int num_reg_arguments, 3088 int num_double_arguments) { 3089 DCHECK(has_frame()); 3090 // Just call directly. The function called cannot cause a GC, or 3091 // allow preemption, so the return address in the link register 3092 // stays correct. 3093 Register dest = function; 3094 #if ABI_USES_FUNCTION_DESCRIPTORS && !defined(USE_SIMULATOR) 3095 // AIX uses a function descriptor. When calling C code be aware 3096 // of this descriptor and pick up values from it 3097 LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(function, kPointerSize)); 3098 LoadP(ip, MemOperand(function, 0)); 3099 dest = ip; 3100 #elif ABI_CALL_VIA_IP 3101 Move(ip, function); 3102 dest = ip; 3103 #endif 3104 3105 Call(dest); 3106 3107 // Remove frame bought in PrepareCallCFunction 3108 int stack_passed_arguments = 3109 CalculateStackPassedWords(num_reg_arguments, num_double_arguments); 3110 int stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments; 3111 if (ActivationFrameAlignment() > kPointerSize) { 3112 LoadP(sp, MemOperand(sp, stack_space * kPointerSize)); 3113 } else { 3114 addi(sp, sp, Operand(stack_space * kPointerSize)); 3115 } 3116 } 3117 3118 3119 void MacroAssembler::FlushICache(Register address, size_t size, 3120 Register scratch) { 3121 if (CpuFeatures::IsSupported(INSTR_AND_DATA_CACHE_COHERENCY)) { 3122 sync(); 3123 icbi(r0, address); 3124 isync(); 3125 return; 3126 } 3127 3128 Label done; 3129 3130 dcbf(r0, address); 3131 sync(); 3132 icbi(r0, address); 3133 isync(); 3134 3135 // This code handles ranges which cross a single cacheline boundary. 3136 // scratch is last cacheline which intersects range. 3137 const int kCacheLineSizeLog2 = WhichPowerOf2(CpuFeatures::cache_line_size()); 3138 3139 DCHECK(size > 0 && size <= (size_t)(1 << kCacheLineSizeLog2)); 3140 addi(scratch, address, Operand(size - 1)); 3141 ClearRightImm(scratch, scratch, Operand(kCacheLineSizeLog2)); 3142 cmpl(scratch, address); 3143 ble(&done); 3144 3145 dcbf(r0, scratch); 3146 sync(); 3147 icbi(r0, scratch); 3148 isync(); 3149 3150 bind(&done); 3151 } 3152 3153 3154 void MacroAssembler::DecodeConstantPoolOffset(Register result, 3155 Register location) { 3156 Label overflow_access, done; 3157 DCHECK(!AreAliased(result, location, r0)); 3158 3159 // Determine constant pool access type 3160 // Caller has already placed the instruction word at location in result. 3161 ExtractBitRange(r0, result, 31, 26); 3162 cmpi(r0, Operand(ADDIS >> 26)); 3163 beq(&overflow_access); 3164 3165 // Regular constant pool access 3166 // extract the load offset 3167 andi(result, result, Operand(kImm16Mask)); 3168 b(&done); 3169 3170 bind(&overflow_access); 3171 // Overflow constant pool access 3172 // shift addis immediate 3173 slwi(r0, result, Operand(16)); 3174 // sign-extend and add the load offset 3175 lwz(result, MemOperand(location, kInstrSize)); 3176 extsh(result, result); 3177 add(result, r0, result); 3178 3179 bind(&done); 3180 } 3181 3182 3183 void MacroAssembler::CheckPageFlag( 3184 Register object, 3185 Register scratch, // scratch may be same register as object 3186 int mask, Condition cc, Label* condition_met) { 3187 DCHECK(cc == ne || cc == eq); 3188 ClearRightImm(scratch, object, Operand(kPageSizeBits)); 3189 LoadP(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset)); 3190 3191 And(r0, scratch, Operand(mask), SetRC); 3192 3193 if (cc == ne) { 3194 bne(condition_met, cr0); 3195 } 3196 if (cc == eq) { 3197 beq(condition_met, cr0); 3198 } 3199 } 3200 3201 3202 void MacroAssembler::JumpIfBlack(Register object, Register scratch0, 3203 Register scratch1, Label* on_black) { 3204 HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern. 3205 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 3206 } 3207 3208 3209 void MacroAssembler::HasColor(Register object, Register bitmap_scratch, 3210 Register mask_scratch, Label* has_color, 3211 int first_bit, int second_bit) { 3212 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, no_reg)); 3213 3214 GetMarkBits(object, bitmap_scratch, mask_scratch); 3215 3216 Label other_color, word_boundary; 3217 lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); 3218 // Test the first bit 3219 and_(r0, ip, mask_scratch, SetRC); 3220 b(first_bit == 1 ? eq : ne, &other_color, cr0); 3221 // Shift left 1 3222 // May need to load the next cell 3223 slwi(mask_scratch, mask_scratch, Operand(1), SetRC); 3224 beq(&word_boundary, cr0); 3225 // Test the second bit 3226 and_(r0, ip, mask_scratch, SetRC); 3227 b(second_bit == 1 ? ne : eq, has_color, cr0); 3228 b(&other_color); 3229 3230 bind(&word_boundary); 3231 lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kIntSize)); 3232 andi(r0, ip, Operand(1)); 3233 b(second_bit == 1 ? ne : eq, has_color, cr0); 3234 bind(&other_color); 3235 } 3236 3237 3238 void MacroAssembler::GetMarkBits(Register addr_reg, Register bitmap_reg, 3239 Register mask_reg) { 3240 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg)); 3241 DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0); 3242 lis(r0, Operand((~Page::kPageAlignmentMask >> 16))); 3243 and_(bitmap_reg, addr_reg, r0); 3244 const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2; 3245 ExtractBitRange(mask_reg, addr_reg, kLowBits - 1, kPointerSizeLog2); 3246 ExtractBitRange(ip, addr_reg, kPageSizeBits - 1, kLowBits); 3247 ShiftLeftImm(ip, ip, Operand(Bitmap::kBytesPerCellLog2)); 3248 add(bitmap_reg, bitmap_reg, ip); 3249 li(ip, Operand(1)); 3250 slw(mask_reg, ip, mask_reg); 3251 } 3252 3253 3254 void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch, 3255 Register mask_scratch, Register load_scratch, 3256 Label* value_is_white) { 3257 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip)); 3258 GetMarkBits(value, bitmap_scratch, mask_scratch); 3259 3260 // If the value is black or grey we don't need to do anything. 3261 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); 3262 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 3263 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); 3264 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); 3265 3266 // Since both black and grey have a 1 in the first position and white does 3267 // not have a 1 there we only need to check one bit. 3268 lwz(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); 3269 and_(r0, mask_scratch, load_scratch, SetRC); 3270 beq(value_is_white, cr0); 3271 } 3272 3273 3274 // Saturate a value into 8-bit unsigned integer 3275 // if input_value < 0, output_value is 0 3276 // if input_value > 255, output_value is 255 3277 // otherwise output_value is the input_value 3278 void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) { 3279 int satval = (1 << 8) - 1; 3280 3281 if (CpuFeatures::IsSupported(ISELECT)) { 3282 // set to 0 if negative 3283 cmpi(input_reg, Operand::Zero()); 3284 isel(lt, output_reg, r0, input_reg); 3285 3286 // set to satval if > satval 3287 li(r0, Operand(satval)); 3288 cmpi(output_reg, Operand(satval)); 3289 isel(lt, output_reg, output_reg, r0); 3290 } else { 3291 Label done, negative_label, overflow_label; 3292 cmpi(input_reg, Operand::Zero()); 3293 blt(&negative_label); 3294 3295 cmpi(input_reg, Operand(satval)); 3296 bgt(&overflow_label); 3297 if (!output_reg.is(input_reg)) { 3298 mr(output_reg, input_reg); 3299 } 3300 b(&done); 3301 3302 bind(&negative_label); 3303 li(output_reg, Operand::Zero()); // set to 0 if negative 3304 b(&done); 3305 3306 bind(&overflow_label); // set to satval if > satval 3307 li(output_reg, Operand(satval)); 3308 3309 bind(&done); 3310 } 3311 } 3312 3313 3314 void MacroAssembler::SetRoundingMode(FPRoundingMode RN) { mtfsfi(7, RN); } 3315 3316 3317 void MacroAssembler::ResetRoundingMode() { 3318 mtfsfi(7, kRoundToNearest); // reset (default is kRoundToNearest) 3319 } 3320 3321 3322 void MacroAssembler::ClampDoubleToUint8(Register result_reg, 3323 DoubleRegister input_reg, 3324 DoubleRegister double_scratch) { 3325 Label above_zero; 3326 Label done; 3327 Label in_bounds; 3328 3329 LoadDoubleLiteral(double_scratch, 0.0, result_reg); 3330 fcmpu(input_reg, double_scratch); 3331 bgt(&above_zero); 3332 3333 // Double value is less than zero, NaN or Inf, return 0. 3334 LoadIntLiteral(result_reg, 0); 3335 b(&done); 3336 3337 // Double value is >= 255, return 255. 3338 bind(&above_zero); 3339 LoadDoubleLiteral(double_scratch, 255.0, result_reg); 3340 fcmpu(input_reg, double_scratch); 3341 ble(&in_bounds); 3342 LoadIntLiteral(result_reg, 255); 3343 b(&done); 3344 3345 // In 0-255 range, round and truncate. 3346 bind(&in_bounds); 3347 3348 // round to nearest (default rounding mode) 3349 fctiw(double_scratch, input_reg); 3350 MovDoubleLowToInt(result_reg, double_scratch); 3351 bind(&done); 3352 } 3353 3354 3355 void MacroAssembler::LoadInstanceDescriptors(Register map, 3356 Register descriptors) { 3357 LoadP(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset)); 3358 } 3359 3360 3361 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { 3362 lwz(dst, FieldMemOperand(map, Map::kBitField3Offset)); 3363 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); 3364 } 3365 3366 3367 void MacroAssembler::EnumLength(Register dst, Register map) { 3368 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0); 3369 lwz(dst, FieldMemOperand(map, Map::kBitField3Offset)); 3370 ExtractBitMask(dst, dst, Map::EnumLengthBits::kMask); 3371 SmiTag(dst); 3372 } 3373 3374 3375 void MacroAssembler::LoadAccessor(Register dst, Register holder, 3376 int accessor_index, 3377 AccessorComponent accessor) { 3378 LoadP(dst, FieldMemOperand(holder, HeapObject::kMapOffset)); 3379 LoadInstanceDescriptors(dst, dst); 3380 LoadP(dst, 3381 FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index))); 3382 const int getterOffset = AccessorPair::kGetterOffset; 3383 const int setterOffset = AccessorPair::kSetterOffset; 3384 int offset = ((accessor == ACCESSOR_GETTER) ? getterOffset : setterOffset); 3385 LoadP(dst, FieldMemOperand(dst, offset)); 3386 } 3387 3388 3389 void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) { 3390 Register empty_fixed_array_value = r9; 3391 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); 3392 Label next, start; 3393 mr(r5, r3); 3394 3395 // Check if the enum length field is properly initialized, indicating that 3396 // there is an enum cache. 3397 LoadP(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); 3398 3399 EnumLength(r6, r4); 3400 CmpSmiLiteral(r6, Smi::FromInt(kInvalidEnumCacheSentinel), r0); 3401 beq(call_runtime); 3402 3403 b(&start); 3404 3405 bind(&next); 3406 LoadP(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); 3407 3408 // For all objects but the receiver, check that the cache is empty. 3409 EnumLength(r6, r4); 3410 CmpSmiLiteral(r6, Smi::FromInt(0), r0); 3411 bne(call_runtime); 3412 3413 bind(&start); 3414 3415 // Check that there are no elements. Register r5 contains the current JS 3416 // object we've reached through the prototype chain. 3417 Label no_elements; 3418 LoadP(r5, FieldMemOperand(r5, JSObject::kElementsOffset)); 3419 cmp(r5, empty_fixed_array_value); 3420 beq(&no_elements); 3421 3422 // Second chance, the object may be using the empty slow element dictionary. 3423 CompareRoot(r5, Heap::kEmptySlowElementDictionaryRootIndex); 3424 bne(call_runtime); 3425 3426 bind(&no_elements); 3427 LoadP(r5, FieldMemOperand(r4, Map::kPrototypeOffset)); 3428 cmp(r5, null_value); 3429 bne(&next); 3430 } 3431 3432 3433 //////////////////////////////////////////////////////////////////////////////// 3434 // 3435 // New MacroAssembler Interfaces added for PPC 3436 // 3437 //////////////////////////////////////////////////////////////////////////////// 3438 void MacroAssembler::LoadIntLiteral(Register dst, int value) { 3439 mov(dst, Operand(value)); 3440 } 3441 3442 3443 void MacroAssembler::LoadSmiLiteral(Register dst, Smi* smi) { 3444 mov(dst, Operand(smi)); 3445 } 3446 3447 3448 void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, double value, 3449 Register scratch) { 3450 if (FLAG_enable_embedded_constant_pool && is_constant_pool_available() && 3451 !(scratch.is(r0) && ConstantPoolAccessIsInOverflow())) { 3452 ConstantPoolEntry::Access access = ConstantPoolAddEntry(value); 3453 if (access == ConstantPoolEntry::OVERFLOWED) { 3454 addis(scratch, kConstantPoolRegister, Operand::Zero()); 3455 lfd(result, MemOperand(scratch, 0)); 3456 } else { 3457 lfd(result, MemOperand(kConstantPoolRegister, 0)); 3458 } 3459 return; 3460 } 3461 3462 // avoid gcc strict aliasing error using union cast 3463 union { 3464 double dval; 3465 #if V8_TARGET_ARCH_PPC64 3466 intptr_t ival; 3467 #else 3468 intptr_t ival[2]; 3469 #endif 3470 } litVal; 3471 3472 litVal.dval = value; 3473 3474 #if V8_TARGET_ARCH_PPC64 3475 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { 3476 mov(scratch, Operand(litVal.ival)); 3477 mtfprd(result, scratch); 3478 return; 3479 } 3480 #endif 3481 3482 addi(sp, sp, Operand(-kDoubleSize)); 3483 #if V8_TARGET_ARCH_PPC64 3484 mov(scratch, Operand(litVal.ival)); 3485 std(scratch, MemOperand(sp)); 3486 #else 3487 LoadIntLiteral(scratch, litVal.ival[0]); 3488 stw(scratch, MemOperand(sp, 0)); 3489 LoadIntLiteral(scratch, litVal.ival[1]); 3490 stw(scratch, MemOperand(sp, 4)); 3491 #endif 3492 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3493 lfd(result, MemOperand(sp, 0)); 3494 addi(sp, sp, Operand(kDoubleSize)); 3495 } 3496 3497 3498 void MacroAssembler::MovIntToDouble(DoubleRegister dst, Register src, 3499 Register scratch) { 3500 // sign-extend src to 64-bit 3501 #if V8_TARGET_ARCH_PPC64 3502 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { 3503 mtfprwa(dst, src); 3504 return; 3505 } 3506 #endif 3507 3508 DCHECK(!src.is(scratch)); 3509 subi(sp, sp, Operand(kDoubleSize)); 3510 #if V8_TARGET_ARCH_PPC64 3511 extsw(scratch, src); 3512 std(scratch, MemOperand(sp, 0)); 3513 #else 3514 srawi(scratch, src, 31); 3515 stw(scratch, MemOperand(sp, Register::kExponentOffset)); 3516 stw(src, MemOperand(sp, Register::kMantissaOffset)); 3517 #endif 3518 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3519 lfd(dst, MemOperand(sp, 0)); 3520 addi(sp, sp, Operand(kDoubleSize)); 3521 } 3522 3523 3524 void MacroAssembler::MovUnsignedIntToDouble(DoubleRegister dst, Register src, 3525 Register scratch) { 3526 // zero-extend src to 64-bit 3527 #if V8_TARGET_ARCH_PPC64 3528 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { 3529 mtfprwz(dst, src); 3530 return; 3531 } 3532 #endif 3533 3534 DCHECK(!src.is(scratch)); 3535 subi(sp, sp, Operand(kDoubleSize)); 3536 #if V8_TARGET_ARCH_PPC64 3537 clrldi(scratch, src, Operand(32)); 3538 std(scratch, MemOperand(sp, 0)); 3539 #else 3540 li(scratch, Operand::Zero()); 3541 stw(scratch, MemOperand(sp, Register::kExponentOffset)); 3542 stw(src, MemOperand(sp, Register::kMantissaOffset)); 3543 #endif 3544 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3545 lfd(dst, MemOperand(sp, 0)); 3546 addi(sp, sp, Operand(kDoubleSize)); 3547 } 3548 3549 3550 void MacroAssembler::MovInt64ToDouble(DoubleRegister dst, 3551 #if !V8_TARGET_ARCH_PPC64 3552 Register src_hi, 3553 #endif 3554 Register src) { 3555 #if V8_TARGET_ARCH_PPC64 3556 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { 3557 mtfprd(dst, src); 3558 return; 3559 } 3560 #endif 3561 3562 subi(sp, sp, Operand(kDoubleSize)); 3563 #if V8_TARGET_ARCH_PPC64 3564 std(src, MemOperand(sp, 0)); 3565 #else 3566 stw(src_hi, MemOperand(sp, Register::kExponentOffset)); 3567 stw(src, MemOperand(sp, Register::kMantissaOffset)); 3568 #endif 3569 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3570 lfd(dst, MemOperand(sp, 0)); 3571 addi(sp, sp, Operand(kDoubleSize)); 3572 } 3573 3574 3575 #if V8_TARGET_ARCH_PPC64 3576 void MacroAssembler::MovInt64ComponentsToDouble(DoubleRegister dst, 3577 Register src_hi, 3578 Register src_lo, 3579 Register scratch) { 3580 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { 3581 sldi(scratch, src_hi, Operand(32)); 3582 rldimi(scratch, src_lo, 0, 32); 3583 mtfprd(dst, scratch); 3584 return; 3585 } 3586 3587 subi(sp, sp, Operand(kDoubleSize)); 3588 stw(src_hi, MemOperand(sp, Register::kExponentOffset)); 3589 stw(src_lo, MemOperand(sp, Register::kMantissaOffset)); 3590 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3591 lfd(dst, MemOperand(sp)); 3592 addi(sp, sp, Operand(kDoubleSize)); 3593 } 3594 #endif 3595 3596 3597 void MacroAssembler::InsertDoubleLow(DoubleRegister dst, Register src, 3598 Register scratch) { 3599 #if V8_TARGET_ARCH_PPC64 3600 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { 3601 mffprd(scratch, dst); 3602 rldimi(scratch, src, 0, 32); 3603 mtfprd(dst, scratch); 3604 return; 3605 } 3606 #endif 3607 3608 subi(sp, sp, Operand(kDoubleSize)); 3609 stfd(dst, MemOperand(sp)); 3610 stw(src, MemOperand(sp, Register::kMantissaOffset)); 3611 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3612 lfd(dst, MemOperand(sp)); 3613 addi(sp, sp, Operand(kDoubleSize)); 3614 } 3615 3616 3617 void MacroAssembler::InsertDoubleHigh(DoubleRegister dst, Register src, 3618 Register scratch) { 3619 #if V8_TARGET_ARCH_PPC64 3620 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { 3621 mffprd(scratch, dst); 3622 rldimi(scratch, src, 32, 0); 3623 mtfprd(dst, scratch); 3624 return; 3625 } 3626 #endif 3627 3628 subi(sp, sp, Operand(kDoubleSize)); 3629 stfd(dst, MemOperand(sp)); 3630 stw(src, MemOperand(sp, Register::kExponentOffset)); 3631 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3632 lfd(dst, MemOperand(sp)); 3633 addi(sp, sp, Operand(kDoubleSize)); 3634 } 3635 3636 3637 void MacroAssembler::MovDoubleLowToInt(Register dst, DoubleRegister src) { 3638 #if V8_TARGET_ARCH_PPC64 3639 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { 3640 mffprwz(dst, src); 3641 return; 3642 } 3643 #endif 3644 3645 subi(sp, sp, Operand(kDoubleSize)); 3646 stfd(src, MemOperand(sp)); 3647 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3648 lwz(dst, MemOperand(sp, Register::kMantissaOffset)); 3649 addi(sp, sp, Operand(kDoubleSize)); 3650 } 3651 3652 3653 void MacroAssembler::MovDoubleHighToInt(Register dst, DoubleRegister src) { 3654 #if V8_TARGET_ARCH_PPC64 3655 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { 3656 mffprd(dst, src); 3657 srdi(dst, dst, Operand(32)); 3658 return; 3659 } 3660 #endif 3661 3662 subi(sp, sp, Operand(kDoubleSize)); 3663 stfd(src, MemOperand(sp)); 3664 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3665 lwz(dst, MemOperand(sp, Register::kExponentOffset)); 3666 addi(sp, sp, Operand(kDoubleSize)); 3667 } 3668 3669 3670 void MacroAssembler::MovDoubleToInt64( 3671 #if !V8_TARGET_ARCH_PPC64 3672 Register dst_hi, 3673 #endif 3674 Register dst, DoubleRegister src) { 3675 #if V8_TARGET_ARCH_PPC64 3676 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) { 3677 mffprd(dst, src); 3678 return; 3679 } 3680 #endif 3681 3682 subi(sp, sp, Operand(kDoubleSize)); 3683 stfd(src, MemOperand(sp)); 3684 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3685 #if V8_TARGET_ARCH_PPC64 3686 ld(dst, MemOperand(sp, 0)); 3687 #else 3688 lwz(dst_hi, MemOperand(sp, Register::kExponentOffset)); 3689 lwz(dst, MemOperand(sp, Register::kMantissaOffset)); 3690 #endif 3691 addi(sp, sp, Operand(kDoubleSize)); 3692 } 3693 3694 3695 void MacroAssembler::MovIntToFloat(DoubleRegister dst, Register src) { 3696 subi(sp, sp, Operand(kFloatSize)); 3697 stw(src, MemOperand(sp, 0)); 3698 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3699 lfs(dst, MemOperand(sp, 0)); 3700 addi(sp, sp, Operand(kFloatSize)); 3701 } 3702 3703 3704 void MacroAssembler::MovFloatToInt(Register dst, DoubleRegister src) { 3705 subi(sp, sp, Operand(kFloatSize)); 3706 frsp(src, src); 3707 stfs(src, MemOperand(sp, 0)); 3708 nop(GROUP_ENDING_NOP); // LHS/RAW optimization 3709 lwz(dst, MemOperand(sp, 0)); 3710 addi(sp, sp, Operand(kFloatSize)); 3711 } 3712 3713 3714 void MacroAssembler::Add(Register dst, Register src, intptr_t value, 3715 Register scratch) { 3716 if (is_int16(value)) { 3717 addi(dst, src, Operand(value)); 3718 } else { 3719 mov(scratch, Operand(value)); 3720 add(dst, src, scratch); 3721 } 3722 } 3723 3724 3725 void MacroAssembler::Cmpi(Register src1, const Operand& src2, Register scratch, 3726 CRegister cr) { 3727 intptr_t value = src2.immediate(); 3728 if (is_int16(value)) { 3729 cmpi(src1, src2, cr); 3730 } else { 3731 mov(scratch, src2); 3732 cmp(src1, scratch, cr); 3733 } 3734 } 3735 3736 3737 void MacroAssembler::Cmpli(Register src1, const Operand& src2, Register scratch, 3738 CRegister cr) { 3739 intptr_t value = src2.immediate(); 3740 if (is_uint16(value)) { 3741 cmpli(src1, src2, cr); 3742 } else { 3743 mov(scratch, src2); 3744 cmpl(src1, scratch, cr); 3745 } 3746 } 3747 3748 3749 void MacroAssembler::Cmpwi(Register src1, const Operand& src2, Register scratch, 3750 CRegister cr) { 3751 intptr_t value = src2.immediate(); 3752 if (is_int16(value)) { 3753 cmpwi(src1, src2, cr); 3754 } else { 3755 mov(scratch, src2); 3756 cmpw(src1, scratch, cr); 3757 } 3758 } 3759 3760 3761 void MacroAssembler::Cmplwi(Register src1, const Operand& src2, 3762 Register scratch, CRegister cr) { 3763 intptr_t value = src2.immediate(); 3764 if (is_uint16(value)) { 3765 cmplwi(src1, src2, cr); 3766 } else { 3767 mov(scratch, src2); 3768 cmplw(src1, scratch, cr); 3769 } 3770 } 3771 3772 3773 void MacroAssembler::And(Register ra, Register rs, const Operand& rb, 3774 RCBit rc) { 3775 if (rb.is_reg()) { 3776 and_(ra, rs, rb.rm(), rc); 3777 } else { 3778 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == SetRC) { 3779 andi(ra, rs, rb); 3780 } else { 3781 // mov handles the relocation. 3782 DCHECK(!rs.is(r0)); 3783 mov(r0, rb); 3784 and_(ra, rs, r0, rc); 3785 } 3786 } 3787 } 3788 3789 3790 void MacroAssembler::Or(Register ra, Register rs, const Operand& rb, RCBit rc) { 3791 if (rb.is_reg()) { 3792 orx(ra, rs, rb.rm(), rc); 3793 } else { 3794 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == LeaveRC) { 3795 ori(ra, rs, rb); 3796 } else { 3797 // mov handles the relocation. 3798 DCHECK(!rs.is(r0)); 3799 mov(r0, rb); 3800 orx(ra, rs, r0, rc); 3801 } 3802 } 3803 } 3804 3805 3806 void MacroAssembler::Xor(Register ra, Register rs, const Operand& rb, 3807 RCBit rc) { 3808 if (rb.is_reg()) { 3809 xor_(ra, rs, rb.rm(), rc); 3810 } else { 3811 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == LeaveRC) { 3812 xori(ra, rs, rb); 3813 } else { 3814 // mov handles the relocation. 3815 DCHECK(!rs.is(r0)); 3816 mov(r0, rb); 3817 xor_(ra, rs, r0, rc); 3818 } 3819 } 3820 } 3821 3822 3823 void MacroAssembler::CmpSmiLiteral(Register src1, Smi* smi, Register scratch, 3824 CRegister cr) { 3825 #if V8_TARGET_ARCH_PPC64 3826 LoadSmiLiteral(scratch, smi); 3827 cmp(src1, scratch, cr); 3828 #else 3829 Cmpi(src1, Operand(smi), scratch, cr); 3830 #endif 3831 } 3832 3833 3834 void MacroAssembler::CmplSmiLiteral(Register src1, Smi* smi, Register scratch, 3835 CRegister cr) { 3836 #if V8_TARGET_ARCH_PPC64 3837 LoadSmiLiteral(scratch, smi); 3838 cmpl(src1, scratch, cr); 3839 #else 3840 Cmpli(src1, Operand(smi), scratch, cr); 3841 #endif 3842 } 3843 3844 3845 void MacroAssembler::AddSmiLiteral(Register dst, Register src, Smi* smi, 3846 Register scratch) { 3847 #if V8_TARGET_ARCH_PPC64 3848 LoadSmiLiteral(scratch, smi); 3849 add(dst, src, scratch); 3850 #else 3851 Add(dst, src, reinterpret_cast<intptr_t>(smi), scratch); 3852 #endif 3853 } 3854 3855 3856 void MacroAssembler::SubSmiLiteral(Register dst, Register src, Smi* smi, 3857 Register scratch) { 3858 #if V8_TARGET_ARCH_PPC64 3859 LoadSmiLiteral(scratch, smi); 3860 sub(dst, src, scratch); 3861 #else 3862 Add(dst, src, -(reinterpret_cast<intptr_t>(smi)), scratch); 3863 #endif 3864 } 3865 3866 3867 void MacroAssembler::AndSmiLiteral(Register dst, Register src, Smi* smi, 3868 Register scratch, RCBit rc) { 3869 #if V8_TARGET_ARCH_PPC64 3870 LoadSmiLiteral(scratch, smi); 3871 and_(dst, src, scratch, rc); 3872 #else 3873 And(dst, src, Operand(smi), rc); 3874 #endif 3875 } 3876 3877 3878 // Load a "pointer" sized value from the memory location 3879 void MacroAssembler::LoadP(Register dst, const MemOperand& mem, 3880 Register scratch) { 3881 int offset = mem.offset(); 3882 3883 if (!is_int16(offset)) { 3884 /* cannot use d-form */ 3885 DCHECK(!scratch.is(no_reg)); 3886 mov(scratch, Operand(offset)); 3887 #if V8_TARGET_ARCH_PPC64 3888 ldx(dst, MemOperand(mem.ra(), scratch)); 3889 #else 3890 lwzx(dst, MemOperand(mem.ra(), scratch)); 3891 #endif 3892 } else { 3893 #if V8_TARGET_ARCH_PPC64 3894 int misaligned = (offset & 3); 3895 if (misaligned) { 3896 // adjust base to conform to offset alignment requirements 3897 // Todo: enhance to use scratch if dst is unsuitable 3898 DCHECK(!dst.is(r0)); 3899 addi(dst, mem.ra(), Operand((offset & 3) - 4)); 3900 ld(dst, MemOperand(dst, (offset & ~3) + 4)); 3901 } else { 3902 ld(dst, mem); 3903 } 3904 #else 3905 lwz(dst, mem); 3906 #endif 3907 } 3908 } 3909 3910 3911 // Store a "pointer" sized value to the memory location 3912 void MacroAssembler::StoreP(Register src, const MemOperand& mem, 3913 Register scratch) { 3914 int offset = mem.offset(); 3915 3916 if (!is_int16(offset)) { 3917 /* cannot use d-form */ 3918 DCHECK(!scratch.is(no_reg)); 3919 mov(scratch, Operand(offset)); 3920 #if V8_TARGET_ARCH_PPC64 3921 stdx(src, MemOperand(mem.ra(), scratch)); 3922 #else 3923 stwx(src, MemOperand(mem.ra(), scratch)); 3924 #endif 3925 } else { 3926 #if V8_TARGET_ARCH_PPC64 3927 int misaligned = (offset & 3); 3928 if (misaligned) { 3929 // adjust base to conform to offset alignment requirements 3930 // a suitable scratch is required here 3931 DCHECK(!scratch.is(no_reg)); 3932 if (scratch.is(r0)) { 3933 LoadIntLiteral(scratch, offset); 3934 stdx(src, MemOperand(mem.ra(), scratch)); 3935 } else { 3936 addi(scratch, mem.ra(), Operand((offset & 3) - 4)); 3937 std(src, MemOperand(scratch, (offset & ~3) + 4)); 3938 } 3939 } else { 3940 std(src, mem); 3941 } 3942 #else 3943 stw(src, mem); 3944 #endif 3945 } 3946 } 3947 3948 void MacroAssembler::LoadWordArith(Register dst, const MemOperand& mem, 3949 Register scratch) { 3950 int offset = mem.offset(); 3951 3952 if (!is_int16(offset)) { 3953 DCHECK(!scratch.is(no_reg)); 3954 mov(scratch, Operand(offset)); 3955 lwax(dst, MemOperand(mem.ra(), scratch)); 3956 } else { 3957 #if V8_TARGET_ARCH_PPC64 3958 int misaligned = (offset & 3); 3959 if (misaligned) { 3960 // adjust base to conform to offset alignment requirements 3961 // Todo: enhance to use scratch if dst is unsuitable 3962 DCHECK(!dst.is(r0)); 3963 addi(dst, mem.ra(), Operand((offset & 3) - 4)); 3964 lwa(dst, MemOperand(dst, (offset & ~3) + 4)); 3965 } else { 3966 lwa(dst, mem); 3967 } 3968 #else 3969 lwz(dst, mem); 3970 #endif 3971 } 3972 } 3973 3974 3975 // Variable length depending on whether offset fits into immediate field 3976 // MemOperand currently only supports d-form 3977 void MacroAssembler::LoadWord(Register dst, const MemOperand& mem, 3978 Register scratch) { 3979 Register base = mem.ra(); 3980 int offset = mem.offset(); 3981 3982 if (!is_int16(offset)) { 3983 LoadIntLiteral(scratch, offset); 3984 lwzx(dst, MemOperand(base, scratch)); 3985 } else { 3986 lwz(dst, mem); 3987 } 3988 } 3989 3990 3991 // Variable length depending on whether offset fits into immediate field 3992 // MemOperand current only supports d-form 3993 void MacroAssembler::StoreWord(Register src, const MemOperand& mem, 3994 Register scratch) { 3995 Register base = mem.ra(); 3996 int offset = mem.offset(); 3997 3998 if (!is_int16(offset)) { 3999 LoadIntLiteral(scratch, offset); 4000 stwx(src, MemOperand(base, scratch)); 4001 } else { 4002 stw(src, mem); 4003 } 4004 } 4005 4006 4007 void MacroAssembler::LoadHalfWordArith(Register dst, const MemOperand& mem, 4008 Register scratch) { 4009 int offset = mem.offset(); 4010 4011 if (!is_int16(offset)) { 4012 DCHECK(!scratch.is(no_reg)); 4013 mov(scratch, Operand(offset)); 4014 lhax(dst, MemOperand(mem.ra(), scratch)); 4015 } else { 4016 lha(dst, mem); 4017 } 4018 } 4019 4020 4021 // Variable length depending on whether offset fits into immediate field 4022 // MemOperand currently only supports d-form 4023 void MacroAssembler::LoadHalfWord(Register dst, const MemOperand& mem, 4024 Register scratch) { 4025 Register base = mem.ra(); 4026 int offset = mem.offset(); 4027 4028 if (!is_int16(offset)) { 4029 LoadIntLiteral(scratch, offset); 4030 lhzx(dst, MemOperand(base, scratch)); 4031 } else { 4032 lhz(dst, mem); 4033 } 4034 } 4035 4036 4037 // Variable length depending on whether offset fits into immediate field 4038 // MemOperand current only supports d-form 4039 void MacroAssembler::StoreHalfWord(Register src, const MemOperand& mem, 4040 Register scratch) { 4041 Register base = mem.ra(); 4042 int offset = mem.offset(); 4043 4044 if (!is_int16(offset)) { 4045 LoadIntLiteral(scratch, offset); 4046 sthx(src, MemOperand(base, scratch)); 4047 } else { 4048 sth(src, mem); 4049 } 4050 } 4051 4052 4053 // Variable length depending on whether offset fits into immediate field 4054 // MemOperand currently only supports d-form 4055 void MacroAssembler::LoadByte(Register dst, const MemOperand& mem, 4056 Register scratch) { 4057 Register base = mem.ra(); 4058 int offset = mem.offset(); 4059 4060 if (!is_int16(offset)) { 4061 LoadIntLiteral(scratch, offset); 4062 lbzx(dst, MemOperand(base, scratch)); 4063 } else { 4064 lbz(dst, mem); 4065 } 4066 } 4067 4068 4069 // Variable length depending on whether offset fits into immediate field 4070 // MemOperand current only supports d-form 4071 void MacroAssembler::StoreByte(Register src, const MemOperand& mem, 4072 Register scratch) { 4073 Register base = mem.ra(); 4074 int offset = mem.offset(); 4075 4076 if (!is_int16(offset)) { 4077 LoadIntLiteral(scratch, offset); 4078 stbx(src, MemOperand(base, scratch)); 4079 } else { 4080 stb(src, mem); 4081 } 4082 } 4083 4084 4085 void MacroAssembler::LoadRepresentation(Register dst, const MemOperand& mem, 4086 Representation r, Register scratch) { 4087 DCHECK(!r.IsDouble()); 4088 if (r.IsInteger8()) { 4089 LoadByte(dst, mem, scratch); 4090 extsb(dst, dst); 4091 } else if (r.IsUInteger8()) { 4092 LoadByte(dst, mem, scratch); 4093 } else if (r.IsInteger16()) { 4094 LoadHalfWordArith(dst, mem, scratch); 4095 } else if (r.IsUInteger16()) { 4096 LoadHalfWord(dst, mem, scratch); 4097 #if V8_TARGET_ARCH_PPC64 4098 } else if (r.IsInteger32()) { 4099 LoadWordArith(dst, mem, scratch); 4100 #endif 4101 } else { 4102 LoadP(dst, mem, scratch); 4103 } 4104 } 4105 4106 4107 void MacroAssembler::StoreRepresentation(Register src, const MemOperand& mem, 4108 Representation r, Register scratch) { 4109 DCHECK(!r.IsDouble()); 4110 if (r.IsInteger8() || r.IsUInteger8()) { 4111 StoreByte(src, mem, scratch); 4112 } else if (r.IsInteger16() || r.IsUInteger16()) { 4113 StoreHalfWord(src, mem, scratch); 4114 #if V8_TARGET_ARCH_PPC64 4115 } else if (r.IsInteger32()) { 4116 StoreWord(src, mem, scratch); 4117 #endif 4118 } else { 4119 if (r.IsHeapObject()) { 4120 AssertNotSmi(src); 4121 } else if (r.IsSmi()) { 4122 AssertSmi(src); 4123 } 4124 StoreP(src, mem, scratch); 4125 } 4126 } 4127 4128 4129 void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem, 4130 Register scratch) { 4131 Register base = mem.ra(); 4132 int offset = mem.offset(); 4133 4134 if (!is_int16(offset)) { 4135 mov(scratch, Operand(offset)); 4136 lfdx(dst, MemOperand(base, scratch)); 4137 } else { 4138 lfd(dst, mem); 4139 } 4140 } 4141 4142 4143 void MacroAssembler::StoreDouble(DoubleRegister src, const MemOperand& mem, 4144 Register scratch) { 4145 Register base = mem.ra(); 4146 int offset = mem.offset(); 4147 4148 if (!is_int16(offset)) { 4149 mov(scratch, Operand(offset)); 4150 stfdx(src, MemOperand(base, scratch)); 4151 } else { 4152 stfd(src, mem); 4153 } 4154 } 4155 4156 4157 void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg, 4158 Register scratch_reg, 4159 Label* no_memento_found) { 4160 ExternalReference new_space_start = 4161 ExternalReference::new_space_start(isolate()); 4162 ExternalReference new_space_allocation_top = 4163 ExternalReference::new_space_allocation_top_address(isolate()); 4164 addi(scratch_reg, receiver_reg, 4165 Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag)); 4166 Cmpi(scratch_reg, Operand(new_space_start), r0); 4167 blt(no_memento_found); 4168 mov(ip, Operand(new_space_allocation_top)); 4169 LoadP(ip, MemOperand(ip)); 4170 cmp(scratch_reg, ip); 4171 bgt(no_memento_found); 4172 LoadP(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize)); 4173 Cmpi(scratch_reg, Operand(isolate()->factory()->allocation_memento_map()), 4174 r0); 4175 } 4176 4177 4178 Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3, 4179 Register reg4, Register reg5, 4180 Register reg6) { 4181 RegList regs = 0; 4182 if (reg1.is_valid()) regs |= reg1.bit(); 4183 if (reg2.is_valid()) regs |= reg2.bit(); 4184 if (reg3.is_valid()) regs |= reg3.bit(); 4185 if (reg4.is_valid()) regs |= reg4.bit(); 4186 if (reg5.is_valid()) regs |= reg5.bit(); 4187 if (reg6.is_valid()) regs |= reg6.bit(); 4188 4189 const RegisterConfiguration* config = 4190 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT); 4191 for (int i = 0; i < config->num_allocatable_general_registers(); ++i) { 4192 int code = config->GetAllocatableGeneralCode(i); 4193 Register candidate = Register::from_code(code); 4194 if (regs & candidate.bit()) continue; 4195 return candidate; 4196 } 4197 UNREACHABLE(); 4198 return no_reg; 4199 } 4200 4201 4202 void MacroAssembler::JumpIfDictionaryInPrototypeChain(Register object, 4203 Register scratch0, 4204 Register scratch1, 4205 Label* found) { 4206 DCHECK(!scratch1.is(scratch0)); 4207 Register current = scratch0; 4208 Label loop_again, end; 4209 4210 // scratch contained elements pointer. 4211 mr(current, object); 4212 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset)); 4213 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset)); 4214 CompareRoot(current, Heap::kNullValueRootIndex); 4215 beq(&end); 4216 4217 // Loop based on the map going up the prototype chain. 4218 bind(&loop_again); 4219 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset)); 4220 4221 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE); 4222 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE); 4223 lbz(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset)); 4224 cmpi(scratch1, Operand(JS_OBJECT_TYPE)); 4225 blt(found); 4226 4227 lbz(scratch1, FieldMemOperand(current, Map::kBitField2Offset)); 4228 DecodeField<Map::ElementsKindBits>(scratch1); 4229 cmpi(scratch1, Operand(DICTIONARY_ELEMENTS)); 4230 beq(found); 4231 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset)); 4232 CompareRoot(current, Heap::kNullValueRootIndex); 4233 bne(&loop_again); 4234 4235 bind(&end); 4236 } 4237 4238 4239 #ifdef DEBUG 4240 bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4, 4241 Register reg5, Register reg6, Register reg7, Register reg8, 4242 Register reg9, Register reg10) { 4243 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() + 4244 reg4.is_valid() + reg5.is_valid() + reg6.is_valid() + 4245 reg7.is_valid() + reg8.is_valid() + reg9.is_valid() + 4246 reg10.is_valid(); 4247 4248 RegList regs = 0; 4249 if (reg1.is_valid()) regs |= reg1.bit(); 4250 if (reg2.is_valid()) regs |= reg2.bit(); 4251 if (reg3.is_valid()) regs |= reg3.bit(); 4252 if (reg4.is_valid()) regs |= reg4.bit(); 4253 if (reg5.is_valid()) regs |= reg5.bit(); 4254 if (reg6.is_valid()) regs |= reg6.bit(); 4255 if (reg7.is_valid()) regs |= reg7.bit(); 4256 if (reg8.is_valid()) regs |= reg8.bit(); 4257 if (reg9.is_valid()) regs |= reg9.bit(); 4258 if (reg10.is_valid()) regs |= reg10.bit(); 4259 int n_of_non_aliasing_regs = NumRegs(regs); 4260 4261 return n_of_valid_regs != n_of_non_aliasing_regs; 4262 } 4263 #endif 4264 4265 4266 CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions, 4267 FlushICache flush_cache) 4268 : address_(address), 4269 size_(instructions * Assembler::kInstrSize), 4270 masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo), 4271 flush_cache_(flush_cache) { 4272 // Create a new macro assembler pointing to the address of the code to patch. 4273 // The size is adjusted with kGap on order for the assembler to generate size 4274 // bytes of instructions without failing with buffer size constraints. 4275 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 4276 } 4277 4278 4279 CodePatcher::~CodePatcher() { 4280 // Indicate that code has changed. 4281 if (flush_cache_ == FLUSH) { 4282 Assembler::FlushICache(masm_.isolate(), address_, size_); 4283 } 4284 4285 // Check that the code was patched as expected. 4286 DCHECK(masm_.pc_ == address_ + size_); 4287 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 4288 } 4289 4290 4291 void CodePatcher::Emit(Instr instr) { masm()->emit(instr); } 4292 4293 4294 void CodePatcher::EmitCondition(Condition cond) { 4295 Instr instr = Assembler::instr_at(masm_.pc_); 4296 switch (cond) { 4297 case eq: 4298 instr = (instr & ~kCondMask) | BT; 4299 break; 4300 case ne: 4301 instr = (instr & ~kCondMask) | BF; 4302 break; 4303 default: 4304 UNIMPLEMENTED(); 4305 } 4306 masm_.emit(instr); 4307 } 4308 4309 4310 void MacroAssembler::TruncatingDiv(Register result, Register dividend, 4311 int32_t divisor) { 4312 DCHECK(!dividend.is(result)); 4313 DCHECK(!dividend.is(r0)); 4314 DCHECK(!result.is(r0)); 4315 base::MagicNumbersForDivision<uint32_t> mag = 4316 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor)); 4317 mov(r0, Operand(mag.multiplier)); 4318 mulhw(result, dividend, r0); 4319 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0; 4320 if (divisor > 0 && neg) { 4321 add(result, result, dividend); 4322 } 4323 if (divisor < 0 && !neg && mag.multiplier > 0) { 4324 sub(result, result, dividend); 4325 } 4326 if (mag.shift > 0) srawi(result, result, mag.shift); 4327 ExtractBit(r0, dividend, 31); 4328 add(result, result, r0); 4329 } 4330 4331 } // namespace internal 4332 } // namespace v8 4333 4334 #endif // V8_TARGET_ARCH_PPC 4335