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