According to the x86-64 ABI, we need to pass the first 6 INTEGER class
arguments in specific registers and the rest on stack.

Signed-off-by: Eduard - Gabriel Munteanu <eduard.munte...@linux360.ro>
---
 arch/x86/Makefile_32              |    1 +
 arch/x86/Makefile_64              |    1 +
 arch/x86/args.c                   |  121 +++++++++++++++++++++++++++++++++++++
 arch/x86/include/arch/args.h      |   49 +++++++++++++++
 arch/x86/include/arch/config_64.h |    2 +
 arch/x86/insn-selector.brg        |  103 +++++++++++++++++++++++++++++++-
 include/jit/args.h                |   10 +++-
 include/jit/expression.h          |    1 +
 include/vm/method.h               |    3 +
 jit/args.c                        |   33 +++++++++--
 jit/invoke-bc.c                   |    6 +-
 jit/object-bc.c                   |    4 +-
 vm/method.c                       |    4 +
 13 files changed, 327 insertions(+), 11 deletions(-)
 create mode 100644 arch/x86/args.c
 create mode 100644 arch/x86/include/arch/args.h

diff --git a/arch/x86/Makefile_32 b/arch/x86/Makefile_32
index 71c9b85..ed00c94 100644
--- a/arch/x86/Makefile_32
+++ b/arch/x86/Makefile_32
@@ -1,4 +1,5 @@
 ARCH_OBJS = \
+       arch/x86/args.o                 \
        arch/x86/backtrace.o            \
        arch/x86/disassemble.o          \
        arch/x86/emit-code.o            \
diff --git a/arch/x86/Makefile_64 b/arch/x86/Makefile_64
index ab8c946..fed2c16 100644
--- a/arch/x86/Makefile_64
+++ b/arch/x86/Makefile_64
@@ -2,6 +2,7 @@ ARCH_INCLUDES   = -I/usr/include/libffi
 ARCH_LIBS      = -L/usr/lib64/libffi -lffi
 
 ARCH_OBJS = \
+       arch/x86/args.o                 \
        arch/x86/backtrace.o            \
        arch/x86/disassemble.o          \
        arch/x86/emit-code.o            \
