예제 #1
0
/**
  *  Generates monitor exit.
  *  The code should not contain safepoints.
  *
  *  @param[in] ss buffer to put the assembly code to
  *  @param[in] input_param1 register should point to the lockword in object header.
  *  If input_param1 == ecx it reduce one register mov.
  *  The code use and do not restore eax, ecx registers.
  *  @return 0 if success in eax register
  */
char* gen_monitor_exit_helper(char *ss, const R_Opnd & input_param1) {
    if (&input_param1 != &ecx_opnd) {
        ss = mov(ss, ecx_opnd,  input_param1);
    }
#ifdef ASM_MONITOR_HELPER
	ss = mov(ss,  eax_opnd, M_Base_Opnd(ecx_reg, 0));               //  mov eax,dword[ecx]
	ss = test(ss, eax_opnd, Imm_Opnd(0x80000000), size_32);         //  test eax,0x80000000
	ss = branch8(ss, Condition_NZ,  Imm_Opnd(size_8, 0));           //  jnz fat
	char *fat = ((char *)ss) - 1;
	ss = mov(ss, eax_opnd, M_Base_Opnd(ecx_reg, 1), size_8);        //  mov al, byte[ecx+1]

    ss = alu(ss, sub_opc,  eax_opnd, Imm_Opnd(size_8,0x8),size_8);  //  sub al, 0x8
	ss = branch8(ss, Condition_C,  Imm_Opnd(size_8, 0));            //  jc zero_rec
	char *zero_rec = ((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)zero_rec - 1;              //zero_rec:
    *zero_rec = (char)offset;

    ss = mov(ss, M_Base_Opnd(ecx_reg, 2), Imm_Opnd(size_16, 0), size_16);// mov word[ecx+2],0
	ss = ret(ss,  Imm_Opnd(4));                                     // ret 4

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

#endif

    ss = push(ss,  ecx_opnd);
    ss = call(ss, (char *)hythread_thin_monitor_exit);
    ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(4)); // pop parameters
    return ss;
}
static char* get_reg(char* ss, const R_Opnd & dst, Reg_No base, int64 offset,
                       bool check_null = false, bool preserve_flags = false)
{
    char* patch_offset = NULL;

    ss = mov(ss, dst,  M_Base_Opnd(base, (I_32)offset));

    if (check_null)
    {
        if (preserve_flags)
            *ss++ = (char)0x9C; // PUSHFD

        ss = test(ss, dst, dst);
        ss = branch8(ss, Condition_Z,  Imm_Opnd(size_8, 0));
        patch_offset = ((char*)ss) - 1; // Store location for jump patch
    }

    ss = mov(ss, dst,  M_Base_Opnd(dst.reg_no(), 0));

    if (check_null)
    {
        // Patch conditional jump
        POINTER_SIZE_SINT offset =
            (POINTER_SIZE_SINT)ss - (POINTER_SIZE_SINT)patch_offset - 1;
        assert(offset >= -128 && offset < 127);
        *patch_offset = (char)offset;

        if (preserve_flags)
            *ss++ = (char)0x9D; // POPFD
    }

    return ss;
}
void JIT::emit_op_ret_object_or_this(Instruction* currentInstruction)
{
    unsigned result = currentInstruction[1].u.operand;
    unsigned thisReg = currentInstruction[2].u.operand;

    emitLoad(result, regT1, regT0);
    Jump notJSCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
    loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
    Jump notObject = branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));

    emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
    emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);

    restoreReturnAddressBeforeReturn(regT2);
    ret();

    notJSCell.link(this);
    notObject.link(this);
    emitLoad(thisReg, regT1, regT0);

    emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
    emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);

    restoreReturnAddressBeforeReturn(regT2);
    ret();
}
예제 #4
0
void JIT::emit_op_ret_object_or_this(Instruction* currentInstruction)
{
    unsigned result = currentInstruction[1].u.operand;
    unsigned thisReg = currentInstruction[2].u.operand;

    // We could JIT generate the deref, only calling out to C when the refcount hits zero.
    if (m_codeBlock->needsFullScopeChain())
        JITStubCall(this, cti_op_ret_scopeChain).call();

    emitLoad(result, regT1, regT0);
    Jump notJSCell = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
    Jump notObject = branch8(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType));

    emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
    emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);

    restoreReturnAddressBeforeReturn(regT2);
    ret();

    notJSCell.link(this);
    notObject.link(this);
    emitLoad(thisReg, regT1, regT0);

    emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
    emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);

    restoreReturnAddressBeforeReturn(regT2);
    ret();
}
예제 #5
0
파일: ini_iA32.cpp 프로젝트: dacut/juliet
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;
}
static transfer_control_stub_type gen_transfer_control_stub()
{
    static transfer_control_stub_type addr = NULL;

    if (addr) {
        return addr;
    }

    const int STUB_SIZE = 255;
    char * stub = (char *)malloc_fixed_code_for_jit(STUB_SIZE,
        DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_COLD, CAA_Allocate);
    char * ss = stub;
#ifndef NDEBUG
    memset(stub, 0xcc /*int 3*/, STUB_SIZE);
#endif

    //
    // ************* LOW LEVEL DEPENDENCY! ***************
    // This code sequence must be atomic.  The "atomicity" effect is achieved by
    // changing the rsp at the very end of the sequence.

    // rdx holds the pointer to the stack iterator
#if defined (PLATFORM_POSIX) // RDI holds 1st parameter on Linux
    ss = mov(ss, rdx_opnd, rdi_opnd);
#else // RCX holds 1st parameter on Windows
    ss = mov(ss, rdx_opnd, rcx_opnd);
#endif

    // Restore general registers
    ss = get_reg(ss, rbp_opnd, rdx_reg, CONTEXT_OFFSET(p_rbp), false);
    ss = get_reg(ss, rbx_opnd, rdx_reg, CONTEXT_OFFSET(p_rbx), true);
    ss = get_reg(ss, r12_opnd, rdx_reg, CONTEXT_OFFSET(p_r12), true);
    ss = get_reg(ss, r13_opnd, rdx_reg, CONTEXT_OFFSET(p_r13), true);
    ss = get_reg(ss, r14_opnd, rdx_reg, CONTEXT_OFFSET(p_r14), true);
    ss = get_reg(ss, r15_opnd, rdx_reg, CONTEXT_OFFSET(p_r15), true);
    ss = get_reg(ss, rsi_opnd, rdx_reg, CONTEXT_OFFSET(p_rsi), true);
    ss = get_reg(ss, rdi_opnd, rdx_reg, CONTEXT_OFFSET(p_rdi), true);
    ss = get_reg(ss, r8_opnd,  rdx_reg, CONTEXT_OFFSET(p_r8),  true);
    ss = get_reg(ss, r9_opnd,  rdx_reg, CONTEXT_OFFSET(p_r9),  true);
    ss = get_reg(ss, r10_opnd, rdx_reg, CONTEXT_OFFSET(p_r10), true);
    ss = get_reg(ss, r11_opnd, rdx_reg, CONTEXT_OFFSET(p_r11), true);

    // Get the new RSP
    M_Base_Opnd saved_rsp(rdx_reg, CONTEXT_OFFSET(rsp));
    ss = mov(ss, rax_opnd, saved_rsp);
    // Store it over return address for future use
    ss = mov(ss, M_Base_Opnd(rsp_reg, 0), rax_opnd);
    // Get the new RIP
    ss = get_reg(ss, rcx_opnd, rdx_reg, CONTEXT_OFFSET(p_rip), false);
    // Store RIP to [<new RSP> - 136] to preserve 128 bytes under RSP
    // which are 'reserved' on Linux
    ss = mov(ss,  M_Base_Opnd(rax_reg, -136), rcx_opnd);

    ss = get_reg(ss, rax_opnd, rdx_reg, CONTEXT_OFFSET(p_rax), true);

    // Restore processor flags
    ss = movzx(ss, rcx_opnd,  M_Base_Opnd(rdx_reg, CONTEXT_OFFSET(eflags)), size_16);
    ss = test(ss, rcx_opnd, rcx_opnd);
    ss = branch8(ss, Condition_Z,  Imm_Opnd(size_8, 0));
    char* patch_offset = ((char*)ss) - 1; // Store location for jump patch
    *ss++ = (char)0x9C; // PUSHFQ
    M_Base_Opnd sflags(rsp_reg, 0);
    ss = alu(ss, and_opc, sflags, Imm_Opnd(size_32,FLG_CLEAR_MASK), size_32);
    ss = alu(ss, and_opc, rcx_opnd, Imm_Opnd(size_32,FLG_SET_MASK), size_32);
    ss = alu(ss, or_opc, sflags, rcx_opnd, size_32);
    *ss++ = (char)0x9D; // POPFQ
    // Patch conditional jump
    POINTER_SIZE_SINT offset =
        (POINTER_SIZE_SINT)ss - (POINTER_SIZE_SINT)patch_offset - 1;
    *patch_offset = (char)offset;

    ss = get_reg(ss, rcx_opnd, rdx_reg, CONTEXT_OFFSET(p_rcx), true, true);
    ss = get_reg(ss, rdx_opnd, rdx_reg, CONTEXT_OFFSET(p_rdx), true, true);

    // Setup stack pointer to previously saved value
    ss = mov(ss,  rsp_opnd,  M_Base_Opnd(rsp_reg, 0));

    // Jump to address stored to [<new RSP> - 136]
    ss = jump(ss,  M_Base_Opnd(rsp_reg, -136));

    addr = (transfer_control_stub_type)stub;
    assert(ss-stub <= STUB_SIZE);

    /*
       The following code will be generated:

        mov         rdx,rcx
        mov         rbp,qword ptr [rdx+10h]
        mov         rbp,qword ptr [rbp]
        mov         rbx,qword ptr [rdx+20h]
        test        rbx,rbx
        je          __label1__
        mov         rbx,qword ptr [rbx]
__label1__
        ; .... The same for r12,r13,r14,r15,rsi,rdi,r8,r9,r10
        mov         r11,qword ptr [rdx+88h]
        test        r11,r11
        je          __label11__
        mov         r11,qword ptr [r11]
__label11__
        mov         rax,qword ptr [rdx+8]
        mov         qword ptr [rsp],rax
        mov         rcx,qword ptr [rdx+18h]
        mov         rcx,qword ptr [rcx]
        mov         qword ptr [rax-88h],rcx
        mov         rax,qword ptr [rdx+48h]
        test        rax,rax
        je          __label12__
        mov         rax,qword ptr [rax]
__label12__
        movzx       rcx,word ptr [rdx+90h]
        test        rcx,rcx
        je          __label13__
        pushfq
        and         dword ptr [rsp], 0x003F7202
        and         ecx, 0x00000CD5
        or          dword ptr [esp], ecx
        popfq
__label13__
        mov         rcx,qword ptr [rdx+50h]
        pushfq
        test        rcx,rcx
        je          __label14__
        mov         rcx,qword ptr [rcx]
__label14__
        popfq
        mov         rdx,qword ptr [rdx+58h]
        pushfq
        test        rdx,rdx
        je          __label15__
        mov         rdx,qword ptr [rdx]
__label15__
        popfq
        mov         rsp,qword ptr [rsp]
        jmp         qword ptr [rsp-88h]
    */

    DUMP_STUB(stub, "getaddress__transfer_control", ss-stub);

    return addr;
}
예제 #7
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;
}