/** * 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; }
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; }
// 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; }