| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/arm/codegen-arm.h" | 5 #include "src/arm/codegen-arm.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_ARM | 7 #if V8_TARGET_ARCH_ARM |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 | 10 |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 DCHECK(masm->has_frame()); | 310 DCHECK(masm->has_frame()); |
| 311 masm->set_has_frame(false); | 311 masm->set_has_frame(false); |
| 312 } | 312 } |
| 313 | 313 |
| 314 | 314 |
| 315 // ------------------------------------------------------------------------- | 315 // ------------------------------------------------------------------------- |
| 316 // Code generators | 316 // Code generators |
| 317 | 317 |
| 318 #define __ ACCESS_MASM(masm) | 318 #define __ ACCESS_MASM(masm) |
| 319 | 319 |
| 320 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( | |
| 321 MacroAssembler* masm, | |
| 322 Register receiver, | |
| 323 Register key, | |
| 324 Register value, | |
| 325 Register target_map, | |
| 326 AllocationSiteMode mode, | |
| 327 Label* allocation_memento_found) { | |
| 328 Register scratch_elements = r4; | |
| 329 DCHECK(!AreAliased(receiver, key, value, target_map, | |
| 330 scratch_elements)); | |
| 331 | |
| 332 if (mode == TRACK_ALLOCATION_SITE) { | |
| 333 DCHECK(allocation_memento_found != NULL); | |
| 334 __ JumpIfJSArrayHasAllocationMemento( | |
| 335 receiver, scratch_elements, allocation_memento_found); | |
| 336 } | |
| 337 | |
| 338 // Set transitioned map. | |
| 339 __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 340 __ RecordWriteField(receiver, | |
| 341 HeapObject::kMapOffset, | |
| 342 target_map, | |
| 343 r9, | |
| 344 kLRHasNotBeenSaved, | |
| 345 kDontSaveFPRegs, | |
| 346 EMIT_REMEMBERED_SET, | |
| 347 OMIT_SMI_CHECK); | |
| 348 } | |
| 349 | |
| 350 | |
| 351 void ElementsTransitionGenerator::GenerateSmiToDouble( | |
| 352 MacroAssembler* masm, | |
| 353 Register receiver, | |
| 354 Register key, | |
| 355 Register value, | |
| 356 Register target_map, | |
| 357 AllocationSiteMode mode, | |
| 358 Label* fail) { | |
| 359 // Register lr contains the return address. | |
| 360 Label loop, entry, convert_hole, gc_required, only_change_map, done; | |
| 361 Register elements = r4; | |
| 362 Register length = r5; | |
| 363 Register array = r6; | |
| 364 Register array_end = array; | |
| 365 | |
| 366 // target_map parameter can be clobbered. | |
| 367 Register scratch1 = target_map; | |
| 368 Register scratch2 = r9; | |
| 369 | |
| 370 // Verify input registers don't conflict with locals. | |
| 371 DCHECK(!AreAliased(receiver, key, value, target_map, | |
| 372 elements, length, array, scratch2)); | |
| 373 | |
| 374 if (mode == TRACK_ALLOCATION_SITE) { | |
| 375 __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail); | |
| 376 } | |
| 377 | |
| 378 // Check for empty arrays, which only require a map transition and no changes | |
| 379 // to the backing store. | |
| 380 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 381 __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex); | |
| 382 __ b(eq, &only_change_map); | |
| 383 | |
| 384 __ push(lr); | |
| 385 __ ldr(length, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 386 // length: number of elements (smi-tagged) | |
| 387 | |
| 388 // Allocate new FixedDoubleArray. | |
| 389 // Use lr as a temporary register. | |
| 390 __ mov(lr, Operand(length, LSL, 2)); | |
| 391 __ add(lr, lr, Operand(FixedDoubleArray::kHeaderSize)); | |
| 392 __ Allocate(lr, array, elements, scratch2, &gc_required, DOUBLE_ALIGNMENT); | |
| 393 __ sub(array, array, Operand(kHeapObjectTag)); | |
| 394 // array: destination FixedDoubleArray, not tagged as heap object. | |
| 395 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 396 // r4: source FixedArray. | |
| 397 | |
| 398 // Set destination FixedDoubleArray's length and map. | |
| 399 __ LoadRoot(scratch2, Heap::kFixedDoubleArrayMapRootIndex); | |
| 400 __ str(length, MemOperand(array, FixedDoubleArray::kLengthOffset)); | |
| 401 // Update receiver's map. | |
| 402 __ str(scratch2, MemOperand(array, HeapObject::kMapOffset)); | |
| 403 | |
| 404 __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 405 __ RecordWriteField(receiver, | |
| 406 HeapObject::kMapOffset, | |
| 407 target_map, | |
| 408 scratch2, | |
| 409 kLRHasBeenSaved, | |
| 410 kDontSaveFPRegs, | |
| 411 OMIT_REMEMBERED_SET, | |
| 412 OMIT_SMI_CHECK); | |
| 413 // Replace receiver's backing store with newly created FixedDoubleArray. | |
| 414 __ add(scratch1, array, Operand(kHeapObjectTag)); | |
| 415 __ str(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 416 __ RecordWriteField(receiver, | |
| 417 JSObject::kElementsOffset, | |
| 418 scratch1, | |
| 419 scratch2, | |
| 420 kLRHasBeenSaved, | |
| 421 kDontSaveFPRegs, | |
| 422 EMIT_REMEMBERED_SET, | |
| 423 OMIT_SMI_CHECK); | |
| 424 | |
| 425 // Prepare for conversion loop. | |
| 426 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 427 __ add(scratch2, array, Operand(FixedDoubleArray::kHeaderSize)); | |
| 428 __ add(array_end, scratch2, Operand(length, LSL, 2)); | |
| 429 | |
| 430 // Repurpose registers no longer in use. | |
| 431 Register hole_lower = elements; | |
| 432 Register hole_upper = length; | |
| 433 | |
| 434 __ mov(hole_lower, Operand(kHoleNanLower32)); | |
| 435 __ mov(hole_upper, Operand(kHoleNanUpper32)); | |
| 436 // scratch1: begin of source FixedArray element fields, not tagged | |
| 437 // hole_lower: kHoleNanLower32 | |
| 438 // hole_upper: kHoleNanUpper32 | |
| 439 // array_end: end of destination FixedDoubleArray, not tagged | |
| 440 // scratch2: begin of FixedDoubleArray element fields, not tagged | |
| 441 | |
| 442 __ b(&entry); | |
| 443 | |
| 444 __ bind(&only_change_map); | |
| 445 __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 446 __ RecordWriteField(receiver, | |
| 447 HeapObject::kMapOffset, | |
| 448 target_map, | |
| 449 scratch2, | |
| 450 kLRHasNotBeenSaved, | |
| 451 kDontSaveFPRegs, | |
| 452 OMIT_REMEMBERED_SET, | |
| 453 OMIT_SMI_CHECK); | |
| 454 __ b(&done); | |
| 455 | |
| 456 // Call into runtime if GC is required. | |
| 457 __ bind(&gc_required); | |
| 458 __ pop(lr); | |
| 459 __ b(fail); | |
| 460 | |
| 461 // Convert and copy elements. | |
| 462 __ bind(&loop); | |
| 463 __ ldr(lr, MemOperand(scratch1, 4, PostIndex)); | |
| 464 // lr: current element | |
| 465 __ UntagAndJumpIfNotSmi(lr, lr, &convert_hole); | |
| 466 | |
| 467 // Normal smi, convert to double and store. | |
| 468 __ vmov(s0, lr); | |
| 469 __ vcvt_f64_s32(d0, s0); | |
| 470 __ vstr(d0, scratch2, 0); | |
| 471 __ add(scratch2, scratch2, Operand(8)); | |
| 472 __ b(&entry); | |
| 473 | |
| 474 // Hole found, store the-hole NaN. | |
| 475 __ bind(&convert_hole); | |
| 476 if (FLAG_debug_code) { | |
| 477 // Restore a "smi-untagged" heap object. | |
| 478 __ SmiTag(lr); | |
| 479 __ orr(lr, lr, Operand(1)); | |
| 480 __ CompareRoot(lr, Heap::kTheHoleValueRootIndex); | |
| 481 __ Assert(eq, kObjectFoundInSmiOnlyArray); | |
| 482 } | |
| 483 __ Strd(hole_lower, hole_upper, MemOperand(scratch2, 8, PostIndex)); | |
| 484 | |
| 485 __ bind(&entry); | |
| 486 __ cmp(scratch2, array_end); | |
| 487 __ b(lt, &loop); | |
| 488 | |
| 489 __ pop(lr); | |
| 490 __ bind(&done); | |
| 491 } | |
| 492 | |
| 493 | |
| 494 void ElementsTransitionGenerator::GenerateDoubleToObject( | |
| 495 MacroAssembler* masm, | |
| 496 Register receiver, | |
| 497 Register key, | |
| 498 Register value, | |
| 499 Register target_map, | |
| 500 AllocationSiteMode mode, | |
| 501 Label* fail) { | |
| 502 // Register lr contains the return address. | |
| 503 Label entry, loop, convert_hole, gc_required, only_change_map; | |
| 504 Register elements = r4; | |
| 505 Register array = r6; | |
| 506 Register length = r5; | |
| 507 Register scratch = r9; | |
| 508 | |
| 509 // Verify input registers don't conflict with locals. | |
| 510 DCHECK(!AreAliased(receiver, key, value, target_map, | |
| 511 elements, array, length, scratch)); | |
| 512 | |
| 513 if (mode == TRACK_ALLOCATION_SITE) { | |
| 514 __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail); | |
| 515 } | |
| 516 | |
| 517 // Check for empty arrays, which only require a map transition and no changes | |
| 518 // to the backing store. | |
| 519 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 520 __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex); | |
| 521 __ b(eq, &only_change_map); | |
| 522 | |
| 523 __ push(lr); | |
| 524 __ Push(target_map, receiver, key, value); | |
| 525 __ ldr(length, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 526 // elements: source FixedDoubleArray | |
| 527 // length: number of elements (smi-tagged) | |
| 528 | |
| 529 // Allocate new FixedArray. | |
| 530 // Re-use value and target_map registers, as they have been saved on the | |
| 531 // stack. | |
| 532 Register array_size = value; | |
| 533 Register allocate_scratch = target_map; | |
| 534 __ mov(array_size, Operand(FixedDoubleArray::kHeaderSize)); | |
| 535 __ add(array_size, array_size, Operand(length, LSL, 1)); | |
| 536 __ Allocate(array_size, array, allocate_scratch, scratch, &gc_required, | |
| 537 NO_ALLOCATION_FLAGS); | |
| 538 // array: destination FixedArray, tagged as heap object | |
| 539 // Set destination FixedDoubleArray's length and map. | |
| 540 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex); | |
| 541 __ str(length, FieldMemOperand(array, FixedDoubleArray::kLengthOffset)); | |
| 542 __ str(scratch, FieldMemOperand(array, HeapObject::kMapOffset)); | |
| 543 | |
| 544 __ sub(array, array, Operand(kHeapObjectTag)); | |
| 545 | |
| 546 // Prepare for conversion loop. | |
| 547 Register src_elements = elements; | |
| 548 Register dst_elements = target_map; | |
| 549 Register dst_end = length; | |
| 550 Register heap_number_map = scratch; | |
| 551 __ add(src_elements, elements, | |
| 552 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag + 4)); | |
| 553 __ add(dst_elements, array, Operand(FixedArray::kHeaderSize)); | |
| 554 __ add(dst_end, dst_elements, Operand(length, LSL, 1)); | |
| 555 | |
| 556 // Allocating heap numbers in the loop below can fail and cause a jump to | |
| 557 // gc_required. We can't leave a partly initialized FixedArray behind, | |
| 558 // so pessimistically fill it with holes now. | |
| 559 Label initialization_loop, initialization_loop_entry; | |
| 560 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); | |
| 561 __ b(&initialization_loop_entry); | |
| 562 __ bind(&initialization_loop); | |
| 563 __ str(scratch, MemOperand(dst_elements, kPointerSize, PostIndex)); | |
| 564 __ bind(&initialization_loop_entry); | |
| 565 __ cmp(dst_elements, dst_end); | |
| 566 __ b(lt, &initialization_loop); | |
| 567 | |
| 568 __ add(dst_elements, array, Operand(FixedArray::kHeaderSize)); | |
| 569 __ add(array, array, Operand(kHeapObjectTag)); | |
| 570 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
| 571 // Using offsetted addresses in src_elements to fully take advantage of | |
| 572 // post-indexing. | |
| 573 // dst_elements: begin of destination FixedArray element fields, not tagged | |
| 574 // src_elements: begin of source FixedDoubleArray element fields, | |
| 575 // not tagged, +4 | |
| 576 // dst_end: end of destination FixedArray, not tagged | |
| 577 // array: destination FixedArray | |
| 578 // heap_number_map: heap number map | |
| 579 __ b(&entry); | |
| 580 | |
| 581 // Call into runtime if GC is required. | |
| 582 __ bind(&gc_required); | |
| 583 __ Pop(target_map, receiver, key, value); | |
| 584 __ pop(lr); | |
| 585 __ b(fail); | |
| 586 | |
| 587 __ bind(&loop); | |
| 588 Register upper_bits = key; | |
| 589 __ ldr(upper_bits, MemOperand(src_elements, 8, PostIndex)); | |
| 590 // upper_bits: current element's upper 32 bit | |
| 591 // src_elements: address of next element's upper 32 bit | |
| 592 __ cmp(upper_bits, Operand(kHoleNanUpper32)); | |
| 593 __ b(eq, &convert_hole); | |
| 594 | |
| 595 // Non-hole double, copy value into a heap number. | |
| 596 Register heap_number = receiver; | |
| 597 Register scratch2 = value; | |
| 598 __ AllocateHeapNumber(heap_number, scratch2, lr, heap_number_map, | |
| 599 &gc_required); | |
| 600 // heap_number: new heap number | |
| 601 __ ldr(scratch2, MemOperand(src_elements, 12, NegOffset)); | |
| 602 __ Strd(scratch2, upper_bits, | |
| 603 FieldMemOperand(heap_number, HeapNumber::kValueOffset)); | |
| 604 __ mov(scratch2, dst_elements); | |
| 605 __ str(heap_number, MemOperand(dst_elements, 4, PostIndex)); | |
| 606 __ RecordWrite(array, | |
| 607 scratch2, | |
| 608 heap_number, | |
| 609 kLRHasBeenSaved, | |
| 610 kDontSaveFPRegs, | |
| 611 EMIT_REMEMBERED_SET, | |
| 612 OMIT_SMI_CHECK); | |
| 613 __ b(&entry); | |
| 614 | |
| 615 // Replace the-hole NaN with the-hole pointer. | |
| 616 __ bind(&convert_hole); | |
| 617 __ LoadRoot(scratch2, Heap::kTheHoleValueRootIndex); | |
| 618 __ str(scratch2, MemOperand(dst_elements, 4, PostIndex)); | |
| 619 | |
| 620 __ bind(&entry); | |
| 621 __ cmp(dst_elements, dst_end); | |
| 622 __ b(lt, &loop); | |
| 623 | |
| 624 __ Pop(target_map, receiver, key, value); | |
| 625 // Replace receiver's backing store with newly created and filled FixedArray. | |
| 626 __ str(array, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
| 627 __ RecordWriteField(receiver, | |
| 628 JSObject::kElementsOffset, | |
| 629 array, | |
| 630 scratch, | |
| 631 kLRHasBeenSaved, | |
| 632 kDontSaveFPRegs, | |
| 633 EMIT_REMEMBERED_SET, | |
| 634 OMIT_SMI_CHECK); | |
| 635 __ pop(lr); | |
| 636 | |
| 637 __ bind(&only_change_map); | |
| 638 // Update receiver's map. | |
| 639 __ str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 640 __ RecordWriteField(receiver, | |
| 641 HeapObject::kMapOffset, | |
| 642 target_map, | |
| 643 scratch, | |
| 644 kLRHasNotBeenSaved, | |
| 645 kDontSaveFPRegs, | |
| 646 OMIT_REMEMBERED_SET, | |
| 647 OMIT_SMI_CHECK); | |
| 648 } | |
| 649 | |
| 650 | |
| 651 void StringCharLoadGenerator::Generate(MacroAssembler* masm, | 320 void StringCharLoadGenerator::Generate(MacroAssembler* masm, |
| 652 Register string, | 321 Register string, |
| 653 Register index, | 322 Register index, |
| 654 Register result, | 323 Register result, |
| 655 Label* call_runtime) { | 324 Label* call_runtime) { |
| 656 // Fetch the instance type of the receiver into result register. | 325 // Fetch the instance type of the receiver into result register. |
| 657 __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); | 326 __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
| 658 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); | 327 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
| 659 | 328 |
| 660 // We need special handling for indirect strings. | 329 // We need special handling for indirect strings. |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 802 patcher.masm()->ldr(pc, MemOperand(pc, -4)); | 471 patcher.masm()->ldr(pc, MemOperand(pc, -4)); |
| 803 patcher.masm()->emit_code_stub_address(stub); | 472 patcher.masm()->emit_code_stub_address(stub); |
| 804 } | 473 } |
| 805 } | 474 } |
| 806 | 475 |
| 807 | 476 |
| 808 } // namespace internal | 477 } // namespace internal |
| 809 } // namespace v8 | 478 } // namespace v8 |
| 810 | 479 |
| 811 #endif // V8_TARGET_ARCH_ARM | 480 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |