void *_jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf)
{
	unsigned char prolog[JIT_PROLOG_SIZE];
	unsigned char *inst = prolog;
	int reg;

	/* Push ebp onto the stack */
	x86_push_reg(inst, X86_EBP);

	/* Initialize EBP for the current frame */
	x86_mov_reg_reg(inst, X86_EBP, X86_ESP, sizeof(void *));

	/* Allocate space for the local variable frame */
	if(func->builder->frame_size > 0)
	{
		x86_alu_reg_imm(inst, X86_SUB, X86_ESP,
			 			(int)(func->builder->frame_size));
	}

	/* Save registers that we need to preserve */
	for(reg = 0; reg <= 7; ++reg)
	{
		if(jit_reg_is_used(gen->touched, reg) &&
		   (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
		{
			x86_push_reg(inst, _jit_reg_info[reg].cpu_reg);
		}
	}

	/* Copy the prolog into place and return the adjusted entry position */
	reg = (int)(inst - prolog);
	jit_memcpy(((unsigned char *)buf) + JIT_PROLOG_SIZE - reg, prolog, reg);
	return (void *)(((unsigned char *)buf) + JIT_PROLOG_SIZE - reg);
}
Beispiel #2
0
void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func)
{
	int reg, regset;
	arm_inst_buf inst;
	void **fixup;
	void **next;
	jit_nint offset;

	/* Initialize the instruction buffer */
	jit_gen_load_inst_ptr(gen, inst);

	/* Determine which registers need to be restored when we return */
	regset = 0;
	for(reg = 0; reg <= 15; ++reg)
	{
		if(jit_reg_is_used(gen->touched, reg) &&
		   (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
		{
			regset |= (1 << reg);
		}
	}

	/* Apply fixups for blocks that jump to the epilog */
	fixup = (void **)(gen->epilog_fixup);
	while(fixup != 0)
	{
		offset = (((jit_nint)(fixup[0])) & 0x00FFFFFF) << 2;
		if(!offset)
		{
			next = 0;
		}
		else
		{
			next = (void **)(((unsigned char *)fixup) - offset);
		}
		arm_patch(inst, fixup, arm_inst_get_posn(inst));
		fixup = next;
	}
	gen->epilog_fixup = 0;

	/* Pop the local stack frame and return */
	arm_pop_frame(inst, regset);
	jit_gen_save_inst_ptr(gen, inst);

	/* Flush the remainder of the constant pool */
	flush_constants(gen, 1);
}
Beispiel #3
0
void *_jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf)
{
	unsigned int prolog[JIT_PROLOG_SIZE / sizeof(int)];
	arm_inst_buf inst;
	int reg, regset;
	unsigned int saved;
	unsigned int frame_size;

	/* Initialize the instruction buffer */
	arm_inst_buf_init(inst, prolog, prolog + JIT_PROLOG_SIZE / sizeof(int));

	/* Determine which registers need to be preserved */
	regset = 0;
	saved = 0;
	for(reg = 0; reg <= 15; ++reg)
	{
		if(jit_reg_is_used(gen->touched, reg) &&
		   (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
		{
			regset |= (1 << reg);
			saved += sizeof(void *);
		}
	}

	/* Setup the frame, pushing all the callee-save registers */
	arm_setup_frame(inst, regset);

	/* Allocate space for the local variable frame.  Subtract off
	   the space for the registers that we just saved.  The pc, lr,
	   and fp registers are always saved, so account for them too */
	frame_size = func->builder->frame_size - (saved + 3 * sizeof(void *));
	frame_size += (unsigned int)(func->builder->param_area_size);
	if(frame_size > 0)
	{
		arm_alu_reg_imm(inst, ARM_SUB, ARM_SP, ARM_SP, frame_size);
	}

	/* Copy the prolog into place and return the adjusted entry position */
	reg = (int)((arm_inst_get_posn(inst) - prolog) * sizeof(unsigned int));
	jit_memcpy(((unsigned char *)buf) + JIT_PROLOG_SIZE - reg, prolog, reg);
	return (void *)(((unsigned char *)buf) + JIT_PROLOG_SIZE - reg);
}
void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func)
{
	jit_nint pop_bytes = 0;
	int reg, offset;
	unsigned char *inst;
	int struct_return_offset = 0;
	void **fixup;
	void **next;

	/* Check if there is sufficient space for the epilog */
	_jit_cache_check_space(&gen->posn, 48);

#if JIT_APPLY_X86_FASTCALL == 1
	/* Determine the number of parameter bytes to pop when we return */
	{
		jit_type_t signature;
		unsigned int num_params;
		unsigned int param;
		signature = func->signature;
		if(jit_type_get_abi(signature) == jit_abi_stdcall ||
            jit_type_get_abi(signature) == jit_abi_thiscall||
            jit_type_get_abi(signature) == jit_abi_fastcall)
		{
			if(func->nested_parent)
			{
				pop_bytes += sizeof(void *);
			}
			if(jit_type_return_via_pointer(jit_type_get_return(signature)))
			{
				struct_return_offset = 2 * sizeof(void *) + pop_bytes;
				pop_bytes += sizeof(void *);
			}
			num_params = jit_type_num_params(signature);
			for(param = 0; param < num_params; ++param)
			{
				pop_bytes += ROUND_STACK
						(jit_type_get_size
							(jit_type_get_param(signature, param)));
			}
			if(jit_type_get_abi(signature) == jit_abi_fastcall)
			{
				/* The first two words are in fastcall registers */
				if(pop_bytes > (2 * sizeof(void *)))
				{
					pop_bytes -= 2 * sizeof(void *);
				}
				else
				{
					pop_bytes = 0;
				}
				struct_return_offset = 0;
			}
            else if(jit_type_get_abi(signature) == jit_abi_thiscall)
            {
                /* The this is in ECX register */
                if(pop_bytes > (1 * sizeof(void *)))
                {
                    pop_bytes -= 1 * sizeof(void *);
                }
                else
                {
                    pop_bytes = 0;
                }
                struct_return_offset = 0;
            }
		}
		else if(!(func->nested_parent) &&
				jit_type_return_via_pointer(jit_type_get_return(signature)))
		{
#if JIT_APPLY_X86_POP_STRUCT_RETURN == 1
			pop_bytes += sizeof(void *);
#endif
			struct_return_offset = 2 * sizeof(void *);
		}
	}
#else
	{
		/* We only need to pop structure pointers in non-nested functions */
		jit_type_t signature;
		signature = func->signature;
		if(!(func->nested_parent) &&
		   jit_type_return_via_pointer(jit_type_get_return(signature)))
		{
#if JIT_APPLY_X86_POP_STRUCT_RETURN == 1
			pop_bytes += sizeof(void *);
#endif
			struct_return_offset = 2 * sizeof(void *);
		}
	}
#endif

	/* Perform fixups on any blocks that jump to the epilog */
	inst = gen->posn.ptr;
	fixup = (void **)(gen->epilog_fixup);
	while(fixup != 0)
	{
		next = (void **)(fixup[0]);
		fixup[0] = (void *)(((jit_nint)inst) - ((jit_nint)fixup) - 4);
		fixup = next;
	}
	gen->epilog_fixup = 0;

	/* If we are returning a structure via a pointer, then copy
	   the pointer value into EAX when we return */
	if(struct_return_offset != 0)
	{
		x86_mov_reg_membase(inst, X86_EAX, X86_EBP, struct_return_offset, 4);
	}

	/* Restore the callee save registers that we used */
	if(gen->stack_changed)
	{
		offset = -(func->builder->frame_size);
		for(reg = 0; reg <= 7; ++reg)
		{
			if(jit_reg_is_used(gen->touched, reg) &&
			   (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
			{
				offset -= sizeof(void *);
				x86_mov_reg_membase(inst, _jit_reg_info[reg].cpu_reg,
									X86_EBP, offset, sizeof(void *));
			}
		}
	}
	else
	{
		for(reg = 7; reg >= 0; --reg)
		{
			if(jit_reg_is_used(gen->touched, reg) &&
			   (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
			{
				x86_pop_reg(inst, _jit_reg_info[reg].cpu_reg);
			}
		}
	}

	/* Pop the stack frame and restore the saved copy of ebp */
	if(gen->stack_changed || func->builder->frame_size > 0)
	{
		x86_mov_reg_reg(inst, X86_ESP, X86_EBP, sizeof(void *));
	}
	x86_pop_reg(inst, X86_EBP);

	/* Return from the current function */
	if(pop_bytes > 0)
	{
		x86_ret_imm(inst, pop_bytes);
	}
	else
	{
		x86_ret(inst);
	}
	gen->posn.ptr = inst;
}