diff --git a/arch/x86/args.c b/arch/x86/args.c
new file mode 100644
index 0000000..c52f3cd
--- /dev/null
+++ b/arch/x86/args.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2009 Eduard - Gabriel Munteanu <eduard.munte...@linux360.ro>
+ * 
+ * This file is released under the GPL version 2 with the following
+ * clarification and special exception:
+ *
+ *     Linking this library statically or dynamically with other modules is
+ *     making a combined work based on this library. Thus, the terms and
+ *     conditions of the GNU General Public License cover the whole
+ *     combination.
+ *
+ *     As a special exception, the copyright holders of this library give you
+ *     permission to link this library with independent modules to produce an
+ *     executable, regardless of the license terms of these independent
+ *     modules, and to copy and distribute the resulting executable under terms
+ *     of your choice, provided that you also meet, for each linked independent
+ *     module, the terms and conditions of the license of that module. An
+ *     independent module is a module which is not derived from or based on
+ *     this library. If you modify this library, you may extend this exception
+ *     to your version of the library, but you are not obligated to do so. If
+ *     you do not wish to do so, delete this exception statement from your
+ *     version.
+ *
+ * Please refer to the file LICENSE for details.
+ */
+
+#include <assert.h>
+
+#include "arch/args.h"
+
+#include "jit/args.h"
+#include "jit/expression.h"
+
+#include "vm/method.h"
+
+#ifdef CONFIG_X86_64
+
+int args_init(unsigned long *state,
+             struct vm_method *method,
+             unsigned long nr_args)
+{
+       char *type;
+
+       for (type = method->type; *type != ')'; type++) {
+               if (*type == 'I' || *type == 'L') {
+                       method->args_count--;
+                       method->reg_args_count++;
+               }
+
+               if (method->reg_args_count == 6)
+                       break;
+       }
+
+       *state = 1;
+
+       return 0;
+}
+
+int args_set(unsigned long *state,
+            struct vm_method *method,
+            struct expression *expr)
+{
+       struct expression *value_expr = to_expr(expr->arg_expression);
+       unsigned long reg;
+
+       if ((int) *state <= method->args_count) {
+               (*state)++;
+               expr->arg_private = NULL;
+               return 0;
+       }
+
+       assert((value_expr->vm_type == J_INT || value_expr->vm_type == J_LONG));
+
+       reg = (6 - method->reg_args_count) + (*state)++ - method->args_count;
+       expr->arg_private = (void *) reg;
+
+       return 0;
+}
+
+static enum machine_reg __args_select_reg(unsigned long arg_idx)
+{
+       switch (arg_idx) {
+       case 0:
+               return REG_UNASSIGNED;
+       case 6:
+               return REG_RDI;
+       case 5:
+               return REG_RSI;
+       case 4:
+               return REG_RDX;
+       case 3:
+               return REG_RCX;
+       case 2:
+               return REG_R8;
+       case 1:
+               return REG_R9;
+       default:
+               assert(arg_idx > 6);
+               return REG_UNASSIGNED;
+       }
+}
+
+enum machine_reg args_select_reg(struct expression *expr)
+{
+       return __args_select_reg((unsigned long) expr->arg_private);
+}
+
+enum machine_reg args_local_to_reg(struct vm_method *method, int local_idx)
+{
+       local_idx++;
+
+       /* Check if local_idx refers to *this or stack parameters. */
+       if (local_idx > method->reg_args_count)
+               return REG_UNASSIGNED;
+
+       return __args_select_reg(local_idx);
+}
+
+#else /* CONFIG_X86_64 */
+
+#endif /* CONFIG_X86_64 */
diff --git a/arch/x86/include/arch/args.h b/arch/x86/include/arch/args.h
new file mode 100644
index 0000000..12b7efa
--- /dev/null
+++ b/arch/x86/include/arch/args.h
@@ -0,0 +1,49 @@
+#ifndef __X86_ARGS_H
+#define __X86_ARGS_H
+
+#include "arch/registers.h"
+
+#include "jit/expression.h"
+
+#include "vm/method.h"
+
+static inline void args_finish(unsigned long *state)
+{
+}
+
+#ifdef CONFIG_X86_64
+
+extern int args_init(unsigned long *state,
+                    struct vm_method *method,
+                    unsigned long nr_args);
+extern int args_set(unsigned long *state,
+                   struct vm_method *method,
+                   struct expression *expr);
+extern enum machine_reg args_select_reg(struct expression *expr);
+extern enum machine_reg args_local_to_reg(struct vm_method *method,
+                                         int local_idx);
+
+static inline int args_stack_index(struct vm_method *method, int local_idx)
+{
+       return local_idx - method->reg_args_count;
+}
+
+#else /* CONFIG_X86_64 */
+
+static inline int args_init(unsigned long *state,
+                           struct vm_method *method,
+                           unsigned long nr_args)
+{
+       return 0;
+}
+
+static inline int args_set(unsigned long *state,
+                          struct vm_method *method,
+                          struct expression *expr)
+{
+       return 0;
+}
+
+#endif /* CONFIG_X86_64 */
+
+#endif /* __X86_ARGS_H */
diff --git a/arch/x86/include/arch/config_64.h 
b/arch/x86/include/arch/config_64.h
index bf8cb20..2e803fe 100644
--- a/arch/x86/include/arch/config_64.h
+++ b/arch/x86/include/arch/config_64.h
@@ -1,2 +1,4 @@
 #define CONFIG_X86_64 1
 #define USE_FFI 1
+#define CONFIG_REGPARM 1
+
diff --git a/arch/x86/insn-selector.brg b/arch/x86/insn-selector.brg
index ac34ec0..375b2ee 100644
--- a/arch/x86/insn-selector.brg
+++ b/arch/x86/insn-selector.brg
@@ -16,6 +16,7 @@
 #include <jit/bc-offset-mapping.h>
 #include <jit/exception.h>
 
+#include <arch/args.h>
 #include <arch/instruction.h>
 #include <arch/stack-frame.h>
 #include <arch/thread.h>
