It is incorrect to convert invocations into expressions which are
pushed onto mimic stack because pushed expressions can be evaluated
any time later after they are pushed. This can result in breaking the
execution sequence, where methods are not invoked in the order they
appear in bytecode.

Invocations are now handled as statements and their result is pushed
onto mimic stack.

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 Makefile                     |    5 +-
 arch/x86/insn-selector.brg   |  236 ++++++++++++++----------------------------
 include/jit/expression.h     |   48 +---------
 include/jit/statement.h      |   21 ++++
 jit/expression.c             |   67 ------------
 jit/invoke-bc.c              |  142 ++++++++++++++------------
 jit/ostack-bc.c              |   14 +---
 jit/statement.c              |   14 +++
 jit/tree-printer.c           |  123 ++++++++++------------
 regression/jvm/InvokeTest.j  |   33 ++++++
 regression/run-suite.sh      |    1 +
 test/jit/bc-test-utils.c     |   15 ++-
 test/jit/bc-test-utils.h     |    3 +-
 test/jit/invoke-bc-test.c    |  214 ++++++++++----------------------------
 test/jit/tree-printer-test.c |   49 ++++-----
 15 files changed, 374 insertions(+), 611 deletions(-)
 create mode 100644 regression/jvm/InvokeTest.j

diff --git a/Makefile b/Makefile
index be74fb6..8d57627 100644
--- a/Makefile
+++ b/Makefile
@@ -307,10 +307,11 @@ REGRESSION_TEST_SUITE_CLASSES = \
 
 JASMIN_REGRESSION_TEST_SUITE_CLASSES = \
        regression/jvm/DupTest.j \
+       regression/jvm/InvokeResultTest.j \
+       regression/jvm/InvokeTest.j \
        regression/jvm/PopTest.j \
        regression/jvm/SubroutineTest.j \
-       regression/jvm/WideTest.j \
-       regression/jvm/InvokeResultTest.j
+       regression/jvm/WideTest.j
 
 java-regression: FORCE
        $(E) "  JAVAC   " $(REGRESSION_TEST_SUITE_CLASSES)
diff --git a/arch/x86/insn-selector.brg b/arch/x86/insn-selector.brg
index e587c96..43f6960 100644
--- a/arch/x86/insn-selector.brg
+++ b/arch/x86/insn-selector.brg
@@ -58,7 +58,7 @@ struct _MBState;
 
 static void select_insn(struct basic_block *bb, struct tree_node *tree, struct 
insn *instruction);
 static void select_exception_test(struct basic_block *bb, struct tree_node 
*tree);
-void finvoke_return_value(struct _MBState *state, struct basic_block *s, 
struct tree_node *tree, enum vm_type ret_vm_type);
+void save_invoke_result(struct basic_block *s, struct tree_node *tree, struct 
vm_method *method, struct statement *stmt);
 
 static unsigned char size_to_scale(int size)
 {
@@ -697,130 +697,6 @@ reg:      OP_XOR(reg, reg) 1
        binop_reg_reg_high(state, s, tree, INSN_XOR_REG_REG);
 }
 
-reg:   EXPR_INVOKE(arg) 1
-{
-       struct var_info *eax, *edx = NULL;
-       struct compilation_unit *cu;
-       struct vm_method *method;
-       struct expression *expr;
-
-       expr    = to_expr(tree);
-       method  = expr->target_method;
-       cu      = method->compilation_unit;
-
-       eax = get_fixed_var(s->b_parent, MACH_REG_xAX);
-       state->reg1 = get_var(s->b_parent, J_INT);
-
-       if (get_method_return_type(method->type) == J_LONG) {
-               edx = get_fixed_var(s->b_parent, MACH_REG_xDX);
-               state->reg2 = get_var(s->b_parent, J_INT);
-       }
-
-       invoke(s, tree, cu, method);
-
-       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, eax, state->reg1));
-       if (edx != NULL)
-               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, edx, 
state->reg2));
-}
-
-freg:  EXPR_FINVOKEINTERFACE(arg) 1
-{
-       enum vm_type ret_vm_type;
-       struct expression *expr;
-       struct vm_method *method;
-
-       expr    = to_expr(tree);
-       method  = expr->target_method;
-
-       ret_vm_type = method_return_type(method);
-       state->reg1 = get_var(s->b_parent, ret_vm_type);
-
-       invokeinterface(state, s, tree);
-       finvoke_return_value(state, s, tree, ret_vm_type);
-}
-
-reg:   EXPR_INVOKEINTERFACE(arg) 1
-{
-       struct var_info *eax, *edx = NULL;
-       struct expression *expr;
-       struct vm_method *method;
-
-       expr    = to_expr(tree);
-       method  = expr->target_method;
-
-       eax = get_fixed_var(s->b_parent, MACH_REG_xAX);
-       state->reg1 = get_var(s->b_parent, J_INT);
-
-       if (get_method_return_type(method->type) == J_LONG) {
-               edx = get_fixed_var(s->b_parent, MACH_REG_xDX);
-               state->reg2 = get_var(s->b_parent, J_INT);
-       }
-
-       invokeinterface(state, s, tree);
-
-       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, eax, state->reg1));
-       if (edx != NULL)
-               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, edx, 
state->reg2));
-}
-
-freg:  EXPR_FINVOKE(arg) 1
-{
-       struct compilation_unit *cu;
-       enum vm_type ret_vm_type;
-       struct vm_method *method;
-       struct expression *expr;
-
-       expr    = to_expr(tree);
-       method  = expr->target_method;
-       cu      = method->compilation_unit;
-
-       ret_vm_type = method_return_type(method);
-       state->reg1 = get_var(s->b_parent, ret_vm_type);
-
-       invoke(s, tree, cu, method);
-       finvoke_return_value(state, s, tree, ret_vm_type);
-}
-
-reg:   EXPR_INVOKEVIRTUAL(arg) 1
-{
-       struct var_info *eax, *edx = NULL;
-       struct vm_method *method;
-       struct expression *expr;
-
-       expr    = to_expr(tree);
-       method  = expr->target_method;
-
-       eax = get_fixed_var(s->b_parent, MACH_REG_xAX);
-       state->reg1 = get_var(s->b_parent, J_INT);
-
-       if (get_method_return_type(method->type) == J_LONG) {
-               edx = get_fixed_var(s->b_parent, MACH_REG_xDX);
-               state->reg2 = get_var(s->b_parent, J_INT);
-       }
-
-       invokevirtual(state, s, tree);
-
-       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, eax, state->reg1));
-       if (edx != NULL)
-               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, edx, 
state->reg2));
-}
-
-freg:  EXPR_FINVOKEVIRTUAL(arg) 1
-{
-       enum vm_type ret_vm_type;
-       struct expression *expr;
-       struct vm_method *method;
-
-       expr    = to_expr(tree);
-       method  = expr->target_method;
-
-       ret_vm_type = method_return_type(method);
-       state->reg1 = get_var(s->b_parent, ret_vm_type);
-
-       invokevirtual(state, s, tree);
-       finvoke_return_value(state, s, tree, ret_vm_type);
-}
-
 reg:   OP_CMPL(freg, freg) 1
 {
        struct var_info *esp, *eax;
@@ -1897,6 +1773,21 @@ reg:     EXPR_EXCEPTION_REF
        select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, slot, 
result));
 }
 
