This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[gcjx] Patch: FYI: implement BC ABI
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 03 Apr 2005 17:46:02 -0600
- Subject: [gcjx] Patch: FYI: implement BC ABI
- Reply-to: tromey at redhat dot com
I'm checking this in on the gcjx branch.
This is the first draft of the implementation of the BC ABI.
Tom
Index: gcjx/ChangeLog
from Tom Tromey <tromey@redhat.com>
* aot/aotclass.cc (register_indirect_call): Handle constructors
and other atable methods.
Index: gcc/java/ChangeLog
from Tom Tromey <tromey@redhat.com>
* tree.cc (visit_assert): Updated for change to map_new.
(create_stringbuffer): Likewise.
(visit_new): Likewise.
* decl.cc (build_oa_table_types): Elements of otable are of
type_jint.
* abi.hh (gcj_abi::build_new): Changed type of 'constructor'
argument.
(cxx_abi::build_new): Updated.
(bc_abi::build_new): Updated.
* builtins.hh (tree_builtins::get_atable_decl): Declare.
(tree_builtins::get_otable_decl): Likewise.
(tree_builtins::atable_map): New field.
(tree_builtins::otable_map): New field.
(tree_builtins::map_new): Updated.
* builtins.cc (get_atable_decl): New method.
(get_otable_decl): Likewise.
(map_new): Changed type of 'constructor'.
* abi.cc (build_class_reference): Added assertion.
(build_field_reference): Get otable and atable.
(build_new): Wrote. Updated argument types.
(build_method_call): Wrote.
Index: gcjx/aot/aotclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/aot/Attic/aotclass.cc,v
retrieving revision 1.1.2.8
diff -u -r1.1.2.8 aotclass.cc
--- gcjx/aot/aotclass.cc 21 Mar 2005 22:02:25 -0000 1.1.2.8
+++ gcjx/aot/aotclass.cc 3 Apr 2005 23:45:37 -0000
@@ -266,7 +266,13 @@
int
aot_class::register_indirect_call (model_method *m)
{
- return register_something (m->static_p () ? atable_map : otable_map, m);
+ assert (! m->get_declaring_class ()->interface_p ());
+ if (m->static_p () || m->constructor_p ()
+ || (m->get_modifiers () & ACC_PRIVATE) != 0
+ || (m->final_p ()
+ && m->get_declaring_class () == global->get_compiler ()->java_lang_Object ()))
+ return register_something (atable_map, m);
+ return register_something (otable_map, m);
}
int
Index: gcc/java/abi.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/abi.cc,v
retrieving revision 1.1.2.18
diff -u -r1.1.2.18 abi.cc
--- gcc/java/abi.cc 24 Mar 2005 19:57:29 -0000 1.1.2.18
+++ gcc/java/abi.cc 3 Apr 2005 23:45:45 -0000
@@ -63,6 +63,8 @@
}
else if (meth->get_declaring_class ()->interface_p ())
{
+ assert (obj != NULL_TREE);
+
// FIXME: use _Jv_LookupInterfaceMethodIdx.
tree klass_tree
@@ -97,7 +99,8 @@
// leave it to the optimizers to deduce that 'this != null' and
// remove checks in this case. We force a real check because in
// the case of a final method, a SEGV will not be generated.
- if (! meth->constructor_p ())
+ if (! meth->constructor_p ()
+ && (meth->get_modifiers () & ACC_PRIVATE) == 0)
obj = builtins->check_reference (obj, true);
args = tree_cons (NULL_TREE, obj, args);
@@ -210,7 +213,8 @@
tree
cxx_abi::build_new (tree_builtins *builtins, aot_class *current,
- model_class *klass, tree constructor, tree arguments)
+ model_class *klass, model_method *constructor,
+ tree arguments)
{
tree allocator = builtin_Jv_AllocObject; // FIXME: finalizer
tree klass_tree = builtins->map_type (klass);
@@ -228,11 +232,10 @@
tree mem = save_expr (n);
// Call the constructor.
- n = build3 (CALL_EXPR, void_type_node, build_address_of (constructor),
- tree_cons (NULL_TREE, mem, arguments),
- NULL_TREE);
- TREE_SIDE_EFFECTS (n) = 1;
+ n = build_method_call (builtins, current, mem, arguments, constructor,
+ false);
+ // Yield the new object
n = build2 (COMPOUND_EXPR, klass_tree, n, mem);
TREE_SIDE_EFFECTS (n) = 1;
@@ -263,50 +266,164 @@
tree
-bc_abi::build_method_call (tree_builtins *, aot_class *current, tree obj,
- tree args, model_method *meth, bool is_super)
-{
- return NULL_TREE;
+bc_abi::build_method_call (tree_builtins *builtins, aot_class *current,
+ tree obj, tree args,
+ model_method *meth, bool /*is_super*/)
+{
+ tree meth_tree = builtins->map_method (meth);
+ tree meth_ptr_type = build_pointer_type (TREE_TYPE (meth_tree));
+
+ tree func;
+
+ // FIXME: the tests here must be kept in sync with aotclass. We
+ // should encapsulate this info in a single place.
+ if (meth->static_p ())
+ {
+ assert (obj == NULL_TREE);
+
+ int slot = current->register_indirect_call (meth);
+ tree atable = builtins->get_atable_decl (current->get ());
+
+ tree atable_ref = build4 (ARRAY_REF, ptr_type_node, atable,
+ build_int_cst (type_jint, slot),
+ NULL_TREE, NULL_TREE);
+ func = build1 (INDIRECT_REF, meth_ptr_type,
+ convert (build_pointer_type (meth_ptr_type),
+ atable_ref));
+ }
+ else if (meth->get_declaring_class ()->interface_p ())
+ {
+ assert (obj != NULL_TREE);
+
+// int slot = current->register_interface_call (meth);
+// tree itable = builtins->get_itable_decl (current->get ());
+ abort ();
+ }
+ // Note that, unlike the C++ ABI, we call final methods via the
+ // vtable. This is because a final method can be made non-final and
+ // the call must still work properly. Note however that we don't do
+ // this for final methods in Object, due to an old gcj peculiarity.
+ // We suspect that these methods will not be made non-final anyway.
+ else if (meth->constructor_p ()
+ || (meth->get_modifiers () & ACC_PRIVATE) != 0
+ || (meth->final_p ()
+ && meth->get_declaring_class () == global->get_compiler ()->java_lang_Object ()))
+ {
+ assert (obj != NULL_TREE);
+
+ int slot = current->register_indirect_call (meth);
+ tree atable = builtins->get_atable_decl (current->get ());
+
+ // For final methods we have to do an explicit check.
+ if (! meth->constructor_p ()
+ && (meth->get_modifiers () & ACC_PRIVATE) == 0)
+ obj = builtins->check_reference (obj, true);
+
+ tree atable_ref = build4 (ARRAY_REF, ptr_type_node, atable,
+ build_int_cst (type_jint, slot),
+ NULL_TREE, NULL_TREE);
+ func = build1 (INDIRECT_REF, meth_ptr_type,
+ convert (build_pointer_type (meth_ptr_type),
+ atable_ref));
+ }
+ else
+ {
+ // FIXME: 'super' invocations need special work.
+
+ // Virtual dispatch.
+ assert (obj != NULL_TREE);
+
+ int slot = current->register_indirect_call (meth);
+
+ tree otable = builtins->get_otable_decl (current->get ());
+ tree index = build4 (ARRAY_REF, type_jint, otable,
+ build_int_cst (type_jint, slot),
+ NULL_TREE, NULL_TREE);
+
+ // FIXME: we could do this at link time and have the otable hold
+ // a pure byte offset.
+ index = size_binop (MULT_EXPR, index,
+ TYPE_SIZE_UNIT (type_nativecode_ptr_ptr));
+ if (TARGET_VTABLE_USES_DESCRIPTORS)
+ index = size_binop (MULT_EXPR, index,
+ size_int (TARGET_VTABLE_USES_DESCRIPTORS));
+
+ // Dereference the object to find the table. Check for a null
+ // reference if needed.
+ obj = builtins->check_reference (obj);
+
+ // Find the vtable by looking for the 'vtable' field.
+ tree dtable = build1 (INDIRECT_REF, type_object,
+ build1 (NOP_EXPR, type_object_ptr, obj));
+ dtable = build3 (COMPONENT_REF, type_dtable_ptr,
+ dtable,
+ builtins->find_decl (type_object, "vtable"),
+ NULL_TREE);
+
+ func = build2 (PLUS_EXPR, type_nativecode_ptr_ptr, dtable,
+ convert (type_nativecode_ptr_ptr, index));
+ if (! TARGET_VTABLE_USES_DESCRIPTORS)
+ func = build1 (INDIRECT_REF, type_nativecode_ptr, func);
+ // Cast back to the correct type, not just 'void *'.
+ func = build1 (NOP_EXPR, meth_ptr_type, func);
+ }
+
+ // METH_TREE is a method decl, so we need one TREE_TYPE to get the
+ // method's type and one to get the method's return type.
+ tree call = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (meth_tree)),
+ func, args, NULL_TREE);
+ TREE_SIDE_EFFECTS (call) = 1;
+
+ // call = check_for_builtin (method, call);
+
+ return call;
}
tree
-bc_abi::build_field_reference (tree_builtins *builtins,
- aot_class *current,
+bc_abi::build_field_reference (tree_builtins *builtins, aot_class *current,
tree obj, model_field *field)
{
tree result;
int slot = current->register_field_reference (field);
+ tree field_type = builtins->map_type (field->type ());
if (field->static_p ())
{
assert (obj == NULL_TREE);
- // FIXME: find the class' atable and then build a reference to
- // the appropriate part of it.
- tree atable_ref = NULL_TREE;
+
+ tree atable = builtins->get_atable_decl (current->get ());
+ tree atable_ref = build4 (ARRAY_REF, ptr_type_node, atable,
+ build_int_cst (type_jint, slot),
+ NULL_TREE, NULL_TREE);
+
result = build1 (INDIRECT_REF,
// Note we don't need ARRAY_REF, we
// just generate a direct reference.
- builtins->map_type (field->type ()),
- // FIXME find_atable_slot must cast to the
- // correct type!
- atable_ref);
+ field_type,
+ convert (build_pointer_type (field_type),
+ atable_ref));
}
else
{
assert (obj != NULL_TREE);
- // FIXME: find the class' otable and then build a reference to
- // the appropriate part of it.
- tree otable_ref = NULL_TREE;
- // FIXME cast OBJ to pointer to field type -- this works
- // due to structure layout rules ... ?
- result = build4 (ARRAY_REF, builtins->map_type (field->type ()),
- obj, otable_ref, NULL_TREE, NULL_TREE);
+
+ tree otable = builtins->get_otable_decl (current->get ());
+ tree otable_ref = build4 (ARRAY_REF, type_jint, otable,
+ build_int_cst (type_jint, slot),
+ NULL_TREE, NULL_TREE);
+
+ obj = builtins->check_reference (obj);
+ // Generate *(TYPE *) ((char *) OBJ + OFFSET)
+ result = build1 (INDIRECT_REF, field_type,
+ convert (build_pointer_type (field_type),
+ build2 (PLUS_EXPR, ptr_type_node,
+ convert (ptr_type_node, obj),
+ otable_ref)));
}
return result;
}
tree
-bc_abi::build_class_reference (tree_builtins *builtins,
- aot_class *current,
+bc_abi::build_class_reference (tree_builtins *builtins, aot_class *current,
const std::string &classname)
{
// FIXME: handle primitive classes
@@ -318,11 +435,10 @@
}
tree
-bc_abi::build_class_reference (tree_builtins *builtins,
- aot_class *current,
+bc_abi::build_class_reference (tree_builtins *builtins, aot_class *current,
model_type *klass)
{
- // FIXME: handle primitive classes
+ assert (! klass->primitive_p () && klass != primitive_void_type);
int index = current->add (assert_cast<model_class *> (klass));
tree cpool = builtins->get_constant_pool_decl (current->get ());
return build4 (ARRAY_REF, type_class_ptr,
@@ -332,7 +448,32 @@
tree
bc_abi::build_new (tree_builtins *builtins, aot_class *current,
- model_class *klass, tree constructor, tree arguments)
+ model_class *klass, model_method *constructor,
+ tree arguments)
{
- abort ();
+ tree allocator = builtin_Jv_AllocObject;
+ tree klass_tree = build_class_reference (builtins, current, klass);
+ // Allocate the object.
+ tree n = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (allocator)), allocator,
+ build_tree_list (NULL_TREE,
+ build_class_reference (builtins, current,
+ klass)),
+ NULL_TREE);
+ TREE_SIDE_EFFECTS (n) = 1;
+
+ n = build1 (NOP_EXPR, klass_tree, n);
+ TREE_SIDE_EFFECTS (n) = 1;
+
+ tree mem = save_expr (n);
+
+ // Call the constructor.
+ n = build_method_call (builtins, current, mem, arguments, constructor,
+ false);
+ TREE_SIDE_EFFECTS (n) = 1;
+
+ // Yield the new object.
+ n = build2 (COMPOUND_EXPR, klass_tree, n, mem);
+ TREE_SIDE_EFFECTS (n) = 1;
+
+ return n;
}
Index: gcc/java/abi.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/abi.hh,v
retrieving revision 1.1.2.7
diff -u -r1.1.2.7 abi.hh
--- gcc/java/abi.hh 9 Mar 2005 02:19:09 -0000 1.1.2.7
+++ gcc/java/abi.hh 3 Apr 2005 23:45:45 -0000
@@ -99,7 +99,7 @@
virtual tree build_new (tree_builtins *builtins,
aot_class *current,
model_class *klass,
- tree constructor, tree args) = 0;
+ model_method *constructor, tree args) = 0;
/// Return an expression representing the size of the class in
/// bytes, or -1 if it can't be known until runtime.
@@ -142,7 +142,8 @@
aot_class *current,
model_type *other);
- tree build_new (tree_builtins *, aot_class *, model_class *, tree, tree);
+ tree build_new (tree_builtins *, aot_class *, model_class *,
+ model_method *, tree);
tree get_size_in_bytes (tree klass)
{
@@ -182,7 +183,8 @@
aot_class *current,
model_type *other);
- tree build_new (tree_builtins *, aot_class *, model_class *, tree, tree);
+ tree build_new (tree_builtins *, aot_class *, model_class *,
+ model_method *, tree);
tree get_size_in_bytes (tree klass)
{
Index: gcc/java/builtins.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/builtins.cc,v
retrieving revision 1.1.2.27
diff -u -r1.1.2.27 builtins.cc
--- gcc/java/builtins.cc 27 Mar 2005 02:57:14 -0000 1.1.2.27
+++ gcc/java/builtins.cc 3 Apr 2005 23:45:45 -0000
@@ -396,7 +396,7 @@
tree
tree_builtins::map_new (aot_class *current, model_class *klass,
- tree constructor, tree arguments)
+ model_method *constructor, tree arguments)
{
gcj_abi *abi = find_abi ();
return abi->build_new (this, current, klass, constructor, arguments);
@@ -540,6 +540,36 @@
return cpool_map[klass];
}
+tree
+tree_builtins::get_atable_decl (model_class *klass)
+{
+ if (atable_map.find (klass) == atable_map.end ())
+ {
+ tree decl = build_decl (VAR_DECL, get_symbol (), type_atable);
+ TREE_STATIC (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ atable_map[klass] = decl;
+ pushdecl (decl);
+ }
+ return atable_map[klass];
+}
+
+tree
+tree_builtins::get_otable_decl (model_class *klass)
+{
+ if (otable_map.find (klass) == otable_map.end ())
+ {
+ tree decl = build_decl (VAR_DECL, get_symbol (), type_otable);
+ TREE_STATIC (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ otable_map[klass] = decl;
+ pushdecl (decl);
+ }
+ return otable_map[klass];
+}
+
// FIXME: this whole method should probably migrate into the ABI or
// into classobj.cc. There's no need, I think, for it to be a generic
// part of the builtins.
Index: gcc/java/builtins.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/builtins.hh,v
retrieving revision 1.1.2.12
diff -u -r1.1.2.12 builtins.hh
--- gcc/java/builtins.hh 9 Mar 2005 02:19:09 -0000 1.1.2.12
+++ gcc/java/builtins.hh 3 Apr 2005 23:45:45 -0000
@@ -55,6 +55,10 @@
// Utf8Const.
std::map<std::string, tree> utf8map;
+ // Registry of otable and atable decls.
+ std::map<model_class *, tree> atable_map;
+ std::map<model_class *, tree> otable_map;
+
// Used when creating symbol names.
int symbol_count;
@@ -94,7 +98,7 @@
const std::string &);
tree map_method_call (aot_class *, tree, tree, model_method *, bool);
- tree map_new (aot_class *, model_class *, tree, tree);
+ tree map_new (aot_class *, model_class *, model_method *, tree);
tree map_class_object (model_class *);
/// Memoize a utf8const.
@@ -131,6 +135,9 @@
/// Return some code to initialize a class.
tree build_class_init (model_class *);
+
+ tree get_atable_decl (model_class *);
+ tree get_otable_decl (model_class *);
};
#endif // GCC_TREE_BUILTINS_HH
Index: gcc/java/decl.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/decl.cc,v
retrieving revision 1.1.2.17
diff -u -r1.1.2.17 decl.cc
--- gcc/java/decl.cc 27 Mar 2005 03:01:24 -0000 1.1.2.17
+++ gcc/java/decl.cc 3 Apr 2005 23:45:45 -0000
@@ -322,8 +322,7 @@
TYPE_NONALIASED_COMPONENT (type_atable) = 1;
type_atable_ptr = build_pointer_type (type_atable);
- type_otable = build_array_type (integer_type_node,
- one_elt_array_domain_type);
+ type_otable = build_array_type (type_jint, one_elt_array_domain_type);
TYPE_NONALIASED_COMPONENT (type_otable) = 1;
type_otable_ptr = build_pointer_type (type_otable);
}
Index: gcc/java/tree.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/tree.cc,v
retrieving revision 1.1.2.37
diff -u -r1.1.2.37 tree.cc
--- gcc/java/tree.cc 27 Mar 2005 03:13:12 -0000 1.1.2.37
+++ gcc/java/tree.cc 3 Apr 2005 23:45:45 -0000
@@ -374,10 +374,8 @@
model_method *init = find_method ("<init>", errclass, arg_type,
primitive_void_type, element);
- tree init_tree = gcc_builtins->map_method (init);
- tree new_tree = gcc_builtins->map_new (class_wrapper, errclass,
- init_tree, args);
+ tree new_tree = gcc_builtins->map_new (class_wrapper, errclass, init, args);
// Generate:
// if (! $assertionsDisabled && ! FIRST) throw new AssertionError (SECOND)
@@ -1262,10 +1260,9 @@
// FIXME: could call a different constructor if the LHS is a String.
model_method *init = find_method ("<init>", sb_class, NULL,
primitive_void_type, model);
- tree init_tree = gcc_builtins->map_method (init);
tree buffer_tree = gcc_builtins->map_new (class_wrapper, sb_class,
- init_tree, NULL_TREE);
+ init, NULL_TREE);
buffer_tree = save_expr (buffer_tree);
*sb_class_r = sb_class;
@@ -2025,7 +2022,7 @@
gcc_builtins->lay_out_class (klassp);
current
= gcc_builtins->map_new (class_wrapper, klassp,
- gcc_builtins->map_method (const_cast<model_method *>(constructor)),
+ const_cast<model_method *>(constructor),
arg_tree);
annotate (current, elt);
}