@@ -74,7 +75,7 @@ static void method_args_cleanup(struct basic_block *bb, 
struct tree_node *tree,
        unsigned long args_size;
 
        stack_ptr = bb->b_parent->stack_ptr;
-       args_size = args_count * sizeof(uint32_t);
+       args_size = args_count * sizeof(long);
 
        select_insn(bb, tree, imm_reg_insn(INSN_ADD_IMM_REG, args_size, 
stack_ptr));
 }
@@ -199,6 +200,7 @@ reg:        EXPR_VALUE      0
        }
 }
 
+%ifdef CONFIG_X86_32
 reg:   EXPR_LOCAL      1
 {
        struct compilation_unit *cu = s->b_parent;
@@ -223,6 +225,32 @@ reg:       EXPR_LOCAL      1
                select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, 
slot, result));
        }
 }
+%else
+reg:   EXPR_LOCAL      1
+{
+       struct compilation_unit *cu = s->b_parent;
+       struct expression *expr;
+       struct stack_slot *slot;
+       struct var_info *result;
+       enum machine_reg reg;
+       int index;
+
+       expr = to_expr(tree);
+       slot = get_local_slot(cu->stack_frame, expr->local_index);
+
+       reg = args_local_to_reg(s->b_parent->method, expr->local_index + 1);
+       if (reg == REG_UNASSIGNED) {
+               index = args_stack_index(cu->method, expr->local_index);
+               slot = get_local_slot(cu->stack_frame, index);
+               result = get_var(s->b_parent, J_LONG);
+               select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG,
+                                                      slot, result));
+       } else
+               result = get_fixed_var(s->b_parent, reg);
+
+       state->reg1 = result;
+}
+%endif
 
 freg:  EXPR_LOCAL 0
 {
@@ -1275,6 +1303,7 @@ arg:      EXPR_NO_ARGS
        state->reg1 = NULL;
 }
 
+%ifdef CONFIG_X86_32
 arg:   EXPR_ARG(EXPR_VALUE) 1
 {
        struct expression *expr, *arg_expr;
@@ -1290,6 +1319,27 @@ arg:     EXPR_ARG(EXPR_VALUE) 1
 
        select_insn(s, tree, imm_insn(INSN_PUSH_IMM, imm & ~0UL));
 }
+%else
+arg:   EXPR_ARG(EXPR_VALUE) 1
+{
+       struct expression *expr, *arg_expr;
+       enum machine_reg reg;
+       struct var_info *dst;
+       unsigned long imm;
+
+       expr = to_expr(tree);
+       arg_expr = to_expr(expr->arg_expression);
+       imm  = arg_expr->value;
+
+       reg = args_select_reg(expr);
+
+       if (reg != REG_UNASSIGNED) {
+               dst = get_fixed_var(s->b_parent, reg);
+               select_insn(s, tree, imm_reg_insn(INSN_MOV_IMM_REG, imm, dst));
+       } else
+               select_insn(s, tree, imm_insn(INSN_PUSH_IMM, imm));
+}
+%endif
 
 arg:   EXPR_ARG(EXPR_FVALUE) 1
 {
@@ -1303,6 +1353,7 @@ arg:      EXPR_ARG(EXPR_FVALUE) 1
        select_insn(s, tree, imm_insn(INSN_PUSH_IMM, imm & ~0UL));
 }
 
+%ifdef CONFIG_X86_32
 arg:   EXPR_ARG(reg)
 {
        struct var_info *src;
@@ -1321,6 +1372,28 @@ arg:     EXPR_ARG(reg)
 
        state->reg1 = src;
 }
+%else
+arg:   EXPR_ARG(reg) 1
+{
+       struct var_info *src, *dst;
+       struct expression *expr, *arg_expr;
+       enum machine_reg reg;
+
+       expr = to_expr(tree);
+       arg_expr = to_expr(expr->arg_expression);
+
+       src = state->left->reg1;
+
+       reg = args_select_reg(expr);
+
+       if (reg != REG_UNASSIGNED) {
+               dst = get_fixed_var(s->b_parent, reg);
+               select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, src, dst));
+
+       } else
+               select_insn(s, tree, reg_insn(INSN_PUSH_REG, src));
+}
+%endif
 
 arg:   EXPR_ARGS_LIST(arg, arg)
 {
@@ -1489,6 +1562,7 @@ stmt:     STMT_STORE(EXPR_LOCAL, reg)
        }
 }
 
