We use the top of the x87 stack as is specified by the i386 SystemV ABI.

Signed-off-by: Arthur Huillet <arthur.huil...@free.fr>
---
 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
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to