+stmt:  STMT_INVOKE(arg) 1
+{
+       invoke(s, tree);
+}
+
+stmt:  STMT_INVOKEINTERFACE(arg) 1
+{
+       invokeinterface(state, s, tree);
+}
+
+stmt:  STMT_INVOKEVIRTUAL(arg) 1
+{
+       invokevirtual(state, s, tree);
+}
+
 %ifdef CONFIG_X86_32
 stmt:  STMT_RETURN(reg) 1
 {
@@ -3012,26 +2903,53 @@ static void select_trace_return_value(struct 
basic_block *s,
        }
 }
 
-void finvoke_return_value(struct _MBState *state, struct basic_block *s,
-                         struct tree_node *tree, enum vm_type ret_vm_type)
+void save_invoke_result(struct basic_block *s, struct tree_node *tree,
+                       struct vm_method *method, struct statement *stmt)
 {
-       struct var_info *esp;
        struct stack_slot *scratch;
+       struct expression *tmp;
+       struct var_info *esp;
+       struct var_info *eax;
+       struct var_info *edx;
 
-       esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
+       if (opt_trace_invoke_verbose)
+               select_trace_return_value(s, tree, method);
 
-       if (ret_vm_type == J_FLOAT) {
+       tmp = stmt->invoke_result;
+       if (!tmp)
+               return;
+
+       switch (tmp->vm_type) {
+       case J_FLOAT:
                scratch = get_scratch_slot(s->b_parent);
+               esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
                select_insn(s, tree, memlocal_insn(INSN_FSTP_MEMLOCAL, 
scratch));
-               select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_XMM, 
scratch, state->reg1));
-       } else {
+               select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_XMM, 
scratch, tmp->tmp_low));
+               break;
+       case J_DOUBLE:
                scratch = get_scratch_slot(s->b_parent);
+               esp = get_fixed_var(s->b_parent, MACH_REG_xSP);
                select_insn(s, tree, memlocal_insn(INSN_FSTP_64_MEMLOCAL, 
scratch));
-               select_insn(s, tree, 
memlocal_reg_insn(INSN_MOV_64_MEMLOCAL_XMM, scratch, state->reg1));
+               select_insn(s, tree, 
memlocal_reg_insn(INSN_MOV_64_MEMLOCAL_XMM, scratch, tmp->tmp_low));
+               break;
+       case J_LONG:
+               eax = get_fixed_var(s->b_parent, MACH_REG_xAX);
+               edx = get_fixed_var(s->b_parent, MACH_REG_xDX);
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, eax, 
tmp->tmp_low));
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, edx, 
tmp->tmp_high));
+               break;
+       case J_INT:
+       case J_REFERENCE:
+               eax = get_fixed_var(s->b_parent, MACH_REG_xAX);
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, eax, 
tmp->tmp_low));
+               break;
+       default:
+               error("invalid result type");
        }
 }
 
 static void select_vm_native_call(struct basic_block *s, struct tree_node 
*tree,
+                                 struct vm_method *method, struct statement 
*stmt,
                                  struct insn *call_insn, void *target)
 {
        struct var_info *offset_reg;
@@ -3076,6 +2994,8 @@ static void select_vm_native_call(struct basic_block *s, 
struct tree_node *tree,
 
        select_insn(s, tree, call_insn);
 
+       save_invoke_result(s, tree, method, stmt);
+
        /* Restore vm_native_stack_offset (pop) */
        select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG,
                        sizeof(struct vm_native_stack_entry), offset_reg));
@@ -3095,12 +3015,19 @@ static void select_safepoint(struct basic_block *s, 
struct tree_node *tree)
        select_insn(s, tree, gc_safepoint_insn);
 }
 
