1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <limits.h> // For LONG_MIN, LONG_MAX. 6 7 #if V8_TARGET_ARCH_ARM 8 9 #include "src/base/bits.h" 10 #include "src/base/division-by-constant.h" 11 #include "src/bootstrapper.h" 12 #include "src/codegen.h" 13 #include "src/debug/debug.h" 14 #include "src/register-configuration.h" 15 #include "src/runtime/runtime.h" 16 17 #include "src/arm/macro-assembler-arm.h" 18 19 namespace v8 { 20 namespace internal { 21 22 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size, 23 CodeObjectRequired create_code_object) 24 : Assembler(arg_isolate, buffer, size), 25 generating_stub_(false), 26 has_frame_(false) { 27 if (create_code_object == CodeObjectRequired::kYes) { 28 code_object_ = 29 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate()); 30 } 31 } 32 33 34 void MacroAssembler::Jump(Register target, Condition cond) { 35 bx(target, cond); 36 } 37 38 39 void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode, 40 Condition cond) { 41 DCHECK(RelocInfo::IsCodeTarget(rmode)); 42 mov(pc, Operand(target, rmode), LeaveCC, cond); 43 } 44 45 46 void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode, 47 Condition cond) { 48 DCHECK(!RelocInfo::IsCodeTarget(rmode)); 49 Jump(reinterpret_cast<intptr_t>(target), rmode, cond); 50 } 51 52 53 void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode, 54 Condition cond) { 55 DCHECK(RelocInfo::IsCodeTarget(rmode)); 56 // 'code' is always generated ARM code, never THUMB code 57 AllowDeferredHandleDereference embedding_raw_address; 58 Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond); 59 } 60 61 62 int MacroAssembler::CallSize(Register target, Condition cond) { 63 return kInstrSize; 64 } 65 66 67 void MacroAssembler::Call(Register target, Condition cond) { 68 // Block constant pool for the call instruction sequence. 69 BlockConstPoolScope block_const_pool(this); 70 Label start; 71 bind(&start); 72 blx(target, cond); 73 DCHECK_EQ(CallSize(target, cond), SizeOfCodeGeneratedSince(&start)); 74 } 75 76 77 int MacroAssembler::CallSize( 78 Address target, RelocInfo::Mode rmode, Condition cond) { 79 Instr mov_instr = cond | MOV | LeaveCC; 80 Operand mov_operand = Operand(reinterpret_cast<intptr_t>(target), rmode); 81 return kInstrSize + 82 mov_operand.instructions_required(this, mov_instr) * kInstrSize; 83 } 84 85 86 int MacroAssembler::CallStubSize( 87 CodeStub* stub, TypeFeedbackId ast_id, Condition cond) { 88 return CallSize(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond); 89 } 90 91 92 int MacroAssembler::CallSizeNotPredictableCodeSize(Isolate* isolate, 93 Address target, 94 RelocInfo::Mode rmode, 95 Condition cond) { 96 Instr mov_instr = cond | MOV | LeaveCC; 97 Operand mov_operand = Operand(reinterpret_cast<intptr_t>(target), rmode); 98 return kInstrSize + 99 mov_operand.instructions_required(NULL, mov_instr) * kInstrSize; 100 } 101 102 103 void MacroAssembler::Call(Address target, 104 RelocInfo::Mode rmode, 105 Condition cond, 106 TargetAddressStorageMode mode) { 107 // Block constant pool for the call instruction sequence. 108 BlockConstPoolScope block_const_pool(this); 109 Label start; 110 bind(&start); 111 112 bool old_predictable_code_size = predictable_code_size(); 113 if (mode == NEVER_INLINE_TARGET_ADDRESS) { 114 set_predictable_code_size(true); 115 } 116 117 #ifdef DEBUG 118 // Check the expected size before generating code to ensure we assume the same 119 // constant pool availability (e.g., whether constant pool is full or not). 120 int expected_size = CallSize(target, rmode, cond); 121 #endif 122 123 // Call sequence on V7 or later may be : 124 // movw ip, #... @ call address low 16 125 // movt ip, #... @ call address high 16 126 // blx ip 127 // @ return address 128 // Or for pre-V7 or values that may be back-patched 129 // to avoid ICache flushes: 130 // ldr ip, [pc, #...] @ call address 131 // blx ip 132 // @ return address 133 134 // Statement positions are expected to be recorded when the target 135 // address is loaded. The mov method will automatically record 136 // positions when pc is the target, since this is not the case here 137 // we have to do it explicitly. 138 positions_recorder()->WriteRecordedPositions(); 139 140 mov(ip, Operand(reinterpret_cast<int32_t>(target), rmode)); 141 blx(ip, cond); 142 143 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start)); 144 if (mode == NEVER_INLINE_TARGET_ADDRESS) { 145 set_predictable_code_size(old_predictable_code_size); 146 } 147 } 148 149 150 int MacroAssembler::CallSize(Handle<Code> code, 151 RelocInfo::Mode rmode, 152 TypeFeedbackId ast_id, 153 Condition cond) { 154 AllowDeferredHandleDereference using_raw_address; 155 return CallSize(reinterpret_cast<Address>(code.location()), rmode, cond); 156 } 157 158 159 void MacroAssembler::Call(Handle<Code> code, 160 RelocInfo::Mode rmode, 161 TypeFeedbackId ast_id, 162 Condition cond, 163 TargetAddressStorageMode mode) { 164 Label start; 165 bind(&start); 166 DCHECK(RelocInfo::IsCodeTarget(rmode)); 167 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) { 168 SetRecordedAstId(ast_id); 169 rmode = RelocInfo::CODE_TARGET_WITH_ID; 170 } 171 // 'code' is always generated ARM code, never THUMB code 172 AllowDeferredHandleDereference embedding_raw_address; 173 Call(reinterpret_cast<Address>(code.location()), rmode, cond, mode); 174 } 175 176 177 void MacroAssembler::Ret(Condition cond) { 178 bx(lr, cond); 179 } 180 181 182 void MacroAssembler::Drop(int count, Condition cond) { 183 if (count > 0) { 184 add(sp, sp, Operand(count * kPointerSize), LeaveCC, cond); 185 } 186 } 187 188 189 void MacroAssembler::Ret(int drop, Condition cond) { 190 Drop(drop, cond); 191 Ret(cond); 192 } 193 194 195 void MacroAssembler::Swap(Register reg1, 196 Register reg2, 197 Register scratch, 198 Condition cond) { 199 if (scratch.is(no_reg)) { 200 eor(reg1, reg1, Operand(reg2), LeaveCC, cond); 201 eor(reg2, reg2, Operand(reg1), LeaveCC, cond); 202 eor(reg1, reg1, Operand(reg2), LeaveCC, cond); 203 } else { 204 mov(scratch, reg1, LeaveCC, cond); 205 mov(reg1, reg2, LeaveCC, cond); 206 mov(reg2, scratch, LeaveCC, cond); 207 } 208 } 209 210 211 void MacroAssembler::Call(Label* target) { 212 bl(target); 213 } 214 215 216 void MacroAssembler::Push(Handle<Object> handle) { 217 mov(ip, Operand(handle)); 218 push(ip); 219 } 220 221 222 void MacroAssembler::Move(Register dst, Handle<Object> value) { 223 AllowDeferredHandleDereference smi_check; 224 if (value->IsSmi()) { 225 mov(dst, Operand(value)); 226 } else { 227 DCHECK(value->IsHeapObject()); 228 if (isolate()->heap()->InNewSpace(*value)) { 229 Handle<Cell> cell = isolate()->factory()->NewCell(value); 230 mov(dst, Operand(cell)); 231 ldr(dst, FieldMemOperand(dst, Cell::kValueOffset)); 232 } else { 233 mov(dst, Operand(value)); 234 } 235 } 236 } 237 238 239 void MacroAssembler::Move(Register dst, Register src, Condition cond) { 240 if (!dst.is(src)) { 241 mov(dst, src, LeaveCC, cond); 242 } 243 } 244 245 246 void MacroAssembler::Move(DwVfpRegister dst, DwVfpRegister src) { 247 if (!dst.is(src)) { 248 vmov(dst, src); 249 } 250 } 251 252 253 void MacroAssembler::Mls(Register dst, Register src1, Register src2, 254 Register srcA, Condition cond) { 255 if (CpuFeatures::IsSupported(MLS)) { 256 CpuFeatureScope scope(this, MLS); 257 mls(dst, src1, src2, srcA, cond); 258 } else { 259 DCHECK(!srcA.is(ip)); 260 mul(ip, src1, src2, LeaveCC, cond); 261 sub(dst, srcA, ip, LeaveCC, cond); 262 } 263 } 264 265 266 void MacroAssembler::And(Register dst, Register src1, const Operand& src2, 267 Condition cond) { 268 if (!src2.is_reg() && 269 !src2.must_output_reloc_info(this) && 270 src2.immediate() == 0) { 271 mov(dst, Operand::Zero(), LeaveCC, cond); 272 } else if (!(src2.instructions_required(this) == 1) && 273 !src2.must_output_reloc_info(this) && 274 CpuFeatures::IsSupported(ARMv7) && 275 base::bits::IsPowerOfTwo32(src2.immediate() + 1)) { 276 ubfx(dst, src1, 0, 277 WhichPowerOf2(static_cast<uint32_t>(src2.immediate()) + 1), cond); 278 } else { 279 and_(dst, src1, src2, LeaveCC, cond); 280 } 281 } 282 283 284 void MacroAssembler::Ubfx(Register dst, Register src1, int lsb, int width, 285 Condition cond) { 286 DCHECK(lsb < 32); 287 if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) { 288 int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1); 289 and_(dst, src1, Operand(mask), LeaveCC, cond); 290 if (lsb != 0) { 291 mov(dst, Operand(dst, LSR, lsb), LeaveCC, cond); 292 } 293 } else { 294 ubfx(dst, src1, lsb, width, cond); 295 } 296 } 297 298 299 void MacroAssembler::Sbfx(Register dst, Register src1, int lsb, int width, 300 Condition cond) { 301 DCHECK(lsb < 32); 302 if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) { 303 int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1); 304 and_(dst, src1, Operand(mask), LeaveCC, cond); 305 int shift_up = 32 - lsb - width; 306 int shift_down = lsb + shift_up; 307 if (shift_up != 0) { 308 mov(dst, Operand(dst, LSL, shift_up), LeaveCC, cond); 309 } 310 if (shift_down != 0) { 311 mov(dst, Operand(dst, ASR, shift_down), LeaveCC, cond); 312 } 313 } else { 314 sbfx(dst, src1, lsb, width, cond); 315 } 316 } 317 318 319 void MacroAssembler::Bfi(Register dst, 320 Register src, 321 Register scratch, 322 int lsb, 323 int width, 324 Condition cond) { 325 DCHECK(0 <= lsb && lsb < 32); 326 DCHECK(0 <= width && width < 32); 327 DCHECK(lsb + width < 32); 328 DCHECK(!scratch.is(dst)); 329 if (width == 0) return; 330 if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) { 331 int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1); 332 bic(dst, dst, Operand(mask)); 333 and_(scratch, src, Operand((1 << width) - 1)); 334 mov(scratch, Operand(scratch, LSL, lsb)); 335 orr(dst, dst, scratch); 336 } else { 337 bfi(dst, src, lsb, width, cond); 338 } 339 } 340 341 342 void MacroAssembler::Bfc(Register dst, Register src, int lsb, int width, 343 Condition cond) { 344 DCHECK(lsb < 32); 345 if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) { 346 int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1); 347 bic(dst, src, Operand(mask)); 348 } else { 349 Move(dst, src, cond); 350 bfc(dst, lsb, width, cond); 351 } 352 } 353 354 355 void MacroAssembler::Usat(Register dst, int satpos, const Operand& src, 356 Condition cond) { 357 if (!CpuFeatures::IsSupported(ARMv7) || predictable_code_size()) { 358 DCHECK(!dst.is(pc) && !src.rm().is(pc)); 359 DCHECK((satpos >= 0) && (satpos <= 31)); 360 361 // These asserts are required to ensure compatibility with the ARMv7 362 // implementation. 363 DCHECK((src.shift_op() == ASR) || (src.shift_op() == LSL)); 364 DCHECK(src.rs().is(no_reg)); 365 366 Label done; 367 int satval = (1 << satpos) - 1; 368 369 if (cond != al) { 370 b(NegateCondition(cond), &done); // Skip saturate if !condition. 371 } 372 if (!(src.is_reg() && dst.is(src.rm()))) { 373 mov(dst, src); 374 } 375 tst(dst, Operand(~satval)); 376 b(eq, &done); 377 mov(dst, Operand::Zero(), LeaveCC, mi); // 0 if negative. 378 mov(dst, Operand(satval), LeaveCC, pl); // satval if positive. 379 bind(&done); 380 } else { 381 usat(dst, satpos, src, cond); 382 } 383 } 384 385 386 void MacroAssembler::Load(Register dst, 387 const MemOperand& src, 388 Representation r) { 389 DCHECK(!r.IsDouble()); 390 if (r.IsInteger8()) { 391 ldrsb(dst, src); 392 } else if (r.IsUInteger8()) { 393 ldrb(dst, src); 394 } else if (r.IsInteger16()) { 395 ldrsh(dst, src); 396 } else if (r.IsUInteger16()) { 397 ldrh(dst, src); 398 } else { 399 ldr(dst, src); 400 } 401 } 402 403 404 void MacroAssembler::Store(Register src, 405 const MemOperand& dst, 406 Representation r) { 407 DCHECK(!r.IsDouble()); 408 if (r.IsInteger8() || r.IsUInteger8()) { 409 strb(src, dst); 410 } else if (r.IsInteger16() || r.IsUInteger16()) { 411 strh(src, dst); 412 } else { 413 if (r.IsHeapObject()) { 414 AssertNotSmi(src); 415 } else if (r.IsSmi()) { 416 AssertSmi(src); 417 } 418 str(src, dst); 419 } 420 } 421 422 423 void MacroAssembler::LoadRoot(Register destination, 424 Heap::RootListIndex index, 425 Condition cond) { 426 if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) && 427 isolate()->heap()->RootCanBeTreatedAsConstant(index) && 428 !predictable_code_size()) { 429 // The CPU supports fast immediate values, and this root will never 430 // change. We will load it as a relocatable immediate value. 431 Handle<Object> root = isolate()->heap()->root_handle(index); 432 mov(destination, Operand(root), LeaveCC, cond); 433 return; 434 } 435 ldr(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), cond); 436 } 437 438 439 void MacroAssembler::StoreRoot(Register source, 440 Heap::RootListIndex index, 441 Condition cond) { 442 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); 443 str(source, MemOperand(kRootRegister, index << kPointerSizeLog2), cond); 444 } 445 446 447 void MacroAssembler::InNewSpace(Register object, 448 Register scratch, 449 Condition cond, 450 Label* branch) { 451 DCHECK(cond == eq || cond == ne); 452 and_(scratch, object, Operand(ExternalReference::new_space_mask(isolate()))); 453 cmp(scratch, Operand(ExternalReference::new_space_start(isolate()))); 454 b(cond, branch); 455 } 456 457 458 void MacroAssembler::RecordWriteField( 459 Register object, 460 int offset, 461 Register value, 462 Register dst, 463 LinkRegisterStatus lr_status, 464 SaveFPRegsMode save_fp, 465 RememberedSetAction remembered_set_action, 466 SmiCheck smi_check, 467 PointersToHereCheck pointers_to_here_check_for_value) { 468 // First, check if a write barrier is even needed. The tests below 469 // catch stores of Smis. 470 Label done; 471 472 // Skip barrier if writing a smi. 473 if (smi_check == INLINE_SMI_CHECK) { 474 JumpIfSmi(value, &done); 475 } 476 477 // Although the object register is tagged, the offset is relative to the start 478 // of the object, so so offset must be a multiple of kPointerSize. 479 DCHECK(IsAligned(offset, kPointerSize)); 480 481 add(dst, object, Operand(offset - kHeapObjectTag)); 482 if (emit_debug_code()) { 483 Label ok; 484 tst(dst, Operand((1 << kPointerSizeLog2) - 1)); 485 b(eq, &ok); 486 stop("Unaligned cell in write barrier"); 487 bind(&ok); 488 } 489 490 RecordWrite(object, 491 dst, 492 value, 493 lr_status, 494 save_fp, 495 remembered_set_action, 496 OMIT_SMI_CHECK, 497 pointers_to_here_check_for_value); 498 499 bind(&done); 500 501 // Clobber clobbered input registers when running with the debug-code flag 502 // turned on to provoke errors. 503 if (emit_debug_code()) { 504 mov(value, Operand(bit_cast<int32_t>(kZapValue + 4))); 505 mov(dst, Operand(bit_cast<int32_t>(kZapValue + 8))); 506 } 507 } 508 509 510 // Will clobber 4 registers: object, map, dst, ip. The 511 // register 'object' contains a heap object pointer. 512 void MacroAssembler::RecordWriteForMap(Register object, 513 Register map, 514 Register dst, 515 LinkRegisterStatus lr_status, 516 SaveFPRegsMode fp_mode) { 517 if (emit_debug_code()) { 518 ldr(dst, FieldMemOperand(map, HeapObject::kMapOffset)); 519 cmp(dst, Operand(isolate()->factory()->meta_map())); 520 Check(eq, kWrongAddressOrValuePassedToRecordWrite); 521 } 522 523 if (!FLAG_incremental_marking) { 524 return; 525 } 526 527 if (emit_debug_code()) { 528 ldr(ip, FieldMemOperand(object, HeapObject::kMapOffset)); 529 cmp(ip, map); 530 Check(eq, kWrongAddressOrValuePassedToRecordWrite); 531 } 532 533 Label done; 534 535 // A single check of the map's pages interesting flag suffices, since it is 536 // only set during incremental collection, and then it's also guaranteed that 537 // the from object's page's interesting flag is also set. This optimization 538 // relies on the fact that maps can never be in new space. 539 CheckPageFlag(map, 540 map, // Used as scratch. 541 MemoryChunk::kPointersToHereAreInterestingMask, 542 eq, 543 &done); 544 545 add(dst, object, Operand(HeapObject::kMapOffset - kHeapObjectTag)); 546 if (emit_debug_code()) { 547 Label ok; 548 tst(dst, Operand((1 << kPointerSizeLog2) - 1)); 549 b(eq, &ok); 550 stop("Unaligned cell in write barrier"); 551 bind(&ok); 552 } 553 554 // Record the actual write. 555 if (lr_status == kLRHasNotBeenSaved) { 556 push(lr); 557 } 558 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET, 559 fp_mode); 560 CallStub(&stub); 561 if (lr_status == kLRHasNotBeenSaved) { 562 pop(lr); 563 } 564 565 bind(&done); 566 567 // Count number of write barriers in generated code. 568 isolate()->counters()->write_barriers_static()->Increment(); 569 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, dst); 570 571 // Clobber clobbered registers when running with the debug-code flag 572 // turned on to provoke errors. 573 if (emit_debug_code()) { 574 mov(dst, Operand(bit_cast<int32_t>(kZapValue + 12))); 575 mov(map, Operand(bit_cast<int32_t>(kZapValue + 16))); 576 } 577 } 578 579 580 // Will clobber 4 registers: object, address, scratch, ip. The 581 // register 'object' contains a heap object pointer. The heap object 582 // tag is shifted away. 583 void MacroAssembler::RecordWrite( 584 Register object, 585 Register address, 586 Register value, 587 LinkRegisterStatus lr_status, 588 SaveFPRegsMode fp_mode, 589 RememberedSetAction remembered_set_action, 590 SmiCheck smi_check, 591 PointersToHereCheck pointers_to_here_check_for_value) { 592 DCHECK(!object.is(value)); 593 if (emit_debug_code()) { 594 ldr(ip, MemOperand(address)); 595 cmp(ip, value); 596 Check(eq, kWrongAddressOrValuePassedToRecordWrite); 597 } 598 599 if (remembered_set_action == OMIT_REMEMBERED_SET && 600 !FLAG_incremental_marking) { 601 return; 602 } 603 604 // First, check if a write barrier is even needed. The tests below 605 // catch stores of smis and stores into the young generation. 606 Label done; 607 608 if (smi_check == INLINE_SMI_CHECK) { 609 JumpIfSmi(value, &done); 610 } 611 612 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { 613 CheckPageFlag(value, 614 value, // Used as scratch. 615 MemoryChunk::kPointersToHereAreInterestingMask, 616 eq, 617 &done); 618 } 619 CheckPageFlag(object, 620 value, // Used as scratch. 621 MemoryChunk::kPointersFromHereAreInterestingMask, 622 eq, 623 &done); 624 625 // Record the actual write. 626 if (lr_status == kLRHasNotBeenSaved) { 627 push(lr); 628 } 629 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, 630 fp_mode); 631 CallStub(&stub); 632 if (lr_status == kLRHasNotBeenSaved) { 633 pop(lr); 634 } 635 636 bind(&done); 637 638 // Count number of write barriers in generated code. 639 isolate()->counters()->write_barriers_static()->Increment(); 640 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, 641 value); 642 643 // Clobber clobbered registers when running with the debug-code flag 644 // turned on to provoke errors. 645 if (emit_debug_code()) { 646 mov(address, Operand(bit_cast<int32_t>(kZapValue + 12))); 647 mov(value, Operand(bit_cast<int32_t>(kZapValue + 16))); 648 } 649 } 650 651 652 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests. 653 Register address, 654 Register scratch, 655 SaveFPRegsMode fp_mode, 656 RememberedSetFinalAction and_then) { 657 Label done; 658 if (emit_debug_code()) { 659 Label ok; 660 JumpIfNotInNewSpace(object, scratch, &ok); 661 stop("Remembered set pointer is in new space"); 662 bind(&ok); 663 } 664 // Load store buffer top. 665 ExternalReference store_buffer = 666 ExternalReference::store_buffer_top(isolate()); 667 mov(ip, Operand(store_buffer)); 668 ldr(scratch, MemOperand(ip)); 669 // Store pointer to buffer and increment buffer top. 670 str(address, MemOperand(scratch, kPointerSize, PostIndex)); 671 // Write back new top of buffer. 672 str(scratch, MemOperand(ip)); 673 // Call stub on end of buffer. 674 // Check for end of buffer. 675 tst(scratch, Operand(StoreBuffer::kStoreBufferOverflowBit)); 676 if (and_then == kFallThroughAtEnd) { 677 b(eq, &done); 678 } else { 679 DCHECK(and_then == kReturnAtEnd); 680 Ret(eq); 681 } 682 push(lr); 683 StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode); 684 CallStub(&store_buffer_overflow); 685 pop(lr); 686 bind(&done); 687 if (and_then == kReturnAtEnd) { 688 Ret(); 689 } 690 } 691 692 693 void MacroAssembler::PushFixedFrame(Register marker_reg) { 694 DCHECK(!marker_reg.is_valid() || marker_reg.code() < cp.code()); 695 stm(db_w, sp, (marker_reg.is_valid() ? marker_reg.bit() : 0) | cp.bit() | 696 (FLAG_enable_embedded_constant_pool ? pp.bit() : 0) | 697 fp.bit() | lr.bit()); 698 } 699 700 701 void MacroAssembler::PopFixedFrame(Register marker_reg) { 702 DCHECK(!marker_reg.is_valid() || marker_reg.code() < cp.code()); 703 ldm(ia_w, sp, (marker_reg.is_valid() ? marker_reg.bit() : 0) | cp.bit() | 704 (FLAG_enable_embedded_constant_pool ? pp.bit() : 0) | 705 fp.bit() | lr.bit()); 706 } 707 708 709 // Push and pop all registers that can hold pointers. 710 void MacroAssembler::PushSafepointRegisters() { 711 // Safepoints expect a block of contiguous register values starting with r0. 712 // except when FLAG_enable_embedded_constant_pool, which omits pp. 713 DCHECK(kSafepointSavedRegisters == 714 (FLAG_enable_embedded_constant_pool 715 ? ((1 << (kNumSafepointSavedRegisters + 1)) - 1) & ~pp.bit() 716 : (1 << kNumSafepointSavedRegisters) - 1)); 717 // Safepoints expect a block of kNumSafepointRegisters values on the 718 // stack, so adjust the stack for unsaved registers. 719 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; 720 DCHECK(num_unsaved >= 0); 721 sub(sp, sp, Operand(num_unsaved * kPointerSize)); 722 stm(db_w, sp, kSafepointSavedRegisters); 723 } 724 725 726 void MacroAssembler::PopSafepointRegisters() { 727 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; 728 ldm(ia_w, sp, kSafepointSavedRegisters); 729 add(sp, sp, Operand(num_unsaved * kPointerSize)); 730 } 731 732 733 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { 734 str(src, SafepointRegisterSlot(dst)); 735 } 736 737 738 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { 739 ldr(dst, SafepointRegisterSlot(src)); 740 } 741 742 743 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { 744 // The registers are pushed starting with the highest encoding, 745 // which means that lowest encodings are closest to the stack pointer. 746 if (FLAG_enable_embedded_constant_pool && reg_code > pp.code()) { 747 // RegList omits pp. 748 reg_code -= 1; 749 } 750 DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters); 751 return reg_code; 752 } 753 754 755 MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) { 756 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); 757 } 758 759 760 MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) { 761 // Number of d-regs not known at snapshot time. 762 DCHECK(!serializer_enabled()); 763 // General purpose registers are pushed last on the stack. 764 const RegisterConfiguration* config = 765 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT); 766 int doubles_size = config->num_allocatable_double_registers() * kDoubleSize; 767 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize; 768 return MemOperand(sp, doubles_size + register_offset); 769 } 770 771 772 void MacroAssembler::Ldrd(Register dst1, Register dst2, 773 const MemOperand& src, Condition cond) { 774 DCHECK(src.rm().is(no_reg)); 775 DCHECK(!dst1.is(lr)); // r14. 776 777 // V8 does not use this addressing mode, so the fallback code 778 // below doesn't support it yet. 779 DCHECK((src.am() != PreIndex) && (src.am() != NegPreIndex)); 780 781 // Generate two ldr instructions if ldrd is not available. 782 if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size() && 783 (dst1.code() % 2 == 0) && (dst1.code() + 1 == dst2.code())) { 784 CpuFeatureScope scope(this, ARMv7); 785 ldrd(dst1, dst2, src, cond); 786 } else { 787 if ((src.am() == Offset) || (src.am() == NegOffset)) { 788 MemOperand src2(src); 789 src2.set_offset(src2.offset() + 4); 790 if (dst1.is(src.rn())) { 791 ldr(dst2, src2, cond); 792 ldr(dst1, src, cond); 793 } else { 794 ldr(dst1, src, cond); 795 ldr(dst2, src2, cond); 796 } 797 } else { // PostIndex or NegPostIndex. 798 DCHECK((src.am() == PostIndex) || (src.am() == NegPostIndex)); 799 if (dst1.is(src.rn())) { 800 ldr(dst2, MemOperand(src.rn(), 4, Offset), cond); 801 ldr(dst1, src, cond); 802 } else { 803 MemOperand src2(src); 804 src2.set_offset(src2.offset() - 4); 805 ldr(dst1, MemOperand(src.rn(), 4, PostIndex), cond); 806 ldr(dst2, src2, cond); 807 } 808 } 809 } 810 } 811 812 813 void MacroAssembler::Strd(Register src1, Register src2, 814 const MemOperand& dst, Condition cond) { 815 DCHECK(dst.rm().is(no_reg)); 816 DCHECK(!src1.is(lr)); // r14. 817 818 // V8 does not use this addressing mode, so the fallback code 819 // below doesn't support it yet. 820 DCHECK((dst.am() != PreIndex) && (dst.am() != NegPreIndex)); 821 822 // Generate two str instructions if strd is not available. 823 if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size() && 824 (src1.code() % 2 == 0) && (src1.code() + 1 == src2.code())) { 825 CpuFeatureScope scope(this, ARMv7); 826 strd(src1, src2, dst, cond); 827 } else { 828 MemOperand dst2(dst); 829 if ((dst.am() == Offset) || (dst.am() == NegOffset)) { 830 dst2.set_offset(dst2.offset() + 4); 831 str(src1, dst, cond); 832 str(src2, dst2, cond); 833 } else { // PostIndex or NegPostIndex. 834 DCHECK((dst.am() == PostIndex) || (dst.am() == NegPostIndex)); 835 dst2.set_offset(dst2.offset() - 4); 836 str(src1, MemOperand(dst.rn(), 4, PostIndex), cond); 837 str(src2, dst2, cond); 838 } 839 } 840 } 841 842 843 void MacroAssembler::VFPEnsureFPSCRState(Register scratch) { 844 // If needed, restore wanted bits of FPSCR. 845 Label fpscr_done; 846 vmrs(scratch); 847 if (emit_debug_code()) { 848 Label rounding_mode_correct; 849 tst(scratch, Operand(kVFPRoundingModeMask)); 850 b(eq, &rounding_mode_correct); 851 // Don't call Assert here, since Runtime_Abort could re-enter here. 852 stop("Default rounding mode not set"); 853 bind(&rounding_mode_correct); 854 } 855 tst(scratch, Operand(kVFPDefaultNaNModeControlBit)); 856 b(ne, &fpscr_done); 857 orr(scratch, scratch, Operand(kVFPDefaultNaNModeControlBit)); 858 vmsr(scratch); 859 bind(&fpscr_done); 860 } 861 862 863 void MacroAssembler::VFPCanonicalizeNaN(const DwVfpRegister dst, 864 const DwVfpRegister src, 865 const Condition cond) { 866 vsub(dst, src, kDoubleRegZero, cond); 867 } 868 869 870 void MacroAssembler::VFPCompareAndSetFlags(const SwVfpRegister src1, 871 const SwVfpRegister src2, 872 const Condition cond) { 873 // Compare and move FPSCR flags to the normal condition flags. 874 VFPCompareAndLoadFlags(src1, src2, pc, cond); 875 } 876 877 void MacroAssembler::VFPCompareAndSetFlags(const SwVfpRegister src1, 878 const float src2, 879 const Condition cond) { 880 // Compare and move FPSCR flags to the normal condition flags. 881 VFPCompareAndLoadFlags(src1, src2, pc, cond); 882 } 883 884 885 void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1, 886 const DwVfpRegister src2, 887 const Condition cond) { 888 // Compare and move FPSCR flags to the normal condition flags. 889 VFPCompareAndLoadFlags(src1, src2, pc, cond); 890 } 891 892 void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1, 893 const double src2, 894 const Condition cond) { 895 // Compare and move FPSCR flags to the normal condition flags. 896 VFPCompareAndLoadFlags(src1, src2, pc, cond); 897 } 898 899 900 void MacroAssembler::VFPCompareAndLoadFlags(const SwVfpRegister src1, 901 const SwVfpRegister src2, 902 const Register fpscr_flags, 903 const Condition cond) { 904 // Compare and load FPSCR. 905 vcmp(src1, src2, cond); 906 vmrs(fpscr_flags, cond); 907 } 908 909 void MacroAssembler::VFPCompareAndLoadFlags(const SwVfpRegister src1, 910 const float src2, 911 const Register fpscr_flags, 912 const Condition cond) { 913 // Compare and load FPSCR. 914 vcmp(src1, src2, cond); 915 vmrs(fpscr_flags, cond); 916 } 917 918 919 void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1, 920 const DwVfpRegister src2, 921 const Register fpscr_flags, 922 const Condition cond) { 923 // Compare and load FPSCR. 924 vcmp(src1, src2, cond); 925 vmrs(fpscr_flags, cond); 926 } 927 928 void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1, 929 const double src2, 930 const Register fpscr_flags, 931 const Condition cond) { 932 // Compare and load FPSCR. 933 vcmp(src1, src2, cond); 934 vmrs(fpscr_flags, cond); 935 } 936 937 938 void MacroAssembler::Vmov(const DwVfpRegister dst, 939 const double imm, 940 const Register scratch) { 941 static const DoubleRepresentation minus_zero(-0.0); 942 static const DoubleRepresentation zero(0.0); 943 DoubleRepresentation value_rep(imm); 944 // Handle special values first. 945 if (value_rep == zero) { 946 vmov(dst, kDoubleRegZero); 947 } else if (value_rep == minus_zero) { 948 vneg(dst, kDoubleRegZero); 949 } else { 950 vmov(dst, imm, scratch); 951 } 952 } 953 954 955 void MacroAssembler::VmovHigh(Register dst, DwVfpRegister src) { 956 if (src.code() < 16) { 957 const LowDwVfpRegister loc = LowDwVfpRegister::from_code(src.code()); 958 vmov(dst, loc.high()); 959 } else { 960 vmov(dst, VmovIndexHi, src); 961 } 962 } 963 964 965 void MacroAssembler::VmovHigh(DwVfpRegister dst, Register src) { 966 if (dst.code() < 16) { 967 const LowDwVfpRegister loc = LowDwVfpRegister::from_code(dst.code()); 968 vmov(loc.high(), src); 969 } else { 970 vmov(dst, VmovIndexHi, src); 971 } 972 } 973 974 975 void MacroAssembler::VmovLow(Register dst, DwVfpRegister src) { 976 if (src.code() < 16) { 977 const LowDwVfpRegister loc = LowDwVfpRegister::from_code(src.code()); 978 vmov(dst, loc.low()); 979 } else { 980 vmov(dst, VmovIndexLo, src); 981 } 982 } 983 984 985 void MacroAssembler::VmovLow(DwVfpRegister dst, Register src) { 986 if (dst.code() < 16) { 987 const LowDwVfpRegister loc = LowDwVfpRegister::from_code(dst.code()); 988 vmov(loc.low(), src); 989 } else { 990 vmov(dst, VmovIndexLo, src); 991 } 992 } 993 994 995 void MacroAssembler::LoadConstantPoolPointerRegisterFromCodeTargetAddress( 996 Register code_target_address) { 997 DCHECK(FLAG_enable_embedded_constant_pool); 998 ldr(pp, MemOperand(code_target_address, 999 Code::kConstantPoolOffset - Code::kHeaderSize)); 1000 add(pp, pp, code_target_address); 1001 } 1002 1003 1004 void MacroAssembler::LoadConstantPoolPointerRegister() { 1005 DCHECK(FLAG_enable_embedded_constant_pool); 1006 int entry_offset = pc_offset() + Instruction::kPCReadOffset; 1007 sub(ip, pc, Operand(entry_offset)); 1008 LoadConstantPoolPointerRegisterFromCodeTargetAddress(ip); 1009 } 1010 1011 1012 void MacroAssembler::StubPrologue() { 1013 PushFixedFrame(); 1014 Push(Smi::FromInt(StackFrame::STUB)); 1015 // Adjust FP to point to saved FP. 1016 add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); 1017 if (FLAG_enable_embedded_constant_pool) { 1018 LoadConstantPoolPointerRegister(); 1019 set_constant_pool_available(true); 1020 } 1021 } 1022 1023 1024 void MacroAssembler::Prologue(bool code_pre_aging) { 1025 { PredictableCodeSizeScope predictible_code_size_scope( 1026 this, kNoCodeAgeSequenceLength); 1027 // The following three instructions must remain together and unmodified 1028 // for code aging to work properly. 1029 if (code_pre_aging) { 1030 // Pre-age the code. 1031 Code* stub = Code::GetPreAgedCodeAgeStub(isolate()); 1032 add(r0, pc, Operand(-8)); 1033 ldr(pc, MemOperand(pc, -4)); 1034 emit_code_stub_address(stub); 1035 } else { 1036 PushFixedFrame(r1); 1037 nop(ip.code()); 1038 // Adjust FP to point to saved FP. 1039 add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); 1040 } 1041 } 1042 if (FLAG_enable_embedded_constant_pool) { 1043 LoadConstantPoolPointerRegister(); 1044 set_constant_pool_available(true); 1045 } 1046 } 1047 1048 1049 void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) { 1050 ldr(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1051 ldr(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset)); 1052 ldr(vector, 1053 FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset)); 1054 } 1055 1056 1057 void MacroAssembler::EnterFrame(StackFrame::Type type, 1058 bool load_constant_pool_pointer_reg) { 1059 // r0-r3: preserved 1060 PushFixedFrame(); 1061 if (FLAG_enable_embedded_constant_pool && load_constant_pool_pointer_reg) { 1062 LoadConstantPoolPointerRegister(); 1063 } 1064 mov(ip, Operand(Smi::FromInt(type))); 1065 push(ip); 1066 mov(ip, Operand(CodeObject())); 1067 push(ip); 1068 // Adjust FP to point to saved FP. 1069 add(fp, sp, 1070 Operand(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize)); 1071 } 1072 1073 1074 int MacroAssembler::LeaveFrame(StackFrame::Type type) { 1075 // r0: preserved 1076 // r1: preserved 1077 // r2: preserved 1078 1079 // Drop the execution stack down to the frame pointer and restore 1080 // the caller frame pointer, return address and constant pool pointer 1081 // (if FLAG_enable_embedded_constant_pool). 1082 int frame_ends; 1083 if (FLAG_enable_embedded_constant_pool) { 1084 add(sp, fp, Operand(StandardFrameConstants::kConstantPoolOffset)); 1085 frame_ends = pc_offset(); 1086 ldm(ia_w, sp, pp.bit() | fp.bit() | lr.bit()); 1087 } else { 1088 mov(sp, fp); 1089 frame_ends = pc_offset(); 1090 ldm(ia_w, sp, fp.bit() | lr.bit()); 1091 } 1092 return frame_ends; 1093 } 1094 1095 1096 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { 1097 // Set up the frame structure on the stack. 1098 DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); 1099 DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); 1100 DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); 1101 Push(lr, fp); 1102 mov(fp, Operand(sp)); // Set up new frame pointer. 1103 // Reserve room for saved entry sp and code object. 1104 sub(sp, sp, Operand(ExitFrameConstants::kFrameSize)); 1105 if (emit_debug_code()) { 1106 mov(ip, Operand::Zero()); 1107 str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); 1108 } 1109 if (FLAG_enable_embedded_constant_pool) { 1110 str(pp, MemOperand(fp, ExitFrameConstants::kConstantPoolOffset)); 1111 } 1112 mov(ip, Operand(CodeObject())); 1113 str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset)); 1114 1115 // Save the frame pointer and the context in top. 1116 mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); 1117 str(fp, MemOperand(ip)); 1118 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); 1119 str(cp, MemOperand(ip)); 1120 1121 // Optionally save all double registers. 1122 if (save_doubles) { 1123 SaveFPRegs(sp, ip); 1124 // Note that d0 will be accessible at 1125 // fp - ExitFrameConstants::kFrameSize - 1126 // DwVfpRegister::kMaxNumRegisters * kDoubleSize, 1127 // since the sp slot, code slot and constant pool slot (if 1128 // FLAG_enable_embedded_constant_pool) were pushed after the fp. 1129 } 1130 1131 // Reserve place for the return address and stack space and align the frame 1132 // preparing for calling the runtime function. 1133 const int frame_alignment = MacroAssembler::ActivationFrameAlignment(); 1134 sub(sp, sp, Operand((stack_space + 1) * kPointerSize)); 1135 if (frame_alignment > 0) { 1136 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 1137 and_(sp, sp, Operand(-frame_alignment)); 1138 } 1139 1140 // Set the exit frame sp value to point just before the return address 1141 // location. 1142 add(ip, sp, Operand(kPointerSize)); 1143 str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); 1144 } 1145 1146 1147 void MacroAssembler::InitializeNewString(Register string, 1148 Register length, 1149 Heap::RootListIndex map_index, 1150 Register scratch1, 1151 Register scratch2) { 1152 SmiTag(scratch1, length); 1153 LoadRoot(scratch2, map_index); 1154 str(scratch1, FieldMemOperand(string, String::kLengthOffset)); 1155 mov(scratch1, Operand(String::kEmptyHashField)); 1156 str(scratch2, FieldMemOperand(string, HeapObject::kMapOffset)); 1157 str(scratch1, FieldMemOperand(string, String::kHashFieldOffset)); 1158 } 1159 1160 1161 int MacroAssembler::ActivationFrameAlignment() { 1162 #if V8_HOST_ARCH_ARM 1163 // Running on the real platform. Use the alignment as mandated by the local 1164 // environment. 1165 // Note: This will break if we ever start generating snapshots on one ARM 1166 // platform for another ARM platform with a different alignment. 1167 return base::OS::ActivationFrameAlignment(); 1168 #else // V8_HOST_ARCH_ARM 1169 // If we are using the simulator then we should always align to the expected 1170 // alignment. As the simulator is used to generate snapshots we do not know 1171 // if the target platform will need alignment, so this is controlled from a 1172 // flag. 1173 return FLAG_sim_stack_alignment; 1174 #endif // V8_HOST_ARCH_ARM 1175 } 1176 1177 1178 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count, 1179 bool restore_context, 1180 bool argument_count_is_length) { 1181 ConstantPoolUnavailableScope constant_pool_unavailable(this); 1182 1183 // Optionally restore all double registers. 1184 if (save_doubles) { 1185 // Calculate the stack location of the saved doubles and restore them. 1186 const int offset = ExitFrameConstants::kFrameSize; 1187 sub(r3, fp, 1188 Operand(offset + DwVfpRegister::kMaxNumRegisters * kDoubleSize)); 1189 RestoreFPRegs(r3, ip); 1190 } 1191 1192 // Clear top frame. 1193 mov(r3, Operand::Zero()); 1194 mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); 1195 str(r3, MemOperand(ip)); 1196 1197 // Restore current context from top and clear it in debug mode. 1198 if (restore_context) { 1199 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); 1200 ldr(cp, MemOperand(ip)); 1201 } 1202 #ifdef DEBUG 1203 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate()))); 1204 str(r3, MemOperand(ip)); 1205 #endif 1206 1207 // Tear down the exit frame, pop the arguments, and return. 1208 if (FLAG_enable_embedded_constant_pool) { 1209 ldr(pp, MemOperand(fp, ExitFrameConstants::kConstantPoolOffset)); 1210 } 1211 mov(sp, Operand(fp)); 1212 ldm(ia_w, sp, fp.bit() | lr.bit()); 1213 if (argument_count.is_valid()) { 1214 if (argument_count_is_length) { 1215 add(sp, sp, argument_count); 1216 } else { 1217 add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2)); 1218 } 1219 } 1220 } 1221 1222 1223 void MacroAssembler::MovFromFloatResult(const DwVfpRegister dst) { 1224 if (use_eabi_hardfloat()) { 1225 Move(dst, d0); 1226 } else { 1227 vmov(dst, r0, r1); 1228 } 1229 } 1230 1231 1232 // On ARM this is just a synonym to make the purpose clear. 1233 void MacroAssembler::MovFromFloatParameter(DwVfpRegister dst) { 1234 MovFromFloatResult(dst); 1235 } 1236 1237 1238 void MacroAssembler::InvokePrologue(const ParameterCount& expected, 1239 const ParameterCount& actual, 1240 Label* done, 1241 bool* definitely_mismatches, 1242 InvokeFlag flag, 1243 const CallWrapper& call_wrapper) { 1244 bool definitely_matches = false; 1245 *definitely_mismatches = false; 1246 Label regular_invoke; 1247 1248 // Check whether the expected and actual arguments count match. If not, 1249 // setup registers according to contract with ArgumentsAdaptorTrampoline: 1250 // r0: actual arguments count 1251 // r1: function (passed through to callee) 1252 // r2: expected arguments count 1253 1254 // The code below is made a lot easier because the calling code already sets 1255 // up actual and expected registers according to the contract if values are 1256 // passed in registers. 1257 DCHECK(actual.is_immediate() || actual.reg().is(r0)); 1258 DCHECK(expected.is_immediate() || expected.reg().is(r2)); 1259 1260 if (expected.is_immediate()) { 1261 DCHECK(actual.is_immediate()); 1262 mov(r0, Operand(actual.immediate())); 1263 if (expected.immediate() == actual.immediate()) { 1264 definitely_matches = true; 1265 } else { 1266 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel; 1267 if (expected.immediate() == sentinel) { 1268 // Don't worry about adapting arguments for builtins that 1269 // don't want that done. Skip adaption code by making it look 1270 // like we have a match between expected and actual number of 1271 // arguments. 1272 definitely_matches = true; 1273 } else { 1274 *definitely_mismatches = true; 1275 mov(r2, Operand(expected.immediate())); 1276 } 1277 } 1278 } else { 1279 if (actual.is_immediate()) { 1280 mov(r0, Operand(actual.immediate())); 1281 cmp(expected.reg(), Operand(actual.immediate())); 1282 b(eq, ®ular_invoke); 1283 } else { 1284 cmp(expected.reg(), Operand(actual.reg())); 1285 b(eq, ®ular_invoke); 1286 } 1287 } 1288 1289 if (!definitely_matches) { 1290 Handle<Code> adaptor = 1291 isolate()->builtins()->ArgumentsAdaptorTrampoline(); 1292 if (flag == CALL_FUNCTION) { 1293 call_wrapper.BeforeCall(CallSize(adaptor)); 1294 Call(adaptor); 1295 call_wrapper.AfterCall(); 1296 if (!*definitely_mismatches) { 1297 b(done); 1298 } 1299 } else { 1300 Jump(adaptor, RelocInfo::CODE_TARGET); 1301 } 1302 bind(®ular_invoke); 1303 } 1304 } 1305 1306 1307 void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target, 1308 const ParameterCount& expected, 1309 const ParameterCount& actual) { 1310 Label skip_flooding; 1311 ExternalReference step_in_enabled = 1312 ExternalReference::debug_step_in_enabled_address(isolate()); 1313 mov(r4, Operand(step_in_enabled)); 1314 ldrb(r4, MemOperand(r4)); 1315 cmp(r4, Operand(0)); 1316 b(eq, &skip_flooding); 1317 { 1318 FrameScope frame(this, 1319 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); 1320 if (expected.is_reg()) { 1321 SmiTag(expected.reg()); 1322 Push(expected.reg()); 1323 } 1324 if (actual.is_reg()) { 1325 SmiTag(actual.reg()); 1326 Push(actual.reg()); 1327 } 1328 if (new_target.is_valid()) { 1329 Push(new_target); 1330 } 1331 Push(fun); 1332 Push(fun); 1333 CallRuntime(Runtime::kDebugPrepareStepInIfStepping, 1); 1334 Pop(fun); 1335 if (new_target.is_valid()) { 1336 Pop(new_target); 1337 } 1338 if (actual.is_reg()) { 1339 Pop(actual.reg()); 1340 SmiUntag(actual.reg()); 1341 } 1342 if (expected.is_reg()) { 1343 Pop(expected.reg()); 1344 SmiUntag(expected.reg()); 1345 } 1346 } 1347 bind(&skip_flooding); 1348 } 1349 1350 1351 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, 1352 const ParameterCount& expected, 1353 const ParameterCount& actual, 1354 InvokeFlag flag, 1355 const CallWrapper& call_wrapper) { 1356 // You can't call a function without a valid frame. 1357 DCHECK(flag == JUMP_FUNCTION || has_frame()); 1358 DCHECK(function.is(r1)); 1359 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r3)); 1360 1361 if (call_wrapper.NeedsDebugStepCheck()) { 1362 FloodFunctionIfStepping(function, new_target, expected, actual); 1363 } 1364 1365 // Clear the new.target register if not given. 1366 if (!new_target.is_valid()) { 1367 LoadRoot(r3, Heap::kUndefinedValueRootIndex); 1368 } 1369 1370 Label done; 1371 bool definitely_mismatches = false; 1372 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag, 1373 call_wrapper); 1374 if (!definitely_mismatches) { 1375 // We call indirectly through the code field in the function to 1376 // allow recompilation to take effect without changing any of the 1377 // call sites. 1378 Register code = r4; 1379 ldr(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); 1380 if (flag == CALL_FUNCTION) { 1381 call_wrapper.BeforeCall(CallSize(code)); 1382 Call(code); 1383 call_wrapper.AfterCall(); 1384 } else { 1385 DCHECK(flag == JUMP_FUNCTION); 1386 Jump(code); 1387 } 1388 1389 // Continue here if InvokePrologue does handle the invocation due to 1390 // mismatched parameter counts. 1391 bind(&done); 1392 } 1393 } 1394 1395 1396 void MacroAssembler::InvokeFunction(Register fun, 1397 Register new_target, 1398 const ParameterCount& actual, 1399 InvokeFlag flag, 1400 const CallWrapper& call_wrapper) { 1401 // You can't call a function without a valid frame. 1402 DCHECK(flag == JUMP_FUNCTION || has_frame()); 1403 1404 // Contract with called JS functions requires that function is passed in r1. 1405 DCHECK(fun.is(r1)); 1406 1407 Register expected_reg = r2; 1408 Register temp_reg = r4; 1409 1410 ldr(temp_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 1411 ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 1412 ldr(expected_reg, 1413 FieldMemOperand(temp_reg, 1414 SharedFunctionInfo::kFormalParameterCountOffset)); 1415 SmiUntag(expected_reg); 1416 1417 ParameterCount expected(expected_reg); 1418 InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper); 1419 } 1420 1421 1422 void MacroAssembler::InvokeFunction(Register function, 1423 const ParameterCount& expected, 1424 const ParameterCount& actual, 1425 InvokeFlag flag, 1426 const CallWrapper& call_wrapper) { 1427 // You can't call a function without a valid frame. 1428 DCHECK(flag == JUMP_FUNCTION || has_frame()); 1429 1430 // Contract with called JS functions requires that function is passed in r1. 1431 DCHECK(function.is(r1)); 1432 1433 // Get the function and setup the context. 1434 ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 1435 1436 InvokeFunctionCode(r1, no_reg, expected, actual, flag, call_wrapper); 1437 } 1438 1439 1440 void MacroAssembler::InvokeFunction(Handle<JSFunction> function, 1441 const ParameterCount& expected, 1442 const ParameterCount& actual, 1443 InvokeFlag flag, 1444 const CallWrapper& call_wrapper) { 1445 Move(r1, function); 1446 InvokeFunction(r1, expected, actual, flag, call_wrapper); 1447 } 1448 1449 1450 void MacroAssembler::IsObjectJSStringType(Register object, 1451 Register scratch, 1452 Label* fail) { 1453 DCHECK(kNotStringTag != 0); 1454 1455 ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 1456 ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); 1457 tst(scratch, Operand(kIsNotStringMask)); 1458 b(ne, fail); 1459 } 1460 1461 1462 void MacroAssembler::IsObjectNameType(Register object, 1463 Register scratch, 1464 Label* fail) { 1465 ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 1466 ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); 1467 cmp(scratch, Operand(LAST_NAME_TYPE)); 1468 b(hi, fail); 1469 } 1470 1471 1472 void MacroAssembler::DebugBreak() { 1473 mov(r0, Operand::Zero()); 1474 mov(r1, 1475 Operand(ExternalReference(Runtime::kHandleDebuggerStatement, isolate()))); 1476 CEntryStub ces(isolate(), 1); 1477 DCHECK(AllowThisStubCall(&ces)); 1478 Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); 1479 } 1480 1481 1482 void MacroAssembler::PushStackHandler() { 1483 // Adjust this code if not the case. 1484 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); 1485 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); 1486 1487 // Link the current handler as the next handler. 1488 mov(r6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); 1489 ldr(r5, MemOperand(r6)); 1490 push(r5); 1491 1492 // Set this new handler as the current one. 1493 str(sp, MemOperand(r6)); 1494 } 1495 1496 1497 void MacroAssembler::PopStackHandler() { 1498 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 1499 pop(r1); 1500 mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); 1501 add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); 1502 str(r1, MemOperand(ip)); 1503 } 1504 1505 1506 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, 1507 Register scratch, 1508 Label* miss) { 1509 Label same_contexts; 1510 1511 DCHECK(!holder_reg.is(scratch)); 1512 DCHECK(!holder_reg.is(ip)); 1513 DCHECK(!scratch.is(ip)); 1514 1515 // Load current lexical context from the stack frame. 1516 ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); 1517 // In debug mode, make sure the lexical context is set. 1518 #ifdef DEBUG 1519 cmp(scratch, Operand::Zero()); 1520 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext); 1521 #endif 1522 1523 // Load the native context of the current context. 1524 ldr(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX)); 1525 1526 // Check the context is a native context. 1527 if (emit_debug_code()) { 1528 // Cannot use ip as a temporary in this verification code. Due to the fact 1529 // that ip is clobbered as part of cmp with an object Operand. 1530 push(holder_reg); // Temporarily save holder on the stack. 1531 // Read the first word and compare to the native_context_map. 1532 ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); 1533 LoadRoot(ip, Heap::kNativeContextMapRootIndex); 1534 cmp(holder_reg, ip); 1535 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); 1536 pop(holder_reg); // Restore holder. 1537 } 1538 1539 // Check if both contexts are the same. 1540 ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); 1541 cmp(scratch, Operand(ip)); 1542 b(eq, &same_contexts); 1543 1544 // Check the context is a native context. 1545 if (emit_debug_code()) { 1546 // Cannot use ip as a temporary in this verification code. Due to the fact 1547 // that ip is clobbered as part of cmp with an object Operand. 1548 push(holder_reg); // Temporarily save holder on the stack. 1549 mov(holder_reg, ip); // Move ip to its holding place. 1550 LoadRoot(ip, Heap::kNullValueRootIndex); 1551 cmp(holder_reg, ip); 1552 Check(ne, kJSGlobalProxyContextShouldNotBeNull); 1553 1554 ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); 1555 LoadRoot(ip, Heap::kNativeContextMapRootIndex); 1556 cmp(holder_reg, ip); 1557 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); 1558 // Restore ip is not needed. ip is reloaded below. 1559 pop(holder_reg); // Restore holder. 1560 // Restore ip to holder's context. 1561 ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); 1562 } 1563 1564 // Check that the security token in the calling global object is 1565 // compatible with the security token in the receiving global 1566 // object. 1567 int token_offset = Context::kHeaderSize + 1568 Context::SECURITY_TOKEN_INDEX * kPointerSize; 1569 1570 ldr(scratch, FieldMemOperand(scratch, token_offset)); 1571 ldr(ip, FieldMemOperand(ip, token_offset)); 1572 cmp(scratch, Operand(ip)); 1573 b(ne, miss); 1574 1575 bind(&same_contexts); 1576 } 1577 1578 1579 // Compute the hash code from the untagged key. This must be kept in sync with 1580 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in 1581 // code-stub-hydrogen.cc 1582 void MacroAssembler::GetNumberHash(Register t0, Register scratch) { 1583 // First of all we assign the hash seed to scratch. 1584 LoadRoot(scratch, Heap::kHashSeedRootIndex); 1585 SmiUntag(scratch); 1586 1587 // Xor original key with a seed. 1588 eor(t0, t0, Operand(scratch)); 1589 1590 // Compute the hash code from the untagged key. This must be kept in sync 1591 // with ComputeIntegerHash in utils.h. 1592 // 1593 // hash = ~hash + (hash << 15); 1594 mvn(scratch, Operand(t0)); 1595 add(t0, scratch, Operand(t0, LSL, 15)); 1596 // hash = hash ^ (hash >> 12); 1597 eor(t0, t0, Operand(t0, LSR, 12)); 1598 // hash = hash + (hash << 2); 1599 add(t0, t0, Operand(t0, LSL, 2)); 1600 // hash = hash ^ (hash >> 4); 1601 eor(t0, t0, Operand(t0, LSR, 4)); 1602 // hash = hash * 2057; 1603 mov(scratch, Operand(t0, LSL, 11)); 1604 add(t0, t0, Operand(t0, LSL, 3)); 1605 add(t0, t0, scratch); 1606 // hash = hash ^ (hash >> 16); 1607 eor(t0, t0, Operand(t0, LSR, 16)); 1608 bic(t0, t0, Operand(0xc0000000u)); 1609 } 1610 1611 1612 void MacroAssembler::LoadFromNumberDictionary(Label* miss, 1613 Register elements, 1614 Register key, 1615 Register result, 1616 Register t0, 1617 Register t1, 1618 Register t2) { 1619 // Register use: 1620 // 1621 // elements - holds the slow-case elements of the receiver on entry. 1622 // Unchanged unless 'result' is the same register. 1623 // 1624 // key - holds the smi key on entry. 1625 // Unchanged unless 'result' is the same register. 1626 // 1627 // result - holds the result on exit if the load succeeded. 1628 // Allowed to be the same as 'key' or 'result'. 1629 // Unchanged on bailout so 'key' or 'result' can be used 1630 // in further computation. 1631 // 1632 // Scratch registers: 1633 // 1634 // t0 - holds the untagged key on entry and holds the hash once computed. 1635 // 1636 // t1 - used to hold the capacity mask of the dictionary 1637 // 1638 // t2 - used for the index into the dictionary. 1639 Label done; 1640 1641 GetNumberHash(t0, t1); 1642 1643 // Compute the capacity mask. 1644 ldr(t1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset)); 1645 SmiUntag(t1); 1646 sub(t1, t1, Operand(1)); 1647 1648 // Generate an unrolled loop that performs a few probes before giving up. 1649 for (int i = 0; i < kNumberDictionaryProbes; i++) { 1650 // Use t2 for index calculations and keep the hash intact in t0. 1651 mov(t2, t0); 1652 // Compute the masked index: (hash + i + i * i) & mask. 1653 if (i > 0) { 1654 add(t2, t2, Operand(SeededNumberDictionary::GetProbeOffset(i))); 1655 } 1656 and_(t2, t2, Operand(t1)); 1657 1658 // Scale the index by multiplying by the element size. 1659 DCHECK(SeededNumberDictionary::kEntrySize == 3); 1660 add(t2, t2, Operand(t2, LSL, 1)); // t2 = t2 * 3 1661 1662 // Check if the key is identical to the name. 1663 add(t2, elements, Operand(t2, LSL, kPointerSizeLog2)); 1664 ldr(ip, FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset)); 1665 cmp(key, Operand(ip)); 1666 if (i != kNumberDictionaryProbes - 1) { 1667 b(eq, &done); 1668 } else { 1669 b(ne, miss); 1670 } 1671 } 1672 1673 bind(&done); 1674 // Check that the value is a field property. 1675 // t2: elements + (index * kPointerSize) 1676 const int kDetailsOffset = 1677 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize; 1678 ldr(t1, FieldMemOperand(t2, kDetailsOffset)); 1679 DCHECK_EQ(DATA, 0); 1680 tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask))); 1681 b(ne, miss); 1682 1683 // Get the value at the masked, scaled index and return. 1684 const int kValueOffset = 1685 SeededNumberDictionary::kElementsStartOffset + kPointerSize; 1686 ldr(result, FieldMemOperand(t2, kValueOffset)); 1687 } 1688 1689 1690 void MacroAssembler::Allocate(int object_size, 1691 Register result, 1692 Register scratch1, 1693 Register scratch2, 1694 Label* gc_required, 1695 AllocationFlags flags) { 1696 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize); 1697 if (!FLAG_inline_new) { 1698 if (emit_debug_code()) { 1699 // Trash the registers to simulate an allocation failure. 1700 mov(result, Operand(0x7091)); 1701 mov(scratch1, Operand(0x7191)); 1702 mov(scratch2, Operand(0x7291)); 1703 } 1704 jmp(gc_required); 1705 return; 1706 } 1707 1708 DCHECK(!AreAliased(result, scratch1, scratch2, ip)); 1709 1710 // Make object size into bytes. 1711 if ((flags & SIZE_IN_WORDS) != 0) { 1712 object_size *= kPointerSize; 1713 } 1714 DCHECK_EQ(0, object_size & kObjectAlignmentMask); 1715 1716 // Check relative positions of allocation top and limit addresses. 1717 // The values must be adjacent in memory to allow the use of LDM. 1718 // Also, assert that the registers are numbered such that the values 1719 // are loaded in the correct order. 1720 ExternalReference allocation_top = 1721 AllocationUtils::GetAllocationTopReference(isolate(), flags); 1722 ExternalReference allocation_limit = 1723 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 1724 1725 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address()); 1726 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address()); 1727 DCHECK((limit - top) == kPointerSize); 1728 DCHECK(result.code() < ip.code()); 1729 1730 // Set up allocation top address register. 1731 Register top_address = scratch1; 1732 // This code stores a temporary value in ip. This is OK, as the code below 1733 // does not need ip for implicit literal generation. 1734 Register alloc_limit = ip; 1735 Register result_end = scratch2; 1736 mov(top_address, Operand(allocation_top)); 1737 1738 if ((flags & RESULT_CONTAINS_TOP) == 0) { 1739 // Load allocation top into result and allocation limit into alloc_limit. 1740 ldm(ia, top_address, result.bit() | alloc_limit.bit()); 1741 } else { 1742 if (emit_debug_code()) { 1743 // Assert that result actually contains top on entry. 1744 ldr(alloc_limit, MemOperand(top_address)); 1745 cmp(result, alloc_limit); 1746 Check(eq, kUnexpectedAllocationTop); 1747 } 1748 // Load allocation limit. Result already contains allocation top. 1749 ldr(alloc_limit, MemOperand(top_address, limit - top)); 1750 } 1751 1752 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1753 // Align the next allocation. Storing the filler map without checking top is 1754 // safe in new-space because the limit of the heap is aligned there. 1755 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment); 1756 and_(result_end, result, Operand(kDoubleAlignmentMask), SetCC); 1757 Label aligned; 1758 b(eq, &aligned); 1759 if ((flags & PRETENURE) != 0) { 1760 cmp(result, Operand(alloc_limit)); 1761 b(hs, gc_required); 1762 } 1763 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); 1764 str(result_end, MemOperand(result, kDoubleSize / 2, PostIndex)); 1765 bind(&aligned); 1766 } 1767 1768 // Calculate new top and bail out if new space is exhausted. Use result 1769 // to calculate the new top. We must preserve the ip register at this 1770 // point, so we cannot just use add(). 1771 DCHECK(object_size > 0); 1772 Register source = result; 1773 Condition cond = al; 1774 int shift = 0; 1775 while (object_size != 0) { 1776 if (((object_size >> shift) & 0x03) == 0) { 1777 shift += 2; 1778 } else { 1779 int bits = object_size & (0xff << shift); 1780 object_size -= bits; 1781 shift += 8; 1782 Operand bits_operand(bits); 1783 DCHECK(bits_operand.instructions_required(this) == 1); 1784 add(result_end, source, bits_operand, SetCC, cond); 1785 source = result_end; 1786 cond = cc; 1787 } 1788 } 1789 b(cs, gc_required); 1790 cmp(result_end, Operand(alloc_limit)); 1791 b(hi, gc_required); 1792 str(result_end, MemOperand(top_address)); 1793 1794 // Tag object if requested. 1795 if ((flags & TAG_OBJECT) != 0) { 1796 add(result, result, Operand(kHeapObjectTag)); 1797 } 1798 } 1799 1800 1801 void MacroAssembler::Allocate(Register object_size, Register result, 1802 Register result_end, Register scratch, 1803 Label* gc_required, AllocationFlags flags) { 1804 if (!FLAG_inline_new) { 1805 if (emit_debug_code()) { 1806 // Trash the registers to simulate an allocation failure. 1807 mov(result, Operand(0x7091)); 1808 mov(scratch, Operand(0x7191)); 1809 mov(result_end, Operand(0x7291)); 1810 } 1811 jmp(gc_required); 1812 return; 1813 } 1814 1815 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag 1816 // is not specified. Other registers must not overlap. 1817 DCHECK(!AreAliased(object_size, result, scratch, ip)); 1818 DCHECK(!AreAliased(result_end, result, scratch, ip)); 1819 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end)); 1820 1821 // Check relative positions of allocation top and limit addresses. 1822 // The values must be adjacent in memory to allow the use of LDM. 1823 // Also, assert that the registers are numbered such that the values 1824 // are loaded in the correct order. 1825 ExternalReference allocation_top = 1826 AllocationUtils::GetAllocationTopReference(isolate(), flags); 1827 ExternalReference allocation_limit = 1828 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 1829 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address()); 1830 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address()); 1831 DCHECK((limit - top) == kPointerSize); 1832 DCHECK(result.code() < ip.code()); 1833 1834 // Set up allocation top address and allocation limit registers. 1835 Register top_address = scratch; 1836 // This code stores a temporary value in ip. This is OK, as the code below 1837 // does not need ip for implicit literal generation. 1838 Register alloc_limit = ip; 1839 mov(top_address, Operand(allocation_top)); 1840 1841 if ((flags & RESULT_CONTAINS_TOP) == 0) { 1842 // Load allocation top into result and allocation limit into alloc_limit. 1843 ldm(ia, top_address, result.bit() | alloc_limit.bit()); 1844 } else { 1845 if (emit_debug_code()) { 1846 // Assert that result actually contains top on entry. 1847 ldr(alloc_limit, MemOperand(top_address)); 1848 cmp(result, alloc_limit); 1849 Check(eq, kUnexpectedAllocationTop); 1850 } 1851 // Load allocation limit. Result already contains allocation top. 1852 ldr(alloc_limit, MemOperand(top_address, limit - top)); 1853 } 1854 1855 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1856 // Align the next allocation. Storing the filler map without checking top is 1857 // safe in new-space because the limit of the heap is aligned there. 1858 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1859 and_(result_end, result, Operand(kDoubleAlignmentMask), SetCC); 1860 Label aligned; 1861 b(eq, &aligned); 1862 if ((flags & PRETENURE) != 0) { 1863 cmp(result, Operand(alloc_limit)); 1864 b(hs, gc_required); 1865 } 1866 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map())); 1867 str(result_end, MemOperand(result, kDoubleSize / 2, PostIndex)); 1868 bind(&aligned); 1869 } 1870 1871 // Calculate new top and bail out if new space is exhausted. Use result 1872 // to calculate the new top. Object size may be in words so a shift is 1873 // required to get the number of bytes. 1874 if ((flags & SIZE_IN_WORDS) != 0) { 1875 add(result_end, result, Operand(object_size, LSL, kPointerSizeLog2), SetCC); 1876 } else { 1877 add(result_end, result, Operand(object_size), SetCC); 1878 } 1879 b(cs, gc_required); 1880 cmp(result_end, Operand(alloc_limit)); 1881 b(hi, gc_required); 1882 1883 // Update allocation top. result temporarily holds the new top. 1884 if (emit_debug_code()) { 1885 tst(result_end, Operand(kObjectAlignmentMask)); 1886 Check(eq, kUnalignedAllocationInNewSpace); 1887 } 1888 str(result_end, MemOperand(top_address)); 1889 1890 // Tag object if requested. 1891 if ((flags & TAG_OBJECT) != 0) { 1892 add(result, result, Operand(kHeapObjectTag)); 1893 } 1894 } 1895 1896 1897 void MacroAssembler::AllocateTwoByteString(Register result, 1898 Register length, 1899 Register scratch1, 1900 Register scratch2, 1901 Register scratch3, 1902 Label* gc_required) { 1903 // Calculate the number of bytes needed for the characters in the string while 1904 // observing object alignment. 1905 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); 1906 mov(scratch1, Operand(length, LSL, 1)); // Length in bytes, not chars. 1907 add(scratch1, scratch1, 1908 Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize)); 1909 and_(scratch1, scratch1, Operand(~kObjectAlignmentMask)); 1910 1911 // Allocate two-byte string in new space. 1912 Allocate(scratch1, 1913 result, 1914 scratch2, 1915 scratch3, 1916 gc_required, 1917 TAG_OBJECT); 1918 1919 // Set the map, length and hash field. 1920 InitializeNewString(result, 1921 length, 1922 Heap::kStringMapRootIndex, 1923 scratch1, 1924 scratch2); 1925 } 1926 1927 1928 void MacroAssembler::AllocateOneByteString(Register result, Register length, 1929 Register scratch1, Register scratch2, 1930 Register scratch3, 1931 Label* gc_required) { 1932 // Calculate the number of bytes needed for the characters in the string while 1933 // observing object alignment. 1934 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); 1935 DCHECK(kCharSize == 1); 1936 add(scratch1, length, 1937 Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize)); 1938 and_(scratch1, scratch1, Operand(~kObjectAlignmentMask)); 1939 1940 // Allocate one-byte string in new space. 1941 Allocate(scratch1, 1942 result, 1943 scratch2, 1944 scratch3, 1945 gc_required, 1946 TAG_OBJECT); 1947 1948 // Set the map, length and hash field. 1949 InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex, 1950 scratch1, scratch2); 1951 } 1952 1953 1954 void MacroAssembler::AllocateTwoByteConsString(Register result, 1955 Register length, 1956 Register scratch1, 1957 Register scratch2, 1958 Label* gc_required) { 1959 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, 1960 TAG_OBJECT); 1961 1962 InitializeNewString(result, 1963 length, 1964 Heap::kConsStringMapRootIndex, 1965 scratch1, 1966 scratch2); 1967 } 1968 1969 1970 void MacroAssembler::AllocateOneByteConsString(Register result, Register length, 1971 Register scratch1, 1972 Register scratch2, 1973 Label* gc_required) { 1974 Allocate(ConsString::kSize, 1975 result, 1976 scratch1, 1977 scratch2, 1978 gc_required, 1979 TAG_OBJECT); 1980 1981 InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex, 1982 scratch1, scratch2); 1983 } 1984 1985 1986 void MacroAssembler::AllocateTwoByteSlicedString(Register result, 1987 Register length, 1988 Register scratch1, 1989 Register scratch2, 1990 Label* gc_required) { 1991 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, 1992 TAG_OBJECT); 1993 1994 InitializeNewString(result, 1995 length, 1996 Heap::kSlicedStringMapRootIndex, 1997 scratch1, 1998 scratch2); 1999 } 2000 2001 2002 void MacroAssembler::AllocateOneByteSlicedString(Register result, 2003 Register length, 2004 Register scratch1, 2005 Register scratch2, 2006 Label* gc_required) { 2007 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, 2008 TAG_OBJECT); 2009 2010 InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex, 2011 scratch1, scratch2); 2012 } 2013 2014 2015 void MacroAssembler::CompareObjectType(Register object, 2016 Register map, 2017 Register type_reg, 2018 InstanceType type) { 2019 const Register temp = type_reg.is(no_reg) ? ip : type_reg; 2020 2021 ldr(map, FieldMemOperand(object, HeapObject::kMapOffset)); 2022 CompareInstanceType(map, temp, type); 2023 } 2024 2025 2026 void MacroAssembler::CompareInstanceType(Register map, 2027 Register type_reg, 2028 InstanceType type) { 2029 // Registers map and type_reg can be ip. These two lines assert 2030 // that ip can be used with the two instructions (the constants 2031 // will never need ip). 2032 STATIC_ASSERT(Map::kInstanceTypeOffset < 4096); 2033 STATIC_ASSERT(LAST_TYPE < 256); 2034 ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); 2035 cmp(type_reg, Operand(type)); 2036 } 2037 2038 2039 void MacroAssembler::CompareRoot(Register obj, 2040 Heap::RootListIndex index) { 2041 DCHECK(!obj.is(ip)); 2042 LoadRoot(ip, index); 2043 cmp(obj, ip); 2044 } 2045 2046 2047 void MacroAssembler::CheckFastElements(Register map, 2048 Register scratch, 2049 Label* fail) { 2050 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 2051 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 2052 STATIC_ASSERT(FAST_ELEMENTS == 2); 2053 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); 2054 ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset)); 2055 cmp(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue)); 2056 b(hi, fail); 2057 } 2058 2059 2060 void MacroAssembler::CheckFastObjectElements(Register map, 2061 Register scratch, 2062 Label* fail) { 2063 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 2064 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 2065 STATIC_ASSERT(FAST_ELEMENTS == 2); 2066 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); 2067 ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset)); 2068 cmp(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue)); 2069 b(ls, fail); 2070 cmp(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue)); 2071 b(hi, fail); 2072 } 2073 2074 2075 void MacroAssembler::CheckFastSmiElements(Register map, 2076 Register scratch, 2077 Label* fail) { 2078 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 2079 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 2080 ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset)); 2081 cmp(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue)); 2082 b(hi, fail); 2083 } 2084 2085 2086 void MacroAssembler::StoreNumberToDoubleElements( 2087 Register value_reg, 2088 Register key_reg, 2089 Register elements_reg, 2090 Register scratch1, 2091 LowDwVfpRegister double_scratch, 2092 Label* fail, 2093 int elements_offset) { 2094 DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1)); 2095 Label smi_value, store; 2096 2097 // Handle smi values specially. 2098 JumpIfSmi(value_reg, &smi_value); 2099 2100 // Ensure that the object is a heap number 2101 CheckMap(value_reg, 2102 scratch1, 2103 isolate()->factory()->heap_number_map(), 2104 fail, 2105 DONT_DO_SMI_CHECK); 2106 2107 vldr(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); 2108 // Force a canonical NaN. 2109 if (emit_debug_code()) { 2110 vmrs(ip); 2111 tst(ip, Operand(kVFPDefaultNaNModeControlBit)); 2112 Assert(ne, kDefaultNaNModeNotSet); 2113 } 2114 VFPCanonicalizeNaN(double_scratch); 2115 b(&store); 2116 2117 bind(&smi_value); 2118 SmiToDouble(double_scratch, value_reg); 2119 2120 bind(&store); 2121 add(scratch1, elements_reg, Operand::DoubleOffsetFromSmiKey(key_reg)); 2122 vstr(double_scratch, 2123 FieldMemOperand(scratch1, 2124 FixedDoubleArray::kHeaderSize - elements_offset)); 2125 } 2126 2127 2128 void MacroAssembler::CompareMap(Register obj, 2129 Register scratch, 2130 Handle<Map> map, 2131 Label* early_success) { 2132 ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); 2133 CompareMap(scratch, map, early_success); 2134 } 2135 2136 2137 void MacroAssembler::CompareMap(Register obj_map, 2138 Handle<Map> map, 2139 Label* early_success) { 2140 cmp(obj_map, Operand(map)); 2141 } 2142 2143 2144 void MacroAssembler::CheckMap(Register obj, 2145 Register scratch, 2146 Handle<Map> map, 2147 Label* fail, 2148 SmiCheckType smi_check_type) { 2149 if (smi_check_type == DO_SMI_CHECK) { 2150 JumpIfSmi(obj, fail); 2151 } 2152 2153 Label success; 2154 CompareMap(obj, scratch, map, &success); 2155 b(ne, fail); 2156 bind(&success); 2157 } 2158 2159 2160 void MacroAssembler::CheckMap(Register obj, 2161 Register scratch, 2162 Heap::RootListIndex index, 2163 Label* fail, 2164 SmiCheckType smi_check_type) { 2165 if (smi_check_type == DO_SMI_CHECK) { 2166 JumpIfSmi(obj, fail); 2167 } 2168 ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); 2169 LoadRoot(ip, index); 2170 cmp(scratch, ip); 2171 b(ne, fail); 2172 } 2173 2174 2175 void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1, 2176 Register scratch2, Handle<WeakCell> cell, 2177 Handle<Code> success, 2178 SmiCheckType smi_check_type) { 2179 Label fail; 2180 if (smi_check_type == DO_SMI_CHECK) { 2181 JumpIfSmi(obj, &fail); 2182 } 2183 ldr(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset)); 2184 CmpWeakValue(scratch1, cell, scratch2); 2185 Jump(success, RelocInfo::CODE_TARGET, eq); 2186 bind(&fail); 2187 } 2188 2189 2190 void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell, 2191 Register scratch) { 2192 mov(scratch, Operand(cell)); 2193 ldr(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset)); 2194 cmp(value, scratch); 2195 } 2196 2197 2198 void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) { 2199 mov(value, Operand(cell)); 2200 ldr(value, FieldMemOperand(value, WeakCell::kValueOffset)); 2201 } 2202 2203 2204 void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell, 2205 Label* miss) { 2206 GetWeakValue(value, cell); 2207 JumpIfSmi(value, miss); 2208 } 2209 2210 2211 void MacroAssembler::GetMapConstructor(Register result, Register map, 2212 Register temp, Register temp2) { 2213 Label done, loop; 2214 ldr(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset)); 2215 bind(&loop); 2216 JumpIfSmi(result, &done); 2217 CompareObjectType(result, temp, temp2, MAP_TYPE); 2218 b(ne, &done); 2219 ldr(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset)); 2220 b(&loop); 2221 bind(&done); 2222 } 2223 2224 2225 void MacroAssembler::TryGetFunctionPrototype(Register function, Register result, 2226 Register scratch, Label* miss) { 2227 // Get the prototype or initial map from the function. 2228 ldr(result, 2229 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 2230 2231 // If the prototype or initial map is the hole, don't return it and 2232 // simply miss the cache instead. This will allow us to allocate a 2233 // prototype object on-demand in the runtime system. 2234 LoadRoot(ip, Heap::kTheHoleValueRootIndex); 2235 cmp(result, ip); 2236 b(eq, miss); 2237 2238 // If the function does not have an initial map, we're done. 2239 Label done; 2240 CompareObjectType(result, scratch, scratch, MAP_TYPE); 2241 b(ne, &done); 2242 2243 // Get the prototype from the initial map. 2244 ldr(result, FieldMemOperand(result, Map::kPrototypeOffset)); 2245 2246 // All done. 2247 bind(&done); 2248 } 2249 2250 2251 void MacroAssembler::CallStub(CodeStub* stub, 2252 TypeFeedbackId ast_id, 2253 Condition cond) { 2254 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. 2255 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond); 2256 } 2257 2258 2259 void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) { 2260 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond); 2261 } 2262 2263 2264 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { 2265 return has_frame_ || !stub->SometimesSetsUpAFrame(); 2266 } 2267 2268 2269 void MacroAssembler::IndexFromHash(Register hash, Register index) { 2270 // If the hash field contains an array index pick it out. The assert checks 2271 // that the constants for the maximum number of digits for an array index 2272 // cached in the hash field and the number of bits reserved for it does not 2273 // conflict. 2274 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < 2275 (1 << String::kArrayIndexValueBits)); 2276 DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash); 2277 } 2278 2279 2280 void MacroAssembler::SmiToDouble(LowDwVfpRegister value, Register smi) { 2281 if (CpuFeatures::IsSupported(VFP3)) { 2282 vmov(value.low(), smi); 2283 vcvt_f64_s32(value, 1); 2284 } else { 2285 SmiUntag(ip, smi); 2286 vmov(value.low(), ip); 2287 vcvt_f64_s32(value, value.low()); 2288 } 2289 } 2290 2291 2292 void MacroAssembler::TestDoubleIsInt32(DwVfpRegister double_input, 2293 LowDwVfpRegister double_scratch) { 2294 DCHECK(!double_input.is(double_scratch)); 2295 vcvt_s32_f64(double_scratch.low(), double_input); 2296 vcvt_f64_s32(double_scratch, double_scratch.low()); 2297 VFPCompareAndSetFlags(double_input, double_scratch); 2298 } 2299 2300 2301 void MacroAssembler::TryDoubleToInt32Exact(Register result, 2302 DwVfpRegister double_input, 2303 LowDwVfpRegister double_scratch) { 2304 DCHECK(!double_input.is(double_scratch)); 2305 vcvt_s32_f64(double_scratch.low(), double_input); 2306 vmov(result, double_scratch.low()); 2307 vcvt_f64_s32(double_scratch, double_scratch.low()); 2308 VFPCompareAndSetFlags(double_input, double_scratch); 2309 } 2310 2311 2312 void MacroAssembler::TryInt32Floor(Register result, 2313 DwVfpRegister double_input, 2314 Register input_high, 2315 LowDwVfpRegister double_scratch, 2316 Label* done, 2317 Label* exact) { 2318 DCHECK(!result.is(input_high)); 2319 DCHECK(!double_input.is(double_scratch)); 2320 Label negative, exception; 2321 2322 VmovHigh(input_high, double_input); 2323 2324 // Test for NaN and infinities. 2325 Sbfx(result, input_high, 2326 HeapNumber::kExponentShift, HeapNumber::kExponentBits); 2327 cmp(result, Operand(-1)); 2328 b(eq, &exception); 2329 // Test for values that can be exactly represented as a 2330 // signed 32-bit integer. 2331 TryDoubleToInt32Exact(result, double_input, double_scratch); 2332 // If exact, return (result already fetched). 2333 b(eq, exact); 2334 cmp(input_high, Operand::Zero()); 2335 b(mi, &negative); 2336 2337 // Input is in ]+0, +inf[. 2338 // If result equals 0x7fffffff input was out of range or 2339 // in ]0x7fffffff, 0x80000000[. We ignore this last case which 2340 // could fits into an int32, that means we always think input was 2341 // out of range and always go to exception. 2342 // If result < 0x7fffffff, go to done, result fetched. 2343 cmn(result, Operand(1)); 2344 b(mi, &exception); 2345 b(done); 2346 2347 // Input is in ]-inf, -0[. 2348 // If x is a non integer negative number, 2349 // floor(x) <=> round_to_zero(x) - 1. 2350 bind(&negative); 2351 sub(result, result, Operand(1), SetCC); 2352 // If result is still negative, go to done, result fetched. 2353 // Else, we had an overflow and we fall through exception. 2354 b(mi, done); 2355 bind(&exception); 2356 } 2357 2358 void MacroAssembler::TryInlineTruncateDoubleToI(Register result, 2359 DwVfpRegister double_input, 2360 Label* done) { 2361 LowDwVfpRegister double_scratch = kScratchDoubleReg; 2362 vcvt_s32_f64(double_scratch.low(), double_input); 2363 vmov(result, double_scratch.low()); 2364 2365 // If result is not saturated (0x7fffffff or 0x80000000), we are done. 2366 sub(ip, result, Operand(1)); 2367 cmp(ip, Operand(0x7ffffffe)); 2368 b(lt, done); 2369 } 2370 2371 2372 void MacroAssembler::TruncateDoubleToI(Register result, 2373 DwVfpRegister double_input) { 2374 Label done; 2375 2376 TryInlineTruncateDoubleToI(result, double_input, &done); 2377 2378 // If we fell through then inline version didn't succeed - call stub instead. 2379 push(lr); 2380 sub(sp, sp, Operand(kDoubleSize)); // Put input on stack. 2381 vstr(double_input, MemOperand(sp, 0)); 2382 2383 DoubleToIStub stub(isolate(), sp, result, 0, true, true); 2384 CallStub(&stub); 2385 2386 add(sp, sp, Operand(kDoubleSize)); 2387 pop(lr); 2388 2389 bind(&done); 2390 } 2391 2392 2393 void MacroAssembler::TruncateHeapNumberToI(Register result, 2394 Register object) { 2395 Label done; 2396 LowDwVfpRegister double_scratch = kScratchDoubleReg; 2397 DCHECK(!result.is(object)); 2398 2399 vldr(double_scratch, 2400 MemOperand(object, HeapNumber::kValueOffset - kHeapObjectTag)); 2401 TryInlineTruncateDoubleToI(result, double_scratch, &done); 2402 2403 // If we fell through then inline version didn't succeed - call stub instead. 2404 push(lr); 2405 DoubleToIStub stub(isolate(), 2406 object, 2407 result, 2408 HeapNumber::kValueOffset - kHeapObjectTag, 2409 true, 2410 true); 2411 CallStub(&stub); 2412 pop(lr); 2413 2414 bind(&done); 2415 } 2416 2417 2418 void MacroAssembler::TruncateNumberToI(Register object, 2419 Register result, 2420 Register heap_number_map, 2421 Register scratch1, 2422 Label* not_number) { 2423 Label done; 2424 DCHECK(!result.is(object)); 2425 2426 UntagAndJumpIfSmi(result, object, &done); 2427 JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); 2428 TruncateHeapNumberToI(result, object); 2429 2430 bind(&done); 2431 } 2432 2433 2434 void MacroAssembler::GetLeastBitsFromSmi(Register dst, 2435 Register src, 2436 int num_least_bits) { 2437 if (CpuFeatures::IsSupported(ARMv7) && !predictable_code_size()) { 2438 ubfx(dst, src, kSmiTagSize, num_least_bits); 2439 } else { 2440 SmiUntag(dst, src); 2441 and_(dst, dst, Operand((1 << num_least_bits) - 1)); 2442 } 2443 } 2444 2445 2446 void MacroAssembler::GetLeastBitsFromInt32(Register dst, 2447 Register src, 2448 int num_least_bits) { 2449 and_(dst, src, Operand((1 << num_least_bits) - 1)); 2450 } 2451 2452 2453 void MacroAssembler::CallRuntime(const Runtime::Function* f, 2454 int num_arguments, 2455 SaveFPRegsMode save_doubles) { 2456 // All parameters are on the stack. r0 has the return value after call. 2457 2458 // If the expected number of arguments of the runtime function is 2459 // constant, we check that the actual number of arguments match the 2460 // expectation. 2461 CHECK(f->nargs < 0 || f->nargs == num_arguments); 2462 2463 // TODO(1236192): Most runtime routines don't need the number of 2464 // arguments passed in because it is constant. At some point we 2465 // should remove this need and make the runtime routine entry code 2466 // smarter. 2467 mov(r0, Operand(num_arguments)); 2468 mov(r1, Operand(ExternalReference(f, isolate()))); 2469 CEntryStub stub(isolate(), 1, save_doubles); 2470 CallStub(&stub); 2471 } 2472 2473 2474 void MacroAssembler::CallExternalReference(const ExternalReference& ext, 2475 int num_arguments) { 2476 mov(r0, Operand(num_arguments)); 2477 mov(r1, Operand(ext)); 2478 2479 CEntryStub stub(isolate(), 1); 2480 CallStub(&stub); 2481 } 2482 2483 2484 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { 2485 const Runtime::Function* function = Runtime::FunctionForId(fid); 2486 DCHECK_EQ(1, function->result_size); 2487 if (function->nargs >= 0) { 2488 // TODO(1236192): Most runtime routines don't need the number of 2489 // arguments passed in because it is constant. At some point we 2490 // should remove this need and make the runtime routine entry code 2491 // smarter. 2492 mov(r0, Operand(function->nargs)); 2493 } 2494 JumpToExternalReference(ExternalReference(fid, isolate())); 2495 } 2496 2497 2498 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) { 2499 #if defined(__thumb__) 2500 // Thumb mode builtin. 2501 DCHECK((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1); 2502 #endif 2503 mov(r1, Operand(builtin)); 2504 CEntryStub stub(isolate(), 1); 2505 Jump(stub.GetCode(), RelocInfo::CODE_TARGET); 2506 } 2507 2508 2509 void MacroAssembler::InvokeBuiltin(int native_context_index, InvokeFlag flag, 2510 const CallWrapper& call_wrapper) { 2511 // You can't call a builtin without a valid frame. 2512 DCHECK(flag == JUMP_FUNCTION || has_frame()); 2513 2514 // Fake a parameter count to avoid emitting code to do the check. 2515 ParameterCount expected(0); 2516 LoadNativeContextSlot(native_context_index, r1); 2517 InvokeFunctionCode(r1, no_reg, expected, expected, flag, call_wrapper); 2518 } 2519 2520 2521 void MacroAssembler::SetCounter(StatsCounter* counter, int value, 2522 Register scratch1, Register scratch2) { 2523 if (FLAG_native_code_counters && counter->Enabled()) { 2524 mov(scratch1, Operand(value)); 2525 mov(scratch2, Operand(ExternalReference(counter))); 2526 str(scratch1, MemOperand(scratch2)); 2527 } 2528 } 2529 2530 2531 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value, 2532 Register scratch1, Register scratch2) { 2533 DCHECK(value > 0); 2534 if (FLAG_native_code_counters && counter->Enabled()) { 2535 mov(scratch2, Operand(ExternalReference(counter))); 2536 ldr(scratch1, MemOperand(scratch2)); 2537 add(scratch1, scratch1, Operand(value)); 2538 str(scratch1, MemOperand(scratch2)); 2539 } 2540 } 2541 2542 2543 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, 2544 Register scratch1, Register scratch2) { 2545 DCHECK(value > 0); 2546 if (FLAG_native_code_counters && counter->Enabled()) { 2547 mov(scratch2, Operand(ExternalReference(counter))); 2548 ldr(scratch1, MemOperand(scratch2)); 2549 sub(scratch1, scratch1, Operand(value)); 2550 str(scratch1, MemOperand(scratch2)); 2551 } 2552 } 2553 2554 2555 void MacroAssembler::Assert(Condition cond, BailoutReason reason) { 2556 if (emit_debug_code()) 2557 Check(cond, reason); 2558 } 2559 2560 2561 void MacroAssembler::AssertFastElements(Register elements) { 2562 if (emit_debug_code()) { 2563 DCHECK(!elements.is(ip)); 2564 Label ok; 2565 push(elements); 2566 ldr(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); 2567 LoadRoot(ip, Heap::kFixedArrayMapRootIndex); 2568 cmp(elements, ip); 2569 b(eq, &ok); 2570 LoadRoot(ip, Heap::kFixedDoubleArrayMapRootIndex); 2571 cmp(elements, ip); 2572 b(eq, &ok); 2573 LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); 2574 cmp(elements, ip); 2575 b(eq, &ok); 2576 Abort(kJSObjectWithFastElementsMapHasSlowElements); 2577 bind(&ok); 2578 pop(elements); 2579 } 2580 } 2581 2582 2583 void MacroAssembler::Check(Condition cond, BailoutReason reason) { 2584 Label L; 2585 b(cond, &L); 2586 Abort(reason); 2587 // will not return here 2588 bind(&L); 2589 } 2590 2591 2592 void MacroAssembler::Abort(BailoutReason reason) { 2593 Label abort_start; 2594 bind(&abort_start); 2595 #ifdef DEBUG 2596 const char* msg = GetBailoutReason(reason); 2597 if (msg != NULL) { 2598 RecordComment("Abort message: "); 2599 RecordComment(msg); 2600 } 2601 2602 if (FLAG_trap_on_abort) { 2603 stop(msg); 2604 return; 2605 } 2606 #endif 2607 2608 mov(r0, Operand(Smi::FromInt(reason))); 2609 push(r0); 2610 2611 // Disable stub call restrictions to always allow calls to abort. 2612 if (!has_frame_) { 2613 // We don't actually want to generate a pile of code for this, so just 2614 // claim there is a stack frame, without generating one. 2615 FrameScope scope(this, StackFrame::NONE); 2616 CallRuntime(Runtime::kAbort, 1); 2617 } else { 2618 CallRuntime(Runtime::kAbort, 1); 2619 } 2620 // will not return here 2621 if (is_const_pool_blocked()) { 2622 // If the calling code cares about the exact number of 2623 // instructions generated, we insert padding here to keep the size 2624 // of the Abort macro constant. 2625 static const int kExpectedAbortInstructions = 7; 2626 int abort_instructions = InstructionsGeneratedSince(&abort_start); 2627 DCHECK(abort_instructions <= kExpectedAbortInstructions); 2628 while (abort_instructions++ < kExpectedAbortInstructions) { 2629 nop(); 2630 } 2631 } 2632 } 2633 2634 2635 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { 2636 if (context_chain_length > 0) { 2637 // Move up the chain of contexts to the context containing the slot. 2638 ldr(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX))); 2639 for (int i = 1; i < context_chain_length; i++) { 2640 ldr(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); 2641 } 2642 } else { 2643 // Slot is in the current function context. Move it into the 2644 // destination register in case we store into it (the write barrier 2645 // cannot be allowed to destroy the context in esi). 2646 mov(dst, cp); 2647 } 2648 } 2649 2650 2651 void MacroAssembler::LoadTransitionedArrayMapConditional( 2652 ElementsKind expected_kind, 2653 ElementsKind transitioned_kind, 2654 Register map_in_out, 2655 Register scratch, 2656 Label* no_map_match) { 2657 DCHECK(IsFastElementsKind(expected_kind)); 2658 DCHECK(IsFastElementsKind(transitioned_kind)); 2659 2660 // Check that the function's map is the same as the expected cached map. 2661 ldr(scratch, NativeContextMemOperand()); 2662 ldr(ip, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind))); 2663 cmp(map_in_out, ip); 2664 b(ne, no_map_match); 2665 2666 // Use the transitioned cached map. 2667 ldr(map_in_out, 2668 ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind))); 2669 } 2670 2671 2672 void MacroAssembler::LoadNativeContextSlot(int index, Register dst) { 2673 ldr(dst, NativeContextMemOperand()); 2674 ldr(dst, ContextMemOperand(dst, index)); 2675 } 2676 2677 2678 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, 2679 Register map, 2680 Register scratch) { 2681 // Load the initial map. The global functions all have initial maps. 2682 ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 2683 if (emit_debug_code()) { 2684 Label ok, fail; 2685 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); 2686 b(&ok); 2687 bind(&fail); 2688 Abort(kGlobalFunctionsMustHaveInitialMap); 2689 bind(&ok); 2690 } 2691 } 2692 2693 2694 void MacroAssembler::JumpIfNotPowerOfTwoOrZero( 2695 Register reg, 2696 Register scratch, 2697 Label* not_power_of_two_or_zero) { 2698 sub(scratch, reg, Operand(1), SetCC); 2699 b(mi, not_power_of_two_or_zero); 2700 tst(scratch, reg); 2701 b(ne, not_power_of_two_or_zero); 2702 } 2703 2704 2705 void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg( 2706 Register reg, 2707 Register scratch, 2708 Label* zero_and_neg, 2709 Label* not_power_of_two) { 2710 sub(scratch, reg, Operand(1), SetCC); 2711 b(mi, zero_and_neg); 2712 tst(scratch, reg); 2713 b(ne, not_power_of_two); 2714 } 2715 2716 2717 void MacroAssembler::JumpIfNotBothSmi(Register reg1, 2718 Register reg2, 2719 Label* on_not_both_smi) { 2720 STATIC_ASSERT(kSmiTag == 0); 2721 tst(reg1, Operand(kSmiTagMask)); 2722 tst(reg2, Operand(kSmiTagMask), eq); 2723 b(ne, on_not_both_smi); 2724 } 2725 2726 2727 void MacroAssembler::UntagAndJumpIfSmi( 2728 Register dst, Register src, Label* smi_case) { 2729 STATIC_ASSERT(kSmiTag == 0); 2730 SmiUntag(dst, src, SetCC); 2731 b(cc, smi_case); // Shifter carry is not set for a smi. 2732 } 2733 2734 2735 void MacroAssembler::UntagAndJumpIfNotSmi( 2736 Register dst, Register src, Label* non_smi_case) { 2737 STATIC_ASSERT(kSmiTag == 0); 2738 SmiUntag(dst, src, SetCC); 2739 b(cs, non_smi_case); // Shifter carry is set for a non-smi. 2740 } 2741 2742 2743 void MacroAssembler::JumpIfEitherSmi(Register reg1, 2744 Register reg2, 2745 Label* on_either_smi) { 2746 STATIC_ASSERT(kSmiTag == 0); 2747 tst(reg1, Operand(kSmiTagMask)); 2748 tst(reg2, Operand(kSmiTagMask), ne); 2749 b(eq, on_either_smi); 2750 } 2751 2752 2753 void MacroAssembler::AssertNotSmi(Register object) { 2754 if (emit_debug_code()) { 2755 STATIC_ASSERT(kSmiTag == 0); 2756 tst(object, Operand(kSmiTagMask)); 2757 Check(ne, kOperandIsASmi); 2758 } 2759 } 2760 2761 2762 void MacroAssembler::AssertSmi(Register object) { 2763 if (emit_debug_code()) { 2764 STATIC_ASSERT(kSmiTag == 0); 2765 tst(object, Operand(kSmiTagMask)); 2766 Check(eq, kOperandIsNotSmi); 2767 } 2768 } 2769 2770 2771 void MacroAssembler::AssertString(Register object) { 2772 if (emit_debug_code()) { 2773 STATIC_ASSERT(kSmiTag == 0); 2774 tst(object, Operand(kSmiTagMask)); 2775 Check(ne, kOperandIsASmiAndNotAString); 2776 push(object); 2777 ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); 2778 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); 2779 pop(object); 2780 Check(lo, kOperandIsNotAString); 2781 } 2782 } 2783 2784 2785 void MacroAssembler::AssertName(Register object) { 2786 if (emit_debug_code()) { 2787 STATIC_ASSERT(kSmiTag == 0); 2788 tst(object, Operand(kSmiTagMask)); 2789 Check(ne, kOperandIsASmiAndNotAName); 2790 push(object); 2791 ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); 2792 CompareInstanceType(object, object, LAST_NAME_TYPE); 2793 pop(object); 2794 Check(le, kOperandIsNotAName); 2795 } 2796 } 2797 2798 2799 void MacroAssembler::AssertFunction(Register object) { 2800 if (emit_debug_code()) { 2801 STATIC_ASSERT(kSmiTag == 0); 2802 tst(object, Operand(kSmiTagMask)); 2803 Check(ne, kOperandIsASmiAndNotAFunction); 2804 push(object); 2805 CompareObjectType(object, object, object, JS_FUNCTION_TYPE); 2806 pop(object); 2807 Check(eq, kOperandIsNotAFunction); 2808 } 2809 } 2810 2811 2812 void MacroAssembler::AssertBoundFunction(Register object) { 2813 if (emit_debug_code()) { 2814 STATIC_ASSERT(kSmiTag == 0); 2815 tst(object, Operand(kSmiTagMask)); 2816 Check(ne, kOperandIsASmiAndNotABoundFunction); 2817 push(object); 2818 CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE); 2819 pop(object); 2820 Check(eq, kOperandIsNotABoundFunction); 2821 } 2822 } 2823 2824 2825 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object, 2826 Register scratch) { 2827 if (emit_debug_code()) { 2828 Label done_checking; 2829 AssertNotSmi(object); 2830 CompareRoot(object, Heap::kUndefinedValueRootIndex); 2831 b(eq, &done_checking); 2832 ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 2833 CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex); 2834 Assert(eq, kExpectedUndefinedOrCell); 2835 bind(&done_checking); 2836 } 2837 } 2838 2839 2840 void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) { 2841 if (emit_debug_code()) { 2842 CompareRoot(reg, index); 2843 Check(eq, kHeapNumberMapRegisterClobbered); 2844 } 2845 } 2846 2847 2848 void MacroAssembler::JumpIfNotHeapNumber(Register object, 2849 Register heap_number_map, 2850 Register scratch, 2851 Label* on_not_heap_number) { 2852 ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 2853 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 2854 cmp(scratch, heap_number_map); 2855 b(ne, on_not_heap_number); 2856 } 2857 2858 2859 void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings( 2860 Register first, Register second, Register scratch1, Register scratch2, 2861 Label* failure) { 2862 // Test that both first and second are sequential one-byte strings. 2863 // Assume that they are non-smis. 2864 ldr(scratch1, FieldMemOperand(first, HeapObject::kMapOffset)); 2865 ldr(scratch2, FieldMemOperand(second, HeapObject::kMapOffset)); 2866 ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); 2867 ldrb(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset)); 2868 2869 JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1, 2870 scratch2, failure); 2871 } 2872 2873 void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first, 2874 Register second, 2875 Register scratch1, 2876 Register scratch2, 2877 Label* failure) { 2878 // Check that neither is a smi. 2879 and_(scratch1, first, Operand(second)); 2880 JumpIfSmi(scratch1, failure); 2881 JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1, 2882 scratch2, failure); 2883 } 2884 2885 2886 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg, 2887 Label* not_unique_name) { 2888 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); 2889 Label succeed; 2890 tst(reg, Operand(kIsNotStringMask | kIsNotInternalizedMask)); 2891 b(eq, &succeed); 2892 cmp(reg, Operand(SYMBOL_TYPE)); 2893 b(ne, not_unique_name); 2894 2895 bind(&succeed); 2896 } 2897 2898 2899 // Allocates a heap number or jumps to the need_gc label if the young space 2900 // is full and a scavenge is needed. 2901 void MacroAssembler::AllocateHeapNumber(Register result, 2902 Register scratch1, 2903 Register scratch2, 2904 Register heap_number_map, 2905 Label* gc_required, 2906 TaggingMode tagging_mode, 2907 MutableMode mode) { 2908 // Allocate an object in the heap for the heap number and tag it as a heap 2909 // object. 2910 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required, 2911 tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS); 2912 2913 Heap::RootListIndex map_index = mode == MUTABLE 2914 ? Heap::kMutableHeapNumberMapRootIndex 2915 : Heap::kHeapNumberMapRootIndex; 2916 AssertIsRoot(heap_number_map, map_index); 2917 2918 // Store heap number map in the allocated object. 2919 if (tagging_mode == TAG_RESULT) { 2920 str(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset)); 2921 } else { 2922 str(heap_number_map, MemOperand(result, HeapObject::kMapOffset)); 2923 } 2924 } 2925 2926 2927 void MacroAssembler::AllocateHeapNumberWithValue(Register result, 2928 DwVfpRegister value, 2929 Register scratch1, 2930 Register scratch2, 2931 Register heap_number_map, 2932 Label* gc_required) { 2933 AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required); 2934 sub(scratch1, result, Operand(kHeapObjectTag)); 2935 vstr(value, scratch1, HeapNumber::kValueOffset); 2936 } 2937 2938 2939 void MacroAssembler::AllocateJSValue(Register result, Register constructor, 2940 Register value, Register scratch1, 2941 Register scratch2, Label* gc_required) { 2942 DCHECK(!result.is(constructor)); 2943 DCHECK(!result.is(scratch1)); 2944 DCHECK(!result.is(scratch2)); 2945 DCHECK(!result.is(value)); 2946 2947 // Allocate JSValue in new space. 2948 Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT); 2949 2950 // Initialize the JSValue. 2951 LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2); 2952 str(scratch1, FieldMemOperand(result, HeapObject::kMapOffset)); 2953 LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex); 2954 str(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset)); 2955 str(scratch1, FieldMemOperand(result, JSObject::kElementsOffset)); 2956 str(value, FieldMemOperand(result, JSValue::kValueOffset)); 2957 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); 2958 } 2959 2960 2961 void MacroAssembler::CopyBytes(Register src, 2962 Register dst, 2963 Register length, 2964 Register scratch) { 2965 Label align_loop_1, word_loop, byte_loop, byte_loop_1, done; 2966 2967 // Align src before copying in word size chunks. 2968 cmp(length, Operand(kPointerSize)); 2969 b(le, &byte_loop); 2970 2971 bind(&align_loop_1); 2972 tst(src, Operand(kPointerSize - 1)); 2973 b(eq, &word_loop); 2974 ldrb(scratch, MemOperand(src, 1, PostIndex)); 2975 strb(scratch, MemOperand(dst, 1, PostIndex)); 2976 sub(length, length, Operand(1), SetCC); 2977 b(&align_loop_1); 2978 // Copy bytes in word size chunks. 2979 bind(&word_loop); 2980 if (emit_debug_code()) { 2981 tst(src, Operand(kPointerSize - 1)); 2982 Assert(eq, kExpectingAlignmentForCopyBytes); 2983 } 2984 cmp(length, Operand(kPointerSize)); 2985 b(lt, &byte_loop); 2986 ldr(scratch, MemOperand(src, kPointerSize, PostIndex)); 2987 if (CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) { 2988 str(scratch, MemOperand(dst, kPointerSize, PostIndex)); 2989 } else { 2990 strb(scratch, MemOperand(dst, 1, PostIndex)); 2991 mov(scratch, Operand(scratch, LSR, 8)); 2992 strb(scratch, MemOperand(dst, 1, PostIndex)); 2993 mov(scratch, Operand(scratch, LSR, 8)); 2994 strb(scratch, MemOperand(dst, 1, PostIndex)); 2995 mov(scratch, Operand(scratch, LSR, 8)); 2996 strb(scratch, MemOperand(dst, 1, PostIndex)); 2997 } 2998 sub(length, length, Operand(kPointerSize)); 2999 b(&word_loop); 3000 3001 // Copy the last bytes if any left. 3002 bind(&byte_loop); 3003 cmp(length, Operand::Zero()); 3004 b(eq, &done); 3005 bind(&byte_loop_1); 3006 ldrb(scratch, MemOperand(src, 1, PostIndex)); 3007 strb(scratch, MemOperand(dst, 1, PostIndex)); 3008 sub(length, length, Operand(1), SetCC); 3009 b(ne, &byte_loop_1); 3010 bind(&done); 3011 } 3012 3013 3014 void MacroAssembler::InitializeFieldsWithFiller(Register current_address, 3015 Register end_address, 3016 Register filler) { 3017 Label loop, entry; 3018 b(&entry); 3019 bind(&loop); 3020 str(filler, MemOperand(current_address, kPointerSize, PostIndex)); 3021 bind(&entry); 3022 cmp(current_address, end_address); 3023 b(lo, &loop); 3024 } 3025 3026 3027 void MacroAssembler::CheckFor32DRegs(Register scratch) { 3028 mov(scratch, Operand(ExternalReference::cpu_features())); 3029 ldr(scratch, MemOperand(scratch)); 3030 tst(scratch, Operand(1u << VFP32DREGS)); 3031 } 3032 3033 3034 void MacroAssembler::SaveFPRegs(Register location, Register scratch) { 3035 CheckFor32DRegs(scratch); 3036 vstm(db_w, location, d16, d31, ne); 3037 sub(location, location, Operand(16 * kDoubleSize), LeaveCC, eq); 3038 vstm(db_w, location, d0, d15); 3039 } 3040 3041 3042 void MacroAssembler::RestoreFPRegs(Register location, Register scratch) { 3043 CheckFor32DRegs(scratch); 3044 vldm(ia_w, location, d0, d15); 3045 vldm(ia_w, location, d16, d31, ne); 3046 add(location, location, Operand(16 * kDoubleSize), LeaveCC, eq); 3047 } 3048 3049 3050 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte( 3051 Register first, Register second, Register scratch1, Register scratch2, 3052 Label* failure) { 3053 const int kFlatOneByteStringMask = 3054 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; 3055 const int kFlatOneByteStringTag = 3056 kStringTag | kOneByteStringTag | kSeqStringTag; 3057 and_(scratch1, first, Operand(kFlatOneByteStringMask)); 3058 and_(scratch2, second, Operand(kFlatOneByteStringMask)); 3059 cmp(scratch1, Operand(kFlatOneByteStringTag)); 3060 // Ignore second test if first test failed. 3061 cmp(scratch2, Operand(kFlatOneByteStringTag), eq); 3062 b(ne, failure); 3063 } 3064 3065 3066 void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type, 3067 Register scratch, 3068 Label* failure) { 3069 const int kFlatOneByteStringMask = 3070 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; 3071 const int kFlatOneByteStringTag = 3072 kStringTag | kOneByteStringTag | kSeqStringTag; 3073 and_(scratch, type, Operand(kFlatOneByteStringMask)); 3074 cmp(scratch, Operand(kFlatOneByteStringTag)); 3075 b(ne, failure); 3076 } 3077 3078 static const int kRegisterPassedArguments = 4; 3079 3080 3081 int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments, 3082 int num_double_arguments) { 3083 int stack_passed_words = 0; 3084 if (use_eabi_hardfloat()) { 3085 // In the hard floating point calling convention, we can use 3086 // all double registers to pass doubles. 3087 if (num_double_arguments > DoubleRegister::NumRegisters()) { 3088 stack_passed_words += 3089 2 * (num_double_arguments - DoubleRegister::NumRegisters()); 3090 } 3091 } else { 3092 // In the soft floating point calling convention, every double 3093 // argument is passed using two registers. 3094 num_reg_arguments += 2 * num_double_arguments; 3095 } 3096 // Up to four simple arguments are passed in registers r0..r3. 3097 if (num_reg_arguments > kRegisterPassedArguments) { 3098 stack_passed_words += num_reg_arguments - kRegisterPassedArguments; 3099 } 3100 return stack_passed_words; 3101 } 3102 3103 3104 void MacroAssembler::EmitSeqStringSetCharCheck(Register string, 3105 Register index, 3106 Register value, 3107 uint32_t encoding_mask) { 3108 Label is_object; 3109 SmiTst(string); 3110 Check(ne, kNonObject); 3111 3112 ldr(ip, FieldMemOperand(string, HeapObject::kMapOffset)); 3113 ldrb(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset)); 3114 3115 and_(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask)); 3116 cmp(ip, Operand(encoding_mask)); 3117 Check(eq, kUnexpectedStringType); 3118 3119 // The index is assumed to be untagged coming in, tag it to compare with the 3120 // string length without using a temp register, it is restored at the end of 3121 // this function. 3122 Label index_tag_ok, index_tag_bad; 3123 TrySmiTag(index, index, &index_tag_bad); 3124 b(&index_tag_ok); 3125 bind(&index_tag_bad); 3126 Abort(kIndexIsTooLarge); 3127 bind(&index_tag_ok); 3128 3129 ldr(ip, FieldMemOperand(string, String::kLengthOffset)); 3130 cmp(index, ip); 3131 Check(lt, kIndexIsTooLarge); 3132 3133 cmp(index, Operand(Smi::FromInt(0))); 3134 Check(ge, kIndexIsNegative); 3135 3136 SmiUntag(index, index); 3137 } 3138 3139 3140 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, 3141 int num_double_arguments, 3142 Register scratch) { 3143 int frame_alignment = ActivationFrameAlignment(); 3144 int stack_passed_arguments = CalculateStackPassedWords( 3145 num_reg_arguments, num_double_arguments); 3146 if (frame_alignment > kPointerSize) { 3147 // Make stack end at alignment and make room for num_arguments - 4 words 3148 // and the original value of sp. 3149 mov(scratch, sp); 3150 sub(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize)); 3151 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 3152 and_(sp, sp, Operand(-frame_alignment)); 3153 str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); 3154 } else { 3155 sub(sp, sp, Operand(stack_passed_arguments * kPointerSize)); 3156 } 3157 } 3158 3159 3160 void MacroAssembler::PrepareCallCFunction(int num_reg_arguments, 3161 Register scratch) { 3162 PrepareCallCFunction(num_reg_arguments, 0, scratch); 3163 } 3164 3165 3166 void MacroAssembler::MovToFloatParameter(DwVfpRegister src) { 3167 DCHECK(src.is(d0)); 3168 if (!use_eabi_hardfloat()) { 3169 vmov(r0, r1, src); 3170 } 3171 } 3172 3173 3174 // On ARM this is just a synonym to make the purpose clear. 3175 void MacroAssembler::MovToFloatResult(DwVfpRegister src) { 3176 MovToFloatParameter(src); 3177 } 3178 3179 3180 void MacroAssembler::MovToFloatParameters(DwVfpRegister src1, 3181 DwVfpRegister src2) { 3182 DCHECK(src1.is(d0)); 3183 DCHECK(src2.is(d1)); 3184 if (!use_eabi_hardfloat()) { 3185 vmov(r0, r1, src1); 3186 vmov(r2, r3, src2); 3187 } 3188 } 3189 3190 3191 void MacroAssembler::CallCFunction(ExternalReference function, 3192 int num_reg_arguments, 3193 int num_double_arguments) { 3194 mov(ip, Operand(function)); 3195 CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments); 3196 } 3197 3198 3199 void MacroAssembler::CallCFunction(Register function, 3200 int num_reg_arguments, 3201 int num_double_arguments) { 3202 CallCFunctionHelper(function, num_reg_arguments, num_double_arguments); 3203 } 3204 3205 3206 void MacroAssembler::CallCFunction(ExternalReference function, 3207 int num_arguments) { 3208 CallCFunction(function, num_arguments, 0); 3209 } 3210 3211 3212 void MacroAssembler::CallCFunction(Register function, 3213 int num_arguments) { 3214 CallCFunction(function, num_arguments, 0); 3215 } 3216 3217 3218 void MacroAssembler::CallCFunctionHelper(Register function, 3219 int num_reg_arguments, 3220 int num_double_arguments) { 3221 DCHECK(has_frame()); 3222 // Make sure that the stack is aligned before calling a C function unless 3223 // running in the simulator. The simulator has its own alignment check which 3224 // provides more information. 3225 #if V8_HOST_ARCH_ARM 3226 if (emit_debug_code()) { 3227 int frame_alignment = base::OS::ActivationFrameAlignment(); 3228 int frame_alignment_mask = frame_alignment - 1; 3229 if (frame_alignment > kPointerSize) { 3230 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 3231 Label alignment_as_expected; 3232 tst(sp, Operand(frame_alignment_mask)); 3233 b(eq, &alignment_as_expected); 3234 // Don't use Check here, as it will call Runtime_Abort possibly 3235 // re-entering here. 3236 stop("Unexpected alignment"); 3237 bind(&alignment_as_expected); 3238 } 3239 } 3240 #endif 3241 3242 // Just call directly. The function called cannot cause a GC, or 3243 // allow preemption, so the return address in the link register 3244 // stays correct. 3245 Call(function); 3246 int stack_passed_arguments = CalculateStackPassedWords( 3247 num_reg_arguments, num_double_arguments); 3248 if (ActivationFrameAlignment() > kPointerSize) { 3249 ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); 3250 } else { 3251 add(sp, sp, Operand(stack_passed_arguments * kPointerSize)); 3252 } 3253 } 3254 3255 3256 void MacroAssembler::CheckPageFlag( 3257 Register object, 3258 Register scratch, 3259 int mask, 3260 Condition cc, 3261 Label* condition_met) { 3262 Bfc(scratch, object, 0, kPageSizeBits); 3263 ldr(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset)); 3264 tst(scratch, Operand(mask)); 3265 b(cc, condition_met); 3266 } 3267 3268 3269 void MacroAssembler::JumpIfBlack(Register object, 3270 Register scratch0, 3271 Register scratch1, 3272 Label* on_black) { 3273 HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern. 3274 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 3275 } 3276 3277 3278 void MacroAssembler::HasColor(Register object, 3279 Register bitmap_scratch, 3280 Register mask_scratch, 3281 Label* has_color, 3282 int first_bit, 3283 int second_bit) { 3284 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, no_reg)); 3285 3286 GetMarkBits(object, bitmap_scratch, mask_scratch); 3287 3288 Label other_color, word_boundary; 3289 ldr(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); 3290 tst(ip, Operand(mask_scratch)); 3291 b(first_bit == 1 ? eq : ne, &other_color); 3292 // Shift left 1 by adding. 3293 add(mask_scratch, mask_scratch, Operand(mask_scratch), SetCC); 3294 b(eq, &word_boundary); 3295 tst(ip, Operand(mask_scratch)); 3296 b(second_bit == 1 ? ne : eq, has_color); 3297 jmp(&other_color); 3298 3299 bind(&word_boundary); 3300 ldr(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize)); 3301 tst(ip, Operand(1)); 3302 b(second_bit == 1 ? ne : eq, has_color); 3303 bind(&other_color); 3304 } 3305 3306 3307 void MacroAssembler::GetMarkBits(Register addr_reg, 3308 Register bitmap_reg, 3309 Register mask_reg) { 3310 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg)); 3311 and_(bitmap_reg, addr_reg, Operand(~Page::kPageAlignmentMask)); 3312 Ubfx(mask_reg, addr_reg, kPointerSizeLog2, Bitmap::kBitsPerCellLog2); 3313 const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2; 3314 Ubfx(ip, addr_reg, kLowBits, kPageSizeBits - kLowBits); 3315 add(bitmap_reg, bitmap_reg, Operand(ip, LSL, kPointerSizeLog2)); 3316 mov(ip, Operand(1)); 3317 mov(mask_reg, Operand(ip, LSL, mask_reg)); 3318 } 3319 3320 3321 void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch, 3322 Register mask_scratch, Register load_scratch, 3323 Label* value_is_white) { 3324 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip)); 3325 GetMarkBits(value, bitmap_scratch, mask_scratch); 3326 3327 // If the value is black or grey we don't need to do anything. 3328 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); 3329 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 3330 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); 3331 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); 3332 3333 // Since both black and grey have a 1 in the first position and white does 3334 // not have a 1 there we only need to check one bit. 3335 ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); 3336 tst(mask_scratch, load_scratch); 3337 b(eq, value_is_white); 3338 } 3339 3340 3341 void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) { 3342 Usat(output_reg, 8, Operand(input_reg)); 3343 } 3344 3345 3346 void MacroAssembler::ClampDoubleToUint8(Register result_reg, 3347 DwVfpRegister input_reg, 3348 LowDwVfpRegister double_scratch) { 3349 Label done; 3350 3351 // Handle inputs >= 255 (including +infinity). 3352 Vmov(double_scratch, 255.0, result_reg); 3353 mov(result_reg, Operand(255)); 3354 VFPCompareAndSetFlags(input_reg, double_scratch); 3355 b(ge, &done); 3356 3357 // For inputs < 255 (including negative) vcvt_u32_f64 with round-to-nearest 3358 // rounding mode will provide the correct result. 3359 vcvt_u32_f64(double_scratch.low(), input_reg, kFPSCRRounding); 3360 vmov(result_reg, double_scratch.low()); 3361 3362 bind(&done); 3363 } 3364 3365 3366 void MacroAssembler::LoadInstanceDescriptors(Register map, 3367 Register descriptors) { 3368 ldr(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset)); 3369 } 3370 3371 3372 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { 3373 ldr(dst, FieldMemOperand(map, Map::kBitField3Offset)); 3374 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); 3375 } 3376 3377 3378 void MacroAssembler::EnumLength(Register dst, Register map) { 3379 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0); 3380 ldr(dst, FieldMemOperand(map, Map::kBitField3Offset)); 3381 and_(dst, dst, Operand(Map::EnumLengthBits::kMask)); 3382 SmiTag(dst); 3383 } 3384 3385 3386 void MacroAssembler::LoadAccessor(Register dst, Register holder, 3387 int accessor_index, 3388 AccessorComponent accessor) { 3389 ldr(dst, FieldMemOperand(holder, HeapObject::kMapOffset)); 3390 LoadInstanceDescriptors(dst, dst); 3391 ldr(dst, 3392 FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index))); 3393 int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset 3394 : AccessorPair::kSetterOffset; 3395 ldr(dst, FieldMemOperand(dst, offset)); 3396 } 3397 3398 3399 void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) { 3400 Register empty_fixed_array_value = r6; 3401 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); 3402 Label next, start; 3403 mov(r2, r0); 3404 3405 // Check if the enum length field is properly initialized, indicating that 3406 // there is an enum cache. 3407 ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); 3408 3409 EnumLength(r3, r1); 3410 cmp(r3, Operand(Smi::FromInt(kInvalidEnumCacheSentinel))); 3411 b(eq, call_runtime); 3412 3413 jmp(&start); 3414 3415 bind(&next); 3416 ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); 3417 3418 // For all objects but the receiver, check that the cache is empty. 3419 EnumLength(r3, r1); 3420 cmp(r3, Operand(Smi::FromInt(0))); 3421 b(ne, call_runtime); 3422 3423 bind(&start); 3424 3425 // Check that there are no elements. Register r2 contains the current JS 3426 // object we've reached through the prototype chain. 3427 Label no_elements; 3428 ldr(r2, FieldMemOperand(r2, JSObject::kElementsOffset)); 3429 cmp(r2, empty_fixed_array_value); 3430 b(eq, &no_elements); 3431 3432 // Second chance, the object may be using the empty slow element dictionary. 3433 CompareRoot(r2, Heap::kEmptySlowElementDictionaryRootIndex); 3434 b(ne, call_runtime); 3435 3436 bind(&no_elements); 3437 ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset)); 3438 cmp(r2, null_value); 3439 b(ne, &next); 3440 } 3441 3442 3443 void MacroAssembler::TestJSArrayForAllocationMemento( 3444 Register receiver_reg, 3445 Register scratch_reg, 3446 Label* no_memento_found) { 3447 ExternalReference new_space_start = 3448 ExternalReference::new_space_start(isolate()); 3449 ExternalReference new_space_allocation_top = 3450 ExternalReference::new_space_allocation_top_address(isolate()); 3451 add(scratch_reg, receiver_reg, 3452 Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag)); 3453 cmp(scratch_reg, Operand(new_space_start)); 3454 b(lt, no_memento_found); 3455 mov(ip, Operand(new_space_allocation_top)); 3456 ldr(ip, MemOperand(ip)); 3457 cmp(scratch_reg, ip); 3458 b(gt, no_memento_found); 3459 ldr(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize)); 3460 cmp(scratch_reg, 3461 Operand(isolate()->factory()->allocation_memento_map())); 3462 } 3463 3464 3465 Register GetRegisterThatIsNotOneOf(Register reg1, 3466 Register reg2, 3467 Register reg3, 3468 Register reg4, 3469 Register reg5, 3470 Register reg6) { 3471 RegList regs = 0; 3472 if (reg1.is_valid()) regs |= reg1.bit(); 3473 if (reg2.is_valid()) regs |= reg2.bit(); 3474 if (reg3.is_valid()) regs |= reg3.bit(); 3475 if (reg4.is_valid()) regs |= reg4.bit(); 3476 if (reg5.is_valid()) regs |= reg5.bit(); 3477 if (reg6.is_valid()) regs |= reg6.bit(); 3478 3479 const RegisterConfiguration* config = 3480 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT); 3481 for (int i = 0; i < config->num_allocatable_general_registers(); ++i) { 3482 int code = config->GetAllocatableGeneralCode(i); 3483 Register candidate = Register::from_code(code); 3484 if (regs & candidate.bit()) continue; 3485 return candidate; 3486 } 3487 UNREACHABLE(); 3488 return no_reg; 3489 } 3490 3491 3492 void MacroAssembler::JumpIfDictionaryInPrototypeChain( 3493 Register object, 3494 Register scratch0, 3495 Register scratch1, 3496 Label* found) { 3497 DCHECK(!scratch1.is(scratch0)); 3498 Register current = scratch0; 3499 Label loop_again, end; 3500 3501 // scratch contained elements pointer. 3502 mov(current, object); 3503 ldr(current, FieldMemOperand(current, HeapObject::kMapOffset)); 3504 ldr(current, FieldMemOperand(current, Map::kPrototypeOffset)); 3505 CompareRoot(current, Heap::kNullValueRootIndex); 3506 b(eq, &end); 3507 3508 // Loop based on the map going up the prototype chain. 3509 bind(&loop_again); 3510 ldr(current, FieldMemOperand(current, HeapObject::kMapOffset)); 3511 3512 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE); 3513 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE); 3514 ldrb(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset)); 3515 cmp(scratch1, Operand(JS_OBJECT_TYPE)); 3516 b(lo, found); 3517 3518 ldr(scratch1, FieldMemOperand(current, Map::kBitField2Offset)); 3519 DecodeField<Map::ElementsKindBits>(scratch1); 3520 cmp(scratch1, Operand(DICTIONARY_ELEMENTS)); 3521 b(eq, found); 3522 ldr(current, FieldMemOperand(current, Map::kPrototypeOffset)); 3523 CompareRoot(current, Heap::kNullValueRootIndex); 3524 b(ne, &loop_again); 3525 3526 bind(&end); 3527 } 3528 3529 3530 #ifdef DEBUG 3531 bool AreAliased(Register reg1, 3532 Register reg2, 3533 Register reg3, 3534 Register reg4, 3535 Register reg5, 3536 Register reg6, 3537 Register reg7, 3538 Register reg8) { 3539 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + 3540 reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() + 3541 reg7.is_valid() + reg8.is_valid(); 3542 3543 RegList regs = 0; 3544 if (reg1.is_valid()) regs |= reg1.bit(); 3545 if (reg2.is_valid()) regs |= reg2.bit(); 3546 if (reg3.is_valid()) regs |= reg3.bit(); 3547 if (reg4.is_valid()) regs |= reg4.bit(); 3548 if (reg5.is_valid()) regs |= reg5.bit(); 3549 if (reg6.is_valid()) regs |= reg6.bit(); 3550 if (reg7.is_valid()) regs |= reg7.bit(); 3551 if (reg8.is_valid()) regs |= reg8.bit(); 3552 int n_of_non_aliasing_regs = NumRegs(regs); 3553 3554 return n_of_valid_regs != n_of_non_aliasing_regs; 3555 } 3556 #endif 3557 3558 3559 CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions, 3560 FlushICache flush_cache) 3561 : address_(address), 3562 size_(instructions * Assembler::kInstrSize), 3563 masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo), 3564 flush_cache_(flush_cache) { 3565 // Create a new macro assembler pointing to the address of the code to patch. 3566 // The size is adjusted with kGap on order for the assembler to generate size 3567 // bytes of instructions without failing with buffer size constraints. 3568 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 3569 } 3570 3571 3572 CodePatcher::~CodePatcher() { 3573 // Indicate that code has changed. 3574 if (flush_cache_ == FLUSH) { 3575 Assembler::FlushICache(masm_.isolate(), address_, size_); 3576 } 3577 3578 // Check that the code was patched as expected. 3579 DCHECK(masm_.pc_ == address_ + size_); 3580 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 3581 } 3582 3583 3584 void CodePatcher::Emit(Instr instr) { 3585 masm()->emit(instr); 3586 } 3587 3588 3589 void CodePatcher::Emit(Address addr) { 3590 masm()->emit(reinterpret_cast<Instr>(addr)); 3591 } 3592 3593 3594 void CodePatcher::EmitCondition(Condition cond) { 3595 Instr instr = Assembler::instr_at(masm_.pc_); 3596 instr = (instr & ~kCondMask) | cond; 3597 masm_.emit(instr); 3598 } 3599 3600 3601 void MacroAssembler::TruncatingDiv(Register result, 3602 Register dividend, 3603 int32_t divisor) { 3604 DCHECK(!dividend.is(result)); 3605 DCHECK(!dividend.is(ip)); 3606 DCHECK(!result.is(ip)); 3607 base::MagicNumbersForDivision<uint32_t> mag = 3608 base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor)); 3609 mov(ip, Operand(mag.multiplier)); 3610 bool neg = (mag.multiplier & (1U << 31)) != 0; 3611 if (divisor > 0 && neg) { 3612 smmla(result, dividend, ip, dividend); 3613 } else { 3614 smmul(result, dividend, ip); 3615 if (divisor < 0 && !neg && mag.multiplier > 0) { 3616 sub(result, result, Operand(dividend)); 3617 } 3618 } 3619 if (mag.shift > 0) mov(result, Operand(result, ASR, mag.shift)); 3620 add(result, result, Operand(dividend, LSR, 31)); 3621 } 3622 3623 } // namespace internal 3624 } // namespace v8 3625 3626 #endif // V8_TARGET_ARCH_ARM 3627