Ejemplo n.º 1
0
/**
  *  Generates fast path of monitor enter
  *  the code should not contains safepoint.
  *
  *  @param[in] ss buffer to put the assembly code to
  *  @param[in] input_param1 register which should point to the object lockword.
  *  If input_param1 == ecx it reduces one register mov.
  *  the code use and do not restore ecx, edx, eax registers
  *
  *  @return 0 if success in eax register
  */
char* gen_monitorenter_fast_path_helper(char *ss, const R_Opnd & input_param1) {

    if (&input_param1 != &ecx_opnd) {
        ss = mov(ss, ecx_opnd,  input_param1);
    }
#ifdef ASM_MONITOR_HELPER

    //get self_id
    ss = gen_hythread_self_helper(ss);
    ss = mov(ss,  edx_opnd,  M_Base_Opnd(eax_reg,
            hythread_get_thread_id_offset()));                          // mov edx,dword [eax+off]

    ss = mov(ss, eax_opnd, M_Base_Opnd(ecx_reg, 2), size_16);           // mov ax,word[ecx+2]
	ss = alu(ss, cmp_opc,  edx_opnd,  eax_opnd, size_16);           	// cmp dx,ax
    ss = branch8(ss, Condition_NZ,  Imm_Opnd(size_8, 0));               // jnz check_zero
    char *check_zero = ((char *)ss) - 1;
												                        //; ax==dx it's safe to do inc
	ss = mov(ss, eax_opnd, M_Base_Opnd(ecx_reg, 1), size_8);            // mov al, byte[ecx+1]
	                                                                    //rec_inc:

    ss = alu(ss, add_opc,  eax_opnd,  Imm_Opnd(size_8, 0x8), size_8);   // add al,0x8
    ss = branch8(ss, Condition_C,  Imm_Opnd(size_8, 0));                // jc failed
    char *failed1 = ((char *)ss) - 1;

	ss = mov(ss,  M_Base_Opnd(ecx_reg, 1), eax_opnd, size_8);           // mov byte[ecx+1],al
    ss = ret(ss,  Imm_Opnd(4));                                         // ret 4

    signed offset = (signed)ss - (signed)check_zero - 1;
    *check_zero = (char)offset;                                        //check_zero:

    ss = test(ss,  eax_opnd,  eax_opnd, size_16);                      //  test ax,ax
    ss = branch8(ss, Condition_NZ,  Imm_Opnd(size_8, 0));              //  jnz failed
    char *failed2 = ((char *)ss) - 1;

    ss = prefix(ss, lock_prefix);                                      //; here ax==0.
    ss = cmpxchg(ss,  M_Base_Opnd(ecx_reg, 2),  edx_opnd, size_16);    //  lock cmpxchg16 [ecx+2],dx
    ss = branch8(ss, Condition_NZ,  Imm_Opnd(size_8, 0));              //  jnz failed
    char *failed3 = ((char *)ss) - 1;


#ifdef LOCK_RESERVATION
	ss = mov(ss, eax_opnd, M_Base_Opnd(ecx_reg, 1), size_8);            //  mov al, byte[ecx+1]
    ss = test(ss,  eax_opnd,  Imm_Opnd(size_8, 0x4), size_8);           //  test al,0x4
    ss = branch8(ss, Condition_NZ,  Imm_Opnd(size_8, 0));               //  jnz finish
    char *finish = ((char *)ss) - 1;

    ss = alu(ss, add_opc,  eax_opnd,  Imm_Opnd(size_8, 0x8), size_8);   // add al,0x8
	ss = mov(ss,  M_Base_Opnd(ecx_reg, 1), eax_opnd, size_8);           // mov byte[ecx+1],al

    offset = (signed)ss - (signed)finish - 1;
    *finish = (char)offset;                            		            //finish:

#endif
    ss = ret(ss,  Imm_Opnd(4));                                         // ret 4

    offset = (signed)ss - (signed)failed1 - 1;
    *failed1 = (char)offset;                                 	        //failed:

    offset = (signed)ss - (signed)failed2 - 1;
    *failed2 = (char)offset;

    offset = (signed)ss - (signed)failed3 - 1;
    *failed3 = (char)offset;

#endif //ASM_MONITOR_HELPER
    // the second attempt to lock monitor
    ss = push(ss,  ecx_opnd);
    ss = call(ss, (char *)hythread_thin_monitor_try_enter);
    ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(4)); // pop parameters

    return ss;
}
Ejemplo n.º 2
0
static char* gen_invoke_common_managed_func(char* stub) {
    // Defines stack alignment on managed function enter.
    const I_32 STACK_ALIGNMENT = MANAGED_STACK_ALIGNMENT;
    const I_32 STACK_ALIGNMENT_MASK = ~(STACK_ALIGNMENT - 1);
    const char * LOOP_BEGIN = "loop_begin";
    const char * LOOP_END = "loop_end";

    // [ebp + 8] - args
    // [ebp + 12] - size
    // [ebp + 16] - func
    const I_32 STACK_ARGS_OFFSET = 8;
    const I_32 STACK_NARGS_OFFSET = 12;
    const I_32 STACK_FUNC_OFFSET = 16;
    const I_32 STACK_CALLEE_SAVED_OFFSET = -12;
    
    tl::MemoryPool pool;
    LilCguLabelAddresses labels(&pool, stub);
    
    // Initialize ebp-based stack frame.
    stub = push(stub, ebp_opnd);
    stub = mov(stub, ebp_opnd, esp_opnd);
    
    // Preserve callee-saved registers.
    stub = push(stub, ebx_opnd);
    stub = push(stub, esi_opnd);
    stub = push(stub, edi_opnd);

    // Load an array of arguments ('args') and its size from the stack.
    stub = mov(stub, eax_opnd, M_Base_Opnd(ebp_reg, STACK_ARGS_OFFSET));
    stub = mov(stub, ecx_opnd, M_Base_Opnd(ebp_reg, STACK_NARGS_OFFSET));
    

    // Align memory stack.
    stub = lea(stub, ebx_opnd, M_Index_Opnd(n_reg, ecx_reg, 4, 4));
    stub = mov(stub, esi_opnd, ebx_opnd);
    stub = neg(stub, esi_opnd);
    stub = alu(stub, add_opc, esi_opnd, esp_opnd);
    stub = alu(stub, and_opc, esi_opnd, Imm_Opnd(size_32, STACK_ALIGNMENT_MASK));
    stub = alu(stub, add_opc, ebx_opnd, esi_opnd);
    stub = mov(stub, esp_opnd, ebx_opnd);
    
    // Load a pointer to the last argument of 'args' array.
    stub = lea(stub, eax_opnd, M_Index_Opnd(eax_reg, ecx_reg, -4, 4));
    stub = alu(stub, sub_opc, eax_opnd, esp_opnd);
    stub = alu(stub, or_opc, ecx_opnd, ecx_opnd);
    stub = branch8(stub, Condition_Z, Imm_Opnd(size_8, 0));
    labels.add_patch_to_label(LOOP_END, stub - 1, LPT_Rel8);
    
// LOOP_BEGIN:
    // Push inputs on the stack.
    labels.define_label(LOOP_BEGIN, stub, false);
    
    stub = push(stub, M_Index_Opnd(esp_reg, eax_reg, 0, 1));
    stub = loop(stub, Imm_Opnd(size_8, 0));
    labels.add_patch_to_label(LOOP_BEGIN, stub - 1, LPT_Rel8);

// LOOP_END:    
    labels.define_label(LOOP_END, stub, false);
    
    // Call target function.
    stub = mov(stub, eax_opnd, M_Base_Opnd(ebp_reg, STACK_FUNC_OFFSET));
    stub = call(stub, eax_opnd);
    
    // Restore callee-saved registers from the stack.
    stub = lea(stub, esp_opnd, M_Base_Opnd(ebp_reg, STACK_CALLEE_SAVED_OFFSET));
    stub = pop(stub, edi_opnd);
    stub = pop(stub, esi_opnd);
    stub = pop(stub, ebx_opnd);
    
    // Leave current frame.
    stub = pop(stub, ebp_opnd);

    return stub;
}
Ejemplo n.º 3
0
// rsp should point to the bottom of the activation frame since push may occur
// inputs should be preserved outside if required since we do a call
// num_std_need_to_save registers will be preserved
char * m2n_gen_ts_to_register(char * buf, const R_Opnd * reg,
                              unsigned num_callee_saves_used,
                              unsigned num_callee_saves_max,
                              unsigned num_std_need_to_save,
                              unsigned num_ret_need_to_save) {
    // we can't preserve rax and return value on it at the same time
    assert (num_ret_need_to_save == 0 || reg != &rax_opnd);


//#ifdef PLATFORM_POSIX

    // preserve std places
    unsigned i;
    unsigned num_std_saved = 0;
    // use calle-saves registers first
        while (num_std_saved < num_std_need_to_save &&
        (i = num_callee_saves_used + num_std_saved) < num_callee_saves_max) {
            buf = mov(buf,
                LcgEM64TContext::get_reg_from_map(
                LcgEM64TContext::GR_LOCALS_OFFSET + i),
                LcgEM64TContext::get_reg_from_map(
                    LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved),
                size_64);
            ++num_std_saved;
        }
    // if we still have not preserved std places save them on the stack
    while (num_std_saved < num_std_need_to_save) {
        buf = push(buf,
            LcgEM64TContext::get_reg_from_map(
                LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved),
            size_64);
        ++num_std_saved;
    }
    assert(num_std_saved == num_std_need_to_save);

    // preserve returns
    unsigned num_ret_saved = 0;
        while (num_ret_saved < num_ret_need_to_save &&
        (i = num_callee_saves_used + num_std_saved + num_ret_saved) < num_callee_saves_max) {
            buf = mov(buf,
                LcgEM64TContext::get_reg_from_map(
                    LcgEM64TContext::GR_LOCALS_OFFSET + i),
                LcgEM64TContext::get_reg_from_map(
                    LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved),
                    size_64);
                ++num_ret_saved;
            }
    // if we still have not preserved returns save them on the stack
    while (num_ret_saved < num_ret_need_to_save) {
        buf = push(buf,
            LcgEM64TContext::get_reg_from_map(
                LcgEM64TContext::GR_RETURNS_OFFSET + num_std_saved),
            size_64);
        ++num_ret_saved;
    }
    assert(num_ret_saved == num_ret_need_to_save);

    // TODO: FIXME: only absolute addressing mode is supported now
    buf = mov(buf, rax_opnd, Imm_Opnd(size_64, (uint64)get_thread_ptr), size_64);
#ifdef _WIN64
    buf = alu(buf, add_opc, rsp_opnd, Imm_Opnd(-SHADOW));
#endif
    buf = call(buf, rax_opnd, size_64);
#ifdef _WIN64
    buf = alu(buf, add_opc, rsp_opnd, Imm_Opnd(SHADOW));
#endif
    if (reg != &rax_opnd) {
        buf = mov(buf, *reg,  rax_opnd, size_64);
    }

    // restore returns from the stack
    i = num_callee_saves_used + num_std_saved;
    while (num_ret_saved > 0 && i + num_ret_saved > num_callee_saves_max) {
            --num_ret_saved;
        buf = pop(buf,
            LcgEM64TContext::get_reg_from_map(
                LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved),
            size_64);
        }
    // restore std places from the stack
    while (num_std_saved > 0 && num_callee_saves_used + num_std_saved > num_callee_saves_max) {
            --num_std_saved;
        buf = pop(buf,
            LcgEM64TContext::get_reg_from_map(
                LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved),
            size_64);
        }
    // restore returns from callee-saves registers
    i = num_callee_saves_used + num_std_saved;
        while (num_ret_saved > 0) {
            --num_ret_saved;
        buf = mov(buf,
            LcgEM64TContext::get_reg_from_map(
                LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved),
                LcgEM64TContext::get_reg_from_map(
                LcgEM64TContext::GR_LOCALS_OFFSET + i + num_ret_saved),
                size_64);
        }
    // restore std places from callee-saves registers
        while (num_std_saved > 0) {
            --num_std_saved;
        buf = mov(buf,
            LcgEM64TContext::get_reg_from_map(
                LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved),
                LcgEM64TContext::get_reg_from_map(
                LcgEM64TContext::GR_LOCALS_OFFSET + num_callee_saves_used + num_std_saved),
                size_64);
        }
//#else //!PLATFORM_POSIX
//    buf = prefix(buf, prefix_fs);
//    buf = mov(buf, *reg,  M_Opnd(0x14), size_64);
//#endif //!PLATFORM_POSIX
    return buf;
}