-static void invoke(struct basic_block *s, struct tree_node *tree, struct 
compilation_unit *cu, struct vm_method *method)
+static void invoke(struct basic_block *s, struct tree_node *tree)
 {
-       bool is_compiled;
+       struct compilation_unit *cu;
+       struct vm_method *method;
+       struct statement *stmt;
        struct insn *call_insn;
-       void *target;
        int nr_stack_args;
+       bool is_compiled;
+       void *target;
+
+       stmt    = to_stmt(tree);
+       method  = stmt->target_method;
+       cu      = method->compilation_unit;
 
        if (cu == s->b_parent) {
                /*
@@ -3125,10 +3052,11 @@ static void invoke(struct basic_block *s, struct 
tree_node *tree, struct compila
        call_insn = rel_insn(INSN_CALL_REL, (unsigned long) target);
 
        if (vm_method_is_vm_native(method))
-               select_vm_native_call(s, tree, call_insn,
-                                     vm_method_native_ptr(method));
-       else
+               select_vm_native_call(s, tree, method, stmt, call_insn, 
vm_method_native_ptr(method));
+       else {
                select_insn(s, tree, call_insn);
+               save_invoke_result(s, tree, method, stmt);
+       }
 
        if (!is_compiled) {
                struct fixup_site *fixup;
@@ -3144,9 +3072,6 @@ static void invoke(struct basic_block *s, struct 
tree_node *tree, struct compila
        if (nr_stack_args)
                method_args_cleanup(s, tree, nr_stack_args);
 
-       if (opt_trace_invoke_verbose)
-               select_trace_return_value(s, tree, method);
-
        if (vm_method_is_native(method))
                select_exception_test(s, tree);
 }
@@ -3154,22 +3079,21 @@ static void invoke(struct basic_block *s, struct 
tree_node *tree, struct compila
 
 static void invokevirtual(struct _MBState *state, struct basic_block *s, 
struct tree_node *tree)
 {
-       struct expression *expr;
+       struct statement *stmt;
        struct var_info *call_target;
        unsigned long method_offset;
        struct vm_method *method;
        struct insn *call_insn;
        int nr_stack_args;
 
-       expr    = to_expr(tree);
-       method_offset = expr_method_index(expr) * sizeof(void *);
+       stmt    = to_stmt(tree);
+       method_offset = stmt_method_index(stmt) * sizeof(void *);
 
-       method  = expr->target_method;
+       method  = stmt->target_method;
 
        /* object reference */
        call_target = get_var(s->b_parent, J_REFERENCE);
-       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG,
-                                         state->left->reg1, call_target));
+       select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, state->left->reg1, 
call_target));
 
        /* object class */
        select_insn(s, tree, membase_reg_insn(INSN_MOV_MEMBASE_REG, 
call_target, offsetof(struct vm_object, class), call_target));
@@ -3186,6 +3110,7 @@ static void invokevirtual(struct _MBState *state, struct 
basic_block *s, struct
        call_insn = reg_insn(INSN_CALL_REG, call_target);
 
        select_insn(s, tree, call_insn);
+       save_invoke_result(s, tree, method, stmt);
 
        nr_stack_args = get_stack_args_count(method);
        if (nr_stack_args)
@@ -3193,9 +3118,6 @@ static void invokevirtual(struct _MBState *state, struct 
basic_block *s, struct
 
        if (vm_method_is_native(method))
                select_exception_test(s, tree);
-
-       if (opt_trace_invoke_verbose)
-               select_trace_return_value(s, tree, method);
 }
 
 static void invokeinterface(struct _MBState *state, struct basic_block *s, 
struct tree_node *tree)
@@ -3205,17 +3127,17 @@ static void invokeinterface(struct _MBState *state, 
struct basic_block *s, struc
        struct compilation_unit *cu;
        unsigned long method_offset;
        struct vm_method *method;
-       struct expression *expr;
+       struct statement *stmt;
        struct insn *call_insn;
        int nr_stack_args;
 
-       expr    = to_expr(tree);
-       method  = expr->target_method;
+       stmt    = to_stmt(tree);
+       method  = stmt->target_method;
        cu      = method->compilation_unit;
 
        eax = get_fixed_var(s->b_parent, MACH_REG_xAX);
 
-       method_offset = expr_method_index(expr) * sizeof(void *);
+       method_offset = stmt_method_index(stmt) * sizeof(void *);
 
        /* object reference */
        call_target = state->left->reg1;
@@ -3237,13 +3159,11 @@ static void invokeinterface(struct _MBState *state, 
struct basic_block *s, struc
        call_insn = reg_insn(INSN_CALL_REG, call_target);
 
        select_insn(s, tree, call_insn);
+       save_invoke_result(s, tree, method, stmt);
 
        nr_stack_args = get_stack_args_count(method);
        if (nr_stack_args)
                method_args_cleanup(s, tree, nr_stack_args);
-
-       if (opt_trace_invoke_verbose)
-               select_trace_return_value(s, tree, method);
 }
 
 static void emit_code(struct basic_block *bb, MBState *state, int goal)
diff --git a/include/jit/expression.h b/include/jit/expression.h
index 759e66c..d89ff92 100644
--- a/include/jit/expression.h
+++ b/include/jit/expression.h
@@ -36,12 +36,6 @@ enum expression_type {
        EXPR_CONVERSION_TO_DOUBLE,
        EXPR_CLASS_FIELD,
        EXPR_INSTANCE_FIELD,
-       EXPR_INVOKE,
-       EXPR_FINVOKE,
-       EXPR_INVOKEINTERFACE,
-       EXPR_FINVOKEINTERFACE,
-       EXPR_INVOKEVIRTUAL,
-       EXPR_FINVOKEVIRTUAL,
        EXPR_ARGS_LIST,
        EXPR_ARG,
        EXPR_ARG_THIS,
@@ -191,25 +185,6 @@ struct expression {
                        struct vm_field *instance_field;
                };
 
-               /*  EXPR_INVOKE represents a method invocation expression (see
-                   JLS 15.12.) for which the target method can be determined
-                   statically.  This expression type can contain side-effects
-                   and can be used as an rvalue only.
-
-                   EXPR_INVOKESPECIAL and EXPR_INVOKEVIRTUAL represent a
-                   method invocation (see JLS 15.12.) for which the target
-                   method has to be determined from instance class vtable at
-                   the call site.
-
-                   The first argument in the argument list is always the
-                   object reference for the invocation.  This expression type
-                   can contain side-effects and can be used as an rvalue
-                   only.  */
-               struct {
-                       struct tree_node *args_list;
-                       struct vm_method *target_method;
-               };
-
                /*  EXPR_ARGS_LIST represents list of arguments passed to
                    method. This expression does not evaluate to a value and
                    is used for instruction selection only.  */
@@ -230,7 +205,7 @@ struct expression {
                        enum machine_reg arg_reg;
                };
 
-               /*  EXPR_NO_ARGS is used for EXPR_INVOKE expression type when
+               /*  EXPR_NO_ARGS is used for STMT_INVOKE expression type when
                    there are no arguments to pass.  */
                struct {
                        /* Nothing. */
@@ -352,11 +327,6 @@ struct expression *conversion_to_double_expr(enum vm_type, 
struct expression *);
 
 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 *invokeinterface_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 *arg_this_expr(struct expression *);
@@ -392,20 +362,4 @@ static inline enum vm_type mimic_stack_type(enum vm_type 
type)
        }
 }
 
-static inline int is_invoke_expr(struct expression *expr)
-{
-       enum expression_type type = expr_type(expr);
-
-       return (type == EXPR_INVOKE)
-               || (type == EXPR_INVOKEINTERFACE)
-               || (type == EXPR_INVOKEVIRTUAL)
-               || (type == EXPR_FINVOKE)
-               || (type == EXPR_FINVOKEVIRTUAL);
-}
-
-static inline unsigned long expr_method_index(struct expression *expr)
-{
-       return expr->target_method->virtual_index;
-}
-
 #endif
diff --git a/include/jit/statement.h b/include/jit/statement.h
index 612d8b2..2e79b7c 100644
--- a/include/jit/statement.h
+++ b/include/jit/statement.h
@@ -24,6 +24,9 @@ enum statement_type {
        STMT_ARRAY_STORE_CHECK,
        STMT_TABLESWITCH,
        STMT_LOOKUPSWITCH_JUMP,
+       STMT_INVOKE,
+       STMT_INVOKEINTERFACE,
+       STMT_INVOKEVIRTUAL,
        STMT_LAST,      /* Not a real type. Keep this last.  */
 };
 
@@ -102,9 +105,22 @@ struct statement {
                        struct tree_node *lookupswitch_target;
                };
 
+               struct /* STMT_LOOKUPSWITCH_JUMP */ {
+                       struct tree_node *args_list;
+                       struct vm_method *target_method;
+               };
+
                /* STMT_EXPRESSION, STMT_ARRAY_CHECK */
                struct tree_node *expression;
        };
+
+       union {
+               /* STMT_INVOKE, STMT_INVOKEVIRTUAL, STMT_INVOKEINTERFACE */
+               struct {
+                       struct expression *invoke_result;
+               };
+       };
+
        struct list_head stmt_list_node;
        unsigned long bytecode_offset;
 };
@@ -130,6 +146,11 @@ void free_lookupswitch(struct lookupswitch *);
 int lookupswitch_pair_comp(const void *, const void *);
 struct statement *if_stmt(struct basic_block *, enum vm_type, enum 
binary_operator, struct expression *, struct expression *);
 
+static inline unsigned long stmt_method_index(struct statement *stmt)
+{
+       return stmt->target_method->virtual_index;
+}
+
 #define for_each_stmt(stmt, stmt_list) list_for_each_entry(stmt, stmt_list, 
stmt_list_node)
 
 #endif
diff --git a/jit/expression.c b/jit/expression.c
index ff61275..6368aa1 100644
--- a/jit/expression.c
+++ b/jit/expression.c
@@ -52,12 +52,6 @@ int expr_nr_kids(struct expression *expr)
        case EXPR_CONVERSION_FROM_DOUBLE:
        case EXPR_INSTANCE_FIELD:
        case EXPR_FLOAT_INSTANCE_FIELD:
-       case EXPR_INVOKE:
-       case EXPR_INVOKEINTERFACE:
-       case EXPR_FINVOKEINTERFACE:
-       case EXPR_INVOKEVIRTUAL:
-       case EXPR_FINVOKE:
-       case EXPR_FINVOKEVIRTUAL:
        case EXPR_ARG:
        case EXPR_ARG_THIS:
        case EXPR_NEWARRAY:
@@ -125,12 +119,6 @@ int expr_is_pure(struct expression *expr)
 
                /* These expression types should be always assumed to
                   have side-effects. */
-       case EXPR_INVOKE:
-       case EXPR_INVOKEVIRTUAL:
-       case EXPR_INVOKEINTERFACE:
-       case EXPR_FINVOKEINTERFACE:
-       case EXPR_FINVOKE:
-       case EXPR_FINVOKEVIRTUAL:
        case EXPR_NEWARRAY:
        case EXPR_ANEWARRAY:
        case EXPR_MULTIANEWARRAY:
@@ -423,61 +411,6 @@ struct expression *instance_field_expr(enum vm_type 
vm_type,
        return expr;
 }
 
