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#if V8_TARGET_ARCH_IA32 6 7#include "src/base/bits.h" 8#include "src/base/division-by-constant.h" 9#include "src/bootstrapper.h" 10#include "src/codegen.h" 11#include "src/debug/debug.h" 12#include "src/ia32/frames-ia32.h" 13#include "src/ia32/macro-assembler-ia32.h" 14#include "src/runtime/runtime.h" 15 16namespace v8 { 17namespace internal { 18 19// ------------------------------------------------------------------------- 20// MacroAssembler implementation. 21 22MacroAssembler::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 34void MacroAssembler::Load(Register dst, const Operand& src, Representation r) { 35 DCHECK(!r.IsDouble()); 36 if (r.IsInteger8()) { 37 movsx_b(dst, src); 38 } else if (r.IsUInteger8()) { 39 movzx_b(dst, src); 40 } else if (r.IsInteger16()) { 41 movsx_w(dst, src); 42 } else if (r.IsUInteger16()) { 43 movzx_w(dst, src); 44 } else { 45 mov(dst, src); 46 } 47} 48 49 50void MacroAssembler::Store(Register src, const Operand& dst, Representation r) { 51 DCHECK(!r.IsDouble()); 52 if (r.IsInteger8() || r.IsUInteger8()) { 53 mov_b(dst, src); 54 } else if (r.IsInteger16() || r.IsUInteger16()) { 55 mov_w(dst, src); 56 } else { 57 if (r.IsHeapObject()) { 58 AssertNotSmi(src); 59 } else if (r.IsSmi()) { 60 AssertSmi(src); 61 } 62 mov(dst, src); 63 } 64} 65 66 67void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) { 68 if (isolate()->heap()->RootCanBeTreatedAsConstant(index)) { 69 mov(destination, isolate()->heap()->root_handle(index)); 70 return; 71 } 72 ExternalReference roots_array_start = 73 ExternalReference::roots_array_start(isolate()); 74 mov(destination, Immediate(index)); 75 mov(destination, Operand::StaticArray(destination, 76 times_pointer_size, 77 roots_array_start)); 78} 79 80 81void MacroAssembler::StoreRoot(Register source, 82 Register scratch, 83 Heap::RootListIndex index) { 84 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); 85 ExternalReference roots_array_start = 86 ExternalReference::roots_array_start(isolate()); 87 mov(scratch, Immediate(index)); 88 mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), 89 source); 90} 91 92 93void MacroAssembler::CompareRoot(Register with, 94 Register scratch, 95 Heap::RootListIndex index) { 96 ExternalReference roots_array_start = 97 ExternalReference::roots_array_start(isolate()); 98 mov(scratch, Immediate(index)); 99 cmp(with, Operand::StaticArray(scratch, 100 times_pointer_size, 101 roots_array_start)); 102} 103 104 105void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) { 106 DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index)); 107 cmp(with, isolate()->heap()->root_handle(index)); 108} 109 110 111void MacroAssembler::CompareRoot(const Operand& with, 112 Heap::RootListIndex index) { 113 DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index)); 114 cmp(with, isolate()->heap()->root_handle(index)); 115} 116 117 118void MacroAssembler::PushRoot(Heap::RootListIndex index) { 119 DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index)); 120 Push(isolate()->heap()->root_handle(index)); 121} 122 123#define REG(Name) \ 124 { Register::kCode_##Name } 125 126static const Register saved_regs[] = {REG(eax), REG(ecx), REG(edx)}; 127 128#undef REG 129 130static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register); 131 132void MacroAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, 133 Register exclusion1, Register exclusion2, 134 Register exclusion3) { 135 // We don't allow a GC during a store buffer overflow so there is no need to 136 // store the registers in any particular way, but we do have to store and 137 // restore them. 138 for (int i = 0; i < kNumberOfSavedRegs; i++) { 139 Register reg = saved_regs[i]; 140 if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { 141 push(reg); 142 } 143 } 144 if (fp_mode == kSaveFPRegs) { 145 sub(esp, Immediate(kDoubleSize * (XMMRegister::kMaxNumRegisters - 1))); 146 // Save all XMM registers except XMM0. 147 for (int i = XMMRegister::kMaxNumRegisters - 1; i > 0; i--) { 148 XMMRegister reg = XMMRegister::from_code(i); 149 movsd(Operand(esp, (i - 1) * kDoubleSize), reg); 150 } 151 } 152} 153 154void MacroAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1, 155 Register exclusion2, Register exclusion3) { 156 if (fp_mode == kSaveFPRegs) { 157 // Restore all XMM registers except XMM0. 158 for (int i = XMMRegister::kMaxNumRegisters - 1; i > 0; i--) { 159 XMMRegister reg = XMMRegister::from_code(i); 160 movsd(reg, Operand(esp, (i - 1) * kDoubleSize)); 161 } 162 add(esp, Immediate(kDoubleSize * (XMMRegister::kMaxNumRegisters - 1))); 163 } 164 165 for (int i = kNumberOfSavedRegs - 1; i >= 0; i--) { 166 Register reg = saved_regs[i]; 167 if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { 168 pop(reg); 169 } 170 } 171} 172 173void MacroAssembler::InNewSpace(Register object, Register scratch, Condition cc, 174 Label* condition_met, 175 Label::Distance distance) { 176 const int mask = 177 (1 << MemoryChunk::IN_FROM_SPACE) | (1 << MemoryChunk::IN_TO_SPACE); 178 CheckPageFlag(object, scratch, mask, cc, condition_met, distance); 179} 180 181 182void MacroAssembler::RememberedSetHelper( 183 Register object, // Only used for debug checks. 184 Register addr, 185 Register scratch, 186 SaveFPRegsMode save_fp, 187 MacroAssembler::RememberedSetFinalAction and_then) { 188 Label done; 189 if (emit_debug_code()) { 190 Label ok; 191 JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear); 192 int3(); 193 bind(&ok); 194 } 195 // Load store buffer top. 196 ExternalReference store_buffer = 197 ExternalReference::store_buffer_top(isolate()); 198 mov(scratch, Operand::StaticVariable(store_buffer)); 199 // Store pointer to buffer. 200 mov(Operand(scratch, 0), addr); 201 // Increment buffer top. 202 add(scratch, Immediate(kPointerSize)); 203 // Write back new top of buffer. 204 mov(Operand::StaticVariable(store_buffer), scratch); 205 // Call stub on end of buffer. 206 // Check for end of buffer. 207 test(scratch, Immediate(StoreBuffer::kStoreBufferMask)); 208 if (and_then == kReturnAtEnd) { 209 Label buffer_overflowed; 210 j(equal, &buffer_overflowed, Label::kNear); 211 ret(0); 212 bind(&buffer_overflowed); 213 } else { 214 DCHECK(and_then == kFallThroughAtEnd); 215 j(not_equal, &done, Label::kNear); 216 } 217 StoreBufferOverflowStub store_buffer_overflow(isolate(), save_fp); 218 CallStub(&store_buffer_overflow); 219 if (and_then == kReturnAtEnd) { 220 ret(0); 221 } else { 222 DCHECK(and_then == kFallThroughAtEnd); 223 bind(&done); 224 } 225} 226 227 228void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg, 229 XMMRegister scratch_reg, 230 Register result_reg) { 231 Label done; 232 Label conv_failure; 233 xorps(scratch_reg, scratch_reg); 234 cvtsd2si(result_reg, input_reg); 235 test(result_reg, Immediate(0xFFFFFF00)); 236 j(zero, &done, Label::kNear); 237 cmp(result_reg, Immediate(0x1)); 238 j(overflow, &conv_failure, Label::kNear); 239 mov(result_reg, Immediate(0)); 240 setcc(sign, result_reg); 241 sub(result_reg, Immediate(1)); 242 and_(result_reg, Immediate(255)); 243 jmp(&done, Label::kNear); 244 bind(&conv_failure); 245 Move(result_reg, Immediate(0)); 246 ucomisd(input_reg, scratch_reg); 247 j(below, &done, Label::kNear); 248 Move(result_reg, Immediate(255)); 249 bind(&done); 250} 251 252 253void MacroAssembler::ClampUint8(Register reg) { 254 Label done; 255 test(reg, Immediate(0xFFFFFF00)); 256 j(zero, &done, Label::kNear); 257 setcc(negative, reg); // 1 if negative, 0 if positive. 258 dec_b(reg); // 0 if negative, 255 if positive. 259 bind(&done); 260} 261 262 263void MacroAssembler::SlowTruncateToI(Register result_reg, 264 Register input_reg, 265 int offset) { 266 DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true); 267 call(stub.GetCode(), RelocInfo::CODE_TARGET); 268} 269 270 271void MacroAssembler::TruncateDoubleToI(Register result_reg, 272 XMMRegister input_reg) { 273 Label done; 274 cvttsd2si(result_reg, Operand(input_reg)); 275 cmp(result_reg, 0x1); 276 j(no_overflow, &done, Label::kNear); 277 278 sub(esp, Immediate(kDoubleSize)); 279 movsd(MemOperand(esp, 0), input_reg); 280 SlowTruncateToI(result_reg, esp, 0); 281 add(esp, Immediate(kDoubleSize)); 282 bind(&done); 283} 284 285 286void MacroAssembler::DoubleToI(Register result_reg, XMMRegister input_reg, 287 XMMRegister scratch, 288 MinusZeroMode minus_zero_mode, 289 Label* lost_precision, Label* is_nan, 290 Label* minus_zero, Label::Distance dst) { 291 DCHECK(!input_reg.is(scratch)); 292 cvttsd2si(result_reg, Operand(input_reg)); 293 Cvtsi2sd(scratch, Operand(result_reg)); 294 ucomisd(scratch, input_reg); 295 j(not_equal, lost_precision, dst); 296 j(parity_even, is_nan, dst); 297 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { 298 Label done; 299 // The integer converted back is equal to the original. We 300 // only have to test if we got -0 as an input. 301 test(result_reg, Operand(result_reg)); 302 j(not_zero, &done, Label::kNear); 303 movmskpd(result_reg, input_reg); 304 // Bit 0 contains the sign of the double in input_reg. 305 // If input was positive, we are ok and return 0, otherwise 306 // jump to minus_zero. 307 and_(result_reg, 1); 308 j(not_zero, minus_zero, dst); 309 bind(&done); 310 } 311} 312 313 314void MacroAssembler::TruncateHeapNumberToI(Register result_reg, 315 Register input_reg) { 316 Label done, slow_case; 317 318 if (CpuFeatures::IsSupported(SSE3)) { 319 CpuFeatureScope scope(this, SSE3); 320 Label convert; 321 // Use more powerful conversion when sse3 is available. 322 // Load x87 register with heap number. 323 fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); 324 // Get exponent alone and check for too-big exponent. 325 mov(result_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset)); 326 and_(result_reg, HeapNumber::kExponentMask); 327 const uint32_t kTooBigExponent = 328 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; 329 cmp(Operand(result_reg), Immediate(kTooBigExponent)); 330 j(greater_equal, &slow_case, Label::kNear); 331 332 // Reserve space for 64 bit answer. 333 sub(Operand(esp), Immediate(kDoubleSize)); 334 // Do conversion, which cannot fail because we checked the exponent. 335 fisttp_d(Operand(esp, 0)); 336 mov(result_reg, Operand(esp, 0)); // Low word of answer is the result. 337 add(Operand(esp), Immediate(kDoubleSize)); 338 jmp(&done, Label::kNear); 339 340 // Slow case. 341 bind(&slow_case); 342 if (input_reg.is(result_reg)) { 343 // Input is clobbered. Restore number from fpu stack 344 sub(Operand(esp), Immediate(kDoubleSize)); 345 fstp_d(Operand(esp, 0)); 346 SlowTruncateToI(result_reg, esp, 0); 347 add(esp, Immediate(kDoubleSize)); 348 } else { 349 fstp(0); 350 SlowTruncateToI(result_reg, input_reg); 351 } 352 } else { 353 movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); 354 cvttsd2si(result_reg, Operand(xmm0)); 355 cmp(result_reg, 0x1); 356 j(no_overflow, &done, Label::kNear); 357 // Check if the input was 0x8000000 (kMinInt). 358 // If no, then we got an overflow and we deoptimize. 359 ExternalReference min_int = ExternalReference::address_of_min_int(); 360 ucomisd(xmm0, Operand::StaticVariable(min_int)); 361 j(not_equal, &slow_case, Label::kNear); 362 j(parity_even, &slow_case, Label::kNear); // NaN. 363 jmp(&done, Label::kNear); 364 365 // Slow case. 366 bind(&slow_case); 367 if (input_reg.is(result_reg)) { 368 // Input is clobbered. Restore number from double scratch. 369 sub(esp, Immediate(kDoubleSize)); 370 movsd(MemOperand(esp, 0), xmm0); 371 SlowTruncateToI(result_reg, esp, 0); 372 add(esp, Immediate(kDoubleSize)); 373 } else { 374 SlowTruncateToI(result_reg, input_reg); 375 } 376 } 377 bind(&done); 378} 379 380 381void MacroAssembler::LoadUint32(XMMRegister dst, const Operand& src) { 382 Label done; 383 cmp(src, Immediate(0)); 384 ExternalReference uint32_bias = ExternalReference::address_of_uint32_bias(); 385 Cvtsi2sd(dst, src); 386 j(not_sign, &done, Label::kNear); 387 addsd(dst, Operand::StaticVariable(uint32_bias)); 388 bind(&done); 389} 390 391 392void MacroAssembler::RecordWriteArray( 393 Register object, 394 Register value, 395 Register index, 396 SaveFPRegsMode save_fp, 397 RememberedSetAction remembered_set_action, 398 SmiCheck smi_check, 399 PointersToHereCheck pointers_to_here_check_for_value) { 400 // First, check if a write barrier is even needed. The tests below 401 // catch stores of Smis. 402 Label done; 403 404 // Skip barrier if writing a smi. 405 if (smi_check == INLINE_SMI_CHECK) { 406 DCHECK_EQ(0, kSmiTag); 407 test(value, Immediate(kSmiTagMask)); 408 j(zero, &done); 409 } 410 411 // Array access: calculate the destination address in the same manner as 412 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset 413 // into an array of words. 414 Register dst = index; 415 lea(dst, Operand(object, index, times_half_pointer_size, 416 FixedArray::kHeaderSize - kHeapObjectTag)); 417 418 RecordWrite(object, dst, value, save_fp, remembered_set_action, 419 OMIT_SMI_CHECK, pointers_to_here_check_for_value); 420 421 bind(&done); 422 423 // Clobber clobbered input registers when running with the debug-code flag 424 // turned on to provoke errors. 425 if (emit_debug_code()) { 426 mov(value, Immediate(bit_cast<int32_t>(kZapValue))); 427 mov(index, Immediate(bit_cast<int32_t>(kZapValue))); 428 } 429} 430 431 432void MacroAssembler::RecordWriteField( 433 Register object, 434 int offset, 435 Register value, 436 Register dst, 437 SaveFPRegsMode save_fp, 438 RememberedSetAction remembered_set_action, 439 SmiCheck smi_check, 440 PointersToHereCheck pointers_to_here_check_for_value) { 441 // First, check if a write barrier is even needed. The tests below 442 // catch stores of Smis. 443 Label done; 444 445 // Skip barrier if writing a smi. 446 if (smi_check == INLINE_SMI_CHECK) { 447 JumpIfSmi(value, &done, Label::kNear); 448 } 449 450 // Although the object register is tagged, the offset is relative to the start 451 // of the object, so so offset must be a multiple of kPointerSize. 452 DCHECK(IsAligned(offset, kPointerSize)); 453 454 lea(dst, FieldOperand(object, offset)); 455 if (emit_debug_code()) { 456 Label ok; 457 test_b(dst, Immediate((1 << kPointerSizeLog2) - 1)); 458 j(zero, &ok, Label::kNear); 459 int3(); 460 bind(&ok); 461 } 462 463 RecordWrite(object, dst, value, save_fp, remembered_set_action, 464 OMIT_SMI_CHECK, pointers_to_here_check_for_value); 465 466 bind(&done); 467 468 // Clobber clobbered input registers when running with the debug-code flag 469 // turned on to provoke errors. 470 if (emit_debug_code()) { 471 mov(value, Immediate(bit_cast<int32_t>(kZapValue))); 472 mov(dst, Immediate(bit_cast<int32_t>(kZapValue))); 473 } 474} 475 476 477void MacroAssembler::RecordWriteForMap( 478 Register object, 479 Handle<Map> map, 480 Register scratch1, 481 Register scratch2, 482 SaveFPRegsMode save_fp) { 483 Label done; 484 485 Register address = scratch1; 486 Register value = scratch2; 487 if (emit_debug_code()) { 488 Label ok; 489 lea(address, FieldOperand(object, HeapObject::kMapOffset)); 490 test_b(address, Immediate((1 << kPointerSizeLog2) - 1)); 491 j(zero, &ok, Label::kNear); 492 int3(); 493 bind(&ok); 494 } 495 496 DCHECK(!object.is(value)); 497 DCHECK(!object.is(address)); 498 DCHECK(!value.is(address)); 499 AssertNotSmi(object); 500 501 if (!FLAG_incremental_marking) { 502 return; 503 } 504 505 // Compute the address. 506 lea(address, FieldOperand(object, HeapObject::kMapOffset)); 507 508 // A single check of the map's pages interesting flag suffices, since it is 509 // only set during incremental collection, and then it's also guaranteed that 510 // the from object's page's interesting flag is also set. This optimization 511 // relies on the fact that maps can never be in new space. 512 DCHECK(!isolate()->heap()->InNewSpace(*map)); 513 CheckPageFlagForMap(map, 514 MemoryChunk::kPointersToHereAreInterestingMask, 515 zero, 516 &done, 517 Label::kNear); 518 519 RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET, 520 save_fp); 521 CallStub(&stub); 522 523 bind(&done); 524 525 // Count number of write barriers in generated code. 526 isolate()->counters()->write_barriers_static()->Increment(); 527 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1); 528 529 // Clobber clobbered input registers when running with the debug-code flag 530 // turned on to provoke errors. 531 if (emit_debug_code()) { 532 mov(value, Immediate(bit_cast<int32_t>(kZapValue))); 533 mov(scratch1, Immediate(bit_cast<int32_t>(kZapValue))); 534 mov(scratch2, Immediate(bit_cast<int32_t>(kZapValue))); 535 } 536} 537 538 539void MacroAssembler::RecordWrite( 540 Register object, 541 Register address, 542 Register value, 543 SaveFPRegsMode fp_mode, 544 RememberedSetAction remembered_set_action, 545 SmiCheck smi_check, 546 PointersToHereCheck pointers_to_here_check_for_value) { 547 DCHECK(!object.is(value)); 548 DCHECK(!object.is(address)); 549 DCHECK(!value.is(address)); 550 AssertNotSmi(object); 551 552 if (remembered_set_action == OMIT_REMEMBERED_SET && 553 !FLAG_incremental_marking) { 554 return; 555 } 556 557 if (emit_debug_code()) { 558 Label ok; 559 cmp(value, Operand(address, 0)); 560 j(equal, &ok, Label::kNear); 561 int3(); 562 bind(&ok); 563 } 564 565 // First, check if a write barrier is even needed. The tests below 566 // catch stores of Smis and stores into young gen. 567 Label done; 568 569 if (smi_check == INLINE_SMI_CHECK) { 570 // Skip barrier if writing a smi. 571 JumpIfSmi(value, &done, Label::kNear); 572 } 573 574 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { 575 CheckPageFlag(value, 576 value, // Used as scratch. 577 MemoryChunk::kPointersToHereAreInterestingMask, 578 zero, 579 &done, 580 Label::kNear); 581 } 582 CheckPageFlag(object, 583 value, // Used as scratch. 584 MemoryChunk::kPointersFromHereAreInterestingMask, 585 zero, 586 &done, 587 Label::kNear); 588 589 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, 590 fp_mode); 591 CallStub(&stub); 592 593 bind(&done); 594 595 // Count number of write barriers in generated code. 596 isolate()->counters()->write_barriers_static()->Increment(); 597 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1); 598 599 // Clobber clobbered registers when running with the debug-code flag 600 // turned on to provoke errors. 601 if (emit_debug_code()) { 602 mov(address, Immediate(bit_cast<int32_t>(kZapValue))); 603 mov(value, Immediate(bit_cast<int32_t>(kZapValue))); 604 } 605} 606 607void MacroAssembler::RecordWriteCodeEntryField(Register js_function, 608 Register code_entry, 609 Register scratch) { 610 const int offset = JSFunction::kCodeEntryOffset; 611 612 // Since a code entry (value) is always in old space, we don't need to update 613 // remembered set. If incremental marking is off, there is nothing for us to 614 // do. 615 if (!FLAG_incremental_marking) return; 616 617 DCHECK(!js_function.is(code_entry)); 618 DCHECK(!js_function.is(scratch)); 619 DCHECK(!code_entry.is(scratch)); 620 AssertNotSmi(js_function); 621 622 if (emit_debug_code()) { 623 Label ok; 624 lea(scratch, FieldOperand(js_function, offset)); 625 cmp(code_entry, Operand(scratch, 0)); 626 j(equal, &ok, Label::kNear); 627 int3(); 628 bind(&ok); 629 } 630 631 // First, check if a write barrier is even needed. The tests below 632 // catch stores of Smis and stores into young gen. 633 Label done; 634 635 CheckPageFlag(code_entry, scratch, 636 MemoryChunk::kPointersToHereAreInterestingMask, zero, &done, 637 Label::kNear); 638 CheckPageFlag(js_function, scratch, 639 MemoryChunk::kPointersFromHereAreInterestingMask, zero, &done, 640 Label::kNear); 641 642 // Save input registers. 643 push(js_function); 644 push(code_entry); 645 646 const Register dst = scratch; 647 lea(dst, FieldOperand(js_function, offset)); 648 649 // Save caller-saved registers. 650 PushCallerSaved(kDontSaveFPRegs, js_function, code_entry); 651 652 int argument_count = 3; 653 PrepareCallCFunction(argument_count, code_entry); 654 mov(Operand(esp, 0 * kPointerSize), js_function); 655 mov(Operand(esp, 1 * kPointerSize), dst); // Slot. 656 mov(Operand(esp, 2 * kPointerSize), 657 Immediate(ExternalReference::isolate_address(isolate()))); 658 659 { 660 AllowExternalCallThatCantCauseGC scope(this); 661 CallCFunction( 662 ExternalReference::incremental_marking_record_write_code_entry_function( 663 isolate()), 664 argument_count); 665 } 666 667 // Restore caller-saved registers. 668 PopCallerSaved(kDontSaveFPRegs, js_function, code_entry); 669 670 // Restore input registers. 671 pop(code_entry); 672 pop(js_function); 673 674 bind(&done); 675} 676 677void MacroAssembler::DebugBreak() { 678 Move(eax, Immediate(0)); 679 mov(ebx, Immediate(ExternalReference(Runtime::kHandleDebuggerStatement, 680 isolate()))); 681 CEntryStub ces(isolate(), 1); 682 call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); 683} 684 685void MacroAssembler::Cvtsi2sd(XMMRegister dst, const Operand& src) { 686 xorps(dst, dst); 687 cvtsi2sd(dst, src); 688} 689 690 691void MacroAssembler::Cvtui2ss(XMMRegister dst, Register src, Register tmp) { 692 Label msb_set_src; 693 Label jmp_return; 694 test(src, src); 695 j(sign, &msb_set_src, Label::kNear); 696 cvtsi2ss(dst, src); 697 jmp(&jmp_return, Label::kNear); 698 bind(&msb_set_src); 699 mov(tmp, src); 700 shr(src, 1); 701 // Recover the least significant bit to avoid rounding errors. 702 and_(tmp, Immediate(1)); 703 or_(src, tmp); 704 cvtsi2ss(dst, src); 705 addss(dst, dst); 706 bind(&jmp_return); 707} 708 709void MacroAssembler::ShlPair(Register high, Register low, uint8_t shift) { 710 if (shift >= 32) { 711 mov(high, low); 712 shl(high, shift - 32); 713 xor_(low, low); 714 } else { 715 shld(high, low, shift); 716 shl(low, shift); 717 } 718} 719 720void MacroAssembler::ShlPair_cl(Register high, Register low) { 721 shld_cl(high, low); 722 shl_cl(low); 723 Label done; 724 test(ecx, Immediate(0x20)); 725 j(equal, &done, Label::kNear); 726 mov(high, low); 727 xor_(low, low); 728 bind(&done); 729} 730 731void MacroAssembler::ShrPair(Register high, Register low, uint8_t shift) { 732 if (shift >= 32) { 733 mov(low, high); 734 shr(low, shift - 32); 735 xor_(high, high); 736 } else { 737 shrd(high, low, shift); 738 shr(high, shift); 739 } 740} 741 742void MacroAssembler::ShrPair_cl(Register high, Register low) { 743 shrd_cl(low, high); 744 shr_cl(high); 745 Label done; 746 test(ecx, Immediate(0x20)); 747 j(equal, &done, Label::kNear); 748 mov(low, high); 749 xor_(high, high); 750 bind(&done); 751} 752 753void MacroAssembler::SarPair(Register high, Register low, uint8_t shift) { 754 if (shift >= 32) { 755 mov(low, high); 756 sar(low, shift - 32); 757 sar(high, 31); 758 } else { 759 shrd(high, low, shift); 760 sar(high, shift); 761 } 762} 763 764void MacroAssembler::SarPair_cl(Register high, Register low) { 765 shrd_cl(low, high); 766 sar_cl(high); 767 Label done; 768 test(ecx, Immediate(0x20)); 769 j(equal, &done, Label::kNear); 770 mov(low, high); 771 sar(high, 31); 772 bind(&done); 773} 774 775bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) { 776 static const int kMaxImmediateBits = 17; 777 if (!RelocInfo::IsNone(x.rmode_)) return false; 778 return !is_intn(x.x_, kMaxImmediateBits); 779} 780 781 782void MacroAssembler::SafeMove(Register dst, const Immediate& x) { 783 if (IsUnsafeImmediate(x) && jit_cookie() != 0) { 784 Move(dst, Immediate(x.x_ ^ jit_cookie())); 785 xor_(dst, jit_cookie()); 786 } else { 787 Move(dst, x); 788 } 789} 790 791 792void MacroAssembler::SafePush(const Immediate& x) { 793 if (IsUnsafeImmediate(x) && jit_cookie() != 0) { 794 push(Immediate(x.x_ ^ jit_cookie())); 795 xor_(Operand(esp, 0), Immediate(jit_cookie())); 796 } else { 797 push(x); 798 } 799} 800 801 802void MacroAssembler::CmpObjectType(Register heap_object, 803 InstanceType type, 804 Register map) { 805 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); 806 CmpInstanceType(map, type); 807} 808 809 810void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { 811 cmpb(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(type)); 812} 813 814 815void MacroAssembler::CheckFastElements(Register map, 816 Label* fail, 817 Label::Distance distance) { 818 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 819 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 820 STATIC_ASSERT(FAST_ELEMENTS == 2); 821 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); 822 cmpb(FieldOperand(map, Map::kBitField2Offset), 823 Immediate(Map::kMaximumBitField2FastHoleyElementValue)); 824 j(above, fail, distance); 825} 826 827 828void MacroAssembler::CheckFastObjectElements(Register map, 829 Label* fail, 830 Label::Distance distance) { 831 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 832 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 833 STATIC_ASSERT(FAST_ELEMENTS == 2); 834 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); 835 cmpb(FieldOperand(map, Map::kBitField2Offset), 836 Immediate(Map::kMaximumBitField2FastHoleySmiElementValue)); 837 j(below_equal, fail, distance); 838 cmpb(FieldOperand(map, Map::kBitField2Offset), 839 Immediate(Map::kMaximumBitField2FastHoleyElementValue)); 840 j(above, fail, distance); 841} 842 843 844void MacroAssembler::CheckFastSmiElements(Register map, 845 Label* fail, 846 Label::Distance distance) { 847 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 848 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 849 cmpb(FieldOperand(map, Map::kBitField2Offset), 850 Immediate(Map::kMaximumBitField2FastHoleySmiElementValue)); 851 j(above, fail, distance); 852} 853 854 855void MacroAssembler::StoreNumberToDoubleElements( 856 Register maybe_number, 857 Register elements, 858 Register key, 859 Register scratch1, 860 XMMRegister scratch2, 861 Label* fail, 862 int elements_offset) { 863 Label smi_value, done; 864 JumpIfSmi(maybe_number, &smi_value, Label::kNear); 865 866 CheckMap(maybe_number, 867 isolate()->factory()->heap_number_map(), 868 fail, 869 DONT_DO_SMI_CHECK); 870 871 // Double value, turn potential sNaN into qNaN. 872 Move(scratch2, 1.0); 873 mulsd(scratch2, FieldOperand(maybe_number, HeapNumber::kValueOffset)); 874 jmp(&done, Label::kNear); 875 876 bind(&smi_value); 877 // Value is a smi. Convert to a double and store. 878 // Preserve original value. 879 mov(scratch1, maybe_number); 880 SmiUntag(scratch1); 881 Cvtsi2sd(scratch2, scratch1); 882 bind(&done); 883 movsd(FieldOperand(elements, key, times_4, 884 FixedDoubleArray::kHeaderSize - elements_offset), 885 scratch2); 886} 887 888 889void MacroAssembler::CompareMap(Register obj, Handle<Map> map) { 890 cmp(FieldOperand(obj, HeapObject::kMapOffset), map); 891} 892 893 894void MacroAssembler::CheckMap(Register obj, 895 Handle<Map> map, 896 Label* fail, 897 SmiCheckType smi_check_type) { 898 if (smi_check_type == DO_SMI_CHECK) { 899 JumpIfSmi(obj, fail); 900 } 901 902 CompareMap(obj, map); 903 j(not_equal, fail); 904} 905 906 907void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1, 908 Register scratch2, Handle<WeakCell> cell, 909 Handle<Code> success, 910 SmiCheckType smi_check_type) { 911 Label fail; 912 if (smi_check_type == DO_SMI_CHECK) { 913 JumpIfSmi(obj, &fail); 914 } 915 mov(scratch1, FieldOperand(obj, HeapObject::kMapOffset)); 916 CmpWeakValue(scratch1, cell, scratch2); 917 j(equal, success); 918 919 bind(&fail); 920} 921 922 923Condition MacroAssembler::IsObjectStringType(Register heap_object, 924 Register map, 925 Register instance_type) { 926 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); 927 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); 928 STATIC_ASSERT(kNotStringTag != 0); 929 test(instance_type, Immediate(kIsNotStringMask)); 930 return zero; 931} 932 933 934Condition MacroAssembler::IsObjectNameType(Register heap_object, 935 Register map, 936 Register instance_type) { 937 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); 938 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); 939 cmpb(instance_type, Immediate(LAST_NAME_TYPE)); 940 return below_equal; 941} 942 943 944void MacroAssembler::FCmp() { 945 fucomip(); 946 fstp(0); 947} 948 949 950void MacroAssembler::AssertNumber(Register object) { 951 if (emit_debug_code()) { 952 Label ok; 953 JumpIfSmi(object, &ok); 954 cmp(FieldOperand(object, HeapObject::kMapOffset), 955 isolate()->factory()->heap_number_map()); 956 Check(equal, kOperandNotANumber); 957 bind(&ok); 958 } 959} 960 961void MacroAssembler::AssertNotNumber(Register object) { 962 if (emit_debug_code()) { 963 test(object, Immediate(kSmiTagMask)); 964 Check(not_equal, kOperandIsANumber); 965 cmp(FieldOperand(object, HeapObject::kMapOffset), 966 isolate()->factory()->heap_number_map()); 967 Check(not_equal, kOperandIsANumber); 968 } 969} 970 971void MacroAssembler::AssertSmi(Register object) { 972 if (emit_debug_code()) { 973 test(object, Immediate(kSmiTagMask)); 974 Check(equal, kOperandIsNotASmi); 975 } 976} 977 978 979void MacroAssembler::AssertString(Register object) { 980 if (emit_debug_code()) { 981 test(object, Immediate(kSmiTagMask)); 982 Check(not_equal, kOperandIsASmiAndNotAString); 983 push(object); 984 mov(object, FieldOperand(object, HeapObject::kMapOffset)); 985 CmpInstanceType(object, FIRST_NONSTRING_TYPE); 986 pop(object); 987 Check(below, kOperandIsNotAString); 988 } 989} 990 991 992void MacroAssembler::AssertName(Register object) { 993 if (emit_debug_code()) { 994 test(object, Immediate(kSmiTagMask)); 995 Check(not_equal, kOperandIsASmiAndNotAName); 996 push(object); 997 mov(object, FieldOperand(object, HeapObject::kMapOffset)); 998 CmpInstanceType(object, LAST_NAME_TYPE); 999 pop(object); 1000 Check(below_equal, kOperandIsNotAName); 1001 } 1002} 1003 1004 1005void MacroAssembler::AssertFunction(Register object) { 1006 if (emit_debug_code()) { 1007 test(object, Immediate(kSmiTagMask)); 1008 Check(not_equal, kOperandIsASmiAndNotAFunction); 1009 Push(object); 1010 CmpObjectType(object, JS_FUNCTION_TYPE, object); 1011 Pop(object); 1012 Check(equal, kOperandIsNotAFunction); 1013 } 1014} 1015 1016 1017void MacroAssembler::AssertBoundFunction(Register object) { 1018 if (emit_debug_code()) { 1019 test(object, Immediate(kSmiTagMask)); 1020 Check(not_equal, kOperandIsASmiAndNotABoundFunction); 1021 Push(object); 1022 CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object); 1023 Pop(object); 1024 Check(equal, kOperandIsNotABoundFunction); 1025 } 1026} 1027 1028void MacroAssembler::AssertGeneratorObject(Register object) { 1029 if (emit_debug_code()) { 1030 test(object, Immediate(kSmiTagMask)); 1031 Check(not_equal, kOperandIsASmiAndNotAGeneratorObject); 1032 Push(object); 1033 CmpObjectType(object, JS_GENERATOR_OBJECT_TYPE, object); 1034 Pop(object); 1035 Check(equal, kOperandIsNotAGeneratorObject); 1036 } 1037} 1038 1039void MacroAssembler::AssertReceiver(Register object) { 1040 if (emit_debug_code()) { 1041 test(object, Immediate(kSmiTagMask)); 1042 Check(not_equal, kOperandIsASmiAndNotAReceiver); 1043 Push(object); 1044 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 1045 CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, object); 1046 Pop(object); 1047 Check(above_equal, kOperandIsNotAReceiver); 1048 } 1049} 1050 1051 1052void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) { 1053 if (emit_debug_code()) { 1054 Label done_checking; 1055 AssertNotSmi(object); 1056 cmp(object, isolate()->factory()->undefined_value()); 1057 j(equal, &done_checking); 1058 cmp(FieldOperand(object, 0), 1059 Immediate(isolate()->factory()->allocation_site_map())); 1060 Assert(equal, kExpectedUndefinedOrCell); 1061 bind(&done_checking); 1062 } 1063} 1064 1065 1066void MacroAssembler::AssertNotSmi(Register object) { 1067 if (emit_debug_code()) { 1068 test(object, Immediate(kSmiTagMask)); 1069 Check(not_equal, kOperandIsASmi); 1070 } 1071} 1072 1073void MacroAssembler::StubPrologue(StackFrame::Type type) { 1074 push(ebp); // Caller's frame pointer. 1075 mov(ebp, esp); 1076 push(Immediate(Smi::FromInt(type))); 1077} 1078 1079void MacroAssembler::Prologue(bool code_pre_aging) { 1080 PredictableCodeSizeScope predictible_code_size_scope(this, 1081 kNoCodeAgeSequenceLength); 1082 if (code_pre_aging) { 1083 // Pre-age the code. 1084 call(isolate()->builtins()->MarkCodeAsExecutedOnce(), 1085 RelocInfo::CODE_AGE_SEQUENCE); 1086 Nop(kNoCodeAgeSequenceLength - Assembler::kCallInstructionLength); 1087 } else { 1088 push(ebp); // Caller's frame pointer. 1089 mov(ebp, esp); 1090 push(esi); // Callee's context. 1091 push(edi); // Callee's JS function. 1092 } 1093} 1094 1095 1096void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) { 1097 mov(vector, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1098 mov(vector, FieldOperand(vector, JSFunction::kLiteralsOffset)); 1099 mov(vector, FieldOperand(vector, LiteralsArray::kFeedbackVectorOffset)); 1100} 1101 1102 1103void MacroAssembler::EnterFrame(StackFrame::Type type, 1104 bool load_constant_pool_pointer_reg) { 1105 // Out-of-line constant pool not implemented on ia32. 1106 UNREACHABLE(); 1107} 1108 1109 1110void MacroAssembler::EnterFrame(StackFrame::Type type) { 1111 push(ebp); 1112 mov(ebp, esp); 1113 push(Immediate(Smi::FromInt(type))); 1114 if (type == StackFrame::INTERNAL) { 1115 push(Immediate(CodeObject())); 1116 } 1117 if (emit_debug_code()) { 1118 cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value())); 1119 Check(not_equal, kCodeObjectNotProperlyPatched); 1120 } 1121} 1122 1123 1124void MacroAssembler::LeaveFrame(StackFrame::Type type) { 1125 if (emit_debug_code()) { 1126 cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset), 1127 Immediate(Smi::FromInt(type))); 1128 Check(equal, kStackFrameTypesMustMatch); 1129 } 1130 leave(); 1131} 1132 1133 1134void MacroAssembler::EnterExitFramePrologue() { 1135 // Set up the frame structure on the stack. 1136 DCHECK_EQ(+2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); 1137 DCHECK_EQ(+1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); 1138 DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); 1139 push(ebp); 1140 mov(ebp, esp); 1141 1142 // Reserve room for entry stack pointer and push the code object. 1143 push(Immediate(Smi::FromInt(StackFrame::EXIT))); 1144 DCHECK_EQ(-2 * kPointerSize, ExitFrameConstants::kSPOffset); 1145 push(Immediate(0)); // Saved entry sp, patched before call. 1146 DCHECK_EQ(-3 * kPointerSize, ExitFrameConstants::kCodeOffset); 1147 push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot. 1148 1149 // Save the frame pointer and the context in top. 1150 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate()); 1151 ExternalReference context_address(Isolate::kContextAddress, isolate()); 1152 ExternalReference c_function_address(Isolate::kCFunctionAddress, isolate()); 1153 mov(Operand::StaticVariable(c_entry_fp_address), ebp); 1154 mov(Operand::StaticVariable(context_address), esi); 1155 mov(Operand::StaticVariable(c_function_address), ebx); 1156} 1157 1158 1159void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) { 1160 // Optionally save all XMM registers. 1161 if (save_doubles) { 1162 int space = XMMRegister::kMaxNumRegisters * kDoubleSize + 1163 argc * kPointerSize; 1164 sub(esp, Immediate(space)); 1165 const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp; 1166 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { 1167 XMMRegister reg = XMMRegister::from_code(i); 1168 movsd(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg); 1169 } 1170 } else { 1171 sub(esp, Immediate(argc * kPointerSize)); 1172 } 1173 1174 // Get the required frame alignment for the OS. 1175 const int kFrameAlignment = base::OS::ActivationFrameAlignment(); 1176 if (kFrameAlignment > 0) { 1177 DCHECK(base::bits::IsPowerOfTwo32(kFrameAlignment)); 1178 and_(esp, -kFrameAlignment); 1179 } 1180 1181 // Patch the saved entry sp. 1182 mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp); 1183} 1184 1185 1186void MacroAssembler::EnterExitFrame(int argc, bool save_doubles) { 1187 EnterExitFramePrologue(); 1188 1189 // Set up argc and argv in callee-saved registers. 1190 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; 1191 mov(edi, eax); 1192 lea(esi, Operand(ebp, eax, times_4, offset)); 1193 1194 // Reserve space for argc, argv and isolate. 1195 EnterExitFrameEpilogue(argc, save_doubles); 1196} 1197 1198 1199void MacroAssembler::EnterApiExitFrame(int argc) { 1200 EnterExitFramePrologue(); 1201 EnterExitFrameEpilogue(argc, false); 1202} 1203 1204 1205void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) { 1206 // Optionally restore all XMM registers. 1207 if (save_doubles) { 1208 const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp; 1209 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { 1210 XMMRegister reg = XMMRegister::from_code(i); 1211 movsd(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize))); 1212 } 1213 } 1214 1215 if (pop_arguments) { 1216 // Get the return address from the stack and restore the frame pointer. 1217 mov(ecx, Operand(ebp, 1 * kPointerSize)); 1218 mov(ebp, Operand(ebp, 0 * kPointerSize)); 1219 1220 // Pop the arguments and the receiver from the caller stack. 1221 lea(esp, Operand(esi, 1 * kPointerSize)); 1222 1223 // Push the return address to get ready to return. 1224 push(ecx); 1225 } else { 1226 // Otherwise just leave the exit frame. 1227 leave(); 1228 } 1229 1230 LeaveExitFrameEpilogue(true); 1231} 1232 1233 1234void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) { 1235 // Restore current context from top and clear it in debug mode. 1236 ExternalReference context_address(Isolate::kContextAddress, isolate()); 1237 if (restore_context) { 1238 mov(esi, Operand::StaticVariable(context_address)); 1239 } 1240#ifdef DEBUG 1241 mov(Operand::StaticVariable(context_address), Immediate(0)); 1242#endif 1243 1244 // Clear the top frame. 1245 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, 1246 isolate()); 1247 mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0)); 1248} 1249 1250 1251void MacroAssembler::LeaveApiExitFrame(bool restore_context) { 1252 mov(esp, ebp); 1253 pop(ebp); 1254 1255 LeaveExitFrameEpilogue(restore_context); 1256} 1257 1258 1259void MacroAssembler::PushStackHandler() { 1260 // Adjust this code if not the case. 1261 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); 1262 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 1263 1264 // Link the current handler as the next handler. 1265 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); 1266 push(Operand::StaticVariable(handler_address)); 1267 1268 // Set this new handler as the current one. 1269 mov(Operand::StaticVariable(handler_address), esp); 1270} 1271 1272 1273void MacroAssembler::PopStackHandler() { 1274 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 1275 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); 1276 pop(Operand::StaticVariable(handler_address)); 1277 add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize)); 1278} 1279 1280 1281void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, 1282 Register scratch1, 1283 Register scratch2, 1284 Label* miss) { 1285 Label same_contexts; 1286 1287 DCHECK(!holder_reg.is(scratch1)); 1288 DCHECK(!holder_reg.is(scratch2)); 1289 DCHECK(!scratch1.is(scratch2)); 1290 1291 // Load current lexical context from the active StandardFrame, which 1292 // may require crawling past STUB frames. 1293 Label load_context; 1294 Label has_context; 1295 mov(scratch2, ebp); 1296 bind(&load_context); 1297 mov(scratch1, 1298 MemOperand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset)); 1299 JumpIfNotSmi(scratch1, &has_context); 1300 mov(scratch2, MemOperand(scratch2, CommonFrameConstants::kCallerFPOffset)); 1301 jmp(&load_context); 1302 bind(&has_context); 1303 1304 // When generating debug code, make sure the lexical context is set. 1305 if (emit_debug_code()) { 1306 cmp(scratch1, Immediate(0)); 1307 Check(not_equal, kWeShouldNotHaveAnEmptyLexicalContext); 1308 } 1309 // Load the native context of the current context. 1310 mov(scratch1, ContextOperand(scratch1, Context::NATIVE_CONTEXT_INDEX)); 1311 1312 // Check the context is a native context. 1313 if (emit_debug_code()) { 1314 // Read the first word and compare to native_context_map. 1315 cmp(FieldOperand(scratch1, HeapObject::kMapOffset), 1316 isolate()->factory()->native_context_map()); 1317 Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext); 1318 } 1319 1320 // Check if both contexts are the same. 1321 cmp(scratch1, FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); 1322 j(equal, &same_contexts); 1323 1324 // Compare security tokens, save holder_reg on the stack so we can use it 1325 // as a temporary register. 1326 // 1327 // Check that the security token in the calling global object is 1328 // compatible with the security token in the receiving global 1329 // object. 1330 mov(scratch2, 1331 FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); 1332 1333 // Check the context is a native context. 1334 if (emit_debug_code()) { 1335 cmp(scratch2, isolate()->factory()->null_value()); 1336 Check(not_equal, kJSGlobalProxyContextShouldNotBeNull); 1337 1338 // Read the first word and compare to native_context_map(), 1339 cmp(FieldOperand(scratch2, HeapObject::kMapOffset), 1340 isolate()->factory()->native_context_map()); 1341 Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext); 1342 } 1343 1344 int token_offset = Context::kHeaderSize + 1345 Context::SECURITY_TOKEN_INDEX * kPointerSize; 1346 mov(scratch1, FieldOperand(scratch1, token_offset)); 1347 cmp(scratch1, FieldOperand(scratch2, token_offset)); 1348 j(not_equal, miss); 1349 1350 bind(&same_contexts); 1351} 1352 1353 1354// Compute the hash code from the untagged key. This must be kept in sync with 1355// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in 1356// code-stub-hydrogen.cc 1357// 1358// Note: r0 will contain hash code 1359void MacroAssembler::GetNumberHash(Register r0, Register scratch) { 1360 // Xor original key with a seed. 1361 if (serializer_enabled()) { 1362 ExternalReference roots_array_start = 1363 ExternalReference::roots_array_start(isolate()); 1364 mov(scratch, Immediate(Heap::kHashSeedRootIndex)); 1365 mov(scratch, 1366 Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); 1367 SmiUntag(scratch); 1368 xor_(r0, scratch); 1369 } else { 1370 int32_t seed = isolate()->heap()->HashSeed(); 1371 xor_(r0, Immediate(seed)); 1372 } 1373 1374 // hash = ~hash + (hash << 15); 1375 mov(scratch, r0); 1376 not_(r0); 1377 shl(scratch, 15); 1378 add(r0, scratch); 1379 // hash = hash ^ (hash >> 12); 1380 mov(scratch, r0); 1381 shr(scratch, 12); 1382 xor_(r0, scratch); 1383 // hash = hash + (hash << 2); 1384 lea(r0, Operand(r0, r0, times_4, 0)); 1385 // hash = hash ^ (hash >> 4); 1386 mov(scratch, r0); 1387 shr(scratch, 4); 1388 xor_(r0, scratch); 1389 // hash = hash * 2057; 1390 imul(r0, r0, 2057); 1391 // hash = hash ^ (hash >> 16); 1392 mov(scratch, r0); 1393 shr(scratch, 16); 1394 xor_(r0, scratch); 1395 and_(r0, 0x3fffffff); 1396} 1397 1398 1399 1400void MacroAssembler::LoadFromNumberDictionary(Label* miss, 1401 Register elements, 1402 Register key, 1403 Register r0, 1404 Register r1, 1405 Register r2, 1406 Register result) { 1407 // Register use: 1408 // 1409 // elements - holds the slow-case elements of the receiver and is unchanged. 1410 // 1411 // key - holds the smi key on entry and is unchanged. 1412 // 1413 // Scratch registers: 1414 // 1415 // r0 - holds the untagged key on entry and holds the hash once computed. 1416 // 1417 // r1 - used to hold the capacity mask of the dictionary 1418 // 1419 // r2 - used for the index into the dictionary. 1420 // 1421 // result - holds the result on exit if the load succeeds and we fall through. 1422 1423 Label done; 1424 1425 GetNumberHash(r0, r1); 1426 1427 // Compute capacity mask. 1428 mov(r1, FieldOperand(elements, SeededNumberDictionary::kCapacityOffset)); 1429 shr(r1, kSmiTagSize); // convert smi to int 1430 dec(r1); 1431 1432 // Generate an unrolled loop that performs a few probes before giving up. 1433 for (int i = 0; i < kNumberDictionaryProbes; i++) { 1434 // Use r2 for index calculations and keep the hash intact in r0. 1435 mov(r2, r0); 1436 // Compute the masked index: (hash + i + i * i) & mask. 1437 if (i > 0) { 1438 add(r2, Immediate(SeededNumberDictionary::GetProbeOffset(i))); 1439 } 1440 and_(r2, r1); 1441 1442 // Scale the index by multiplying by the entry size. 1443 DCHECK(SeededNumberDictionary::kEntrySize == 3); 1444 lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 1445 1446 // Check if the key matches. 1447 cmp(key, FieldOperand(elements, 1448 r2, 1449 times_pointer_size, 1450 SeededNumberDictionary::kElementsStartOffset)); 1451 if (i != (kNumberDictionaryProbes - 1)) { 1452 j(equal, &done); 1453 } else { 1454 j(not_equal, miss); 1455 } 1456 } 1457 1458 bind(&done); 1459 // Check that the value is a field property. 1460 const int kDetailsOffset = 1461 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize; 1462 DCHECK_EQ(DATA, 0); 1463 test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), 1464 Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize)); 1465 j(not_zero, miss); 1466 1467 // Get the value at the masked, scaled index. 1468 const int kValueOffset = 1469 SeededNumberDictionary::kElementsStartOffset + kPointerSize; 1470 mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); 1471} 1472 1473 1474void MacroAssembler::LoadAllocationTopHelper(Register result, 1475 Register scratch, 1476 AllocationFlags flags) { 1477 ExternalReference allocation_top = 1478 AllocationUtils::GetAllocationTopReference(isolate(), flags); 1479 1480 // Just return if allocation top is already known. 1481 if ((flags & RESULT_CONTAINS_TOP) != 0) { 1482 // No use of scratch if allocation top is provided. 1483 DCHECK(scratch.is(no_reg)); 1484#ifdef DEBUG 1485 // Assert that result actually contains top on entry. 1486 cmp(result, Operand::StaticVariable(allocation_top)); 1487 Check(equal, kUnexpectedAllocationTop); 1488#endif 1489 return; 1490 } 1491 1492 // Move address of new object to result. Use scratch register if available. 1493 if (scratch.is(no_reg)) { 1494 mov(result, Operand::StaticVariable(allocation_top)); 1495 } else { 1496 mov(scratch, Immediate(allocation_top)); 1497 mov(result, Operand(scratch, 0)); 1498 } 1499} 1500 1501 1502void MacroAssembler::UpdateAllocationTopHelper(Register result_end, 1503 Register scratch, 1504 AllocationFlags flags) { 1505 if (emit_debug_code()) { 1506 test(result_end, Immediate(kObjectAlignmentMask)); 1507 Check(zero, kUnalignedAllocationInNewSpace); 1508 } 1509 1510 ExternalReference allocation_top = 1511 AllocationUtils::GetAllocationTopReference(isolate(), flags); 1512 1513 // Update new top. Use scratch if available. 1514 if (scratch.is(no_reg)) { 1515 mov(Operand::StaticVariable(allocation_top), result_end); 1516 } else { 1517 mov(Operand(scratch, 0), result_end); 1518 } 1519} 1520 1521 1522void MacroAssembler::Allocate(int object_size, 1523 Register result, 1524 Register result_end, 1525 Register scratch, 1526 Label* gc_required, 1527 AllocationFlags flags) { 1528 DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0); 1529 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize); 1530 DCHECK((flags & ALLOCATION_FOLDED) == 0); 1531 if (!FLAG_inline_new) { 1532 if (emit_debug_code()) { 1533 // Trash the registers to simulate an allocation failure. 1534 mov(result, Immediate(0x7091)); 1535 if (result_end.is_valid()) { 1536 mov(result_end, Immediate(0x7191)); 1537 } 1538 if (scratch.is_valid()) { 1539 mov(scratch, Immediate(0x7291)); 1540 } 1541 } 1542 jmp(gc_required); 1543 return; 1544 } 1545 DCHECK(!result.is(result_end)); 1546 1547 // Load address of new object into result. 1548 LoadAllocationTopHelper(result, scratch, flags); 1549 1550 ExternalReference allocation_limit = 1551 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 1552 1553 // Align the next allocation. Storing the filler map without checking top is 1554 // safe in new-space because the limit of the heap is aligned there. 1555 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1556 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1557 Label aligned; 1558 test(result, Immediate(kDoubleAlignmentMask)); 1559 j(zero, &aligned, Label::kNear); 1560 if ((flags & PRETENURE) != 0) { 1561 cmp(result, Operand::StaticVariable(allocation_limit)); 1562 j(above_equal, gc_required); 1563 } 1564 mov(Operand(result, 0), 1565 Immediate(isolate()->factory()->one_pointer_filler_map())); 1566 add(result, Immediate(kDoubleSize / 2)); 1567 bind(&aligned); 1568 } 1569 1570 // Calculate new top and bail out if space is exhausted. 1571 Register top_reg = result_end.is_valid() ? result_end : result; 1572 1573 if (!top_reg.is(result)) { 1574 mov(top_reg, result); 1575 } 1576 add(top_reg, Immediate(object_size)); 1577 cmp(top_reg, Operand::StaticVariable(allocation_limit)); 1578 j(above, gc_required); 1579 1580 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) { 1581 // The top pointer is not updated for allocation folding dominators. 1582 UpdateAllocationTopHelper(top_reg, scratch, flags); 1583 } 1584 1585 if (top_reg.is(result)) { 1586 sub(result, Immediate(object_size - kHeapObjectTag)); 1587 } else { 1588 // Tag the result. 1589 DCHECK(kHeapObjectTag == 1); 1590 inc(result); 1591 } 1592} 1593 1594 1595void MacroAssembler::Allocate(int header_size, 1596 ScaleFactor element_size, 1597 Register element_count, 1598 RegisterValueType element_count_type, 1599 Register result, 1600 Register result_end, 1601 Register scratch, 1602 Label* gc_required, 1603 AllocationFlags flags) { 1604 DCHECK((flags & SIZE_IN_WORDS) == 0); 1605 DCHECK((flags & ALLOCATION_FOLDING_DOMINATOR) == 0); 1606 DCHECK((flags & ALLOCATION_FOLDED) == 0); 1607 if (!FLAG_inline_new) { 1608 if (emit_debug_code()) { 1609 // Trash the registers to simulate an allocation failure. 1610 mov(result, Immediate(0x7091)); 1611 mov(result_end, Immediate(0x7191)); 1612 if (scratch.is_valid()) { 1613 mov(scratch, Immediate(0x7291)); 1614 } 1615 // Register element_count is not modified by the function. 1616 } 1617 jmp(gc_required); 1618 return; 1619 } 1620 DCHECK(!result.is(result_end)); 1621 1622 // Load address of new object into result. 1623 LoadAllocationTopHelper(result, scratch, flags); 1624 1625 ExternalReference allocation_limit = 1626 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 1627 1628 // Align the next allocation. Storing the filler map without checking top is 1629 // safe in new-space because the limit of the heap is aligned there. 1630 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1631 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1632 Label aligned; 1633 test(result, Immediate(kDoubleAlignmentMask)); 1634 j(zero, &aligned, Label::kNear); 1635 if ((flags & PRETENURE) != 0) { 1636 cmp(result, Operand::StaticVariable(allocation_limit)); 1637 j(above_equal, gc_required); 1638 } 1639 mov(Operand(result, 0), 1640 Immediate(isolate()->factory()->one_pointer_filler_map())); 1641 add(result, Immediate(kDoubleSize / 2)); 1642 bind(&aligned); 1643 } 1644 1645 // Calculate new top and bail out if space is exhausted. 1646 // We assume that element_count*element_size + header_size does not 1647 // overflow. 1648 if (element_count_type == REGISTER_VALUE_IS_SMI) { 1649 STATIC_ASSERT(static_cast<ScaleFactor>(times_2 - 1) == times_1); 1650 STATIC_ASSERT(static_cast<ScaleFactor>(times_4 - 1) == times_2); 1651 STATIC_ASSERT(static_cast<ScaleFactor>(times_8 - 1) == times_4); 1652 DCHECK(element_size >= times_2); 1653 DCHECK(kSmiTagSize == 1); 1654 element_size = static_cast<ScaleFactor>(element_size - 1); 1655 } else { 1656 DCHECK(element_count_type == REGISTER_VALUE_IS_INT32); 1657 } 1658 1659 lea(result_end, Operand(element_count, element_size, header_size)); 1660 add(result_end, result); 1661 cmp(result_end, Operand::StaticVariable(allocation_limit)); 1662 j(above, gc_required); 1663 1664 // Tag result. 1665 DCHECK(kHeapObjectTag == 1); 1666 inc(result); 1667 1668 UpdateAllocationTopHelper(result_end, scratch, flags); 1669} 1670 1671 1672void MacroAssembler::Allocate(Register object_size, 1673 Register result, 1674 Register result_end, 1675 Register scratch, 1676 Label* gc_required, 1677 AllocationFlags flags) { 1678 DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0); 1679 DCHECK((flags & ALLOCATION_FOLDED) == 0); 1680 if (!FLAG_inline_new) { 1681 if (emit_debug_code()) { 1682 // Trash the registers to simulate an allocation failure. 1683 mov(result, Immediate(0x7091)); 1684 mov(result_end, Immediate(0x7191)); 1685 if (scratch.is_valid()) { 1686 mov(scratch, Immediate(0x7291)); 1687 } 1688 // object_size is left unchanged by this function. 1689 } 1690 jmp(gc_required); 1691 return; 1692 } 1693 DCHECK(!result.is(result_end)); 1694 1695 // Load address of new object into result. 1696 LoadAllocationTopHelper(result, scratch, flags); 1697 1698 ExternalReference allocation_limit = 1699 AllocationUtils::GetAllocationLimitReference(isolate(), flags); 1700 1701 // Align the next allocation. Storing the filler map without checking top is 1702 // safe in new-space because the limit of the heap is aligned there. 1703 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1704 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1705 Label aligned; 1706 test(result, Immediate(kDoubleAlignmentMask)); 1707 j(zero, &aligned, Label::kNear); 1708 if ((flags & PRETENURE) != 0) { 1709 cmp(result, Operand::StaticVariable(allocation_limit)); 1710 j(above_equal, gc_required); 1711 } 1712 mov(Operand(result, 0), 1713 Immediate(isolate()->factory()->one_pointer_filler_map())); 1714 add(result, Immediate(kDoubleSize / 2)); 1715 bind(&aligned); 1716 } 1717 1718 // Calculate new top and bail out if space is exhausted. 1719 if (!object_size.is(result_end)) { 1720 mov(result_end, object_size); 1721 } 1722 add(result_end, result); 1723 cmp(result_end, Operand::StaticVariable(allocation_limit)); 1724 j(above, gc_required); 1725 1726 // Tag result. 1727 DCHECK(kHeapObjectTag == 1); 1728 inc(result); 1729 1730 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) { 1731 // The top pointer is not updated for allocation folding dominators. 1732 UpdateAllocationTopHelper(result_end, scratch, flags); 1733 } 1734} 1735 1736void MacroAssembler::FastAllocate(int object_size, Register result, 1737 Register result_end, AllocationFlags flags) { 1738 DCHECK(!result.is(result_end)); 1739 // Load address of new object into result. 1740 LoadAllocationTopHelper(result, no_reg, flags); 1741 1742 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1743 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1744 Label aligned; 1745 test(result, Immediate(kDoubleAlignmentMask)); 1746 j(zero, &aligned, Label::kNear); 1747 mov(Operand(result, 0), 1748 Immediate(isolate()->factory()->one_pointer_filler_map())); 1749 add(result, Immediate(kDoubleSize / 2)); 1750 bind(&aligned); 1751 } 1752 1753 lea(result_end, Operand(result, object_size)); 1754 UpdateAllocationTopHelper(result_end, no_reg, flags); 1755 1756 DCHECK(kHeapObjectTag == 1); 1757 inc(result); 1758} 1759 1760void MacroAssembler::FastAllocate(Register object_size, Register result, 1761 Register result_end, AllocationFlags flags) { 1762 DCHECK(!result.is(result_end)); 1763 // Load address of new object into result. 1764 LoadAllocationTopHelper(result, no_reg, flags); 1765 1766 if ((flags & DOUBLE_ALIGNMENT) != 0) { 1767 DCHECK(kPointerAlignment * 2 == kDoubleAlignment); 1768 Label aligned; 1769 test(result, Immediate(kDoubleAlignmentMask)); 1770 j(zero, &aligned, Label::kNear); 1771 mov(Operand(result, 0), 1772 Immediate(isolate()->factory()->one_pointer_filler_map())); 1773 add(result, Immediate(kDoubleSize / 2)); 1774 bind(&aligned); 1775 } 1776 1777 lea(result_end, Operand(result, object_size, times_1, 0)); 1778 UpdateAllocationTopHelper(result_end, no_reg, flags); 1779 1780 DCHECK(kHeapObjectTag == 1); 1781 inc(result); 1782} 1783 1784 1785void MacroAssembler::AllocateHeapNumber(Register result, 1786 Register scratch1, 1787 Register scratch2, 1788 Label* gc_required, 1789 MutableMode mode) { 1790 // Allocate heap number in new space. 1791 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required, 1792 NO_ALLOCATION_FLAGS); 1793 1794 Handle<Map> map = mode == MUTABLE 1795 ? isolate()->factory()->mutable_heap_number_map() 1796 : isolate()->factory()->heap_number_map(); 1797 1798 // Set the map. 1799 mov(FieldOperand(result, HeapObject::kMapOffset), Immediate(map)); 1800} 1801 1802 1803void MacroAssembler::AllocateTwoByteString(Register result, 1804 Register length, 1805 Register scratch1, 1806 Register scratch2, 1807 Register scratch3, 1808 Label* gc_required) { 1809 // Calculate the number of bytes needed for the characters in the string while 1810 // observing object alignment. 1811 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); 1812 DCHECK(kShortSize == 2); 1813 // scratch1 = length * 2 + kObjectAlignmentMask. 1814 lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask)); 1815 and_(scratch1, Immediate(~kObjectAlignmentMask)); 1816 1817 // Allocate two byte string in new space. 1818 Allocate(SeqTwoByteString::kHeaderSize, times_1, scratch1, 1819 REGISTER_VALUE_IS_INT32, result, scratch2, scratch3, gc_required, 1820 NO_ALLOCATION_FLAGS); 1821 1822 // Set the map, length and hash field. 1823 mov(FieldOperand(result, HeapObject::kMapOffset), 1824 Immediate(isolate()->factory()->string_map())); 1825 mov(scratch1, length); 1826 SmiTag(scratch1); 1827 mov(FieldOperand(result, String::kLengthOffset), scratch1); 1828 mov(FieldOperand(result, String::kHashFieldOffset), 1829 Immediate(String::kEmptyHashField)); 1830} 1831 1832 1833void MacroAssembler::AllocateOneByteString(Register result, Register length, 1834 Register scratch1, Register scratch2, 1835 Register scratch3, 1836 Label* gc_required) { 1837 // Calculate the number of bytes needed for the characters in the string while 1838 // observing object alignment. 1839 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); 1840 mov(scratch1, length); 1841 DCHECK(kCharSize == 1); 1842 add(scratch1, Immediate(kObjectAlignmentMask)); 1843 and_(scratch1, Immediate(~kObjectAlignmentMask)); 1844 1845 // Allocate one-byte string in new space. 1846 Allocate(SeqOneByteString::kHeaderSize, times_1, scratch1, 1847 REGISTER_VALUE_IS_INT32, result, scratch2, scratch3, gc_required, 1848 NO_ALLOCATION_FLAGS); 1849 1850 // Set the map, length and hash field. 1851 mov(FieldOperand(result, HeapObject::kMapOffset), 1852 Immediate(isolate()->factory()->one_byte_string_map())); 1853 mov(scratch1, length); 1854 SmiTag(scratch1); 1855 mov(FieldOperand(result, String::kLengthOffset), scratch1); 1856 mov(FieldOperand(result, String::kHashFieldOffset), 1857 Immediate(String::kEmptyHashField)); 1858} 1859 1860 1861void MacroAssembler::AllocateOneByteString(Register result, int length, 1862 Register scratch1, Register scratch2, 1863 Label* gc_required) { 1864 DCHECK(length > 0); 1865 1866 // Allocate one-byte string in new space. 1867 Allocate(SeqOneByteString::SizeFor(length), result, scratch1, scratch2, 1868 gc_required, NO_ALLOCATION_FLAGS); 1869 1870 // Set the map, length and hash field. 1871 mov(FieldOperand(result, HeapObject::kMapOffset), 1872 Immediate(isolate()->factory()->one_byte_string_map())); 1873 mov(FieldOperand(result, String::kLengthOffset), 1874 Immediate(Smi::FromInt(length))); 1875 mov(FieldOperand(result, String::kHashFieldOffset), 1876 Immediate(String::kEmptyHashField)); 1877} 1878 1879 1880void MacroAssembler::AllocateTwoByteConsString(Register result, 1881 Register scratch1, 1882 Register scratch2, 1883 Label* gc_required) { 1884 // Allocate heap number in new space. 1885 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, 1886 NO_ALLOCATION_FLAGS); 1887 1888 // Set the map. The other fields are left uninitialized. 1889 mov(FieldOperand(result, HeapObject::kMapOffset), 1890 Immediate(isolate()->factory()->cons_string_map())); 1891} 1892 1893 1894void MacroAssembler::AllocateOneByteConsString(Register result, 1895 Register scratch1, 1896 Register scratch2, 1897 Label* gc_required) { 1898 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, 1899 NO_ALLOCATION_FLAGS); 1900 1901 // Set the map. The other fields are left uninitialized. 1902 mov(FieldOperand(result, HeapObject::kMapOffset), 1903 Immediate(isolate()->factory()->cons_one_byte_string_map())); 1904} 1905 1906 1907void MacroAssembler::AllocateTwoByteSlicedString(Register result, 1908 Register scratch1, 1909 Register scratch2, 1910 Label* gc_required) { 1911 // Allocate heap number in new space. 1912 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, 1913 NO_ALLOCATION_FLAGS); 1914 1915 // Set the map. The other fields are left uninitialized. 1916 mov(FieldOperand(result, HeapObject::kMapOffset), 1917 Immediate(isolate()->factory()->sliced_string_map())); 1918} 1919 1920 1921void MacroAssembler::AllocateOneByteSlicedString(Register result, 1922 Register scratch1, 1923 Register scratch2, 1924 Label* gc_required) { 1925 // Allocate heap number in new space. 1926 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, 1927 NO_ALLOCATION_FLAGS); 1928 1929 // Set the map. The other fields are left uninitialized. 1930 mov(FieldOperand(result, HeapObject::kMapOffset), 1931 Immediate(isolate()->factory()->sliced_one_byte_string_map())); 1932} 1933 1934 1935void MacroAssembler::AllocateJSValue(Register result, Register constructor, 1936 Register value, Register scratch, 1937 Label* gc_required) { 1938 DCHECK(!result.is(constructor)); 1939 DCHECK(!result.is(scratch)); 1940 DCHECK(!result.is(value)); 1941 1942 // Allocate JSValue in new space. 1943 Allocate(JSValue::kSize, result, scratch, no_reg, gc_required, 1944 NO_ALLOCATION_FLAGS); 1945 1946 // Initialize the JSValue. 1947 LoadGlobalFunctionInitialMap(constructor, scratch); 1948 mov(FieldOperand(result, HeapObject::kMapOffset), scratch); 1949 LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); 1950 mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch); 1951 mov(FieldOperand(result, JSObject::kElementsOffset), scratch); 1952 mov(FieldOperand(result, JSValue::kValueOffset), value); 1953 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); 1954} 1955 1956 1957// Copy memory, byte-by-byte, from source to destination. Not optimized for 1958// long or aligned copies. The contents of scratch and length are destroyed. 1959// Source and destination are incremented by length. 1960// Many variants of movsb, loop unrolling, word moves, and indexed operands 1961// have been tried here already, and this is fastest. 1962// A simpler loop is faster on small copies, but 30% slower on large ones. 1963// The cld() instruction must have been emitted, to set the direction flag(), 1964// before calling this function. 1965void MacroAssembler::CopyBytes(Register source, 1966 Register destination, 1967 Register length, 1968 Register scratch) { 1969 Label short_loop, len4, len8, len12, done, short_string; 1970 DCHECK(source.is(esi)); 1971 DCHECK(destination.is(edi)); 1972 DCHECK(length.is(ecx)); 1973 cmp(length, Immediate(4)); 1974 j(below, &short_string, Label::kNear); 1975 1976 // Because source is 4-byte aligned in our uses of this function, 1977 // we keep source aligned for the rep_movs call by copying the odd bytes 1978 // at the end of the ranges. 1979 mov(scratch, Operand(source, length, times_1, -4)); 1980 mov(Operand(destination, length, times_1, -4), scratch); 1981 1982 cmp(length, Immediate(8)); 1983 j(below_equal, &len4, Label::kNear); 1984 cmp(length, Immediate(12)); 1985 j(below_equal, &len8, Label::kNear); 1986 cmp(length, Immediate(16)); 1987 j(below_equal, &len12, Label::kNear); 1988 1989 mov(scratch, ecx); 1990 shr(ecx, 2); 1991 rep_movs(); 1992 and_(scratch, Immediate(0x3)); 1993 add(destination, scratch); 1994 jmp(&done, Label::kNear); 1995 1996 bind(&len12); 1997 mov(scratch, Operand(source, 8)); 1998 mov(Operand(destination, 8), scratch); 1999 bind(&len8); 2000 mov(scratch, Operand(source, 4)); 2001 mov(Operand(destination, 4), scratch); 2002 bind(&len4); 2003 mov(scratch, Operand(source, 0)); 2004 mov(Operand(destination, 0), scratch); 2005 add(destination, length); 2006 jmp(&done, Label::kNear); 2007 2008 bind(&short_string); 2009 test(length, length); 2010 j(zero, &done, Label::kNear); 2011 2012 bind(&short_loop); 2013 mov_b(scratch, Operand(source, 0)); 2014 mov_b(Operand(destination, 0), scratch); 2015 inc(source); 2016 inc(destination); 2017 dec(length); 2018 j(not_zero, &short_loop); 2019 2020 bind(&done); 2021} 2022 2023 2024void MacroAssembler::InitializeFieldsWithFiller(Register current_address, 2025 Register end_address, 2026 Register filler) { 2027 Label loop, entry; 2028 jmp(&entry, Label::kNear); 2029 bind(&loop); 2030 mov(Operand(current_address, 0), filler); 2031 add(current_address, Immediate(kPointerSize)); 2032 bind(&entry); 2033 cmp(current_address, end_address); 2034 j(below, &loop, Label::kNear); 2035} 2036 2037 2038void MacroAssembler::BooleanBitTest(Register object, 2039 int field_offset, 2040 int bit_index) { 2041 bit_index += kSmiTagSize + kSmiShiftSize; 2042 DCHECK(base::bits::IsPowerOfTwo32(kBitsPerByte)); 2043 int byte_index = bit_index / kBitsPerByte; 2044 int byte_bit_index = bit_index & (kBitsPerByte - 1); 2045 test_b(FieldOperand(object, field_offset + byte_index), 2046 Immediate(1 << byte_bit_index)); 2047} 2048 2049 2050 2051void MacroAssembler::NegativeZeroTest(Register result, 2052 Register op, 2053 Label* then_label) { 2054 Label ok; 2055 test(result, result); 2056 j(not_zero, &ok, Label::kNear); 2057 test(op, op); 2058 j(sign, then_label, Label::kNear); 2059 bind(&ok); 2060} 2061 2062 2063void MacroAssembler::NegativeZeroTest(Register result, 2064 Register op1, 2065 Register op2, 2066 Register scratch, 2067 Label* then_label) { 2068 Label ok; 2069 test(result, result); 2070 j(not_zero, &ok, Label::kNear); 2071 mov(scratch, op1); 2072 or_(scratch, op2); 2073 j(sign, then_label, Label::kNear); 2074 bind(&ok); 2075} 2076 2077 2078void MacroAssembler::GetMapConstructor(Register result, Register map, 2079 Register temp) { 2080 Label done, loop; 2081 mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); 2082 bind(&loop); 2083 JumpIfSmi(result, &done, Label::kNear); 2084 CmpObjectType(result, MAP_TYPE, temp); 2085 j(not_equal, &done, Label::kNear); 2086 mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); 2087 jmp(&loop); 2088 bind(&done); 2089} 2090 2091 2092void MacroAssembler::TryGetFunctionPrototype(Register function, Register result, 2093 Register scratch, Label* miss) { 2094 // Get the prototype or initial map from the function. 2095 mov(result, 2096 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 2097 2098 // If the prototype or initial map is the hole, don't return it and 2099 // simply miss the cache instead. This will allow us to allocate a 2100 // prototype object on-demand in the runtime system. 2101 cmp(result, Immediate(isolate()->factory()->the_hole_value())); 2102 j(equal, miss); 2103 2104 // If the function does not have an initial map, we're done. 2105 Label done; 2106 CmpObjectType(result, MAP_TYPE, scratch); 2107 j(not_equal, &done, Label::kNear); 2108 2109 // Get the prototype from the initial map. 2110 mov(result, FieldOperand(result, Map::kPrototypeOffset)); 2111 2112 // All done. 2113 bind(&done); 2114} 2115 2116 2117void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) { 2118 DCHECK(AllowThisStubCall(stub)); // Calls are not allowed in some stubs. 2119 call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id); 2120} 2121 2122 2123void MacroAssembler::TailCallStub(CodeStub* stub) { 2124 jmp(stub->GetCode(), RelocInfo::CODE_TARGET); 2125} 2126 2127 2128void MacroAssembler::StubReturn(int argc) { 2129 DCHECK(argc >= 1 && generating_stub()); 2130 ret((argc - 1) * kPointerSize); 2131} 2132 2133 2134bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { 2135 return has_frame_ || !stub->SometimesSetsUpAFrame(); 2136} 2137 2138 2139void MacroAssembler::IndexFromHash(Register hash, Register index) { 2140 // The assert checks that the constants for the maximum number of digits 2141 // for an array index cached in the hash field and the number of bits 2142 // reserved for it does not conflict. 2143 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < 2144 (1 << String::kArrayIndexValueBits)); 2145 if (!index.is(hash)) { 2146 mov(index, hash); 2147 } 2148 DecodeFieldToSmi<String::ArrayIndexValueBits>(index); 2149} 2150 2151 2152void MacroAssembler::CallRuntime(const Runtime::Function* f, 2153 int num_arguments, 2154 SaveFPRegsMode save_doubles) { 2155 // If the expected number of arguments of the runtime function is 2156 // constant, we check that the actual number of arguments match the 2157 // expectation. 2158 CHECK(f->nargs < 0 || f->nargs == num_arguments); 2159 2160 // TODO(1236192): Most runtime routines don't need the number of 2161 // arguments passed in because it is constant. At some point we 2162 // should remove this need and make the runtime routine entry code 2163 // smarter. 2164 Move(eax, Immediate(num_arguments)); 2165 mov(ebx, Immediate(ExternalReference(f, isolate()))); 2166 CEntryStub ces(isolate(), 1, save_doubles); 2167 CallStub(&ces); 2168} 2169 2170 2171void MacroAssembler::CallExternalReference(ExternalReference ref, 2172 int num_arguments) { 2173 mov(eax, Immediate(num_arguments)); 2174 mov(ebx, Immediate(ref)); 2175 2176 CEntryStub stub(isolate(), 1); 2177 CallStub(&stub); 2178} 2179 2180 2181void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { 2182 // ----------- S t a t e ------------- 2183 // -- esp[0] : return address 2184 // -- esp[8] : argument num_arguments - 1 2185 // ... 2186 // -- esp[8 * num_arguments] : argument 0 (receiver) 2187 // 2188 // For runtime functions with variable arguments: 2189 // -- eax : number of arguments 2190 // ----------------------------------- 2191 2192 const Runtime::Function* function = Runtime::FunctionForId(fid); 2193 DCHECK_EQ(1, function->result_size); 2194 if (function->nargs >= 0) { 2195 // TODO(1236192): Most runtime routines don't need the number of 2196 // arguments passed in because it is constant. At some point we 2197 // should remove this need and make the runtime routine entry code 2198 // smarter. 2199 mov(eax, Immediate(function->nargs)); 2200 } 2201 JumpToExternalReference(ExternalReference(fid, isolate())); 2202} 2203 2204 2205void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) { 2206 // Set the entry point and jump to the C entry runtime stub. 2207 mov(ebx, Immediate(ext)); 2208 CEntryStub ces(isolate(), 1); 2209 jmp(ces.GetCode(), RelocInfo::CODE_TARGET); 2210} 2211 2212void MacroAssembler::PrepareForTailCall( 2213 const ParameterCount& callee_args_count, Register caller_args_count_reg, 2214 Register scratch0, Register scratch1, ReturnAddressState ra_state, 2215 int number_of_temp_values_after_return_address) { 2216#if DEBUG 2217 if (callee_args_count.is_reg()) { 2218 DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0, 2219 scratch1)); 2220 } else { 2221 DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1)); 2222 } 2223 DCHECK(ra_state != ReturnAddressState::kNotOnStack || 2224 number_of_temp_values_after_return_address == 0); 2225#endif 2226 2227 // Calculate the destination address where we will put the return address 2228 // after we drop current frame. 2229 Register new_sp_reg = scratch0; 2230 if (callee_args_count.is_reg()) { 2231 sub(caller_args_count_reg, callee_args_count.reg()); 2232 lea(new_sp_reg, 2233 Operand(ebp, caller_args_count_reg, times_pointer_size, 2234 StandardFrameConstants::kCallerPCOffset - 2235 number_of_temp_values_after_return_address * kPointerSize)); 2236 } else { 2237 lea(new_sp_reg, Operand(ebp, caller_args_count_reg, times_pointer_size, 2238 StandardFrameConstants::kCallerPCOffset - 2239 (callee_args_count.immediate() + 2240 number_of_temp_values_after_return_address) * 2241 kPointerSize)); 2242 } 2243 2244 if (FLAG_debug_code) { 2245 cmp(esp, new_sp_reg); 2246 Check(below, kStackAccessBelowStackPointer); 2247 } 2248 2249 // Copy return address from caller's frame to current frame's return address 2250 // to avoid its trashing and let the following loop copy it to the right 2251 // place. 2252 Register tmp_reg = scratch1; 2253 if (ra_state == ReturnAddressState::kOnStack) { 2254 mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset)); 2255 mov(Operand(esp, number_of_temp_values_after_return_address * kPointerSize), 2256 tmp_reg); 2257 } else { 2258 DCHECK(ReturnAddressState::kNotOnStack == ra_state); 2259 DCHECK_EQ(0, number_of_temp_values_after_return_address); 2260 Push(Operand(ebp, StandardFrameConstants::kCallerPCOffset)); 2261 } 2262 2263 // Restore caller's frame pointer now as it could be overwritten by 2264 // the copying loop. 2265 mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 2266 2267 // +2 here is to copy both receiver and return address. 2268 Register count_reg = caller_args_count_reg; 2269 if (callee_args_count.is_reg()) { 2270 lea(count_reg, Operand(callee_args_count.reg(), 2271 2 + number_of_temp_values_after_return_address)); 2272 } else { 2273 mov(count_reg, Immediate(callee_args_count.immediate() + 2 + 2274 number_of_temp_values_after_return_address)); 2275 // TODO(ishell): Unroll copying loop for small immediate values. 2276 } 2277 2278 // Now copy callee arguments to the caller frame going backwards to avoid 2279 // callee arguments corruption (source and destination areas could overlap). 2280 Label loop, entry; 2281 jmp(&entry, Label::kNear); 2282 bind(&loop); 2283 dec(count_reg); 2284 mov(tmp_reg, Operand(esp, count_reg, times_pointer_size, 0)); 2285 mov(Operand(new_sp_reg, count_reg, times_pointer_size, 0), tmp_reg); 2286 bind(&entry); 2287 cmp(count_reg, Immediate(0)); 2288 j(not_equal, &loop, Label::kNear); 2289 2290 // Leave current frame. 2291 mov(esp, new_sp_reg); 2292} 2293 2294void MacroAssembler::InvokePrologue(const ParameterCount& expected, 2295 const ParameterCount& actual, 2296 Label* done, 2297 bool* definitely_mismatches, 2298 InvokeFlag flag, 2299 Label::Distance done_near, 2300 const CallWrapper& call_wrapper) { 2301 bool definitely_matches = false; 2302 *definitely_mismatches = false; 2303 Label invoke; 2304 if (expected.is_immediate()) { 2305 DCHECK(actual.is_immediate()); 2306 mov(eax, actual.immediate()); 2307 if (expected.immediate() == actual.immediate()) { 2308 definitely_matches = true; 2309 } else { 2310 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel; 2311 if (expected.immediate() == sentinel) { 2312 // Don't worry about adapting arguments for builtins that 2313 // don't want that done. Skip adaption code by making it look 2314 // like we have a match between expected and actual number of 2315 // arguments. 2316 definitely_matches = true; 2317 } else { 2318 *definitely_mismatches = true; 2319 mov(ebx, expected.immediate()); 2320 } 2321 } 2322 } else { 2323 if (actual.is_immediate()) { 2324 // Expected is in register, actual is immediate. This is the 2325 // case when we invoke function values without going through the 2326 // IC mechanism. 2327 mov(eax, actual.immediate()); 2328 cmp(expected.reg(), actual.immediate()); 2329 j(equal, &invoke); 2330 DCHECK(expected.reg().is(ebx)); 2331 } else if (!expected.reg().is(actual.reg())) { 2332 // Both expected and actual are in (different) registers. This 2333 // is the case when we invoke functions using call and apply. 2334 cmp(expected.reg(), actual.reg()); 2335 j(equal, &invoke); 2336 DCHECK(actual.reg().is(eax)); 2337 DCHECK(expected.reg().is(ebx)); 2338 } else { 2339 Move(eax, actual.reg()); 2340 } 2341 } 2342 2343 if (!definitely_matches) { 2344 Handle<Code> adaptor = 2345 isolate()->builtins()->ArgumentsAdaptorTrampoline(); 2346 if (flag == CALL_FUNCTION) { 2347 call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET)); 2348 call(adaptor, RelocInfo::CODE_TARGET); 2349 call_wrapper.AfterCall(); 2350 if (!*definitely_mismatches) { 2351 jmp(done, done_near); 2352 } 2353 } else { 2354 jmp(adaptor, RelocInfo::CODE_TARGET); 2355 } 2356 bind(&invoke); 2357 } 2358} 2359 2360 2361void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target, 2362 const ParameterCount& expected, 2363 const ParameterCount& actual) { 2364 Label skip_flooding; 2365 ExternalReference last_step_action = 2366 ExternalReference::debug_last_step_action_address(isolate()); 2367 STATIC_ASSERT(StepFrame > StepIn); 2368 cmpb(Operand::StaticVariable(last_step_action), Immediate(StepIn)); 2369 j(less, &skip_flooding); 2370 { 2371 FrameScope frame(this, 2372 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); 2373 if (expected.is_reg()) { 2374 SmiTag(expected.reg()); 2375 Push(expected.reg()); 2376 } 2377 if (actual.is_reg()) { 2378 SmiTag(actual.reg()); 2379 Push(actual.reg()); 2380 } 2381 if (new_target.is_valid()) { 2382 Push(new_target); 2383 } 2384 Push(fun); 2385 Push(fun); 2386 CallRuntime(Runtime::kDebugPrepareStepInIfStepping); 2387 Pop(fun); 2388 if (new_target.is_valid()) { 2389 Pop(new_target); 2390 } 2391 if (actual.is_reg()) { 2392 Pop(actual.reg()); 2393 SmiUntag(actual.reg()); 2394 } 2395 if (expected.is_reg()) { 2396 Pop(expected.reg()); 2397 SmiUntag(expected.reg()); 2398 } 2399 } 2400 bind(&skip_flooding); 2401} 2402 2403 2404void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, 2405 const ParameterCount& expected, 2406 const ParameterCount& actual, 2407 InvokeFlag flag, 2408 const CallWrapper& call_wrapper) { 2409 // You can't call a function without a valid frame. 2410 DCHECK(flag == JUMP_FUNCTION || has_frame()); 2411 DCHECK(function.is(edi)); 2412 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(edx)); 2413 2414 if (call_wrapper.NeedsDebugStepCheck()) { 2415 FloodFunctionIfStepping(function, new_target, expected, actual); 2416 } 2417 2418 // Clear the new.target register if not given. 2419 if (!new_target.is_valid()) { 2420 mov(edx, isolate()->factory()->undefined_value()); 2421 } 2422 2423 Label done; 2424 bool definitely_mismatches = false; 2425 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag, 2426 Label::kNear, call_wrapper); 2427 if (!definitely_mismatches) { 2428 // We call indirectly through the code field in the function to 2429 // allow recompilation to take effect without changing any of the 2430 // call sites. 2431 Operand code = FieldOperand(function, JSFunction::kCodeEntryOffset); 2432 if (flag == CALL_FUNCTION) { 2433 call_wrapper.BeforeCall(CallSize(code)); 2434 call(code); 2435 call_wrapper.AfterCall(); 2436 } else { 2437 DCHECK(flag == JUMP_FUNCTION); 2438 jmp(code); 2439 } 2440 bind(&done); 2441 } 2442} 2443 2444 2445void MacroAssembler::InvokeFunction(Register fun, 2446 Register new_target, 2447 const ParameterCount& actual, 2448 InvokeFlag flag, 2449 const CallWrapper& call_wrapper) { 2450 // You can't call a function without a valid frame. 2451 DCHECK(flag == JUMP_FUNCTION || has_frame()); 2452 2453 DCHECK(fun.is(edi)); 2454 mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 2455 mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 2456 mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset)); 2457 SmiUntag(ebx); 2458 2459 ParameterCount expected(ebx); 2460 InvokeFunctionCode(edi, new_target, expected, actual, flag, call_wrapper); 2461} 2462 2463 2464void MacroAssembler::InvokeFunction(Register fun, 2465 const ParameterCount& expected, 2466 const ParameterCount& actual, 2467 InvokeFlag flag, 2468 const CallWrapper& call_wrapper) { 2469 // You can't call a function without a valid frame. 2470 DCHECK(flag == JUMP_FUNCTION || has_frame()); 2471 2472 DCHECK(fun.is(edi)); 2473 mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 2474 2475 InvokeFunctionCode(edi, no_reg, expected, actual, flag, call_wrapper); 2476} 2477 2478 2479void MacroAssembler::InvokeFunction(Handle<JSFunction> function, 2480 const ParameterCount& expected, 2481 const ParameterCount& actual, 2482 InvokeFlag flag, 2483 const CallWrapper& call_wrapper) { 2484 LoadHeapObject(edi, function); 2485 InvokeFunction(edi, expected, actual, flag, call_wrapper); 2486} 2487 2488 2489void MacroAssembler::LoadContext(Register dst, int context_chain_length) { 2490 if (context_chain_length > 0) { 2491 // Move up the chain of contexts to the context containing the slot. 2492 mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX))); 2493 for (int i = 1; i < context_chain_length; i++) { 2494 mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); 2495 } 2496 } else { 2497 // Slot is in the current function context. Move it into the 2498 // destination register in case we store into it (the write barrier 2499 // cannot be allowed to destroy the context in esi). 2500 mov(dst, esi); 2501 } 2502 2503 // We should not have found a with context by walking the context chain 2504 // (i.e., the static scope chain and runtime context chain do not agree). 2505 // A variable occurring in such a scope should have slot type LOOKUP and 2506 // not CONTEXT. 2507 if (emit_debug_code()) { 2508 cmp(FieldOperand(dst, HeapObject::kMapOffset), 2509 isolate()->factory()->with_context_map()); 2510 Check(not_equal, kVariableResolvedToWithContext); 2511 } 2512} 2513 2514 2515void MacroAssembler::LoadGlobalProxy(Register dst) { 2516 mov(dst, NativeContextOperand()); 2517 mov(dst, ContextOperand(dst, Context::GLOBAL_PROXY_INDEX)); 2518} 2519 2520 2521void MacroAssembler::LoadTransitionedArrayMapConditional( 2522 ElementsKind expected_kind, 2523 ElementsKind transitioned_kind, 2524 Register map_in_out, 2525 Register scratch, 2526 Label* no_map_match) { 2527 DCHECK(IsFastElementsKind(expected_kind)); 2528 DCHECK(IsFastElementsKind(transitioned_kind)); 2529 2530 // Check that the function's map is the same as the expected cached map. 2531 mov(scratch, NativeContextOperand()); 2532 cmp(map_in_out, 2533 ContextOperand(scratch, Context::ArrayMapIndex(expected_kind))); 2534 j(not_equal, no_map_match); 2535 2536 // Use the transitioned cached map. 2537 mov(map_in_out, 2538 ContextOperand(scratch, Context::ArrayMapIndex(transitioned_kind))); 2539} 2540 2541 2542void MacroAssembler::LoadGlobalFunction(int index, Register function) { 2543 // Load the native context from the current context. 2544 mov(function, NativeContextOperand()); 2545 // Load the function from the native context. 2546 mov(function, ContextOperand(function, index)); 2547} 2548 2549 2550void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, 2551 Register map) { 2552 // Load the initial map. The global functions all have initial maps. 2553 mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 2554 if (emit_debug_code()) { 2555 Label ok, fail; 2556 CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK); 2557 jmp(&ok); 2558 bind(&fail); 2559 Abort(kGlobalFunctionsMustHaveInitialMap); 2560 bind(&ok); 2561 } 2562} 2563 2564 2565// Store the value in register src in the safepoint register stack 2566// slot for register dst. 2567void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) { 2568 mov(SafepointRegisterSlot(dst), src); 2569} 2570 2571 2572void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Immediate src) { 2573 mov(SafepointRegisterSlot(dst), src); 2574} 2575 2576 2577void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { 2578 mov(dst, SafepointRegisterSlot(src)); 2579} 2580 2581 2582Operand MacroAssembler::SafepointRegisterSlot(Register reg) { 2583 return Operand(esp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); 2584} 2585 2586 2587int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { 2588 // The registers are pushed starting with the lowest encoding, 2589 // which means that lowest encodings are furthest away from 2590 // the stack pointer. 2591 DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters); 2592 return kNumSafepointRegisters - reg_code - 1; 2593} 2594 2595 2596void MacroAssembler::LoadHeapObject(Register result, 2597 Handle<HeapObject> object) { 2598 AllowDeferredHandleDereference embedding_raw_address; 2599 if (isolate()->heap()->InNewSpace(*object)) { 2600 Handle<Cell> cell = isolate()->factory()->NewCell(object); 2601 mov(result, Operand::ForCell(cell)); 2602 } else { 2603 mov(result, object); 2604 } 2605} 2606 2607 2608void MacroAssembler::CmpHeapObject(Register reg, Handle<HeapObject> object) { 2609 AllowDeferredHandleDereference using_raw_address; 2610 if (isolate()->heap()->InNewSpace(*object)) { 2611 Handle<Cell> cell = isolate()->factory()->NewCell(object); 2612 cmp(reg, Operand::ForCell(cell)); 2613 } else { 2614 cmp(reg, object); 2615 } 2616} 2617 2618 2619void MacroAssembler::PushHeapObject(Handle<HeapObject> object) { 2620 AllowDeferredHandleDereference using_raw_address; 2621 if (isolate()->heap()->InNewSpace(*object)) { 2622 Handle<Cell> cell = isolate()->factory()->NewCell(object); 2623 push(Operand::ForCell(cell)); 2624 } else { 2625 Push(object); 2626 } 2627} 2628 2629 2630void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell, 2631 Register scratch) { 2632 mov(scratch, cell); 2633 cmp(value, FieldOperand(scratch, WeakCell::kValueOffset)); 2634} 2635 2636 2637void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) { 2638 mov(value, cell); 2639 mov(value, FieldOperand(value, WeakCell::kValueOffset)); 2640} 2641 2642 2643void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell, 2644 Label* miss) { 2645 GetWeakValue(value, cell); 2646 JumpIfSmi(value, miss); 2647} 2648 2649 2650void MacroAssembler::Ret() { 2651 ret(0); 2652} 2653 2654 2655void MacroAssembler::Ret(int bytes_dropped, Register scratch) { 2656 if (is_uint16(bytes_dropped)) { 2657 ret(bytes_dropped); 2658 } else { 2659 pop(scratch); 2660 add(esp, Immediate(bytes_dropped)); 2661 push(scratch); 2662 ret(0); 2663 } 2664} 2665 2666 2667void MacroAssembler::Drop(int stack_elements) { 2668 if (stack_elements > 0) { 2669 add(esp, Immediate(stack_elements * kPointerSize)); 2670 } 2671} 2672 2673 2674void MacroAssembler::Move(Register dst, Register src) { 2675 if (!dst.is(src)) { 2676 mov(dst, src); 2677 } 2678} 2679 2680 2681void MacroAssembler::Move(Register dst, const Immediate& x) { 2682 if (x.is_zero() && RelocInfo::IsNone(x.rmode_)) { 2683 xor_(dst, dst); // Shorter than mov of 32-bit immediate 0. 2684 } else { 2685 mov(dst, x); 2686 } 2687} 2688 2689 2690void MacroAssembler::Move(const Operand& dst, const Immediate& x) { 2691 mov(dst, x); 2692} 2693 2694 2695void MacroAssembler::Move(XMMRegister dst, uint32_t src) { 2696 if (src == 0) { 2697 pxor(dst, dst); 2698 } else { 2699 unsigned cnt = base::bits::CountPopulation32(src); 2700 unsigned nlz = base::bits::CountLeadingZeros32(src); 2701 unsigned ntz = base::bits::CountTrailingZeros32(src); 2702 if (nlz + cnt + ntz == 32) { 2703 pcmpeqd(dst, dst); 2704 if (ntz == 0) { 2705 psrld(dst, 32 - cnt); 2706 } else { 2707 pslld(dst, 32 - cnt); 2708 if (nlz != 0) psrld(dst, nlz); 2709 } 2710 } else { 2711 push(eax); 2712 mov(eax, Immediate(src)); 2713 movd(dst, Operand(eax)); 2714 pop(eax); 2715 } 2716 } 2717} 2718 2719 2720void MacroAssembler::Move(XMMRegister dst, uint64_t src) { 2721 if (src == 0) { 2722 pxor(dst, dst); 2723 } else { 2724 uint32_t lower = static_cast<uint32_t>(src); 2725 uint32_t upper = static_cast<uint32_t>(src >> 32); 2726 unsigned cnt = base::bits::CountPopulation64(src); 2727 unsigned nlz = base::bits::CountLeadingZeros64(src); 2728 unsigned ntz = base::bits::CountTrailingZeros64(src); 2729 if (nlz + cnt + ntz == 64) { 2730 pcmpeqd(dst, dst); 2731 if (ntz == 0) { 2732 psrlq(dst, 64 - cnt); 2733 } else { 2734 psllq(dst, 64 - cnt); 2735 if (nlz != 0) psrlq(dst, nlz); 2736 } 2737 } else if (lower == 0) { 2738 Move(dst, upper); 2739 psllq(dst, 32); 2740 } else if (CpuFeatures::IsSupported(SSE4_1)) { 2741 CpuFeatureScope scope(this, SSE4_1); 2742 push(eax); 2743 Move(eax, Immediate(lower)); 2744 movd(dst, Operand(eax)); 2745 Move(eax, Immediate(upper)); 2746 pinsrd(dst, Operand(eax), 1); 2747 pop(eax); 2748 } else { 2749 push(Immediate(upper)); 2750 push(Immediate(lower)); 2751 movsd(dst, Operand(esp, 0)); 2752 add(esp, Immediate(kDoubleSize)); 2753 } 2754 } 2755} 2756 2757 2758void MacroAssembler::Pextrd(Register dst, XMMRegister src, int8_t imm8) { 2759 if (imm8 == 0) { 2760 movd(dst, src); 2761 return; 2762 } 2763 DCHECK_EQ(1, imm8); 2764 if (CpuFeatures::IsSupported(SSE4_1)) { 2765 CpuFeatureScope sse_scope(this, SSE4_1); 2766 pextrd(dst, src, imm8); 2767 return; 2768 } 2769 pshufd(xmm0, src, 1); 2770 movd(dst, xmm0); 2771} 2772 2773 2774void MacroAssembler::Pinsrd(XMMRegister dst, const Operand& src, int8_t imm8) { 2775 DCHECK(imm8 == 0 || imm8 == 1); 2776 if (CpuFeatures::IsSupported(SSE4_1)) { 2777 CpuFeatureScope sse_scope(this, SSE4_1); 2778 pinsrd(dst, src, imm8); 2779 return; 2780 } 2781 movd(xmm0, src); 2782 if (imm8 == 1) { 2783 punpckldq(dst, xmm0); 2784 } else { 2785 DCHECK_EQ(0, imm8); 2786 psrlq(dst, 32); 2787 punpckldq(xmm0, dst); 2788 movaps(dst, xmm0); 2789 } 2790} 2791 2792 2793void MacroAssembler::Lzcnt(Register dst, const Operand& src) { 2794 if (CpuFeatures::IsSupported(LZCNT)) { 2795 CpuFeatureScope scope(this, LZCNT); 2796 lzcnt(dst, src); 2797 return; 2798 } 2799 Label not_zero_src; 2800 bsr(dst, src); 2801 j(not_zero, ¬_zero_src, Label::kNear); 2802 Move(dst, Immediate(63)); // 63^31 == 32 2803 bind(¬_zero_src); 2804 xor_(dst, Immediate(31)); // for x in [0..31], 31^x == 31-x. 2805} 2806 2807 2808void MacroAssembler::Tzcnt(Register dst, const Operand& src) { 2809 if (CpuFeatures::IsSupported(BMI1)) { 2810 CpuFeatureScope scope(this, BMI1); 2811 tzcnt(dst, src); 2812 return; 2813 } 2814 Label not_zero_src; 2815 bsf(dst, src); 2816 j(not_zero, ¬_zero_src, Label::kNear); 2817 Move(dst, Immediate(32)); // The result of tzcnt is 32 if src = 0. 2818 bind(¬_zero_src); 2819} 2820 2821 2822void MacroAssembler::Popcnt(Register dst, const Operand& src) { 2823 if (CpuFeatures::IsSupported(POPCNT)) { 2824 CpuFeatureScope scope(this, POPCNT); 2825 popcnt(dst, src); 2826 return; 2827 } 2828 UNREACHABLE(); 2829} 2830 2831 2832void MacroAssembler::SetCounter(StatsCounter* counter, int value) { 2833 if (FLAG_native_code_counters && counter->Enabled()) { 2834 mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value)); 2835 } 2836} 2837 2838 2839void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { 2840 DCHECK(value > 0); 2841 if (FLAG_native_code_counters && counter->Enabled()) { 2842 Operand operand = Operand::StaticVariable(ExternalReference(counter)); 2843 if (value == 1) { 2844 inc(operand); 2845 } else { 2846 add(operand, Immediate(value)); 2847 } 2848 } 2849} 2850 2851 2852void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) { 2853 DCHECK(value > 0); 2854 if (FLAG_native_code_counters && counter->Enabled()) { 2855 Operand operand = Operand::StaticVariable(ExternalReference(counter)); 2856 if (value == 1) { 2857 dec(operand); 2858 } else { 2859 sub(operand, Immediate(value)); 2860 } 2861 } 2862} 2863 2864 2865void MacroAssembler::IncrementCounter(Condition cc, 2866 StatsCounter* counter, 2867 int value) { 2868 DCHECK(value > 0); 2869 if (FLAG_native_code_counters && counter->Enabled()) { 2870 Label skip; 2871 j(NegateCondition(cc), &skip); 2872 pushfd(); 2873 IncrementCounter(counter, value); 2874 popfd(); 2875 bind(&skip); 2876 } 2877} 2878 2879 2880void MacroAssembler::DecrementCounter(Condition cc, 2881 StatsCounter* counter, 2882 int value) { 2883 DCHECK(value > 0); 2884 if (FLAG_native_code_counters && counter->Enabled()) { 2885 Label skip; 2886 j(NegateCondition(cc), &skip); 2887 pushfd(); 2888 DecrementCounter(counter, value); 2889 popfd(); 2890 bind(&skip); 2891 } 2892} 2893 2894 2895void MacroAssembler::Assert(Condition cc, BailoutReason reason) { 2896 if (emit_debug_code()) Check(cc, reason); 2897} 2898 2899 2900void MacroAssembler::AssertFastElements(Register elements) { 2901 if (emit_debug_code()) { 2902 Factory* factory = isolate()->factory(); 2903 Label ok; 2904 cmp(FieldOperand(elements, HeapObject::kMapOffset), 2905 Immediate(factory->fixed_array_map())); 2906 j(equal, &ok); 2907 cmp(FieldOperand(elements, HeapObject::kMapOffset), 2908 Immediate(factory->fixed_double_array_map())); 2909 j(equal, &ok); 2910 cmp(FieldOperand(elements, HeapObject::kMapOffset), 2911 Immediate(factory->fixed_cow_array_map())); 2912 j(equal, &ok); 2913 Abort(kJSObjectWithFastElementsMapHasSlowElements); 2914 bind(&ok); 2915 } 2916} 2917 2918 2919void MacroAssembler::Check(Condition cc, BailoutReason reason) { 2920 Label L; 2921 j(cc, &L); 2922 Abort(reason); 2923 // will not return here 2924 bind(&L); 2925} 2926 2927 2928void MacroAssembler::CheckStackAlignment() { 2929 int frame_alignment = base::OS::ActivationFrameAlignment(); 2930 int frame_alignment_mask = frame_alignment - 1; 2931 if (frame_alignment > kPointerSize) { 2932 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 2933 Label alignment_as_expected; 2934 test(esp, Immediate(frame_alignment_mask)); 2935 j(zero, &alignment_as_expected); 2936 // Abort if stack is not aligned. 2937 int3(); 2938 bind(&alignment_as_expected); 2939 } 2940} 2941 2942 2943void MacroAssembler::Abort(BailoutReason reason) { 2944#ifdef DEBUG 2945 const char* msg = GetBailoutReason(reason); 2946 if (msg != NULL) { 2947 RecordComment("Abort message: "); 2948 RecordComment(msg); 2949 } 2950 2951 if (FLAG_trap_on_abort) { 2952 int3(); 2953 return; 2954 } 2955#endif 2956 2957 push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(reason)))); 2958 // Disable stub call restrictions to always allow calls to abort. 2959 if (!has_frame_) { 2960 // We don't actually want to generate a pile of code for this, so just 2961 // claim there is a stack frame, without generating one. 2962 FrameScope scope(this, StackFrame::NONE); 2963 CallRuntime(Runtime::kAbort); 2964 } else { 2965 CallRuntime(Runtime::kAbort); 2966 } 2967 // will not return here 2968 int3(); 2969} 2970 2971 2972void MacroAssembler::LoadInstanceDescriptors(Register map, 2973 Register descriptors) { 2974 mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset)); 2975} 2976 2977 2978void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { 2979 mov(dst, FieldOperand(map, Map::kBitField3Offset)); 2980 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); 2981} 2982 2983 2984void MacroAssembler::LoadAccessor(Register dst, Register holder, 2985 int accessor_index, 2986 AccessorComponent accessor) { 2987 mov(dst, FieldOperand(holder, HeapObject::kMapOffset)); 2988 LoadInstanceDescriptors(dst, dst); 2989 mov(dst, FieldOperand(dst, DescriptorArray::GetValueOffset(accessor_index))); 2990 int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset 2991 : AccessorPair::kSetterOffset; 2992 mov(dst, FieldOperand(dst, offset)); 2993} 2994 2995 2996void MacroAssembler::LoadPowerOf2(XMMRegister dst, 2997 Register scratch, 2998 int power) { 2999 DCHECK(is_uintn(power + HeapNumber::kExponentBias, 3000 HeapNumber::kExponentBits)); 3001 mov(scratch, Immediate(power + HeapNumber::kExponentBias)); 3002 movd(dst, scratch); 3003 psllq(dst, HeapNumber::kMantissaBits); 3004} 3005 3006 3007void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte( 3008 Register instance_type, Register scratch, Label* failure) { 3009 if (!scratch.is(instance_type)) { 3010 mov(scratch, instance_type); 3011 } 3012 and_(scratch, 3013 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); 3014 cmp(scratch, kStringTag | kSeqStringTag | kOneByteStringTag); 3015 j(not_equal, failure); 3016} 3017 3018 3019void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register object1, 3020 Register object2, 3021 Register scratch1, 3022 Register scratch2, 3023 Label* failure) { 3024 // Check that both objects are not smis. 3025 STATIC_ASSERT(kSmiTag == 0); 3026 mov(scratch1, object1); 3027 and_(scratch1, object2); 3028 JumpIfSmi(scratch1, failure); 3029 3030 // Load instance type for both strings. 3031 mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset)); 3032 mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset)); 3033 movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset)); 3034 movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); 3035 3036 // Check that both are flat one-byte strings. 3037 const int kFlatOneByteStringMask = 3038 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; 3039 const int kFlatOneByteStringTag = 3040 kStringTag | kOneByteStringTag | kSeqStringTag; 3041 // Interleave bits from both instance types and compare them in one check. 3042 DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << 3)); 3043 and_(scratch1, kFlatOneByteStringMask); 3044 and_(scratch2, kFlatOneByteStringMask); 3045 lea(scratch1, Operand(scratch1, scratch2, times_8, 0)); 3046 cmp(scratch1, kFlatOneByteStringTag | (kFlatOneByteStringTag << 3)); 3047 j(not_equal, failure); 3048} 3049 3050 3051void MacroAssembler::JumpIfNotUniqueNameInstanceType(Operand operand, 3052 Label* not_unique_name, 3053 Label::Distance distance) { 3054 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); 3055 Label succeed; 3056 test(operand, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); 3057 j(zero, &succeed); 3058 cmpb(operand, Immediate(SYMBOL_TYPE)); 3059 j(not_equal, not_unique_name, distance); 3060 3061 bind(&succeed); 3062} 3063 3064 3065void MacroAssembler::EmitSeqStringSetCharCheck(Register string, 3066 Register index, 3067 Register value, 3068 uint32_t encoding_mask) { 3069 Label is_object; 3070 JumpIfNotSmi(string, &is_object, Label::kNear); 3071 Abort(kNonObject); 3072 bind(&is_object); 3073 3074 push(value); 3075 mov(value, FieldOperand(string, HeapObject::kMapOffset)); 3076 movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset)); 3077 3078 and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask)); 3079 cmp(value, Immediate(encoding_mask)); 3080 pop(value); 3081 Check(equal, kUnexpectedStringType); 3082 3083 // The index is assumed to be untagged coming in, tag it to compare with the 3084 // string length without using a temp register, it is restored at the end of 3085 // this function. 3086 SmiTag(index); 3087 Check(no_overflow, kIndexIsTooLarge); 3088 3089 cmp(index, FieldOperand(string, String::kLengthOffset)); 3090 Check(less, kIndexIsTooLarge); 3091 3092 cmp(index, Immediate(Smi::FromInt(0))); 3093 Check(greater_equal, kIndexIsNegative); 3094 3095 // Restore the index 3096 SmiUntag(index); 3097} 3098 3099 3100void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { 3101 int frame_alignment = base::OS::ActivationFrameAlignment(); 3102 if (frame_alignment != 0) { 3103 // Make stack end at alignment and make room for num_arguments words 3104 // and the original value of esp. 3105 mov(scratch, esp); 3106 sub(esp, Immediate((num_arguments + 1) * kPointerSize)); 3107 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment)); 3108 and_(esp, -frame_alignment); 3109 mov(Operand(esp, num_arguments * kPointerSize), scratch); 3110 } else { 3111 sub(esp, Immediate(num_arguments * kPointerSize)); 3112 } 3113} 3114 3115 3116void MacroAssembler::CallCFunction(ExternalReference function, 3117 int num_arguments) { 3118 // Trashing eax is ok as it will be the return value. 3119 mov(eax, Immediate(function)); 3120 CallCFunction(eax, num_arguments); 3121} 3122 3123 3124void MacroAssembler::CallCFunction(Register function, 3125 int num_arguments) { 3126 DCHECK(has_frame()); 3127 // Check stack alignment. 3128 if (emit_debug_code()) { 3129 CheckStackAlignment(); 3130 } 3131 3132 call(function); 3133 if (base::OS::ActivationFrameAlignment() != 0) { 3134 mov(esp, Operand(esp, num_arguments * kPointerSize)); 3135 } else { 3136 add(esp, Immediate(num_arguments * kPointerSize)); 3137 } 3138} 3139 3140 3141#ifdef DEBUG 3142bool AreAliased(Register reg1, 3143 Register reg2, 3144 Register reg3, 3145 Register reg4, 3146 Register reg5, 3147 Register reg6, 3148 Register reg7, 3149 Register reg8) { 3150 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + 3151 reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() + 3152 reg7.is_valid() + reg8.is_valid(); 3153 3154 RegList regs = 0; 3155 if (reg1.is_valid()) regs |= reg1.bit(); 3156 if (reg2.is_valid()) regs |= reg2.bit(); 3157 if (reg3.is_valid()) regs |= reg3.bit(); 3158 if (reg4.is_valid()) regs |= reg4.bit(); 3159 if (reg5.is_valid()) regs |= reg5.bit(); 3160 if (reg6.is_valid()) regs |= reg6.bit(); 3161 if (reg7.is_valid()) regs |= reg7.bit(); 3162 if (reg8.is_valid()) regs |= reg8.bit(); 3163 int n_of_non_aliasing_regs = NumRegs(regs); 3164 3165 return n_of_valid_regs != n_of_non_aliasing_regs; 3166} 3167#endif 3168 3169 3170CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size) 3171 : address_(address), 3172 size_(size), 3173 masm_(isolate, address, size + Assembler::kGap, CodeObjectRequired::kNo) { 3174 // Create a new macro assembler pointing to the address of the code to patch. 3175 // The size is adjusted with kGap on order for the assembler to generate size 3176 // bytes of instructions without failing with buffer size constraints. 3177 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 3178} 3179 3180 3181CodePatcher::~CodePatcher() { 3182 // Indicate that code has changed. 3183 Assembler::FlushICache(masm_.isolate(), address_, size_); 3184 3185 // Check that the code was patched as expected. 3186 DCHECK(masm_.pc_ == address_ + size_); 3187 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); 3188} 3189 3190 3191void MacroAssembler::CheckPageFlag( 3192 Register object, 3193 Register scratch, 3194 int mask, 3195 Condition cc, 3196 Label* condition_met, 3197 Label::Distance condition_met_distance) { 3198 DCHECK(cc == zero || cc == not_zero); 3199 if (scratch.is(object)) { 3200 and_(scratch, Immediate(~Page::kPageAlignmentMask)); 3201 } else { 3202 mov(scratch, Immediate(~Page::kPageAlignmentMask)); 3203 and_(scratch, object); 3204 } 3205 if (mask < (1 << kBitsPerByte)) { 3206 test_b(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask)); 3207 } else { 3208 test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask)); 3209 } 3210 j(cc, condition_met, condition_met_distance); 3211} 3212 3213 3214void MacroAssembler::CheckPageFlagForMap( 3215 Handle<Map> map, 3216 int mask, 3217 Condition cc, 3218 Label* condition_met, 3219 Label::Distance condition_met_distance) { 3220 DCHECK(cc == zero || cc == not_zero); 3221 Page* page = Page::FromAddress(map->address()); 3222 DCHECK(!serializer_enabled()); // Serializer cannot match page_flags. 3223 ExternalReference reference(ExternalReference::page_flags(page)); 3224 // The inlined static address check of the page's flags relies 3225 // on maps never being compacted. 3226 DCHECK(!isolate()->heap()->mark_compact_collector()-> 3227 IsOnEvacuationCandidate(*map)); 3228 if (mask < (1 << kBitsPerByte)) { 3229 test_b(Operand::StaticVariable(reference), Immediate(mask)); 3230 } else { 3231 test(Operand::StaticVariable(reference), Immediate(mask)); 3232 } 3233 j(cc, condition_met, condition_met_distance); 3234} 3235 3236 3237void MacroAssembler::JumpIfBlack(Register object, 3238 Register scratch0, 3239 Register scratch1, 3240 Label* on_black, 3241 Label::Distance on_black_near) { 3242 HasColor(object, scratch0, scratch1, on_black, on_black_near, 1, 3243 1); // kBlackBitPattern. 3244 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 3245} 3246 3247 3248void MacroAssembler::HasColor(Register object, 3249 Register bitmap_scratch, 3250 Register mask_scratch, 3251 Label* has_color, 3252 Label::Distance has_color_distance, 3253 int first_bit, 3254 int second_bit) { 3255 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, ecx)); 3256 3257 GetMarkBits(object, bitmap_scratch, mask_scratch); 3258 3259 Label other_color, word_boundary; 3260 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); 3261 j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear); 3262 add(mask_scratch, mask_scratch); // Shift left 1 by adding. 3263 j(zero, &word_boundary, Label::kNear); 3264 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); 3265 j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance); 3266 jmp(&other_color, Label::kNear); 3267 3268 bind(&word_boundary); 3269 test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize), 3270 Immediate(1)); 3271 3272 j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance); 3273 bind(&other_color); 3274} 3275 3276 3277void MacroAssembler::GetMarkBits(Register addr_reg, 3278 Register bitmap_reg, 3279 Register mask_reg) { 3280 DCHECK(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx)); 3281 mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask)); 3282 and_(bitmap_reg, addr_reg); 3283 mov(ecx, addr_reg); 3284 int shift = 3285 Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2; 3286 shr(ecx, shift); 3287 and_(ecx, 3288 (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1)); 3289 3290 add(bitmap_reg, ecx); 3291 mov(ecx, addr_reg); 3292 shr(ecx, kPointerSizeLog2); 3293 and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1); 3294 mov(mask_reg, Immediate(1)); 3295 shl_cl(mask_reg); 3296} 3297 3298 3299void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch, 3300 Register mask_scratch, Label* value_is_white, 3301 Label::Distance distance) { 3302 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ecx)); 3303 GetMarkBits(value, bitmap_scratch, mask_scratch); 3304 3305 // If the value is black or grey we don't need to do anything. 3306 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); 3307 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); 3308 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); 3309 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); 3310 3311 // Since both black and grey have a 1 in the first position and white does 3312 // not have a 1 there we only need to check one bit. 3313 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); 3314 j(zero, value_is_white, Label::kNear); 3315} 3316 3317 3318void MacroAssembler::EnumLength(Register dst, Register map) { 3319 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0); 3320 mov(dst, FieldOperand(map, Map::kBitField3Offset)); 3321 and_(dst, Immediate(Map::EnumLengthBits::kMask)); 3322 SmiTag(dst); 3323} 3324 3325 3326void MacroAssembler::CheckEnumCache(Label* call_runtime) { 3327 Label next, start; 3328 mov(ecx, eax); 3329 3330 // Check if the enum length field is properly initialized, indicating that 3331 // there is an enum cache. 3332 mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); 3333 3334 EnumLength(edx, ebx); 3335 cmp(edx, Immediate(Smi::FromInt(kInvalidEnumCacheSentinel))); 3336 j(equal, call_runtime); 3337 3338 jmp(&start); 3339 3340 bind(&next); 3341 mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); 3342 3343 // For all objects but the receiver, check that the cache is empty. 3344 EnumLength(edx, ebx); 3345 cmp(edx, Immediate(Smi::FromInt(0))); 3346 j(not_equal, call_runtime); 3347 3348 bind(&start); 3349 3350 // Check that there are no elements. Register rcx contains the current JS 3351 // object we've reached through the prototype chain. 3352 Label no_elements; 3353 mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); 3354 cmp(ecx, isolate()->factory()->empty_fixed_array()); 3355 j(equal, &no_elements); 3356 3357 // Second chance, the object may be using the empty slow element dictionary. 3358 cmp(ecx, isolate()->factory()->empty_slow_element_dictionary()); 3359 j(not_equal, call_runtime); 3360 3361 bind(&no_elements); 3362 mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); 3363 cmp(ecx, isolate()->factory()->null_value()); 3364 j(not_equal, &next); 3365} 3366 3367 3368void MacroAssembler::TestJSArrayForAllocationMemento( 3369 Register receiver_reg, 3370 Register scratch_reg, 3371 Label* no_memento_found) { 3372 Label map_check; 3373 Label top_check; 3374 ExternalReference new_space_allocation_top = 3375 ExternalReference::new_space_allocation_top_address(isolate()); 3376 const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag; 3377 const int kMementoEndOffset = kMementoMapOffset + AllocationMemento::kSize; 3378 3379 // Bail out if the object is not in new space. 3380 JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found); 3381 // If the object is in new space, we need to check whether it is on the same 3382 // page as the current top. 3383 lea(scratch_reg, Operand(receiver_reg, kMementoEndOffset)); 3384 xor_(scratch_reg, Operand::StaticVariable(new_space_allocation_top)); 3385 test(scratch_reg, Immediate(~Page::kPageAlignmentMask)); 3386 j(zero, &top_check); 3387 // The object is on a different page than allocation top. Bail out if the 3388 // object sits on the page boundary as no memento can follow and we cannot 3389 // touch the memory following it. 3390 lea(scratch_reg, Operand(receiver_reg, kMementoEndOffset)); 3391 xor_(scratch_reg, receiver_reg); 3392 test(scratch_reg, Immediate(~Page::kPageAlignmentMask)); 3393 j(not_zero, no_memento_found); 3394 // Continue with the actual map check. 3395 jmp(&map_check); 3396 // If top is on the same page as the current object, we need to check whether 3397 // we are below top. 3398 bind(&top_check); 3399 lea(scratch_reg, Operand(receiver_reg, kMementoEndOffset)); 3400 cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top)); 3401 j(greater, no_memento_found); 3402 // Memento map check. 3403 bind(&map_check); 3404 mov(scratch_reg, Operand(receiver_reg, kMementoMapOffset)); 3405 cmp(scratch_reg, Immediate(isolate()->factory()->allocation_memento_map())); 3406} 3407 3408 3409void MacroAssembler::JumpIfDictionaryInPrototypeChain( 3410 Register object, 3411 Register scratch0, 3412 Register scratch1, 3413 Label* found) { 3414 DCHECK(!scratch1.is(scratch0)); 3415 Factory* factory = isolate()->factory(); 3416 Register current = scratch0; 3417 Label loop_again, end; 3418 3419 // scratch contained elements pointer. 3420 mov(current, object); 3421 mov(current, FieldOperand(current, HeapObject::kMapOffset)); 3422 mov(current, FieldOperand(current, Map::kPrototypeOffset)); 3423 cmp(current, Immediate(factory->null_value())); 3424 j(equal, &end); 3425 3426 // Loop based on the map going up the prototype chain. 3427 bind(&loop_again); 3428 mov(current, FieldOperand(current, HeapObject::kMapOffset)); 3429 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE); 3430 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE); 3431 CmpInstanceType(current, JS_OBJECT_TYPE); 3432 j(below, found); 3433 mov(scratch1, FieldOperand(current, Map::kBitField2Offset)); 3434 DecodeField<Map::ElementsKindBits>(scratch1); 3435 cmp(scratch1, Immediate(DICTIONARY_ELEMENTS)); 3436 j(equal, found); 3437 mov(current, FieldOperand(current, Map::kPrototypeOffset)); 3438 cmp(current, Immediate(factory->null_value())); 3439 j(not_equal, &loop_again); 3440 3441 bind(&end); 3442} 3443 3444 3445void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) { 3446 DCHECK(!dividend.is(eax)); 3447 DCHECK(!dividend.is(edx)); 3448 base::MagicNumbersForDivision<uint32_t> mag = 3449 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor)); 3450 mov(eax, Immediate(mag.multiplier)); 3451 imul(dividend); 3452 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0; 3453 if (divisor > 0 && neg) add(edx, dividend); 3454 if (divisor < 0 && !neg && mag.multiplier > 0) sub(edx, dividend); 3455 if (mag.shift > 0) sar(edx, mag.shift); 3456 mov(eax, dividend); 3457 shr(eax, 31); 3458 add(edx, eax); 3459} 3460 3461 3462} // namespace internal 3463} // namespace v8 3464 3465#endif // V8_TARGET_ARCH_IA32 3466