OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 __ j(above_equal, &slow); | 355 __ j(above_equal, &slow); |
356 __ movl(rax, rbx); | 356 __ movl(rax, rbx); |
357 __ and_(rax, Immediate((1 << String::kShortLengthShift) - 1)); | 357 __ and_(rax, Immediate((1 << String::kShortLengthShift) - 1)); |
358 __ shrl(rax, Immediate(String::kLongLengthShift)); | 358 __ shrl(rax, Immediate(String::kLongLengthShift)); |
359 __ jmp(&index_int); | 359 __ jmp(&index_int); |
360 } | 360 } |
361 | 361 |
362 | 362 |
363 void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, | 363 void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, |
364 ExternalArrayType array_type) { | 364 ExternalArrayType array_type) { |
365 GenerateGeneric(masm); | 365 // ----------- S t a t e ------------- |
| 366 // -- rsp[0] : return address |
| 367 // -- rsp[8] : name |
| 368 // -- rsp[16] : receiver |
| 369 // ----------------------------------- |
| 370 Label slow, failed_allocation; |
| 371 |
| 372 // Load name and receiver. |
| 373 __ movq(rax, Operand(rsp, kPointerSize)); |
| 374 __ movq(rcx, Operand(rsp, 2 * kPointerSize)); |
| 375 |
| 376 // Check that the object isn't a smi. |
| 377 __ JumpIfSmi(rcx, &slow); |
| 378 |
| 379 // Check that the key is a smi. |
| 380 __ JumpIfNotSmi(rax, &slow); |
| 381 |
| 382 // Check that the object is a JS object. |
| 383 __ CmpObjectType(rcx, JS_OBJECT_TYPE, rdx); |
| 384 __ j(not_equal, &slow); |
| 385 // Check that the receiver does not require access checks. We need |
| 386 // to check this explicitly since this generic stub does not perform |
| 387 // map checks. The map is already in rdx. |
| 388 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 389 Immediate(1 << Map::kIsAccessCheckNeeded)); |
| 390 __ j(not_zero, &slow); |
| 391 |
| 392 // Check that the elements array is the appropriate type of |
| 393 // ExternalArray. |
| 394 // rax: index (as a smi) |
| 395 // rcx: JSObject |
| 396 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 397 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), |
| 398 Heap::RootIndexForExternalArrayType(array_type)); |
| 399 __ j(not_equal, &slow); |
| 400 |
| 401 // Check that the index is in range. |
| 402 __ SmiToInteger32(rax, rax); |
| 403 __ cmpl(rax, FieldOperand(rcx, ExternalArray::kLengthOffset)); |
| 404 // Unsigned comparison catches both negative and too-large values. |
| 405 __ j(above_equal, &slow); |
| 406 |
| 407 // rax: untagged index |
| 408 // rcx: elements array |
| 409 __ movq(rcx, FieldOperand(rcx, ExternalArray::kExternalPointerOffset)); |
| 410 // rcx: base pointer of external storage |
| 411 switch (array_type) { |
| 412 case kExternalByteArray: |
| 413 __ movsxbq(rax, Operand(rcx, rax, times_1, 0)); |
| 414 break; |
| 415 case kExternalUnsignedByteArray: |
| 416 __ movb(rax, Operand(rcx, rax, times_1, 0)); |
| 417 break; |
| 418 case kExternalShortArray: |
| 419 __ movsxwq(rax, Operand(rcx, rax, times_2, 0)); |
| 420 break; |
| 421 case kExternalUnsignedShortArray: |
| 422 __ movzxwq(rax, Operand(rcx, rax, times_2, 0)); |
| 423 break; |
| 424 case kExternalIntArray: |
| 425 __ movsxlq(rax, Operand(rcx, rax, times_4, 0)); |
| 426 break; |
| 427 case kExternalUnsignedIntArray: |
| 428 __ movl(rax, Operand(rcx, rax, times_4, 0)); |
| 429 break; |
| 430 case kExternalFloatArray: |
| 431 __ fld_s(Operand(rcx, rax, times_4, 0)); |
| 432 break; |
| 433 default: |
| 434 UNREACHABLE(); |
| 435 break; |
| 436 } |
| 437 |
| 438 // For integer array types: |
| 439 // rax: value |
| 440 // For floating-point array type: |
| 441 // FP(0): value |
| 442 |
| 443 if (array_type == kExternalIntArray || |
| 444 array_type == kExternalUnsignedIntArray) { |
| 445 |
| 446 // For the Int and UnsignedInt array types, we need to see whether |
| 447 // the value can be represented in a Smi. If not, we need to convert |
| 448 // it to a HeapNumber. |
| 449 Label box_int; |
| 450 if (array_type == kExternalIntArray) { |
| 451 __ JumpIfNotValidSmiValue(rax, &box_int); |
| 452 } else { |
| 453 ASSERT_EQ(array_type, kExternalUnsignedIntArray); |
| 454 __ JumpIfUIntNotValidSmiValue(rax, &box_int); |
| 455 } |
| 456 |
| 457 __ Integer32ToSmi(rax, rax); |
| 458 __ ret(0); |
| 459 |
| 460 __ bind(&box_int); |
| 461 |
| 462 // Allocate a HeapNumber for the int and perform int-to-double |
| 463 // conversion. |
| 464 __ push(rax); |
| 465 if (array_type == kExternalIntArray) { |
| 466 __ fild_s(Operand(rsp, 0)); |
| 467 } else { |
| 468 ASSERT(array_type == kExternalUnsignedIntArray); |
| 469 // Need to zero-extend the value. |
| 470 __ fild_d(Operand(rsp, 0)); |
| 471 } |
| 472 __ pop(rax); |
| 473 // FP(0): value |
| 474 __ AllocateHeapNumber(rax, rbx, &failed_allocation); |
| 475 // Set the value. |
| 476 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
| 477 __ ret(0); |
| 478 } else if (array_type == kExternalFloatArray) { |
| 479 // For the floating-point array type, we need to always allocate a |
| 480 // HeapNumber. |
| 481 __ AllocateHeapNumber(rax, rbx, &failed_allocation); |
| 482 // Set the value. |
| 483 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
| 484 __ ret(0); |
| 485 } else { |
| 486 __ Integer32ToSmi(rax, rax); |
| 487 __ ret(0); |
| 488 } |
| 489 |
| 490 // If we fail allocation of the HeapNumber, we still have a value on |
| 491 // top of the FPU stack. Remove it. |
| 492 __ bind(&failed_allocation); |
| 493 __ ffree(); |
| 494 __ fincstp(); |
| 495 // Fall through to slow case. |
| 496 |
| 497 // Slow case: Load name and receiver from stack and jump to runtime. |
| 498 __ bind(&slow); |
| 499 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1); |
| 500 Generate(masm, ExternalReference(Runtime::kKeyedGetProperty)); |
366 } | 501 } |
367 | 502 |
368 | 503 |
369 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 504 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
370 // ----------- S t a t e ------------- | 505 // ----------- S t a t e ------------- |
371 // -- rsp[0] : return address | 506 // -- rsp[0] : return address |
372 // -- rsp[8] : name | 507 // -- rsp[8] : name |
373 // -- rsp[16] : receiver | 508 // -- rsp[16] : receiver |
374 // ----------------------------------- | 509 // ----------------------------------- |
375 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); | 510 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 FixedArray::kHeaderSize - kHeapObjectTag), | 688 FixedArray::kHeaderSize - kHeapObjectTag), |
554 rax); | 689 rax); |
555 __ movq(rdx, rax); | 690 __ movq(rdx, rax); |
556 __ RecordWriteNonSmi(rcx, 0, rdx, rbx); | 691 __ RecordWriteNonSmi(rcx, 0, rdx, rbx); |
557 __ ret(0); | 692 __ ret(0); |
558 } | 693 } |
559 | 694 |
560 | 695 |
561 void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, | 696 void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, |
562 ExternalArrayType array_type) { | 697 ExternalArrayType array_type) { |
563 GenerateGeneric(masm); | 698 // ----------- S t a t e ------------- |
| 699 // -- rax : value |
| 700 // -- rsp[0] : return address |
| 701 // -- rsp[8] : key |
| 702 // -- rsp[16] : receiver |
| 703 // ----------------------------------- |
| 704 Label slow, check_heap_number; |
| 705 |
| 706 // Get the receiver from the stack. |
| 707 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); |
| 708 // Check that the object isn't a smi. |
| 709 __ JumpIfSmi(rdx, &slow); |
| 710 // Get the map from the receiver. |
| 711 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 712 // Check that the receiver does not require access checks. We need |
| 713 // to do this because this generic stub does not perform map checks. |
| 714 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), |
| 715 Immediate(1 << Map::kIsAccessCheckNeeded)); |
| 716 __ j(not_zero, &slow); |
| 717 // Get the key from the stack. |
| 718 __ movq(rbx, Operand(rsp, 1 * kPointerSize)); // 1 ~ return address |
| 719 // Check that the key is a smi. |
| 720 __ JumpIfNotSmi(rbx, &slow); |
| 721 |
| 722 // Check that the object is a JS object. |
| 723 __ CmpInstanceType(rcx, JS_OBJECT_TYPE); |
| 724 __ j(not_equal, &slow); |
| 725 |
| 726 // Check that the elements array is the appropriate type of |
| 727 // ExternalArray. |
| 728 // rax: value |
| 729 // rdx: JSObject |
| 730 // rbx: index (as a smi) |
| 731 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 732 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), |
| 733 Heap::RootIndexForExternalArrayType(array_type)); |
| 734 __ j(not_equal, &slow); |
| 735 |
| 736 // Check that the index is in range. |
| 737 __ SmiToInteger32(rbx, rbx); // Untag the index. |
| 738 __ cmpl(rbx, FieldOperand(rcx, ExternalArray::kLengthOffset)); |
| 739 // Unsigned comparison catches both negative and too-large values. |
| 740 __ j(above_equal, &slow); |
| 741 |
| 742 // Handle both smis and HeapNumbers in the fast path. Go to the |
| 743 // runtime for all other kinds of values. |
| 744 // rax: value |
| 745 // rcx: elements array |
| 746 // rbx: untagged index |
| 747 __ JumpIfNotSmi(rax, &check_heap_number); |
| 748 __ movq(rdx, rax); // Save the value. |
| 749 __ SmiToInteger32(rax, rax); |
| 750 __ movq(rcx, FieldOperand(rcx, ExternalArray::kExternalPointerOffset)); |
| 751 // rcx: base pointer of external storage |
| 752 switch (array_type) { |
| 753 case kExternalByteArray: |
| 754 case kExternalUnsignedByteArray: |
| 755 __ movb(Operand(rcx, rbx, times_1, 0), rax); |
| 756 break; |
| 757 case kExternalShortArray: |
| 758 case kExternalUnsignedShortArray: |
| 759 __ movw(Operand(rcx, rbx, times_2, 0), rax); |
| 760 break; |
| 761 case kExternalIntArray: |
| 762 case kExternalUnsignedIntArray: |
| 763 __ movl(Operand(rcx, rbx, times_4, 0), rax); |
| 764 break; |
| 765 case kExternalFloatArray: |
| 766 // Need to perform int-to-float conversion. |
| 767 __ push(rax); |
| 768 __ fild_s(Operand(rsp, 0)); |
| 769 __ pop(rax); |
| 770 __ fstp_s(Operand(rcx, rbx, times_4, 0)); |
| 771 break; |
| 772 default: |
| 773 UNREACHABLE(); |
| 774 break; |
| 775 } |
| 776 __ movq(rax, rdx); // Return the original value. |
| 777 __ ret(0); |
| 778 |
| 779 __ bind(&check_heap_number); |
| 780 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rdx); |
| 781 __ j(not_equal, &slow); |
| 782 |
| 783 // The WebGL specification leaves the behavior of storing NaN and |
| 784 // +/-Infinity into integer arrays basically undefined. For more |
| 785 // reproducible behavior, convert these to zero. |
| 786 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
| 787 __ movq(rdx, rax); // Save the value. |
| 788 __ movq(rcx, FieldOperand(rcx, ExternalArray::kExternalPointerOffset)); |
| 789 // rbx: untagged index |
| 790 // rcx: base pointer of external storage |
| 791 // top of FPU stack: value |
| 792 if (array_type == kExternalFloatArray) { |
| 793 __ fstp_s(Operand(rcx, rbx, times_4, 0)); |
| 794 } else { |
| 795 // Need to perform float-to-int conversion. |
| 796 // Test the top of the FP stack for NaN. |
| 797 Label is_nan; |
| 798 __ fucomi(0); |
| 799 __ j(parity_even, &is_nan); |
| 800 |
| 801 __ push(rax); // Make room on stack |
| 802 __ fistp_d(Operand(rsp, 0)); |
| 803 __ pop(rax); |
| 804 // rax: untagged integer value |
| 805 switch (array_type) { |
| 806 case kExternalByteArray: |
| 807 case kExternalUnsignedByteArray: |
| 808 __ movb(Operand(rcx, rbx, times_1, 0), rax); |
| 809 break; |
| 810 case kExternalShortArray: |
| 811 case kExternalUnsignedShortArray: |
| 812 __ movw(Operand(rcx, rbx, times_2, 0), rax); |
| 813 break; |
| 814 case kExternalIntArray: |
| 815 case kExternalUnsignedIntArray: { |
| 816 // We also need to explicitly check for +/-Infinity. These are |
| 817 // converted to MIN_INT, but we need to be careful not to |
| 818 // confuse with legal uses of MIN_INT. |
| 819 Label not_infinity; |
| 820 // This test would apparently detect both NaN and Infinity, |
| 821 // but we've already checked for NaN using the FPU hardware |
| 822 // above. |
| 823 __ movzxwq(rdi, FieldOperand(rdx, HeapNumber::kValueOffset + 6)); |
| 824 __ and_(rdi, Immediate(0x7FF0)); |
| 825 __ cmpw(rdi, Immediate(0x7FF0)); |
| 826 __ j(not_equal, ¬_infinity); |
| 827 __ movq(rax, Immediate(0)); |
| 828 __ bind(¬_infinity); |
| 829 __ movl(Operand(rcx, rbx, times_4, 0), rax); |
| 830 break; |
| 831 } |
| 832 default: |
| 833 UNREACHABLE(); |
| 834 break; |
| 835 } |
| 836 __ movq(rax, rdx); // Return the original value. |
| 837 __ ret(0); |
| 838 |
| 839 __ bind(&is_nan); |
| 840 __ ffree(); |
| 841 __ fincstp(); |
| 842 __ movq(rax, Immediate(0)); |
| 843 switch (array_type) { |
| 844 case kExternalByteArray: |
| 845 case kExternalUnsignedByteArray: |
| 846 __ movb(Operand(rcx, rbx, times_1, 0), rax); |
| 847 break; |
| 848 case kExternalShortArray: |
| 849 case kExternalUnsignedShortArray: |
| 850 __ movw(Operand(rcx, rbx, times_2, 0), rax); |
| 851 break; |
| 852 case kExternalIntArray: |
| 853 case kExternalUnsignedIntArray: |
| 854 __ movl(Operand(rcx, rbx, times_4, 0), rax); |
| 855 break; |
| 856 default: |
| 857 UNREACHABLE(); |
| 858 break; |
| 859 } |
| 860 __ movq(rax, rdx); // Return the original value. |
| 861 __ ret(0); |
| 862 } |
| 863 |
| 864 // Slow case: call runtime. |
| 865 __ bind(&slow); |
| 866 Generate(masm, ExternalReference(Runtime::kSetProperty)); |
564 } | 867 } |
565 | 868 |
566 | 869 |
567 void CallIC::Generate(MacroAssembler* masm, | 870 void CallIC::Generate(MacroAssembler* masm, |
568 int argc, | 871 int argc, |
569 ExternalReference const& f) { | 872 ExternalReference const& f) { |
570 // Get the receiver of the function from the stack; 1 ~ return address. | 873 // Get the receiver of the function from the stack; 1 ~ return address. |
571 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | 874 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
572 // Get the name of the function to call from the stack. | 875 // Get the name of the function to call from the stack. |
573 // 2 ~ receiver, return address. | 876 // 2 ~ receiver, return address. |
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1023 | 1326 |
1024 // Cache miss: Jump to runtime. | 1327 // Cache miss: Jump to runtime. |
1025 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); | 1328 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); |
1026 } | 1329 } |
1027 | 1330 |
1028 | 1331 |
1029 #undef __ | 1332 #undef __ |
1030 | 1333 |
1031 | 1334 |
1032 } } // namespace v8::internal | 1335 } } // namespace v8::internal |
OLD | NEW |