+%ifdef CONFIG_X86_32
 stmt:  STMT_STORE(EXPR_TEMPORARY, EXPR_LOCAL) 1
 {
        struct expression *exprdest, *exprsrc;
@@ -1512,6 +1586,33 @@ stmt:  STMT_STORE(EXPR_TEMPORARY, EXPR_LOCAL) 1
        }
 
 }
+%else
+stmt:  STMT_STORE(EXPR_TEMPORARY, EXPR_LOCAL) 1
+{
+       struct expression *exprdest, *exprsrc;
+       struct stack_slot *slot;
+       struct statement *stmt;
+       struct var_info *dest;
+       enum machine_reg reg;
+       int index;
+
+       stmt = to_stmt(tree);
+
+       exprsrc = to_expr(stmt->store_src);
+       exprdest = to_expr(stmt->store_dest);
+
+       reg = args_local_to_reg(s->b_parent->method, exprsrc->local_index);
+       if (reg == REG_UNASSIGNED) {
+               index = args_stack_index(s->b_parent->method,
+                                        exprsrc->local_index);
+               slot = get_local_slot(s->b_parent->stack_frame, index);
+               dest = exprdest->tmp_low;
+               select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG,
+                                                      slot, dest));
+       } else
+               exprdest->tmp_low = get_fixed_var(s->b_parent, reg);
+}
+%endif
 
 stmt:  STMT_STORE(EXPR_TEMPORARY, reg) 1
 {
diff --git a/include/jit/args.h b/include/jit/args.h
index 0339660..7ec20b7 100644
--- a/include/jit/args.h
+++ b/include/jit/args.h
@@ -3,10 +3,16 @@
 
 #include "jit/expression.h"
 
+#include "vm/method.h"
 #include "vm/stack.h"
 
-struct expression *insert_arg(struct expression *root, struct expression 
*expr);
-struct expression *convert_args(struct stack *mimic_stack, unsigned long 
nr_args);
+struct expression *insert_arg(struct expression *root,
+                             struct expression *expr,
+                             unsigned long *args_state,
+                             struct vm_method *method);
+struct expression *convert_args(struct stack *mimic_stack,
+                               unsigned long nr_args,
+                               struct vm_method *method);
 const char *parse_method_args(const char *type_str, enum vm_type *vmtype);
 
 #endif
diff --git a/include/jit/expression.h b/include/jit/expression.h
index 86cd568..e029b3d 100644
--- a/include/jit/expression.h
+++ b/include/jit/expression.h
@@ -203,6 +203,7 @@ struct expression {
                    instruction selection only.  */
                struct {
                        struct tree_node *arg_expression;
+                       void *arg_private;
                };
 
                /*  EXPR_NO_ARGS is used for EXPR_INVOKE expression type when
diff --git a/include/vm/method.h b/include/vm/method.h
index e86df11..18626b8 100644
--- a/include/vm/method.h
+++ b/include/vm/method.h
@@ -29,6 +29,9 @@ struct vm_method {
        char *name;
        char *type;
        int args_count;
+#ifdef CONFIG_REGPARM
+       int reg_args_count;
+#endif
 
        struct cafebabe_code_attribute code_attribute;
        struct cafebabe_line_number_table_attribute line_number_table_attribute;
diff --git a/jit/args.c b/jit/args.c
index 0680068..27d00bf 100644
--- a/jit/args.c
+++ b/jit/args.c
@@ -24,41 +24,64 @@
  * Please refer to the file LICENSE for details.
  */
 
+#include <assert.h>
+
+#include "arch/args.h"
+
 #include "jit/expression.h"
 #include "jit/args.h"
 
+#include "vm/method.h"
 #include "vm/stack.h"
 
 struct expression *
-insert_arg(struct expression *root, struct expression *expr)
+insert_arg(struct expression *root,
+          struct expression *expr,
+          unsigned long *args_state,
+          struct vm_method *method)
 {
        struct expression *_expr;
+       int err;
 
        _expr = arg_expr(expr);
        _expr->bytecode_offset = expr->bytecode_offset;
 
+       if (args_state && method) {
+               err = args_set(args_state, method, _expr);
+               if (err)
+                       return NULL;
+       }
+
        if (!root)
                return _expr;
 
        return args_list_expr(root, _expr);
 }
 
-struct expression *
-convert_args(struct stack *mimic_stack, unsigned long nr_args)
+struct expression *convert_args(struct stack *mimic_stack,
+                               unsigned long nr_args,
+                               struct vm_method *method)
 {
        struct expression *args_list = NULL;
-       unsigned long i;
+       unsigned long args_state, i;
+       int err;
 
        if (nr_args == 0) {
                args_list = no_args_expr();
                goto out;
        }
 
+       err = args_init(&args_state, method, nr_args);
+       if (err)
+               return NULL;
+
        for (i = 0; i < nr_args; i++) {
                struct expression *expr = stack_pop(mimic_stack);
-               args_list = insert_arg(args_list, expr);
+               args_list = insert_arg(args_list, expr, &args_state, method);
        }
 
+       args_finish(&args_state);
+
   out:
        return args_list;
 }
diff --git a/jit/invoke-bc.c b/jit/invoke-bc.c
index 628ebf3..7441c64 100644
--- a/jit/invoke-bc.c
+++ b/jit/invoke-bc.c
@@ -72,7 +72,9 @@ static int convert_and_add_args(struct parse_context *ctx,
 {
        struct expression *args_list;
 
-       args_list = convert_args(ctx->bb->mimic_stack, 
method_real_argument_count(invoke_target));
+       args_list = convert_args(ctx->bb->mimic_stack,
+                                method_real_argument_count(invoke_target),
+                                invoke_target);
        if (!args_list)
                return -ENOMEM;
 
@@ -208,7 +210,7 @@ static void append_arg(struct expression *expr, struct 
expression *arg)
 {
        struct expression *args_list;
 
-       args_list = insert_arg(to_expr(expr->args_list), arg);
+       args_list = insert_arg(to_expr(expr->args_list), arg, NULL, NULL);
        expr->args_list = &args_list->node;
 }
 
diff --git a/jit/object-bc.c b/jit/object-bc.c
index e4eb12d..1252911 100644
--- a/jit/object-bc.c
+++ b/jit/object-bc.c
@@ -458,10 +458,12 @@ int convert_multianewarray(struct parse_context *ctx)
        unsigned long type_idx;
        unsigned char dimension;
        struct vm_class *class;
+       struct vm_method *method;
 
        type_idx = bytecode_read_u16(ctx->buffer);
        dimension = bytecode_read_u8(ctx->buffer);
        class = vm_class_resolve_class(ctx->cu->method->class, type_idx);
+       method = ctx->cu->method;
        if (!class)
                return -ENOMEM;
 
@@ -469,7 +471,7 @@ int convert_multianewarray(struct parse_context *ctx)
        if (!arrayref)
                return -ENOMEM;
 
-       args_list = convert_args(ctx->bb->mimic_stack, dimension);
+       args_list = convert_args(ctx->bb->mimic_stack, dimension, method);
 
        size_check = multiarray_size_check_expr(args_list);
        if (!size_check)
diff --git a/vm/method.c b/vm/method.c
index 5a8b688..5727475 100644
--- a/vm/method.c
+++ b/vm/method.c
@@ -66,6 +66,10 @@ int vm_method_init(struct vm_method *vmm,
                return -1;
        }
 
+#ifdef CONFIG_REGPARM
+       vmm->reg_args_count = 0;        /* Updated later. */
+#endif
+
        if (!vm_method_is_static(vmm))
                ++vmm->args_count;
 
-- 
1.6.0.6


------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge  
This is your chance to win up to $100,000 in prizes! For a limited time, 
vendors submitting new applications to BlackBerry App World(TM) will have
the opportunity to enter the BlackBerry Developer Challenge. See full prize  
details at: http://p.sf.net/sfu/Challenge
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to