-static struct expression *
-__invoke_expr(enum expression_type expr_type, enum vm_type vm_type, struct 
vm_method *target_method)
-{
-       struct expression *expr = alloc_expression(expr_type,
-                                                  mimic_stack_type(vm_type));
-
-       if (expr)
-               expr->target_method = target_method;
-
-       return expr;
-}
-
-struct expression *invokeinterface_expr(struct vm_method *target)
-{
-       enum vm_type return_type;
-
-       return_type = method_return_type(target);
-       if (vm_type_is_float(return_type))
-               return __invoke_expr(EXPR_FINVOKEINTERFACE, return_type, 
target);
-
-       return __invoke_expr(EXPR_INVOKEINTERFACE, return_type, target);
-}
-
-struct expression *invokevirtual_expr(struct vm_method *target)
-{
-       enum vm_type return_type;
-
-       return_type = method_return_type(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;
-
-       return_type = method_return_type(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 b0a993a..698dd36 100644
--- a/jit/invoke-bc.c
+++ b/jit/invoke-bc.c
@@ -66,7 +66,7 @@ static unsigned int method_real_argument_count(struct 
vm_method *invoke_target)
 
 static int convert_and_add_args(struct parse_context *ctx,
                                struct vm_method *invoke_target,
-                               struct expression *expr)
+                               struct statement *stmt)
 {
        struct expression *args_list;
 
@@ -74,29 +74,63 @@ static int convert_and_add_args(struct parse_context *ctx,
                                 method_real_argument_count(invoke_target),
                                 invoke_target);
        if (!args_list)
-               return warn("out of memory"), -ENOMEM;
-
-       expr->args_list = &args_list->node;
+               return warn("out of memory"), -EINVAL;
 
+       stmt->args_list = &args_list->node;
        return 0;
 }
 
-static int insert_invoke_expr(struct parse_context *ctx,
-                             struct expression *invoke_expr)
+static struct statement * invoke_stmt(struct parse_context *ctx,
+                                     enum statement_type type,
+                                     struct vm_method *target)
 {
-       if (invoke_expr->vm_type == J_VOID) {
-               struct statement *expr_stmt;
-
-               expr_stmt = alloc_statement(STMT_EXPRESSION);
-               if (!expr_stmt)
-                       return warn("out of memory"), -ENOMEM;
+       struct statement *stmt;
+       enum vm_type return_type;
+
+       assert(type == STMT_INVOKE || type == STMT_INVOKEVIRTUAL ||
+              type == STMT_INVOKEINTERFACE);
+
+       stmt = alloc_statement(type);
+       if (!stmt)
+               return NULL;
+
+       stmt->target_method = target;
+
+       return_type = method_return_type(target);
+       switch (return_type) {
+       case J_VOID:
+               stmt->invoke_result = NULL;
+               break;
+       case J_LONG:
+       case J_FLOAT:
+       case J_DOUBLE:
+               stmt->invoke_result = temporary_expr(return_type, ctx->cu);
+               break;
+       case J_BYTE:
+       case J_BOOLEAN:
+       case J_CHAR:
+       case J_INT:
+       case J_SHORT:
+               stmt->invoke_result = temporary_expr(J_INT, ctx->cu);
+               break;
+       case J_REFERENCE:
+               stmt->invoke_result = temporary_expr(J_REFERENCE, ctx->cu);
+               break;
+       default:
+               error("invalid method return type %d", return_type);
+       };
+
+       return stmt;
+}
 
-               expr_stmt->expression = &invoke_expr->node;
-               convert_statement(ctx, expr_stmt);
-       } else
-               convert_expression(ctx, invoke_expr);
+static void insert_invoke_stmt(struct parse_context *ctx, struct statement 
*stmt)
+{
+       convert_statement(ctx, stmt);
 
-       return 0;
+       if (stmt->invoke_result) {
+               expr_get(stmt->invoke_result);
+               convert_expression(ctx, stmt->invoke_result);
+       }
 }
 
 static struct vm_method *resolve_invoke_target(struct parse_context *ctx)
@@ -150,7 +184,7 @@ static void null_check_this_arg(struct expression *arg)
 int convert_invokeinterface(struct parse_context *ctx)
 {
        struct vm_method *invoke_target;
-       struct expression *expr;
+       struct statement *stmt;
        int count;
        int zero;
        int err;
@@ -159,8 +193,8 @@ int convert_invokeinterface(struct parse_context *ctx)
        if (!invoke_target)
                return warn("unable to resolve invocation target"), -EINVAL;
 
-       expr = invokeinterface_expr(invoke_target);
-       if (!expr)
+       stmt = invoke_stmt(ctx, STMT_INVOKEINTERFACE, invoke_target);
+       if (!stmt)
                return warn("out of memory"), -ENOMEM;
 
        count = bytecode_read_u8(ctx->buffer);
@@ -173,115 +207,91 @@ int convert_invokeinterface(struct parse_context *ctx)
                        -EINVAL;
        }
 
-       err = convert_and_add_args(ctx, invoke_target, expr);
-       if (err)
-               goto failed;
-
-       err = insert_invoke_expr(ctx, expr);
+       err = convert_and_add_args(ctx, invoke_target, stmt);
        if (err)
                goto failed;
 
+       insert_invoke_stmt(ctx, stmt);
        return 0;
 
 failed:
-       expr_put(expr);
+       free_statement(stmt);
        return err;
 }
 
 int convert_invokevirtual(struct parse_context *ctx)
 {
        struct vm_method *invoke_target;
-       struct expression *expr;
+       struct statement *stmt;
        int err = -ENOMEM;
 
        invoke_target = resolve_invoke_target(ctx);
        if (!invoke_target)
                return warn("unable to resolve invocation target"), -EINVAL;
 
-       if (vm_type_is_float(method_return_type(invoke_target)))
-               expr = finvokevirtual_expr(invoke_target);
-       else
-               expr = invokevirtual_expr(invoke_target);
-
-       if (!expr)
+       stmt = invoke_stmt(ctx, STMT_INVOKEVIRTUAL, invoke_target);
+       if (!stmt)
                return warn("out of memory"), -ENOMEM;
 
-       err = convert_and_add_args(ctx, invoke_target, expr);
-       if (err)
-               goto failed;
-
-       err = insert_invoke_expr(ctx, expr);
+       err = convert_and_add_args(ctx, invoke_target, stmt);
        if (err)
                goto failed;
 
+       insert_invoke_stmt(ctx, stmt);
        return 0;
       failed:
-       expr_put(expr);
+       free_statement(stmt);
        return err;
 }
 
 int convert_invokespecial(struct parse_context *ctx)
 {
        struct vm_method *invoke_target;
-       struct expression *expr;
+       struct statement *stmt;
        int err;
 
        invoke_target = resolve_invoke_target(ctx);
        if (!invoke_target)
                return warn("unable to resolve invocation target"), -EINVAL;
 
-       if (vm_type_is_float(method_return_type(invoke_target)))
-               expr = finvoke_expr(invoke_target);
-       else
-               expr = invoke_expr(invoke_target);
-
-       if (!expr)
+       stmt = invoke_stmt(ctx, STMT_INVOKE, invoke_target);
+       if (!stmt)
                return warn("out of memory"), -ENOMEM;
 
-       err = convert_and_add_args(ctx, invoke_target, expr);
+       err = convert_and_add_args(ctx, invoke_target, stmt);
        if (err)
                goto failed;
 
-       null_check_this_arg(to_expr(expr->args_list));
-
-       err = insert_invoke_expr(ctx, expr);
-       if (err)
-               goto failed;
+       null_check_this_arg(to_expr(stmt->args_list));
 
+       insert_invoke_stmt(ctx, stmt);
        return 0;
       failed:
-       expr_put(expr);
+       free_statement(stmt);
        return err;
 }
 
 int convert_invokestatic(struct parse_context *ctx)
 {
        struct vm_method *invoke_target;
-       struct expression *expr;
+       struct statement *stmt;
        int err;
 
        invoke_target = resolve_invoke_target(ctx);
        if (!invoke_target)
                return warn("unable to resolve invocation target"), -EINVAL;
 
-       if (vm_type_is_float(method_return_type(invoke_target)))
-               expr = finvoke_expr(invoke_target);
-       else
-               expr = invoke_expr(invoke_target);
-
-       if (!expr)
+       stmt = invoke_stmt(ctx, STMT_INVOKE, invoke_target);
+       if (!stmt)
                return warn("out of memory"), -ENOMEM;
 
-       err = convert_and_add_args(ctx, invoke_target, expr);
-       if (err)
-               goto failed;
-
-       err = insert_invoke_expr(ctx, expr);
+       err = convert_and_add_args(ctx, invoke_target, stmt);
        if (err)
                goto failed;
 
+       insert_invoke_stmt(ctx, stmt);
        return 0;
       failed:
-       expr_put(expr);
+       free_statement(stmt);
        return err;
 }
diff --git a/jit/ostack-bc.c b/jit/ostack-bc.c
index a6781fc..54f8dd1 100644
--- a/jit/ostack-bc.c
+++ b/jit/ostack-bc.c
@@ -20,19 +20,7 @@
 
 int convert_pop(struct parse_context *ctx)
 {
-       struct expression *expr = stack_pop(ctx->bb->mimic_stack);
-
-       if (is_invoke_expr(expr)) {
-               struct statement *expr_stmt = alloc_statement(STMT_EXPRESSION);
-
-               if (!expr_stmt)
-                       return warn("out of memory"), -ENOMEM;
-
-               expr_stmt->expression = &expr->node;
-               convert_statement(ctx, expr_stmt);
-       } else
-               expr_put(expr);
-
+       expr_put(stack_pop(ctx->bb->mimic_stack));
        return 0;
 }
 
diff --git a/jit/statement.c b/jit/statement.c
index b9431a8..568223e 100644
--- a/jit/statement.c
+++ b/jit/statement.c
@@ -32,6 +32,9 @@ int stmt_nr_kids(struct statement *stmt)
        case STMT_CHECKCAST:
        case STMT_TABLESWITCH:
        case STMT_LOOKUPSWITCH_JUMP:
+       case STMT_INVOKE:
+       case STMT_INVOKEINTERFACE:
+       case STMT_INVOKEVIRTUAL:
                return 1;
        case STMT_GOTO:
        case STMT_VOID_RETURN:
@@ -65,6 +68,17 @@ void free_statement(struct statement *stmt)
                if (stmt->node.kids[i])
                        expr_put(to_expr(stmt->node.kids[i]));
 
+       switch (stmt_type(stmt)) {
+       case STMT_INVOKE:
+       case STMT_INVOKEVIRTUAL:
+       case STMT_INVOKEINTERFACE:
+               if (stmt->invoke_result)
+                       expr_put(stmt->invoke_result);
+               break;
+       default:
+               break;
+       }
+
        free(stmt);
 }
 
