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