We use the top of the x87 stack as is specified by the i386 SystemV ABI.
Signed-off-by: Arthur Huillet <[email protected]>
---
arch/x86/emit-code.c | 12 +++
arch/x86/include/arch/instruction.h | 3 +
arch/x86/insn-selector_32.brg | 126 ++++++++++++++++++++++++++++++++++-
arch/x86/instruction.c | 10 +++
arch/x86/lir-printer.c | 14 ++++
arch/x86/use-def.c | 2 +
include/jit/expression.h | 8 ++-
jit/expression.c | 20 ++++++
jit/invoke-bc.c | 18 ++++-
jit/tree-printer.c | 2 +
10 files changed, 210 insertions(+), 5 deletions(-)
diff --git a/arch/x86/emit-code.c b/arch/x86/emit-code.c
index bb5b299..2a63e50 100644
--- a/arch/x86/emit-code.c
+++ b/arch/x86/emit-code.c
@@ -894,6 +894,16 @@ static void emit_fdiv_reg_reg(struct buffer *buf,
emit_reg_reg(buf, 0x5e, dest, src);
}
+static void emit_fld_membase(struct buffer *buf, struct operand *src)
+{
+ __emit_membase(buf, 0xd9, mach_reg(&src->base_reg), src->disp, 0);
+}
+
+static void emit_fstp_membase(struct buffer *buf, struct operand *dest)
+{
+ __emit_membase(buf, 0xd9, mach_reg(&dest->base_reg), dest->disp, 3);
+}
+
static void emit_add_membase_reg(struct buffer *buf,
struct operand *src, struct operand *dest)
{
@@ -1207,6 +1217,8 @@ struct emitter emitters[] = {
DECL_EMITTER(INSN_FSUB_REG_REG, emit_fsub_reg_reg, TWO_OPERANDS),
DECL_EMITTER(INSN_FMUL_REG_REG, emit_fmul_reg_reg, TWO_OPERANDS),
DECL_EMITTER(INSN_FDIV_REG_REG, emit_fdiv_reg_reg, TWO_OPERANDS),
+ DECL_EMITTER(INSN_FLD_MEMBASE, emit_fld_membase, TWO_OPERANDS),
+ DECL_EMITTER(INSN_FSTP_MEMBASE, emit_fstp_membase, TWO_OPERANDS),
DECL_EMITTER(INSN_CONV_GPR_TO_FPU, emit_conv_gpr_to_fpu, TWO_OPERANDS),
DECL_EMITTER(INSN_CONV_FPU_TO_GPR, emit_conv_fpu_to_gpr, TWO_OPERANDS),
DECL_EMITTER(INSN_MOV_MEMBASE_XMM, emit_mov_membase_xmm, TWO_OPERANDS),
diff --git a/arch/x86/include/arch/instruction.h
b/arch/x86/include/arch/instruction.h
index 056480f..42c3fbb 100644
--- a/arch/x86/include/arch/instruction.h
+++ b/arch/x86/include/arch/instruction.h
@@ -74,6 +74,8 @@ enum insn_type {
INSN_FMUL_REG_REG,
INSN_FDIV_REG_REG,
INSN_FSUB_REG_REG,
+ INSN_FLD_MEMBASE,
+ INSN_FSTP_MEMBASE,
INSN_CONV_FPU_TO_GPR,
INSN_CONV_GPR_TO_FPU,
INSN_JE_BRANCH,
@@ -197,6 +199,7 @@ struct insn *imm_insn(enum insn_type, unsigned long);
struct insn *rel_insn(enum insn_type, unsigned long);
struct insn *branch_insn(enum insn_type, struct basic_block *);
struct insn *memlocal_insn(enum insn_type, struct stack_slot *);
+struct insn *membase_insn(enum insn_type, struct var_info *, long);
/*
* These functions are used by generic code to insert spill/reload
diff --git a/arch/x86/insn-selector_32.brg b/arch/x86/insn-selector_32.brg
index 86d81b9..1ba67b9 100644
--- a/arch/x86/insn-selector_32.brg
+++ b/arch/x86/insn-selector_32.brg
@@ -705,6 +705,63 @@ reg: EXPR_INVOKE(arg) 1
select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, edx,
state->reg2));
}
+freg: EXPR_FINVOKE(arg) 1
+{
+ struct compilation_unit *cu;
+ struct vm_method *method;
+ struct expression *expr;
+ struct insn *call_insn;
+ bool is_compiled;
+ void *target;
+ struct var_info *esp;
+
+ expr = to_expr(tree);
+ method = expr->target_method;
+ cu = method->compilation_unit;
+
+ if (cu == s->b_parent) {
+ /*
+ * This is a recursive method invocation. Threfore, we are
+ * already holding cu->mutex here because we entered
+ * instruction selection through jit_magic_trampoline().
+ */
+ is_compiled = false;
+ target = vm_method_trampoline_ptr(method);
+ } else {
+ pthread_mutex_lock(&cu->mutex);
+ is_compiled = cu->is_compiled;
+
+ if (is_compiled)
+ target = vm_method_native_ptr(method);
+ else
+ target = vm_method_trampoline_ptr(method);
+
+ pthread_mutex_unlock(&cu->mutex);
+ }
+
+ state->reg1 = get_fpu_var(s->b_parent);
+
+ call_insn = rel_insn(INSN_CALL_REL, (unsigned long) target);
+ select_insn(s, tree, call_insn);
+
+ if (!is_compiled) {
+ struct fixup_site *fixup;
+
+ fixup = alloc_fixup_site();
+ fixup->cu = s->b_parent;
+ fixup->relcall_insn = call_insn;
+
+ trampoline_add_fixup_site(method->trampoline, fixup);
+ }
+
+ if (method->args_count)
+ method_args_cleanup(s, tree, method->args_count);
+
+ esp = get_fixed_var(s->b_parent, REG_ESP);
+ select_insn(s, tree, membase_insn(INSN_FSTP_MEMBASE, esp, -4));
+ select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, esp, -4,
state->reg1));
+}
+
reg: EXPR_INVOKEVIRTUAL(arg) 1
{
struct var_info *eax, *edx = NULL;
@@ -761,6 +818,56 @@ reg: EXPR_INVOKEVIRTUAL(arg) 1
select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, edx,
state->reg2));
}
+freg: EXPR_FINVOKEVIRTUAL(arg) 1
+{
+ struct var_info *esp;
+ struct expression *objectref_expr;
+ struct var_info *call_target;
+ struct compilation_unit *cu;
+ unsigned long method_offset;
+ struct vm_method *method;
+ unsigned long args_count;
+ struct expression *expr;
+
+ expr = to_expr(tree);
+ method = expr->target_method;
+ cu = method->compilation_unit;
+
+ method_offset = expr_method_index(expr) * sizeof(void *);
+
+ state->reg1 = get_fpu_var(s->b_parent);
+
+ /* object reference */
+ objectref_expr = get_first_arg(expr->args_list);
+
+ if (expr_type(objectref_expr) == EXPR_VALUE) {
+ call_target = get_var(s->b_parent);
+ select_insn(s, tree, imm_reg_insn(INSN_MOV_IMM_REG,
objectref_expr->value, call_target));
+ } else {
+ call_target = state->left->reg1;
+ }
+
+ /* object class */
+ select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_REG,
call_target, offsetof(struct vm_object, class), call_target));
+
+ /* vtable */
+ select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_REG,
call_target, offsetof(struct vm_class, vtable), call_target));
+
+ /* native ptr */
+ select_insn(s, tree, imm_reg_insn(INSN_ADD_IMM_REG, method_offset,
call_target));
+
+ /* invoke method */
+ select_insn(s, tree, reg_insn(INSN_CALL_REG, call_target));
+
+ args_count = nr_args(to_expr(expr->args_list));
+ if (args_count)
+ method_args_cleanup(s, tree, args_count);
+
+ esp = get_fixed_var(s->b_parent, REG_ESP);
+ select_insn(s, tree, membase_insn(INSN_FSTP_MEMBASE, esp, -4));
+ select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_XMM, esp, -4,
state->reg1));
+}
+
reg: OP_CMPL(freg, freg) 1
{
struct var_info *esp, *eax;
@@ -1260,7 +1367,7 @@ reg: EXPR_EXCEPTION_REF
select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, slot,
result));
}
-stmt: STMT_RETURN(reg)
+stmt: STMT_RETURN(reg) 1
{
struct expression *expr;
struct var_info *src, *eax, *edx;
@@ -1283,6 +1390,23 @@ stmt: STMT_RETURN(reg)
select_insn(s, tree, branch_insn(INSN_JMP_BRANCH,
s->b_parent->exit_bb));
}
+stmt: STMT_RETURN(freg) 1
+{
+ struct expression *expr;
+ struct var_info *src, *esp;
+
+ expr = to_expr(tree);
+ expr = to_expr(expr->unary_expression);
+
+ src = state->left->reg1;
+ esp = get_fixed_var(s->b_parent, REG_ESP);
+
+ select_insn(s, tree, reg_membase_insn(INSN_MOV_XMM_MEMBASE, src, esp,
-4));
+ select_insn(s, tree, membase_insn(INSN_FLD_MEMBASE, esp, -4));
+
+ select_insn(s, tree, branch_insn(INSN_JMP_BRANCH,
s->b_parent->exit_bb));
+}
+
stmt: STMT_VOID_RETURN
{
select_insn(s, tree, branch_insn(INSN_JMP_BRANCH,
s->b_parent->exit_bb));
diff --git a/arch/x86/instruction.c b/arch/x86/instruction.c
index cf43c87..7287c24 100644
--- a/arch/x86/instruction.c
+++ b/arch/x86/instruction.c
@@ -338,3 +338,13 @@ struct insn *memlocal_insn(enum insn_type insn_type,
struct stack_slot *slot)
return insn;
}
+
+struct insn *membase_insn(enum insn_type insn_type, struct var_info
*src_base_reg,
+ long src_disp)
+{
+ struct insn *insn = alloc_insn(insn_type);
+ if (insn) {
+ init_membase_operand(insn, 0, src_base_reg, src_disp);
+ }
+ return insn;
+}
diff --git a/arch/x86/lir-printer.c b/arch/x86/lir-printer.c
index 360eef9..ba0d276 100644
--- a/arch/x86/lir-printer.c
+++ b/arch/x86/lir-printer.c
@@ -236,6 +236,18 @@ static int print_fdiv_reg_reg(struct string *str, struct
insn *insn)
return print_reg_reg(str, insn);
}
+static int print_fld_membase(struct string *str, struct insn *insn)
+{
+ print_func_name(str);
+ return print_membase(str, &insn->operand);
+}
+
+static int print_fstp_membase(struct string *str, struct insn *insn)
+{
+ print_func_name(str);
+ return print_membase(str, &insn->operand);
+}
+
static int print_and_membase_reg(struct string *str, struct insn *insn)
{
print_func_name(str);
@@ -633,6 +645,8 @@ static print_insn_fn insn_printers[] = {
[INSN_FSUB_REG_REG] = print_fsub_reg_reg,
[INSN_FMUL_REG_REG] = print_fmul_reg_reg,
[INSN_FDIV_REG_REG] = print_fdiv_reg_reg,
+ [INSN_FLD_MEMBASE] = print_fld_membase,
+ [INSN_FSTP_MEMBASE] = print_fstp_membase,
[INSN_MOV_MEMBASE_XMM] = print_mov_membase_xmm,
[INSN_MOV_XMM_MEMBASE] = print_mov_xmm_membase,
[INSN_CONV_FPU_TO_GPR] = print_conv_fpu_to_gpr,
diff --git a/arch/x86/use-def.c b/arch/x86/use-def.c
index ee22554..6e5a02c 100644
--- a/arch/x86/use-def.c
+++ b/arch/x86/use-def.c
@@ -49,6 +49,8 @@ static struct insn_info insn_infos[] = {
DECLARE_INFO(INSN_FSUB_REG_REG, USE_SRC | DEF_DST),
DECLARE_INFO(INSN_FMUL_REG_REG, USE_SRC | DEF_DST),
DECLARE_INFO(INSN_FDIV_REG_REG, USE_SRC | DEF_DST),
+ DECLARE_INFO(INSN_FLD_MEMBASE, USE_SRC),
+ DECLARE_INFO(INSN_FSTP_MEMBASE, USE_SRC),
DECLARE_INFO(INSN_CONV_GPR_TO_FPU, USE_SRC | DEF_DST),
DECLARE_INFO(INSN_CONV_FPU_TO_GPR, USE_SRC | DEF_DST),
DECLARE_INFO(INSN_MOV_MEMBASE_XMM, USE_SRC | DEF_DST),
diff --git a/include/jit/expression.h b/include/jit/expression.h
index 8f179c2..3060270 100644
--- a/include/jit/expression.h
+++ b/include/jit/expression.h
@@ -28,7 +28,9 @@ enum expression_type {
EXPR_CLASS_FIELD,
EXPR_INSTANCE_FIELD,
EXPR_INVOKE,
+ EXPR_FINVOKE,
EXPR_INVOKEVIRTUAL,
+ EXPR_FINVOKEVIRTUAL,
EXPR_ARGS_LIST,
EXPR_ARG,
EXPR_NO_ARGS,
@@ -309,6 +311,8 @@ struct expression *class_field_expr(enum vm_type, struct
vm_field *);
struct expression *instance_field_expr(enum vm_type, struct vm_field *, struct
expression *);
struct expression *invoke_expr(struct vm_method *);
struct expression *invokevirtual_expr(struct vm_method *);
+struct expression *finvoke_expr(struct vm_method *);
+struct expression *finvokevirtual_expr(struct vm_method *);
struct expression *args_list_expr(struct expression *, struct expression *);
struct expression *arg_expr(struct expression *);
struct expression *no_args_expr(void);
@@ -333,7 +337,9 @@ static inline int is_invoke_expr(struct expression *expr)
enum expression_type type = expr_type(expr);
return (type == EXPR_INVOKE)
- || (type == EXPR_INVOKEVIRTUAL);
+ || (type == EXPR_INVOKEVIRTUAL)
+ || (type == EXPR_FINVOKE)
+ || (type == EXPR_FINVOKEVIRTUAL);
}
static inline unsigned long expr_method_index(struct expression *expr)
diff --git a/jit/expression.c b/jit/expression.c
index 1f6727a..09d6594 100644
--- a/jit/expression.c
+++ b/jit/expression.c
@@ -33,6 +33,8 @@ int expr_nr_kids(struct expression *expr)
case EXPR_INSTANCE_FIELD:
case EXPR_INVOKE:
case EXPR_INVOKEVIRTUAL:
+ case EXPR_FINVOKE:
+ case EXPR_FINVOKEVIRTUAL:
case EXPR_ARG:
case EXPR_NEWARRAY:
case EXPR_ANEWARRAY:
@@ -90,6 +92,8 @@ int expr_is_pure(struct expression *expr)
have side-effects. */
case EXPR_INVOKE:
case EXPR_INVOKEVIRTUAL:
+ case EXPR_FINVOKE:
+ case EXPR_FINVOKEVIRTUAL:
case EXPR_NEWARRAY:
case EXPR_ANEWARRAY:
case EXPR_MULTIANEWARRAY:
@@ -323,6 +327,14 @@ struct expression *invokevirtual_expr(struct vm_method
*target)
return __invoke_expr(EXPR_INVOKEVIRTUAL, return_type, target);
}
+struct expression *finvokevirtual_expr(struct vm_method *target)
+{
+ enum vm_type return_type;
+
+ return_type = method_return_type(target);
+ return __invoke_expr(EXPR_FINVOKEVIRTUAL, return_type, target);
+}
+
struct expression *invoke_expr(struct vm_method *target)
{
enum vm_type return_type;
@@ -331,6 +343,14 @@ struct expression *invoke_expr(struct vm_method *target)
return __invoke_expr(EXPR_INVOKE, return_type, target);
}
+struct expression *finvoke_expr(struct vm_method *target)
+{
+ enum vm_type return_type;
+
+ return_type = method_return_type(target);
+ return __invoke_expr(EXPR_FINVOKE, return_type, target);
+}
+
struct expression *args_list_expr(struct expression *args_left,
struct expression *args_right)
{
diff --git a/jit/invoke-bc.c b/jit/invoke-bc.c
index e8d1803..b6ac3c5 100644
--- a/jit/invoke-bc.c
+++ b/jit/invoke-bc.c
@@ -131,7 +131,11 @@ int convert_invokevirtual(struct parse_context *ctx)
if (!invoke_target)
return warn("unable to resolve invocation target"), -EINVAL;
- expr = invokevirtual_expr(invoke_target);
+ if (method_return_type(invoke_target) == J_FLOAT)
+ expr = finvokevirtual_expr(invoke_target);
+ else
+ expr = invokevirtual_expr(invoke_target);
+
if (!expr)
return -ENOMEM;
@@ -159,7 +163,11 @@ int convert_invokespecial(struct parse_context *ctx)
if (!invoke_target)
return warn("unable to resolve invocation target"), -EINVAL;
- expr = invoke_expr(invoke_target);
+ if (method_return_type(invoke_target) == J_FLOAT)
+ expr = finvoke_expr(invoke_target);
+ else
+ expr = invoke_expr(invoke_target);
+
if (!expr)
return -ENOMEM;
@@ -189,7 +197,11 @@ int convert_invokestatic(struct parse_context *ctx)
if (!invoke_target)
return warn("unable to resolve invocation target"), -EINVAL;
- expr = invoke_expr(invoke_target);
+ if (method_return_type(invoke_target) == J_FLOAT)
+ expr = finvoke_expr(invoke_target);
+ else
+ expr = invoke_expr(invoke_target);
+
if (!expr)
return -ENOMEM;
diff --git a/jit/tree-printer.c b/jit/tree-printer.c
index 2c7c4c6..6fe997a 100644
--- a/jit/tree-printer.c
+++ b/jit/tree-printer.c
@@ -876,6 +876,8 @@ static print_expr_fn expr_printers[] = {
[EXPR_INSTANCE_FIELD] = print_instance_field_expr,
[EXPR_INVOKE] = print_invoke_expr,
[EXPR_INVOKEVIRTUAL] = print_invokevirtual_expr,
+ [EXPR_FINVOKE] = print_invoke_expr,
+ [EXPR_FINVOKEVIRTUAL] = print_invokevirtual_expr,
[EXPR_ARGS_LIST] = print_args_list_expr,
[EXPR_ARG] = print_arg_expr,
[EXPR_NO_ARGS] = print_no_args_expr,
--
1.6.3.3
------------------------------------------------------------------------------
_______________________________________________
Jatovm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jatovm-devel