Mercurial > hg > truffle
comparison src/cpu/x86/vm/stubGenerator_x86_64.cpp @ 2029:6ce496c8fc07
Merge
author | coleenp |
---|---|
date | Thu, 16 Dec 2010 09:31:55 -0500 |
parents | bbefa3ca1543 |
children | d89a22843c62 |
comparison
equal
deleted
inserted
replaced
2028:450ece4d8a10 | 2029:6ce496c8fc07 |
---|---|
2195 StubCodeMark mark(this, "StubRoutines", name); | 2195 StubCodeMark mark(this, "StubRoutines", name); |
2196 address start = __ pc(); | 2196 address start = __ pc(); |
2197 | 2197 |
2198 __ enter(); // required for proper stackwalking of RuntimeStub frame | 2198 __ enter(); // required for proper stackwalking of RuntimeStub frame |
2199 | 2199 |
2200 checkcast_copy_entry = __ pc(); | |
2201 BLOCK_COMMENT("Entry:"); | |
2202 | |
2203 #ifdef ASSERT | 2200 #ifdef ASSERT |
2204 // caller guarantees that the arrays really are different | 2201 // caller guarantees that the arrays really are different |
2205 // otherwise, we would have to make conjoint checks | 2202 // otherwise, we would have to make conjoint checks |
2206 { Label L; | 2203 { Label L; |
2207 array_overlap_test(L, TIMES_OOP); | 2204 array_overlap_test(L, TIMES_OOP); |
2208 __ stop("checkcast_copy within a single array"); | 2205 __ stop("checkcast_copy within a single array"); |
2209 __ bind(L); | 2206 __ bind(L); |
2210 } | 2207 } |
2211 #endif //ASSERT | 2208 #endif //ASSERT |
2212 | 2209 |
2213 // allocate spill slots for r13, r14 | |
2214 enum { | |
2215 saved_r13_offset, | |
2216 saved_r14_offset, | |
2217 saved_rbp_offset, | |
2218 saved_rip_offset, | |
2219 saved_rarg0_offset | |
2220 }; | |
2221 __ subptr(rsp, saved_rbp_offset * wordSize); | |
2222 __ movptr(Address(rsp, saved_r13_offset * wordSize), r13); | |
2223 __ movptr(Address(rsp, saved_r14_offset * wordSize), r14); | |
2224 setup_arg_regs(4); // from => rdi, to => rsi, length => rdx | 2210 setup_arg_regs(4); // from => rdi, to => rsi, length => rdx |
2225 // ckoff => rcx, ckval => r8 | 2211 // ckoff => rcx, ckval => r8 |
2226 // r9 and r10 may be used to save non-volatile registers | 2212 // r9 and r10 may be used to save non-volatile registers |
2227 #ifdef _WIN64 | 2213 #ifdef _WIN64 |
2228 // last argument (#4) is on stack on Win64 | 2214 // last argument (#4) is on stack on Win64 |
2229 const int ckval_offset = saved_rarg0_offset + 4; | 2215 __ movptr(ckval, Address(rsp, 6 * wordSize)); |
2230 __ movptr(ckval, Address(rsp, ckval_offset * wordSize)); | |
2231 #endif | 2216 #endif |
2217 | |
2218 // Caller of this entry point must set up the argument registers. | |
2219 checkcast_copy_entry = __ pc(); | |
2220 BLOCK_COMMENT("Entry:"); | |
2221 | |
2222 // allocate spill slots for r13, r14 | |
2223 enum { | |
2224 saved_r13_offset, | |
2225 saved_r14_offset, | |
2226 saved_rbp_offset | |
2227 }; | |
2228 __ subptr(rsp, saved_rbp_offset * wordSize); | |
2229 __ movptr(Address(rsp, saved_r13_offset * wordSize), r13); | |
2230 __ movptr(Address(rsp, saved_r14_offset * wordSize), r14); | |
2232 | 2231 |
2233 // check that int operands are properly extended to size_t | 2232 // check that int operands are properly extended to size_t |
2234 assert_clean_int(length, rax); | 2233 assert_clean_int(length, rax); |
2235 assert_clean_int(ckoff, rax); | 2234 assert_clean_int(ckoff, rax); |
2236 | 2235 |
2441 // Input registers | 2440 // Input registers |
2442 const Register src = c_rarg0; // source array oop | 2441 const Register src = c_rarg0; // source array oop |
2443 const Register src_pos = c_rarg1; // source position | 2442 const Register src_pos = c_rarg1; // source position |
2444 const Register dst = c_rarg2; // destination array oop | 2443 const Register dst = c_rarg2; // destination array oop |
2445 const Register dst_pos = c_rarg3; // destination position | 2444 const Register dst_pos = c_rarg3; // destination position |
2446 // elements count is on stack on Win64 | 2445 #ifndef _WIN64 |
2447 #ifdef _WIN64 | 2446 const Register length = c_rarg4; |
2448 #define C_RARG4 Address(rsp, 6 * wordSize) | |
2449 #else | 2447 #else |
2450 #define C_RARG4 c_rarg4 | 2448 const Address length(rsp, 6 * wordSize); // elements count is on stack on Win64 |
2451 #endif | 2449 #endif |
2452 | 2450 |
2453 { int modulus = CodeEntryAlignment; | 2451 { int modulus = CodeEntryAlignment; |
2454 int target = modulus - 5; // 5 = sizeof jmp(L_failed) | 2452 int target = modulus - 5; // 5 = sizeof jmp(L_failed) |
2455 int advance = target - (__ offset() % modulus); | 2453 int advance = target - (__ offset() % modulus); |
2512 guarantee(((j1off ^ j4off) & ~15) != 0, "I$ line of 1st & 4th jumps"); | 2510 guarantee(((j1off ^ j4off) & ~15) != 0, "I$ line of 1st & 4th jumps"); |
2513 | 2511 |
2514 // registers used as temp | 2512 // registers used as temp |
2515 const Register r11_length = r11; // elements count to copy | 2513 const Register r11_length = r11; // elements count to copy |
2516 const Register r10_src_klass = r10; // array klass | 2514 const Register r10_src_klass = r10; // array klass |
2517 const Register r9_dst_klass = r9; // dest array klass | |
2518 | 2515 |
2519 // if (length < 0) return -1; | 2516 // if (length < 0) return -1; |
2520 __ movl(r11_length, C_RARG4); // length (elements count, 32-bits value) | 2517 __ movl(r11_length, length); // length (elements count, 32-bits value) |
2521 __ testl(r11_length, r11_length); | 2518 __ testl(r11_length, r11_length); |
2522 __ jccb(Assembler::negative, L_failed_0); | 2519 __ jccb(Assembler::negative, L_failed_0); |
2523 | 2520 |
2524 __ load_klass(r10_src_klass, src); | 2521 __ load_klass(r10_src_klass, src); |
2525 #ifdef ASSERT | 2522 #ifdef ASSERT |
2526 // assert(src->klass() != NULL); | 2523 // assert(src->klass() != NULL); |
2527 BLOCK_COMMENT("assert klasses not null"); | 2524 { |
2528 { Label L1, L2; | 2525 BLOCK_COMMENT("assert klasses not null {"); |
2526 Label L1, L2; | |
2529 __ testptr(r10_src_klass, r10_src_klass); | 2527 __ testptr(r10_src_klass, r10_src_klass); |
2530 __ jcc(Assembler::notZero, L2); // it is broken if klass is NULL | 2528 __ jcc(Assembler::notZero, L2); // it is broken if klass is NULL |
2531 __ bind(L1); | 2529 __ bind(L1); |
2532 __ stop("broken null klass"); | 2530 __ stop("broken null klass"); |
2533 __ bind(L2); | 2531 __ bind(L2); |
2534 __ load_klass(r9_dst_klass, dst); | 2532 __ load_klass(rax, dst); |
2535 __ cmpq(r9_dst_klass, 0); | 2533 __ cmpq(rax, 0); |
2536 __ jcc(Assembler::equal, L1); // this would be broken also | 2534 __ jcc(Assembler::equal, L1); // this would be broken also |
2537 BLOCK_COMMENT("assert done"); | 2535 BLOCK_COMMENT("} assert klasses not null done"); |
2538 } | 2536 } |
2539 #endif | 2537 #endif |
2540 | 2538 |
2541 // Load layout helper (32-bits) | 2539 // Load layout helper (32-bits) |
2542 // | 2540 // |
2544 // 32 30 24 16 8 2 0 | 2542 // 32 30 24 16 8 2 0 |
2545 // | 2543 // |
2546 // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0 | 2544 // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0 |
2547 // | 2545 // |
2548 | 2546 |
2549 int lh_offset = klassOopDesc::header_size() * HeapWordSize + | 2547 const int lh_offset = klassOopDesc::header_size() * HeapWordSize + |
2550 Klass::layout_helper_offset_in_bytes(); | 2548 Klass::layout_helper_offset_in_bytes(); |
2549 | |
2550 // Handle objArrays completely differently... | |
2551 const jint objArray_lh = Klass::array_layout_helper(T_OBJECT); | |
2552 __ cmpl(Address(r10_src_klass, lh_offset), objArray_lh); | |
2553 __ jcc(Assembler::equal, L_objArray); | |
2554 | |
2555 // if (src->klass() != dst->klass()) return -1; | |
2556 __ load_klass(rax, dst); | |
2557 __ cmpq(r10_src_klass, rax); | |
2558 __ jcc(Assembler::notEqual, L_failed); | |
2551 | 2559 |
2552 const Register rax_lh = rax; // layout helper | 2560 const Register rax_lh = rax; // layout helper |
2553 | |
2554 __ movl(rax_lh, Address(r10_src_klass, lh_offset)); | 2561 __ movl(rax_lh, Address(r10_src_klass, lh_offset)); |
2555 | |
2556 // Handle objArrays completely differently... | |
2557 jint objArray_lh = Klass::array_layout_helper(T_OBJECT); | |
2558 __ cmpl(rax_lh, objArray_lh); | |
2559 __ jcc(Assembler::equal, L_objArray); | |
2560 | |
2561 // if (src->klass() != dst->klass()) return -1; | |
2562 __ load_klass(r9_dst_klass, dst); | |
2563 __ cmpq(r10_src_klass, r9_dst_klass); | |
2564 __ jcc(Assembler::notEqual, L_failed); | |
2565 | 2562 |
2566 // if (!src->is_Array()) return -1; | 2563 // if (!src->is_Array()) return -1; |
2567 __ cmpl(rax_lh, Klass::_lh_neutral_value); | 2564 __ cmpl(rax_lh, Klass::_lh_neutral_value); |
2568 __ jcc(Assembler::greaterEqual, L_failed); | 2565 __ jcc(Assembler::greaterEqual, L_failed); |
2569 | 2566 |
2570 // At this point, it is known to be a typeArray (array_tag 0x3). | 2567 // At this point, it is known to be a typeArray (array_tag 0x3). |
2571 #ifdef ASSERT | 2568 #ifdef ASSERT |
2572 { Label L; | 2569 { |
2570 BLOCK_COMMENT("assert primitive array {"); | |
2571 Label L; | |
2573 __ cmpl(rax_lh, (Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift)); | 2572 __ cmpl(rax_lh, (Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift)); |
2574 __ jcc(Assembler::greaterEqual, L); | 2573 __ jcc(Assembler::greaterEqual, L); |
2575 __ stop("must be a primitive array"); | 2574 __ stop("must be a primitive array"); |
2576 __ bind(L); | 2575 __ bind(L); |
2576 BLOCK_COMMENT("} assert primitive array done"); | |
2577 } | 2577 } |
2578 #endif | 2578 #endif |
2579 | 2579 |
2580 arraycopy_range_checks(src, src_pos, dst, dst_pos, r11_length, | 2580 arraycopy_range_checks(src, src_pos, dst, dst_pos, r11_length, |
2581 r10, L_failed); | 2581 r10, L_failed); |
2629 __ movl2ptr(count, r11_length); // length | 2629 __ movl2ptr(count, r11_length); // length |
2630 __ jump(RuntimeAddress(int_copy_entry)); | 2630 __ jump(RuntimeAddress(int_copy_entry)); |
2631 | 2631 |
2632 __ BIND(L_copy_longs); | 2632 __ BIND(L_copy_longs); |
2633 #ifdef ASSERT | 2633 #ifdef ASSERT |
2634 { Label L; | 2634 { |
2635 BLOCK_COMMENT("assert long copy {"); | |
2636 Label L; | |
2635 __ cmpl(rax_elsize, LogBytesPerLong); | 2637 __ cmpl(rax_elsize, LogBytesPerLong); |
2636 __ jcc(Assembler::equal, L); | 2638 __ jcc(Assembler::equal, L); |
2637 __ stop("must be long copy, but elsize is wrong"); | 2639 __ stop("must be long copy, but elsize is wrong"); |
2638 __ bind(L); | 2640 __ bind(L); |
2641 BLOCK_COMMENT("} assert long copy done"); | |
2639 } | 2642 } |
2640 #endif | 2643 #endif |
2641 __ lea(from, Address(src, src_pos, Address::times_8, 0));// src_addr | 2644 __ lea(from, Address(src, src_pos, Address::times_8, 0));// src_addr |
2642 __ lea(to, Address(dst, dst_pos, Address::times_8, 0));// dst_addr | 2645 __ lea(to, Address(dst, dst_pos, Address::times_8, 0));// dst_addr |
2643 __ movl2ptr(count, r11_length); // length | 2646 __ movl2ptr(count, r11_length); // length |
2644 __ jump(RuntimeAddress(long_copy_entry)); | 2647 __ jump(RuntimeAddress(long_copy_entry)); |
2645 | 2648 |
2646 // objArrayKlass | 2649 // objArrayKlass |
2647 __ BIND(L_objArray); | 2650 __ BIND(L_objArray); |
2648 // live at this point: r10_src_klass, src[_pos], dst[_pos] | 2651 // live at this point: r10_src_klass, r11_length, src[_pos], dst[_pos] |
2649 | 2652 |
2650 Label L_plain_copy, L_checkcast_copy; | 2653 Label L_plain_copy, L_checkcast_copy; |
2651 // test array classes for subtyping | 2654 // test array classes for subtyping |
2652 __ load_klass(r9_dst_klass, dst); | 2655 __ load_klass(rax, dst); |
2653 __ cmpq(r10_src_klass, r9_dst_klass); // usual case is exact equality | 2656 __ cmpq(r10_src_klass, rax); // usual case is exact equality |
2654 __ jcc(Assembler::notEqual, L_checkcast_copy); | 2657 __ jcc(Assembler::notEqual, L_checkcast_copy); |
2655 | 2658 |
2656 // Identically typed arrays can be copied without element-wise checks. | 2659 // Identically typed arrays can be copied without element-wise checks. |
2657 arraycopy_range_checks(src, src_pos, dst, dst_pos, r11_length, | 2660 arraycopy_range_checks(src, src_pos, dst, dst_pos, r11_length, |
2658 r10, L_failed); | 2661 r10, L_failed); |
2664 __ movl2ptr(count, r11_length); // length | 2667 __ movl2ptr(count, r11_length); // length |
2665 __ BIND(L_plain_copy); | 2668 __ BIND(L_plain_copy); |
2666 __ jump(RuntimeAddress(oop_copy_entry)); | 2669 __ jump(RuntimeAddress(oop_copy_entry)); |
2667 | 2670 |
2668 __ BIND(L_checkcast_copy); | 2671 __ BIND(L_checkcast_copy); |
2669 // live at this point: r10_src_klass, !r11_length | 2672 // live at this point: r10_src_klass, r11_length, rax (dst_klass) |
2670 { | 2673 { |
2671 // assert(r11_length == C_RARG4); // will reload from here | |
2672 Register r11_dst_klass = r11; | |
2673 __ load_klass(r11_dst_klass, dst); | |
2674 | |
2675 // Before looking at dst.length, make sure dst is also an objArray. | 2674 // Before looking at dst.length, make sure dst is also an objArray. |
2676 __ cmpl(Address(r11_dst_klass, lh_offset), objArray_lh); | 2675 __ cmpl(Address(rax, lh_offset), objArray_lh); |
2677 __ jcc(Assembler::notEqual, L_failed); | 2676 __ jcc(Assembler::notEqual, L_failed); |
2678 | 2677 |
2679 // It is safe to examine both src.length and dst.length. | 2678 // It is safe to examine both src.length and dst.length. |
2680 #ifndef _WIN64 | |
2681 arraycopy_range_checks(src, src_pos, dst, dst_pos, C_RARG4, | |
2682 rax, L_failed); | |
2683 #else | |
2684 __ movl(r11_length, C_RARG4); // reload | |
2685 arraycopy_range_checks(src, src_pos, dst, dst_pos, r11_length, | 2679 arraycopy_range_checks(src, src_pos, dst, dst_pos, r11_length, |
2686 rax, L_failed); | 2680 rax, L_failed); |
2681 | |
2682 const Register r11_dst_klass = r11; | |
2687 __ load_klass(r11_dst_klass, dst); // reload | 2683 __ load_klass(r11_dst_klass, dst); // reload |
2688 #endif | |
2689 | 2684 |
2690 // Marshal the base address arguments now, freeing registers. | 2685 // Marshal the base address arguments now, freeing registers. |
2691 __ lea(from, Address(src, src_pos, TIMES_OOP, | 2686 __ lea(from, Address(src, src_pos, TIMES_OOP, |
2692 arrayOopDesc::base_offset_in_bytes(T_OBJECT))); | 2687 arrayOopDesc::base_offset_in_bytes(T_OBJECT))); |
2693 __ lea(to, Address(dst, dst_pos, TIMES_OOP, | 2688 __ lea(to, Address(dst, dst_pos, TIMES_OOP, |
2694 arrayOopDesc::base_offset_in_bytes(T_OBJECT))); | 2689 arrayOopDesc::base_offset_in_bytes(T_OBJECT))); |
2695 __ movl(count, C_RARG4); // length (reloaded) | 2690 __ movl(count, length); // length (reloaded) |
2696 Register sco_temp = c_rarg3; // this register is free now | 2691 Register sco_temp = c_rarg3; // this register is free now |
2697 assert_different_registers(from, to, count, sco_temp, | 2692 assert_different_registers(from, to, count, sco_temp, |
2698 r11_dst_klass, r10_src_klass); | 2693 r11_dst_klass, r10_src_klass); |
2699 assert_clean_int(count, sco_temp); | 2694 assert_clean_int(count, sco_temp); |
2700 | 2695 |
2701 // Generate the type check. | 2696 // Generate the type check. |
2702 int sco_offset = (klassOopDesc::header_size() * HeapWordSize + | 2697 const int sco_offset = (klassOopDesc::header_size() * HeapWordSize + |
2703 Klass::super_check_offset_offset_in_bytes()); | 2698 Klass::super_check_offset_offset_in_bytes()); |
2704 __ movl(sco_temp, Address(r11_dst_klass, sco_offset)); | 2699 __ movl(sco_temp, Address(r11_dst_klass, sco_offset)); |
2705 assert_clean_int(sco_temp, rax); | 2700 assert_clean_int(sco_temp, rax); |
2706 generate_type_check(r10_src_klass, sco_temp, r11_dst_klass, L_plain_copy); | 2701 generate_type_check(r10_src_klass, sco_temp, r11_dst_klass, L_plain_copy); |
2707 | 2702 |
2708 // Fetch destination element klass from the objArrayKlass header. | 2703 // Fetch destination element klass from the objArrayKlass header. |
2709 int ek_offset = (klassOopDesc::header_size() * HeapWordSize + | 2704 int ek_offset = (klassOopDesc::header_size() * HeapWordSize + |
2710 objArrayKlass::element_klass_offset_in_bytes()); | 2705 objArrayKlass::element_klass_offset_in_bytes()); |
2711 __ movptr(r11_dst_klass, Address(r11_dst_klass, ek_offset)); | 2706 __ movptr(r11_dst_klass, Address(r11_dst_klass, ek_offset)); |
2712 __ movl(sco_temp, Address(r11_dst_klass, sco_offset)); | 2707 __ movl( sco_temp, Address(r11_dst_klass, sco_offset)); |
2713 assert_clean_int(sco_temp, rax); | 2708 assert_clean_int(sco_temp, rax); |
2714 | 2709 |
2715 // the checkcast_copy loop needs two extra arguments: | 2710 // the checkcast_copy loop needs two extra arguments: |
2716 assert(c_rarg3 == sco_temp, "#3 already in place"); | 2711 assert(c_rarg3 == sco_temp, "#3 already in place"); |
2717 __ movptr(C_RARG4, r11_dst_klass); // dst.klass.element_klass | 2712 // Set up arguments for checkcast_copy_entry. |
2713 setup_arg_regs(4); | |
2714 __ movptr(r8, r11_dst_klass); // dst.klass.element_klass, r8 is c_rarg4 on Linux/Solaris | |
2718 __ jump(RuntimeAddress(checkcast_copy_entry)); | 2715 __ jump(RuntimeAddress(checkcast_copy_entry)); |
2719 } | 2716 } |
2720 | 2717 |
2721 __ BIND(L_failed); | 2718 __ BIND(L_failed); |
2722 __ xorptr(rax, rax); | 2719 __ xorptr(rax, rax); |
2724 __ leave(); // required for proper stackwalking of RuntimeStub frame | 2721 __ leave(); // required for proper stackwalking of RuntimeStub frame |
2725 __ ret(0); | 2722 __ ret(0); |
2726 | 2723 |
2727 return start; | 2724 return start; |
2728 } | 2725 } |
2729 | |
2730 #undef length_arg | |
2731 | 2726 |
2732 void generate_arraycopy_stubs() { | 2727 void generate_arraycopy_stubs() { |
2733 // Call the conjoint generation methods immediately after | 2728 // Call the conjoint generation methods immediately after |
2734 // the disjoint ones so that short branches from the former | 2729 // the disjoint ones so that short branches from the former |
2735 // to the latter can be generated. | 2730 // to the latter can be generated. |