diff --git a/jit/tree-printer.c b/jit/tree-printer.c
index cd8fdec..5e86c2f 100644
--- a/jit/tree-printer.c
+++ b/jit/tree-printer.c
@@ -338,6 +338,58 @@ static int print_lookupswitch_jump_stmt(int lvl, struct 
string *str,
        return err;
 }
 
+
+static int __print_invoke_stmt(int lvl, struct string *str,
+                              struct statement *stmt, const char *name)
+{
+       struct vm_method *method;
+       int err;
+
+       err = append_formatted(lvl, str, "%s:\n", name);
+       if (err)
+               goto out;
+
+       method = stmt->target_method;
+
+       err =
+           append_simple_attr(lvl + 1, str, "target_method",
+                              "%p '%s.%s%s' (%lu)", method,
+                              method->class->name, method->name, method->type,
+                              stmt_method_index(stmt));
+       if (err)
+               goto out;
+
+       err = append_tree_attr(lvl + 1, str, "args_list", stmt->args_list);
+       if (err)
+               goto out;
+
+       if (stmt->invoke_result)
+               err = append_tree_attr(lvl + 1, str, "result", 
&stmt->invoke_result->node);
+       else
+               err = append_simple_attr(lvl + 1, str, "result", "void");
+
+out:
+       return err;
+}
+
+static int print_invoke_stmt(int lvl, struct string *str,
+                                   struct statement *stmt)
+{
+       return __print_invoke_stmt(lvl, str, stmt, "INVOKE");
+}
+
+static int print_invokeinterface_stmt(int lvl, struct string *str,
+                                     struct statement *stmt)
+{
+       return __print_invoke_stmt(lvl, str, stmt, "INVOKEINTERFACE");
+}
+
+static int print_invokevirtual_stmt(int lvl, struct string *str,
+                                   struct statement *stmt)
+{
+       return __print_invoke_stmt(lvl, str, stmt, "INVOKEVIRTUAL");
+}
+
 typedef int (*print_stmt_fn) (int, struct string * str, struct statement *);
 
 static print_stmt_fn stmt_printers[] = {
@@ -355,6 +407,9 @@ static print_stmt_fn stmt_printers[] = {
        [STMT_ARRAY_STORE_CHECK] = print_array_store_check_stmt,
        [STMT_TABLESWITCH] = print_tableswitch_stmt,
        [STMT_LOOKUPSWITCH_JUMP] = print_lookupswitch_jump_stmt,
+       [STMT_INVOKE] = print_invoke_stmt,
+       [STMT_INVOKEINTERFACE] = print_invokeinterface_stmt,
+       [STMT_INVOKEVIRTUAL] = print_invokevirtual_stmt,
 };
 
 static int print_stmt(int lvl, struct tree_node *root, struct string *str)
@@ -709,68 +764,6 @@ out:
        return err;
 }
 
