This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gcjx] Patch: FYI: implement BC ABI


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);
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]