Mercurial > hg > truffle
comparison src/cpu/sparc/vm/sharedRuntime_sparc.cpp @ 116:018d5b58dd4f
6537506: Provide a mechanism for specifying Java-level USDT-like dtrace probes
Summary: Initial checkin of JSDT code
Reviewed-by: acorn, sbohne
author | kamg |
---|---|
date | Thu, 17 Apr 2008 22:18:15 -0400 |
parents | ba764ed4b6f2 |
children | 437d03ea40b1 6b648fefb395 37f87013dfd8 |
comparison
equal
deleted
inserted
replaced
115:e7a91a357527 | 116:018d5b58dd4f |
---|---|
1635 split_long_move(masm, split, dst); | 1635 split_long_move(masm, split, dst); |
1636 } | 1636 } |
1637 } | 1637 } |
1638 } else if (dst.is_single_phys_reg()) { | 1638 } else if (dst.is_single_phys_reg()) { |
1639 if (src.is_adjacent_aligned_on_stack(2)) { | 1639 if (src.is_adjacent_aligned_on_stack(2)) { |
1640 __ ldd(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); | 1640 __ ld_long(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); |
1641 } else { | 1641 } else { |
1642 // dst is a single reg. | 1642 // dst is a single reg. |
1643 // Remember lo is low address not msb for stack slots | 1643 // Remember lo is low address not msb for stack slots |
1644 // and lo is the "real" register for registers | 1644 // and lo is the "real" register for registers |
1645 // src is | 1645 // src is |
2499 oop_maps); | 2499 oop_maps); |
2500 return nm; | 2500 return nm; |
2501 | 2501 |
2502 } | 2502 } |
2503 | 2503 |
2504 #ifdef HAVE_DTRACE_H | |
2505 // --------------------------------------------------------------------------- | |
2506 // Generate a dtrace nmethod for a given signature. The method takes arguments | |
2507 // in the Java compiled code convention, marshals them to the native | |
2508 // abi and then leaves nops at the position you would expect to call a native | |
2509 // function. When the probe is enabled the nops are replaced with a trap | |
2510 // instruction that dtrace inserts and the trace will cause a notification | |
2511 // to dtrace. | |
2512 // | |
2513 // The probes are only able to take primitive types and java/lang/String as | |
2514 // arguments. No other java types are allowed. Strings are converted to utf8 | |
2515 // strings so that from dtrace point of view java strings are converted to C | |
2516 // strings. There is an arbitrary fixed limit on the total space that a method | |
2517 // can use for converting the strings. (256 chars per string in the signature). | |
2518 // So any java string larger then this is truncated. | |
2519 | |
2520 static int fp_offset[ConcreteRegisterImpl::number_of_registers] = { 0 }; | |
2521 static bool offsets_initialized = false; | |
2522 | |
2523 static VMRegPair reg64_to_VMRegPair(Register r) { | |
2524 VMRegPair ret; | |
2525 if (wordSize == 8) { | |
2526 ret.set2(r->as_VMReg()); | |
2527 } else { | |
2528 ret.set_pair(r->successor()->as_VMReg(), r->as_VMReg()); | |
2529 } | |
2530 return ret; | |
2531 } | |
2532 | |
2533 | |
2534 nmethod *SharedRuntime::generate_dtrace_nmethod( | |
2535 MacroAssembler *masm, methodHandle method) { | |
2536 | |
2537 | |
2538 // generate_dtrace_nmethod is guarded by a mutex so we are sure to | |
2539 // be single threaded in this method. | |
2540 assert(AdapterHandlerLibrary_lock->owned_by_self(), "must be"); | |
2541 | |
2542 // Fill in the signature array, for the calling-convention call. | |
2543 int total_args_passed = method->size_of_parameters(); | |
2544 | |
2545 BasicType* in_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); | |
2546 VMRegPair *in_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); | |
2547 | |
2548 // The signature we are going to use for the trap that dtrace will see | |
2549 // java/lang/String is converted. We drop "this" and any other object | |
2550 // is converted to NULL. (A one-slot java/lang/Long object reference | |
2551 // is converted to a two-slot long, which is why we double the allocation). | |
2552 BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed * 2); | |
2553 VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed * 2); | |
2554 | |
2555 int i=0; | |
2556 int total_strings = 0; | |
2557 int first_arg_to_pass = 0; | |
2558 int total_c_args = 0; | |
2559 int box_offset = java_lang_boxing_object::value_offset_in_bytes(); | |
2560 | |
2561 // Skip the receiver as dtrace doesn't want to see it | |
2562 if( !method->is_static() ) { | |
2563 in_sig_bt[i++] = T_OBJECT; | |
2564 first_arg_to_pass = 1; | |
2565 } | |
2566 | |
2567 SignatureStream ss(method->signature()); | |
2568 for ( ; !ss.at_return_type(); ss.next()) { | |
2569 BasicType bt = ss.type(); | |
2570 in_sig_bt[i++] = bt; // Collect remaining bits of signature | |
2571 out_sig_bt[total_c_args++] = bt; | |
2572 if( bt == T_OBJECT) { | |
2573 symbolOop s = ss.as_symbol_or_null(); | |
2574 if (s == vmSymbols::java_lang_String()) { | |
2575 total_strings++; | |
2576 out_sig_bt[total_c_args-1] = T_ADDRESS; | |
2577 } else if (s == vmSymbols::java_lang_Boolean() || | |
2578 s == vmSymbols::java_lang_Byte()) { | |
2579 out_sig_bt[total_c_args-1] = T_BYTE; | |
2580 } else if (s == vmSymbols::java_lang_Character() || | |
2581 s == vmSymbols::java_lang_Short()) { | |
2582 out_sig_bt[total_c_args-1] = T_SHORT; | |
2583 } else if (s == vmSymbols::java_lang_Integer() || | |
2584 s == vmSymbols::java_lang_Float()) { | |
2585 out_sig_bt[total_c_args-1] = T_INT; | |
2586 } else if (s == vmSymbols::java_lang_Long() || | |
2587 s == vmSymbols::java_lang_Double()) { | |
2588 out_sig_bt[total_c_args-1] = T_LONG; | |
2589 out_sig_bt[total_c_args++] = T_VOID; | |
2590 } | |
2591 } else if ( bt == T_LONG || bt == T_DOUBLE ) { | |
2592 in_sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots | |
2593 // We convert double to long | |
2594 out_sig_bt[total_c_args-1] = T_LONG; | |
2595 out_sig_bt[total_c_args++] = T_VOID; | |
2596 } else if ( bt == T_FLOAT) { | |
2597 // We convert float to int | |
2598 out_sig_bt[total_c_args-1] = T_INT; | |
2599 } | |
2600 } | |
2601 | |
2602 assert(i==total_args_passed, "validly parsed signature"); | |
2603 | |
2604 // Now get the compiled-Java layout as input arguments | |
2605 int comp_args_on_stack; | |
2606 comp_args_on_stack = SharedRuntime::java_calling_convention( | |
2607 in_sig_bt, in_regs, total_args_passed, false); | |
2608 | |
2609 // We have received a description of where all the java arg are located | |
2610 // on entry to the wrapper. We need to convert these args to where | |
2611 // the a native (non-jni) function would expect them. To figure out | |
2612 // where they go we convert the java signature to a C signature and remove | |
2613 // T_VOID for any long/double we might have received. | |
2614 | |
2615 | |
2616 // Now figure out where the args must be stored and how much stack space | |
2617 // they require (neglecting out_preserve_stack_slots but space for storing | |
2618 // the 1st six register arguments). It's weird see int_stk_helper. | |
2619 // | |
2620 int out_arg_slots; | |
2621 out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args); | |
2622 | |
2623 // Calculate the total number of stack slots we will need. | |
2624 | |
2625 // First count the abi requirement plus all of the outgoing args | |
2626 int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots; | |
2627 | |
2628 // Plus a temp for possible converion of float/double/long register args | |
2629 | |
2630 int conversion_temp = stack_slots; | |
2631 stack_slots += 2; | |
2632 | |
2633 | |
2634 // Now space for the string(s) we must convert | |
2635 | |
2636 int string_locs = stack_slots; | |
2637 stack_slots += total_strings * | |
2638 (max_dtrace_string_size / VMRegImpl::stack_slot_size); | |
2639 | |
2640 // Ok The space we have allocated will look like: | |
2641 // | |
2642 // | |
2643 // FP-> | | | |
2644 // |---------------------| | |
2645 // | string[n] | | |
2646 // |---------------------| <- string_locs[n] | |
2647 // | string[n-1] | | |
2648 // |---------------------| <- string_locs[n-1] | |
2649 // | ... | | |
2650 // | ... | | |
2651 // |---------------------| <- string_locs[1] | |
2652 // | string[0] | | |
2653 // |---------------------| <- string_locs[0] | |
2654 // | temp | | |
2655 // |---------------------| <- conversion_temp | |
2656 // | outbound memory | | |
2657 // | based arguments | | |
2658 // | | | |
2659 // |---------------------| | |
2660 // | | | |
2661 // SP-> | out_preserved_slots | | |
2662 // | |
2663 // | |
2664 | |
2665 // Now compute actual number of stack words we need rounding to make | |
2666 // stack properly aligned. | |
2667 stack_slots = round_to(stack_slots, 4 * VMRegImpl::slots_per_word); | |
2668 | |
2669 int stack_size = stack_slots * VMRegImpl::stack_slot_size; | |
2670 | |
2671 intptr_t start = (intptr_t)__ pc(); | |
2672 | |
2673 // First thing make an ic check to see if we should even be here | |
2674 | |
2675 { | |
2676 Label L; | |
2677 const Register temp_reg = G3_scratch; | |
2678 Address ic_miss(temp_reg, SharedRuntime::get_ic_miss_stub()); | |
2679 __ verify_oop(O0); | |
2680 __ ld_ptr(O0, oopDesc::klass_offset_in_bytes(), temp_reg); | |
2681 __ cmp(temp_reg, G5_inline_cache_reg); | |
2682 __ brx(Assembler::equal, true, Assembler::pt, L); | |
2683 __ delayed()->nop(); | |
2684 | |
2685 __ jump_to(ic_miss, 0); | |
2686 __ delayed()->nop(); | |
2687 __ align(CodeEntryAlignment); | |
2688 __ bind(L); | |
2689 } | |
2690 | |
2691 int vep_offset = ((intptr_t)__ pc()) - start; | |
2692 | |
2693 | |
2694 // The instruction at the verified entry point must be 5 bytes or longer | |
2695 // because it can be patched on the fly by make_non_entrant. The stack bang | |
2696 // instruction fits that requirement. | |
2697 | |
2698 // Generate stack overflow check before creating frame | |
2699 __ generate_stack_overflow_check(stack_size); | |
2700 | |
2701 assert(((intptr_t)__ pc() - start - vep_offset) >= 5, | |
2702 "valid size for make_non_entrant"); | |
2703 | |
2704 // Generate a new frame for the wrapper. | |
2705 __ save(SP, -stack_size, SP); | |
2706 | |
2707 // Frame is now completed as far a size and linkage. | |
2708 | |
2709 int frame_complete = ((intptr_t)__ pc()) - start; | |
2710 | |
2711 #ifdef ASSERT | |
2712 bool reg_destroyed[RegisterImpl::number_of_registers]; | |
2713 bool freg_destroyed[FloatRegisterImpl::number_of_registers]; | |
2714 for ( int r = 0 ; r < RegisterImpl::number_of_registers ; r++ ) { | |
2715 reg_destroyed[r] = false; | |
2716 } | |
2717 for ( int f = 0 ; f < FloatRegisterImpl::number_of_registers ; f++ ) { | |
2718 freg_destroyed[f] = false; | |
2719 } | |
2720 | |
2721 #endif /* ASSERT */ | |
2722 | |
2723 VMRegPair zero; | |
2724 zero.set2(G0->as_VMReg()); | |
2725 | |
2726 int c_arg, j_arg; | |
2727 | |
2728 Register conversion_off = noreg; | |
2729 | |
2730 for (j_arg = first_arg_to_pass, c_arg = 0 ; | |
2731 j_arg < total_args_passed ; j_arg++, c_arg++ ) { | |
2732 | |
2733 VMRegPair src = in_regs[j_arg]; | |
2734 VMRegPair dst = out_regs[c_arg]; | |
2735 | |
2736 #ifdef ASSERT | |
2737 if (src.first()->is_Register()) { | |
2738 assert(!reg_destroyed[src.first()->as_Register()->encoding()], "ack!"); | |
2739 } else if (src.first()->is_FloatRegister()) { | |
2740 assert(!freg_destroyed[src.first()->as_FloatRegister()->encoding( | |
2741 FloatRegisterImpl::S)], "ack!"); | |
2742 } | |
2743 if (dst.first()->is_Register()) { | |
2744 reg_destroyed[dst.first()->as_Register()->encoding()] = true; | |
2745 } else if (dst.first()->is_FloatRegister()) { | |
2746 freg_destroyed[dst.first()->as_FloatRegister()->encoding( | |
2747 FloatRegisterImpl::S)] = true; | |
2748 } | |
2749 #endif /* ASSERT */ | |
2750 | |
2751 switch (in_sig_bt[j_arg]) { | |
2752 case T_ARRAY: | |
2753 case T_OBJECT: | |
2754 { | |
2755 if (out_sig_bt[c_arg] == T_BYTE || out_sig_bt[c_arg] == T_SHORT || | |
2756 out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) { | |
2757 // need to unbox a one-slot value | |
2758 Register in_reg = L0; | |
2759 Register tmp = L2; | |
2760 if ( src.first()->is_reg() ) { | |
2761 in_reg = src.first()->as_Register(); | |
2762 } else { | |
2763 assert(Assembler::is_simm13(reg2offset(src.first()) + STACK_BIAS), | |
2764 "must be"); | |
2765 __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, in_reg); | |
2766 } | |
2767 // If the final destination is an acceptable register | |
2768 if ( dst.first()->is_reg() ) { | |
2769 if ( dst.is_single_phys_reg() || out_sig_bt[c_arg] != T_LONG ) { | |
2770 tmp = dst.first()->as_Register(); | |
2771 } | |
2772 } | |
2773 | |
2774 Label skipUnbox; | |
2775 if ( wordSize == 4 && out_sig_bt[c_arg] == T_LONG ) { | |
2776 __ mov(G0, tmp->successor()); | |
2777 } | |
2778 __ br_null(in_reg, true, Assembler::pn, skipUnbox); | |
2779 __ delayed()->mov(G0, tmp); | |
2780 | |
2781 switch (out_sig_bt[c_arg]) { | |
2782 case T_BYTE: | |
2783 __ ldub(in_reg, box_offset, tmp); break; | |
2784 case T_SHORT: | |
2785 __ lduh(in_reg, box_offset, tmp); break; | |
2786 case T_INT: | |
2787 __ ld(in_reg, box_offset, tmp); break; | |
2788 case T_LONG: | |
2789 __ ld_long(in_reg, box_offset, tmp); break; | |
2790 default: ShouldNotReachHere(); | |
2791 } | |
2792 | |
2793 __ bind(skipUnbox); | |
2794 // If tmp wasn't final destination copy to final destination | |
2795 if (tmp == L2) { | |
2796 VMRegPair tmp_as_VM = reg64_to_VMRegPair(L2); | |
2797 if (out_sig_bt[c_arg] == T_LONG) { | |
2798 long_move(masm, tmp_as_VM, dst); | |
2799 } else { | |
2800 move32_64(masm, tmp_as_VM, out_regs[c_arg]); | |
2801 } | |
2802 } | |
2803 if (out_sig_bt[c_arg] == T_LONG) { | |
2804 assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); | |
2805 ++c_arg; // move over the T_VOID to keep the loop indices in sync | |
2806 } | |
2807 } else if (out_sig_bt[c_arg] == T_ADDRESS) { | |
2808 Register s = | |
2809 src.first()->is_reg() ? src.first()->as_Register() : L2; | |
2810 Register d = | |
2811 dst.first()->is_reg() ? dst.first()->as_Register() : L2; | |
2812 | |
2813 // We store the oop now so that the conversion pass can reach | |
2814 // while in the inner frame. This will be the only store if | |
2815 // the oop is NULL. | |
2816 if (s != L2) { | |
2817 // src is register | |
2818 if (d != L2) { | |
2819 // dst is register | |
2820 __ mov(s, d); | |
2821 } else { | |
2822 assert(Assembler::is_simm13(reg2offset(dst.first()) + | |
2823 STACK_BIAS), "must be"); | |
2824 __ st_ptr(s, SP, reg2offset(dst.first()) + STACK_BIAS); | |
2825 } | |
2826 } else { | |
2827 // src not a register | |
2828 assert(Assembler::is_simm13(reg2offset(src.first()) + | |
2829 STACK_BIAS), "must be"); | |
2830 __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, d); | |
2831 if (d == L2) { | |
2832 assert(Assembler::is_simm13(reg2offset(dst.first()) + | |
2833 STACK_BIAS), "must be"); | |
2834 __ st_ptr(d, SP, reg2offset(dst.first()) + STACK_BIAS); | |
2835 } | |
2836 } | |
2837 } else if (out_sig_bt[c_arg] != T_VOID) { | |
2838 // Convert the arg to NULL | |
2839 if (dst.first()->is_reg()) { | |
2840 __ mov(G0, dst.first()->as_Register()); | |
2841 } else { | |
2842 assert(Assembler::is_simm13(reg2offset(dst.first()) + | |
2843 STACK_BIAS), "must be"); | |
2844 __ st_ptr(G0, SP, reg2offset(dst.first()) + STACK_BIAS); | |
2845 } | |
2846 } | |
2847 } | |
2848 break; | |
2849 case T_VOID: | |
2850 break; | |
2851 | |
2852 case T_FLOAT: | |
2853 if (src.first()->is_stack()) { | |
2854 // Stack to stack/reg is simple | |
2855 move32_64(masm, src, dst); | |
2856 } else { | |
2857 if (dst.first()->is_reg()) { | |
2858 // freg -> reg | |
2859 int off = | |
2860 STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size; | |
2861 Register d = dst.first()->as_Register(); | |
2862 if (Assembler::is_simm13(off)) { | |
2863 __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), | |
2864 SP, off); | |
2865 __ ld(SP, off, d); | |
2866 } else { | |
2867 if (conversion_off == noreg) { | |
2868 __ set(off, L6); | |
2869 conversion_off = L6; | |
2870 } | |
2871 __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), | |
2872 SP, conversion_off); | |
2873 __ ld(SP, conversion_off , d); | |
2874 } | |
2875 } else { | |
2876 // freg -> mem | |
2877 int off = STACK_BIAS + reg2offset(dst.first()); | |
2878 if (Assembler::is_simm13(off)) { | |
2879 __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), | |
2880 SP, off); | |
2881 } else { | |
2882 if (conversion_off == noreg) { | |
2883 __ set(off, L6); | |
2884 conversion_off = L6; | |
2885 } | |
2886 __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), | |
2887 SP, conversion_off); | |
2888 } | |
2889 } | |
2890 } | |
2891 break; | |
2892 | |
2893 case T_DOUBLE: | |
2894 assert( j_arg + 1 < total_args_passed && | |
2895 in_sig_bt[j_arg + 1] == T_VOID && | |
2896 out_sig_bt[c_arg+1] == T_VOID, "bad arg list"); | |
2897 if (src.first()->is_stack()) { | |
2898 // Stack to stack/reg is simple | |
2899 long_move(masm, src, dst); | |
2900 } else { | |
2901 Register d = dst.first()->is_reg() ? dst.first()->as_Register() : L2; | |
2902 | |
2903 // Destination could be an odd reg on 32bit in which case | |
2904 // we can't load direct to the destination. | |
2905 | |
2906 if (!d->is_even() && wordSize == 4) { | |
2907 d = L2; | |
2908 } | |
2909 int off = STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size; | |
2910 if (Assembler::is_simm13(off)) { | |
2911 __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(), | |
2912 SP, off); | |
2913 __ ld_long(SP, off, d); | |
2914 } else { | |
2915 if (conversion_off == noreg) { | |
2916 __ set(off, L6); | |
2917 conversion_off = L6; | |
2918 } | |
2919 __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(), | |
2920 SP, conversion_off); | |
2921 __ ld_long(SP, conversion_off, d); | |
2922 } | |
2923 if (d == L2) { | |
2924 long_move(masm, reg64_to_VMRegPair(L2), dst); | |
2925 } | |
2926 } | |
2927 break; | |
2928 | |
2929 case T_LONG : | |
2930 // 32bit can't do a split move of something like g1 -> O0, O1 | |
2931 // so use a memory temp | |
2932 if (src.is_single_phys_reg() && wordSize == 4) { | |
2933 Register tmp = L2; | |
2934 if (dst.first()->is_reg() && | |
2935 (wordSize == 8 || dst.first()->as_Register()->is_even())) { | |
2936 tmp = dst.first()->as_Register(); | |
2937 } | |
2938 | |
2939 int off = STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size; | |
2940 if (Assembler::is_simm13(off)) { | |
2941 __ stx(src.first()->as_Register(), SP, off); | |
2942 __ ld_long(SP, off, tmp); | |
2943 } else { | |
2944 if (conversion_off == noreg) { | |
2945 __ set(off, L6); | |
2946 conversion_off = L6; | |
2947 } | |
2948 __ stx(src.first()->as_Register(), SP, conversion_off); | |
2949 __ ld_long(SP, conversion_off, tmp); | |
2950 } | |
2951 | |
2952 if (tmp == L2) { | |
2953 long_move(masm, reg64_to_VMRegPair(L2), dst); | |
2954 } | |
2955 } else { | |
2956 long_move(masm, src, dst); | |
2957 } | |
2958 break; | |
2959 | |
2960 case T_ADDRESS: assert(false, "found T_ADDRESS in java args"); | |
2961 | |
2962 default: | |
2963 move32_64(masm, src, dst); | |
2964 } | |
2965 } | |
2966 | |
2967 | |
2968 // If we have any strings we must store any register based arg to the stack | |
2969 // This includes any still live xmm registers too. | |
2970 | |
2971 if (total_strings > 0 ) { | |
2972 | |
2973 // protect all the arg registers | |
2974 __ save_frame(0); | |
2975 __ mov(G2_thread, L7_thread_cache); | |
2976 const Register L2_string_off = L2; | |
2977 | |
2978 // Get first string offset | |
2979 __ set(string_locs * VMRegImpl::stack_slot_size, L2_string_off); | |
2980 | |
2981 for (c_arg = 0 ; c_arg < total_c_args ; c_arg++ ) { | |
2982 if (out_sig_bt[c_arg] == T_ADDRESS) { | |
2983 | |
2984 VMRegPair dst = out_regs[c_arg]; | |
2985 const Register d = dst.first()->is_reg() ? | |
2986 dst.first()->as_Register()->after_save() : noreg; | |
2987 | |
2988 // It's a string the oop and it was already copied to the out arg | |
2989 // position | |
2990 if (d != noreg) { | |
2991 __ mov(d, O0); | |
2992 } else { | |
2993 assert(Assembler::is_simm13(reg2offset(dst.first()) + STACK_BIAS), | |
2994 "must be"); | |
2995 __ ld_ptr(FP, reg2offset(dst.first()) + STACK_BIAS, O0); | |
2996 } | |
2997 Label skip; | |
2998 | |
2999 __ br_null(O0, false, Assembler::pn, skip); | |
3000 __ delayed()->add(FP, L2_string_off, O1); | |
3001 | |
3002 if (d != noreg) { | |
3003 __ mov(O1, d); | |
3004 } else { | |
3005 assert(Assembler::is_simm13(reg2offset(dst.first()) + STACK_BIAS), | |
3006 "must be"); | |
3007 __ st_ptr(O1, FP, reg2offset(dst.first()) + STACK_BIAS); | |
3008 } | |
3009 | |
3010 __ call(CAST_FROM_FN_PTR(address, SharedRuntime::get_utf), | |
3011 relocInfo::runtime_call_type); | |
3012 __ delayed()->add(L2_string_off, max_dtrace_string_size, L2_string_off); | |
3013 | |
3014 __ bind(skip); | |
3015 | |
3016 } | |
3017 | |
3018 } | |
3019 __ mov(L7_thread_cache, G2_thread); | |
3020 __ restore(); | |
3021 | |
3022 } | |
3023 | |
3024 | |
3025 // Ok now we are done. Need to place the nop that dtrace wants in order to | |
3026 // patch in the trap | |
3027 | |
3028 int patch_offset = ((intptr_t)__ pc()) - start; | |
3029 | |
3030 __ nop(); | |
3031 | |
3032 | |
3033 // Return | |
3034 | |
3035 __ ret(); | |
3036 __ delayed()->restore(); | |
3037 | |
3038 __ flush(); | |
3039 | |
3040 nmethod *nm = nmethod::new_dtrace_nmethod( | |
3041 method, masm->code(), vep_offset, patch_offset, frame_complete, | |
3042 stack_slots / VMRegImpl::slots_per_word); | |
3043 return nm; | |
3044 | |
3045 } | |
3046 | |
3047 #endif // HAVE_DTRACE_H | |
3048 | |
2504 // this function returns the adjust size (in number of words) to a c2i adapter | 3049 // this function returns the adjust size (in number of words) to a c2i adapter |
2505 // activation for use during deoptimization | 3050 // activation for use during deoptimization |
2506 int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals) { | 3051 int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals) { |
2507 assert(callee_locals >= callee_parameters, | 3052 assert(callee_locals >= callee_parameters, |
2508 "test and remove; got more parms than locals"); | 3053 "test and remove; got more parms than locals"); |