-static int print_invoke_expr(int lvl, struct string *str,
-                            struct expression *expr)
-{
-       struct vm_method *method;
-       int err;
-
-       err = append_formatted(lvl, str, "INVOKE:\n");
-       if (err)
-               goto out;
-
-       method = expr->target_method;
-
-       err = append_simple_attr(lvl + 1, str, "target_method", "%p '%s.%s%s'",
-                                method, method->class->name, method->name,
-                                method->type);
-       if (err)
-               goto out;
-
-       err = append_tree_attr(lvl + 1, str, "args_list", expr->args_list);
-
-out:
-       return err;
-}
-
-static int __print_invoke_expr(int lvl, struct string *str,
-                              struct expression *expr, const char *name)
-{
-       struct vm_method *method;
-       int err;
-
-       err = append_formatted(lvl, str, "%s:\n", name);
-       if (err)
-               goto out;
-
-       method = expr->target_method;
-
-       err =
-           append_simple_attr(lvl + 1, str, "target_method",
-                              "%p '%s.%s%s' (%lu)", method,
-                              method->class->name, method->name, method->type,
-                              expr_method_index(expr));
-       if (err)
-               goto out;
-
-       err = append_tree_attr(lvl + 1, str, "args_list", expr->args_list);
-
-out:
-       return err;
-}
-
-static int print_invokeinterface_expr(int lvl, struct string *str,
-                                   struct expression *expr)
-{
-       return __print_invoke_expr(lvl, str, expr, "INVOKEINTERFACE");
-}
-
-static int print_invokevirtual_expr(int lvl, struct string *str,
-                                   struct expression *expr)
-{
-       return __print_invoke_expr(lvl, str, expr, "INVOKEVIRTUAL");
-}
-
 static int print_args_list_expr(int lvl, struct string *str,
                                struct expression *expr)
 {
@@ -1086,12 +1079,6 @@ static print_expr_fn expr_printers[] = {
        [EXPR_FLOAT_CLASS_FIELD] = print_float_class_field_expr,
        [EXPR_INSTANCE_FIELD] = print_instance_field_expr,
        [EXPR_FLOAT_INSTANCE_FIELD] = print_float_instance_field_expr,
-       [EXPR_INVOKE] = print_invoke_expr,
-       [EXPR_INVOKEINTERFACE] = print_invokeinterface_expr,
-       [EXPR_FINVOKEINTERFACE] = print_invokeinterface_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_ARG_THIS] = print_arg_this_expr,
diff --git a/regression/jvm/InvokeTest.j b/regression/jvm/InvokeTest.j
new file mode 100644
index 0000000..640356f
--- /dev/null
+++ b/regression/jvm/InvokeTest.j
@@ -0,0 +1,33 @@
+.class public jvm/InvokeTest
+.super jvm/TestCase
+
+.field public static counter I
+
+.method public static advanceCounter()I
+    getstatic jvm/InvokeTest/counter I
+    iconst_1
+    iadd
+    dup
+    putstatic jvm/InvokeTest/counter I
+    ireturn
+.end method
+
+.method public static main([Ljava/lang/String;)V
+    .limit stack 3
+    .limit locals 1
+
+    iconst_0
+    putstatic jvm/InvokeTest/counter I
+
+    invokestatic jvm/InvokeTest/advanceCounter()I
+
+    getstatic jvm/InvokeTest/counter I
+    iconst_1
+    iadd
+    putstatic jvm/InvokeTest/counter I
+
+    iconst_1
+    swap
+    invokestatic jvm/TestCase/assertEquals(II)V
+    return
+.end method
\ No newline at end of file
diff --git a/regression/run-suite.sh b/regression/run-suite.sh
index 34d3d76..6397c97 100755
--- a/regression/run-suite.sh
+++ b/regression/run-suite.sh
@@ -76,6 +76,7 @@ if [ -z "$CLASS_LIST" ]; then
     run_java jvm.InvokeinterfaceTest 0
     run_java jvm.InvokestaticPatchingTest 0
     run_java jvm.InvokeResultTest 0
+    run_java jvm.InvokeTest 0
     run_java jvm.LoadConstantsTest 0
     run_java jvm.LongArithmeticExceptionsTest 0
     run_java jvm.LongArithmeticTest 0
diff --git a/test/jit/bc-test-utils.c b/test/jit/bc-test-utils.c
index 9cddfac..9d76f0f 100644
--- a/test/jit/bc-test-utils.c
+++ b/test/jit/bc-test-utils.c
@@ -233,15 +233,20 @@ void assert_instance_field_expr(enum vm_type 
expected_vm_type,
        assert_ptr_equals(expected_objectref, 
to_expr(expr->objectref_expression));
 }
 
-void assert_invoke_expr(enum vm_type expected_type,
+void assert_invoke_stmt(enum vm_type result_type,
                        struct vm_method *expected_method,
                        struct tree_node *node)
 {
-       struct expression *expr = to_expr(node);
+       struct statement *stmt = to_stmt(node);
 
-       assert_int_equals(EXPR_INVOKE, expr_type(expr));
-       assert_int_equals(expected_type, expr->vm_type);
-       assert_ptr_equals(expected_method, expr->target_method);
+       assert_int_equals(STMT_INVOKE, stmt_type(stmt));
+
+       if (result_type == J_VOID)
+               assert_ptr_equals(NULL, stmt->invoke_result);
+       else
+               assert_temporary_expr(result_type, &stmt->invoke_result->node);
+
+       assert_ptr_equals(expected_method, stmt->target_method);
 }
 
 void assert_array_size_check_expr(struct expression *expected,
diff --git a/test/jit/bc-test-utils.h b/test/jit/bc-test-utils.h
index aa945bc..7cbb459 100644
--- a/test/jit/bc-test-utils.h
+++ b/test/jit/bc-test-utils.h
@@ -35,8 +35,7 @@ void assert_conv_expr(enum vm_type, enum expression_type, 
struct expression *, s
 void assert_trunc_expr(enum vm_type, enum expression_type, struct expression 
*, struct tree_node *);
 void assert_class_field_expr(enum vm_type, struct vm_field *, struct tree_node 
*);
 void assert_instance_field_expr(enum vm_type, struct vm_field *, struct 
expression *, struct tree_node *);
-void assert_invoke_expr(enum vm_type, struct vm_method *,
-                       struct tree_node *);
+void assert_invoke_stmt(enum vm_type, struct vm_method *, struct tree_node *);
 void assert_array_size_check_expr(struct expression *, struct expression *);
 void assert_multiarray_size_check_expr(struct expression **, int, struct 
expression *);
 void assert_store_stmt(struct statement *);
diff --git a/test/jit/invoke-bc-test.c b/test/jit/invoke-bc-test.c
index 6f7e2f4..7428644 100644
--- a/test/jit/invoke-bc-test.c
+++ b/test/jit/invoke-bc-test.c
@@ -125,34 +125,17 @@ build_invoke_bb(unsigned char invoke_opc,
        return bb;
 }
 
-static void assert_invoke_expression_type(enum expression_type expected_type, 
unsigned char invoke_opc)
-{
-       struct expression *invoke_expr;
-       struct basic_block *bb;
-       struct statement *stmt;
-
-       bb = build_invoke_bb(invoke_opc, "()V", 1, 0, 0, 0, NULL);
-       stmt = first_stmt(bb->b_parent);
-       invoke_expr = to_expr(stmt->expression);
-
-       assert_int_equals(expected_type, expr_type(invoke_expr));
-
-       __free_simple_bb(bb);
-}
-
 static void assert_invoke_passes_objectref(unsigned char invoke_opc,
                                           bool nullcheck)
 {
-       struct expression *invoke_expr;
+       struct statement *invoke_stmt;
        struct expression *arg_expr;
        struct basic_block *bb;
-       struct statement *stmt;
 
        bb = build_invoke_bb(invoke_opc, "()V", 1, 0xdeadbeef, 0, 0, NULL);
 
-       stmt = first_stmt(bb->b_parent);
-       invoke_expr = to_expr(stmt->expression);
-       arg_expr = to_expr(invoke_expr->args_list);
+       invoke_stmt = first_stmt(bb->b_parent);
+       arg_expr = to_expr(invoke_stmt->args_list);
 
        if (nullcheck)
                assert_nullcheck_value_expr(J_REFERENCE, 0xdeadbeef,
@@ -167,16 +150,15 @@ static void assert_invoke_args(unsigned char invoke_opc, 
unsigned long nr_args)
 {
        struct expression *args_list_expr;
        struct expression *args[nr_args];
-       struct expression *invoke_expr;
+       struct statement *invoke_stmt;
        struct expression *second_arg;
        struct basic_block *bb;
-       struct statement *stmt;
        struct string *str;
 
        str = alloc_str();
 
        str_append(str, "(");
-       for (int i = 0; i < nr_args; i++)
+       for (unsigned int i = 0; i < nr_args; i++)
                str_append(str, "I");
        str_append(str, ")V");
 
@@ -184,9 +166,8 @@ static void assert_invoke_args(unsigned char invoke_opc, 
unsigned long nr_args)
        bb = build_invoke_bb(invoke_opc, str->value, nr_args+1, 0, 0, 0, args);
        free_str(str);
 
-       stmt = first_stmt(bb->b_parent);
-       invoke_expr = to_expr(stmt->expression);
-       args_list_expr = to_expr(invoke_expr->args_list);
+       invoke_stmt = first_stmt(bb->b_parent);
+       args_list_expr = to_expr(invoke_stmt->args_list);
        second_arg = to_expr(args_list_expr->args_left);
 
        assert_args(args, ARRAY_SIZE(args), second_arg);
@@ -196,61 +177,21 @@ static void assert_invoke_args(unsigned char invoke_opc, 
unsigned long nr_args)
 
 static void assert_invoke_return_type(unsigned char invoke_opc, enum vm_type 
expected, char *type)
 {
-       struct expression *invoke_expr;
+       struct statement *invoke_stmt;
        struct basic_block *bb;
 
        bb = build_invoke_bb(invoke_opc, type, 1, 0, 0, 0, NULL);
-       invoke_expr = stack_pop(bb->mimic_stack);
-       assert_int_equals(expected, invoke_expr->vm_type);
+       invoke_stmt = first_stmt(bb->b_parent);
 
-       expr_put(invoke_expr);
-       __free_simple_bb(bb);
-}
-
-static struct basic_block *
-invoke_discarded_return_value(unsigned char invoke_opc, struct vm_method 
*target_method)
-{
-       const struct cafebabe_method_info target_method_info = {
-               .access_flags = CAFEBABE_METHOD_ACC_STATIC,
-       };
-
-       unsigned char code[] = {
-               invoke_opc, 0x00, 0x00,
-               OPC_POP
-       };
-       struct vm_method invoker_method = {
-               .code_attribute.code = code,
-               .code_attribute.code_length = ARRAY_SIZE(code),
-       };
-       struct basic_block *bb;
-       
-       target_method->type = "()I";
-       target_method->args_count = 0;
-       target_method->method = &target_method_info;
-
-       bb = __alloc_simple_bb(&invoker_method);
-       convert_ir_invoke(bb->b_parent, target_method, 0);
-
-       return bb;
-}
-
-static void assert_invoke_return_value_discarded(enum expression_type 
expected_type, unsigned char invoke_opc)
-{
-       struct vm_method target_method;
-       struct basic_block *bb;
-       struct statement *stmt;
-
-       bb = invoke_discarded_return_value(invoke_opc, &target_method);
-       stmt = first_stmt(bb->b_parent);
-
-       assert_int_equals(STMT_EXPRESSION, stmt_type(stmt));
-       assert_int_equals(expected_type, expr_type(to_expr(stmt->expression)));
-       assert_true(stack_is_empty(bb->mimic_stack));
+       if (expected == J_VOID)
+               assert_ptr_equals(NULL, invoke_stmt->invoke_result);
+       else
+               assert_temporary_expr(expected, 
&invoke_stmt->invoke_result->node);
 
        __free_simple_bb(bb);
 }
 
-static void assert_converts_to_invoke_expr(enum vm_type expected_vm_type, 
unsigned char opc, char *return_type, int nr_args)
+static void assert_converts_to_invoke_stmt(enum vm_type expected_result_type, 
unsigned char opc, char *return_type, int nr_args)
 {
        const struct cafebabe_method_info target_method_info = {
                .access_flags = CAFEBABE_METHOD_ACC_STATIC,
@@ -262,8 +203,7 @@ static void assert_converts_to_invoke_expr(enum vm_type 
expected_vm_type, unsign
                .args_count = nr_args,
        };
        unsigned char code[] = {
-               opc, 0x00, 0x00,
-               OPC_IRETURN
+               opc, 0x00, 0x00
        };
        struct vm_method method = {
                .code_attribute.code = code,
@@ -281,13 +221,22 @@ static void assert_converts_to_invoke_expr(enum vm_type 
expected_vm_type, unsign
        convert_ir_invoke(bb->b_parent, &target_method, 0);
        stmt = stmt_entry(bb->stmt_list.next);
 
-       assert_int_equals(STMT_RETURN, stmt_type(stmt));
-       assert_invoke_expr(expected_vm_type, &target_method, 
stmt->return_value);
+       assert_invoke_stmt(expected_result_type, &target_method, &stmt->node);
 
-       actual_args = to_expr(to_expr(stmt->return_value)->args_list);
+       actual_args = to_expr(stmt->args_list);
        assert_args(args, nr_args, actual_args);
 
-       assert_true(stack_is_empty(bb->mimic_stack));
+       if (expected_result_type == J_VOID)
+               assert_true(stack_is_empty(bb->mimic_stack));
+       else {
+               struct expression *result;
+
+               assert_false(stack_is_empty(bb->mimic_stack));
+               result = stack_pop(bb->mimic_stack);
+               assert_temporary_expr(expected_result_type, &result->node);
+               expr_put(result);
+               assert_true(stack_is_empty(bb->mimic_stack));
+       }
 
        __free_simple_bb(bb);
 }
@@ -296,19 +245,14 @@ static void assert_converts_to_invoke_expr(enum vm_type 
expected_vm_type, unsign
  *     INVOKESPECIAL
  */
 
-void test_invokespecial_should_be_converted_to_invokespecial_expr(void)
-{
-       assert_invoke_expression_type(EXPR_INVOKE, OPC_INVOKESPECIAL);
-}
-
 void test_invokespecial_should_pass_objectref_as_first_argument(void)
 {
        assert_invoke_passes_objectref(OPC_INVOKESPECIAL, true);
 }
 
-void test_invokespecial_converts_to_invoke_expr(void)
+void test_invokespecial_converts_to_invoke_stmt(void)
 {
-       assert_converts_to_invoke_expr(J_INT, OPC_INVOKESPECIAL, "()I", 0);
+       assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESPECIAL, "()I", 0);
 }
 
 void test_invokespecial_should_parse_passed_arguments(void)
@@ -320,24 +264,21 @@ void 
test_invokespecial_should_parse_passed_arguments(void)
 
 void test_invokespecial_should_parse_return_type(void)
 {
+       assert_invoke_return_type(OPC_INVOKESPECIAL, J_VOID, "()V");
        assert_invoke_return_type(OPC_INVOKESPECIAL, J_INT, "()B");
+       assert_invoke_return_type(OPC_INVOKESPECIAL, J_INT, "()Z");
+       assert_invoke_return_type(OPC_INVOKESPECIAL, J_INT, "()C");
+       assert_invoke_return_type(OPC_INVOKESPECIAL, J_INT, "()S");
        assert_invoke_return_type(OPC_INVOKESPECIAL, J_INT, "()I");
-}
-
-void test_convert_invokespecial_when_return_value_is_discarded(void)
-{
-       assert_invoke_return_value_discarded(EXPR_INVOKE, OPC_INVOKESPECIAL);
+       assert_invoke_return_type(OPC_INVOKESPECIAL, J_LONG, "()L");
+       assert_invoke_return_type(OPC_INVOKESPECIAL, J_FLOAT, "()F");
+       assert_invoke_return_type(OPC_INVOKESPECIAL, J_DOUBLE, "()D");
 }
 
 /*
  *     INVOKEVIRTUAL
  */
 
-void test_invokevirtual_should_be_converted_to_invokevirtual_expr(void)
-{
-       assert_invoke_expression_type(EXPR_INVOKEVIRTUAL, OPC_INVOKEVIRTUAL);
-}
-
 void test_invokevirtual_should_pass_objectref_as_first_argument(void)
 {
        assert_invoke_passes_objectref(OPC_INVOKEVIRTUAL, false);
@@ -352,13 +293,15 @@ void 
test_invokevirtual_should_parse_passed_arguments(void)
 
 void test_invokevirtual_should_parse_return_type(void)
 {
+       assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_VOID, "()V");
        assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_INT, "()B");
+       assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_INT, "()Z");
+       assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_INT, "()C");
+       assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_INT, "()S");
        assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_INT, "()I");
-}
-
-void test_convert_invokevirtual_when_return_value_is_discarded(void)
-{
-       assert_invoke_return_value_discarded(EXPR_INVOKEVIRTUAL, 
OPC_INVOKEVIRTUAL);
+       assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_LONG, "()L");
+       assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_FLOAT, "()F");
+       assert_invoke_return_type(OPC_INVOKEVIRTUAL, J_DOUBLE, "()D");
 }
 
 /*
@@ -367,61 +310,20 @@ void 
test_convert_invokevirtual_when_return_value_is_discarded(void)
 
 void test_convert_invokestatic(void)
 {
-       assert_converts_to_invoke_expr(J_INT, OPC_INVOKESTATIC, "()B", 0);
-       assert_converts_to_invoke_expr(J_INT, OPC_INVOKESTATIC, "()I", 0);
-       assert_converts_to_invoke_expr(J_INT, OPC_INVOKESTATIC, "(I)I", 1);
-       assert_converts_to_invoke_expr(J_INT, OPC_INVOKESTATIC, "(II)I", 2);
-       assert_converts_to_invoke_expr(J_INT, OPC_INVOKESTATIC, "(III)I", 3);
-       assert_converts_to_invoke_expr(J_INT, OPC_INVOKESTATIC, "(IIIII)I", 5);
-}
-
-void test_convert_invokestatic_for_void_return_type(void)
-{
-       struct vm_method mb;
-       unsigned char code[] = {
-               OPC_INVOKESTATIC, 0x00, 0x00,
-       };
-
-       const struct cafebabe_method_info target_method_info = {
-               .access_flags = CAFEBABE_METHOD_ACC_STATIC,
-       };
-
-       struct vm_method method = {
-               .code_attribute.code = code,
-               .code_attribute.code_length = ARRAY_SIZE(code),
-       };
-       struct basic_block *bb;
-       struct statement *stmt;
-
-       mb.type = "()V";
-       mb.args_count = 0;
-       mb.method = &target_method_info;
-
-       bb = __alloc_simple_bb(&method);
-       convert_ir_invoke(bb->b_parent, &mb, 0);
-       stmt = stmt_entry(bb->stmt_list.next);
-
-       assert_int_equals(STMT_EXPRESSION, stmt_type(stmt));
-       assert_invoke_expr(J_VOID, &mb, stmt->expression);
-       assert_true(stack_is_empty(bb->mimic_stack));
-
-       __free_simple_bb(bb);
-}
-
-void test_convert_invokestatic_when_return_value_is_discarded(void)
-{
-       struct basic_block *bb;
-       struct statement *stmt;
-       struct vm_method mb;
-
-       bb = invoke_discarded_return_value(OPC_INVOKESTATIC, &mb);
-       stmt = stmt_entry(bb->stmt_list.next);
-
-       assert_int_equals(STMT_EXPRESSION, stmt_type(stmt));
-       assert_invoke_expr(J_INT, &mb, stmt->expression);
-       assert_true(stack_is_empty(bb->mimic_stack));
-
-       free_compilation_unit(bb->b_parent);
+       assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "()B", 0);
+       assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "()Z", 0);
+       assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "()C", 0);
+       assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "()S", 0);
+       assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "()I", 0);
+       assert_converts_to_invoke_stmt(J_LONG, OPC_INVOKESTATIC, "()L", 0);
+       assert_converts_to_invoke_stmt(J_VOID, OPC_INVOKESTATIC, "()V", 0);
+       assert_converts_to_invoke_stmt(J_FLOAT, OPC_INVOKESTATIC, "()F", 0);
+       assert_converts_to_invoke_stmt(J_DOUBLE, OPC_INVOKESTATIC, "()D", 0);
+
+       assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "(I)I", 1);
+       assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "(II)I", 2);
+       assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "(III)I", 3);
+       assert_converts_to_invoke_stmt(J_INT, OPC_INVOKESTATIC, "(IIIII)I", 5);
 }
 
 /* MISSING: invokeinterface */
diff --git a/test/jit/tree-printer-test.c b/test/jit/tree-printer-test.c
index f4996db..66e8b05 100644
--- a/test/jit/tree-printer-test.c
+++ b/test/jit/tree-printer-test.c
@@ -442,46 +442,41 @@ void test_should_print_instance_field_expression(void)
                &vmf, vmf.class->name, vmf.name), J_INT, &vmf, objectref);
 }
 
-void assert_printed_invoke_expr(struct string *expected,
+void assert_printed_invoke_stmt(enum vm_type type,
+                               struct string *expected,
                                struct vm_method *method,
-                               struct expression *args_list)
+                               struct expression *args_list,
+                               struct expression *result)
 {
-       struct expression *expr;
-
-       expr = invoke_expr(method);
-       expr->args_list = &args_list->node;
-       assert_print_expr(expected, expr);
-}
+       struct statement *stmt;
 
-void test_should_print_invoke_expression(void)
-{      
-       assert_printed_invoke_expr(str_aprintf(
-               "INVOKE:\n"
-               "  target_method: [%p '%s.%s%s']\n"
-               "  args_list: [no args]\n",
-               &vmm, vmm.class->name, vmm.name, vmm.type),
-               &vmm, no_args_expr());
+       stmt = alloc_statement(type);
+       stmt->invoke_result = result;
+       stmt->args_list = &args_list->node;
+       stmt->target_method = method;
+       assert_print_stmt(expected, stmt);
 }
 
-void assert_printed_invokevirtual_expr(struct string *expected,
-                                      struct vm_method *target,
-                                      struct expression *args_list)
+void test_should_print_invoke_statement(void)
 {
-       struct expression *expr;
-
-       expr = invokevirtual_expr(target);
-       expr->args_list = &args_list->node;
-       assert_print_expr(expected, expr);
+       assert_printed_invoke_stmt(STMT_INVOKE, str_aprintf(
+               "INVOKE:\n"
+               "  target_method: [%p '%s.%s%s' (%lu)]\n"
+               "  args_list: [no args]\n"
+               "  result: [void]\n",
+               &vmm, vmm.class->name, vmm.name, vmm.type, vmm.virtual_index),
+               &vmm, no_args_expr(), NULL);
 }
 
 void test_should_print_invokevirtual_expression(void)
 {
-       assert_printed_invokevirtual_expr(str_aprintf(
+       assert_printed_invoke_stmt(STMT_INVOKEVIRTUAL, str_aprintf(
                "INVOKEVIRTUAL:\n"
                "  target_method: [%p '%s.%s%s' (%lu)]\n"
-               "  args_list: [no args]\n",
+               "  args_list: [no args]\n"
+               "  result: [void]\n",
                &vmm, vmm.class->name, vmm.name, vmm.type, vmm.virtual_index),
-               &vmm, no_args_expr());
+               &vmm, no_args_expr(), NULL);
 }
 
 void assert_printed_args_list_expr(struct string *expected,
-- 
1.6.3.3


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to