public inbox for java-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [gcjx] Patch: FYI: create bridge methods
@ 2005-12-12 16:51 Tom Tromey
  0 siblings, 0 replies; only message in thread
From: Tom Tromey @ 2005-12-12 16:51 UTC (permalink / raw)
  To: Java Patch List

I'm checking this in on the gcjx branch.

This adds the initial support for creating bridge methods.

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>
	* model/method.cc (model_method): Updated.
	(hides_or_overrides_p): Set 'override'.
	(check_override): Updated.
	* model/method.hh (model_method::overrides): Removed.
	(model_method::override): New field.
	(model_method): Updated.
	(model_method::get_override): New method.
	(model_method::get_parent): Likewise.
	* Makefile.in: Rebuilt.
	* Makefile.am (headers): Added bridge.hh.
	(bytecode_sources): Added bridge.cc.
	* bytecode/classwriter.hh (class_writer::write_method): Added
	argument.
	* bytecode/classwriter.cc: Include bridge.hh.
	(write): Create bridge method.
	(write_method): Added 'is_bridge' argument.
	* bytecode/bridge.cc: New file.
	* bytecode/bridge.hh: New file.

Index: Makefile.am
===================================================================
--- Makefile.am	(revision 107604)
+++ Makefile.am	(working copy)
@@ -41,22 +41,23 @@
 ################################################################
 
 headers = access.hh buffer.hh directory.hh bytecode/block.hh \
-bytecode/bytegen.hh bytecode/byteutil.hh bytecode/classreader.hh \
-bytecode/classwriter.hh bytecode/cpool.hh bytecode/generate.hh \
-bytecode/insns.hh bytecode/locals.hh bytecode/outpool.hh \
-bytecode/outstream.hh bytecode/relocation.hh classcache.hh codegen.hh \
-compiler.hh conversions.hh defassign.hh exception.hh factory.hh	\
-fold.hh format/format.hh global.hh header/cni.hh header/jni.hh \
-header/jnistub.hh location.hh model/annotation.hh model/annomember.hh \
-model/annotype.hh model/annovalue.hh model/arrayinit.hh	\
-model/arrayref.hh model/arraytype.hh model/assert.hh model/assign.hh \
-model/binary.hh model/block.hh model/blockscope.hh model/break.hh \
-model/bytecode.hh model/cast.hh model/catch.hh model/class.hh \
-model/classinst.hh model/classref.hh model/cond.hh \
-model/constructor.hh model/continue.hh model/declstmt.hh model/do.hh \
-model/element.hh model/empty.hh model/enumconst.hh model/enum.hh \
-model/expr.hh model/exprstmt.hh model/field.hh model/fieldinit.hh \
-model/fieldref.hh model/forenhanced.hh model/for.hh model/fwdtype.hh \
+bytecode/bridge.hh bytecode/bytegen.hh bytecode/byteutil.hh \
+bytecode/classreader.hh bytecode/classwriter.hh bytecode/cpool.hh \
+bytecode/generate.hh bytecode/insns.hh bytecode/locals.hh \
+bytecode/outpool.hh bytecode/outstream.hh bytecode/relocation.hh \
+classcache.hh codegen.hh compiler.hh conversions.hh defassign.hh \
+exception.hh factory.hh fold.hh format/format.hh global.hh \
+header/cni.hh header/jni.hh header/jnistub.hh location.hh \
+model/annotation.hh model/annomember.hh model/annotype.hh \
+model/annovalue.hh model/arrayinit.hh model/arrayref.hh	\
+model/arraytype.hh model/assert.hh model/assign.hh model/binary.hh \
+model/block.hh model/blockscope.hh model/break.hh model/bytecode.hh \
+model/cast.hh model/catch.hh model/class.hh model/classinst.hh \
+model/classref.hh model/cond.hh model/constructor.hh model/continue.hh \
+model/declstmt.hh model/do.hh model/element.hh model/empty.hh \
+model/enumconst.hh model/enum.hh model/expr.hh model/exprstmt.hh \
+model/field.hh model/fieldinit.hh model/fieldref.hh \
+model/forenhanced.hh model/for.hh model/fwdtype.hh \
 model/iannotatable.hh model/icatcher.hh model/icontext.hh \
 model/identifier.hh model/ideprecatable.hh model/if.hh model/ilabel.hh \
 model/imember.hh model/imodifiable.hh model/import.hh model/iname.hh \
@@ -104,11 +105,11 @@
 model/void.cc model/while.cc model/wildcard.cc
 
 bytecode_sources = bytecode/attribute.cc bytecode/block.cc \
-bytecode/bytegen.cc bytecode/classreader.cc bytecode/classwriter.cc \
-bytecode/cpool.cc bytecode/generate.cc bytecode/glue.cc	\
-bytecode/locals.cc bytecode/outpool.cc bytecode/outstream.cc \
-bytecode/poolreader.cc bytecode/relocation.cc bytecode/signature.cc \
-bytecode/verify.cc
+bytecode/bridge.cc bytecode/bytegen.cc bytecode/classreader.cc \
+bytecode/classwriter.cc bytecode/cpool.cc bytecode/generate.cc \
+bytecode/glue.cc bytecode/locals.cc bytecode/outpool.cc	\
+bytecode/outstream.cc bytecode/poolreader.cc bytecode/relocation.cc \
+bytecode/signature.cc bytecode/verify.cc
 
 reader_sources = reader/classbytes.cc reader/fdreader.cc \
 reader/zereader.cc reader/zebuffer.cc reader/mmapbuffer.cc \
Index: bytecode/bridge.hh
===================================================================
--- bytecode/bridge.hh	(revision 0)
+++ bytecode/bridge.hh	(revision 0)
@@ -0,0 +1,60 @@
+// Bridge method generation
+
+// Copyright (C) 2005 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// gcjx is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// gcjx is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with gcjx; see the file COPYING.LIB.  If
+// not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef GCJX_BYTECODE_BRIDGE_HH
+#define GCJX_BYTECODE_BRIDGE_HH
+
+#include "bytecode/attribute.hh"
+
+class bridge_method : public bytecode_attribute
+{
+  // The method which requires a bridge.
+  model_method *method;
+
+  // Facts about the generated bytecode.
+  int max_stack;
+  int max_locals;
+  int bytecode_length;
+
+  int emit_code (bytecode_stream *);
+
+public:
+
+  bridge_method (outgoing_constant_pool *cp, model_method *m)
+    : bytecode_attribute (cp, "Code"),
+      method (m),
+      max_stack (0),
+      max_locals (0)
+  {
+    // emit_code() doubles as a way to compute the size of the
+    // generated bytecode.
+    bytecode_length = emit_code (NULL);
+  }
+
+  void emit (bytecode_stream &);
+
+  int size ();
+
+  /// Return true if the given method requires a bridge.
+  static bool required_p (model_method *);
+};
+
+#endif // GCJX_BYTECODE_BRIDGE_HH
Index: bytecode/classwriter.hh
===================================================================
--- bytecode/classwriter.hh	(revision 107604)
+++ bytecode/classwriter.hh	(working copy)
@@ -49,7 +49,7 @@
   void maybe_write_annotations (IAnnotatable *, bytecode_attribute_list *);
   void maybe_write_parameter_annotations (model_method *,
 					  bytecode_attribute_list *);
-  void write_method (model_method *, bytecode_attribute_list *);
+  void write_method (model_method *, bytecode_attribute_list *, bool = false);
   void write_field (model_field *, bytecode_attribute_list *);
 
 public:
Index: bytecode/bridge.cc
===================================================================
--- bytecode/bridge.cc	(revision 0)
+++ bytecode/bridge.cc	(revision 0)
@@ -0,0 +1,197 @@
+// Bridge method generation
+
+// Copyright (C) 2005 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// gcjx is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// gcjx is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with gcjx; see the file COPYING.LIB.  If
+// not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include "typedefs.hh"
+#include "bytecode/outpool.hh"
+#include "bytecode/locals.hh"
+#include "bytecode/block.hh"
+#include "bytecode/attribute.hh"
+#include "bytecode/bridge.hh"
+#include "bytecode/byteutil.hh"
+
+void
+bridge_method::emit (bytecode_stream &out)
+{
+  bytecode_attribute::emit (out);
+
+  out.put2 (max_stack);
+  out.put2 (max_locals);
+  out.put4 (bytecode_length);
+  emit_code (&out);
+
+  // Exception table.
+  out.put2 (0);
+  // Attributes.
+  out.put2 (0);
+}
+
+int
+bridge_method::emit_code (bytecode_stream *out)
+{
+  model_method *parent = method->get_override ()->get_parent ();
+  assert (parent != NULL);
+
+  std::list<ref_variable_decl> m_parms = method->get_parameters ();
+  std::list<ref_variable_decl> p_parms = parent->get_parameters ();
+
+  std::list<ref_variable_decl>::const_iterator m_it = m_parms.begin ();
+  std::list<ref_variable_decl>::const_iterator p_it = p_parms.begin ();
+
+  int result = 0;
+  int index = 0;
+  max_stack = 0;
+  max_locals = 0;
+
+  // Start with the 'load' opcode for 'this'.
+  if (out)
+    out->put (op_aload_0);
+  else
+    ++result;
+  ++index;
+  ++max_stack;
+  ++max_locals;
+
+  while (m_it != m_parms.end () && p_it != p_parms.end ())
+    {
+      model_type *p_type = (*p_it)->type ()->erasure ();
+
+      max_stack += wide_p (p_type) ? 2 : 1;
+      max_locals += wide_p (p_type) ? 2 : 1;
+
+      // Emit the load opcode for the argument type.
+      int base;
+      if (p_type == primitive_long_type)
+	base = op_lload;
+      else if (p_type == primitive_float_type)
+	base = op_fload;
+      else if (p_type == primitive_double_type)
+	base = op_dload;
+      else if (p_type->reference_p ())
+	base = op_aload;
+      else
+	base = op_iload;
+      if (index <= 3)
+	base = op_iload_0 + 4 * (base - op_iload) + index;
+
+      if (out)
+	{
+	  out->put (base);
+	  if (index > 3)
+	    out->put (index);
+	}
+      else
+	{
+	  ++result;
+	  if (index > 3)
+	    ++result;
+	}
+
+      // Emit the 'checkcast' if needed.
+      model_type *m_type = (*m_it)->type ()->erasure ();
+      if (m_type != p_type)
+	{
+	  assert (p_type->reference_p ());
+	  assert (m_type->reference_p ());
+	  int entry = pool->add (m_type);
+	  if (out)
+	    {
+	      out->put (op_checkcast);
+	      out->put2 (entry);
+	    }
+	  else
+	    result += 3;
+	}
+
+      ++m_it;
+      ++p_it;
+      ++index;
+    }
+
+  // Handle the invoke.
+  int entry = pool->add (method->get_declaring_class (), method);
+  if (out)
+    {
+      out->put (op_invokevirtual);
+      out->put2 (entry);
+    }
+  else
+    result += 3;
+
+  // Handle the return.  FIXME: do we need a checkcast for the return?
+  // I can't see why we would.
+  if (out)
+    {
+      model_type *return_type = method->get_return_type ()->erasure ();
+      int op;
+      if (return_type == primitive_void_type)
+	op = op_return;
+      else if (return_type == primitive_long_type)
+	op = op_lreturn;
+      else if (return_type == primitive_float_type)
+	op = op_freturn;
+      else if (return_type == primitive_double_type)
+	op = op_dreturn;
+      else if (return_type->reference_p ())
+	op = op_areturn;
+      else
+	op = op_ireturn;
+      out->put (op);
+    }
+  else
+    ++result;
+
+  return result;
+}
+
+int
+bridge_method::size ()
+{
+  // Include max stack, locals, etc.
+  return 8 + bytecode_length + 2 + 2;
+}
+
+bool
+bridge_method::required_p (model_method *method)
+{
+  if (method->static_p ())
+    return false;
+  model_method *parent = method->get_override ();
+  if (parent == NULL)
+    return false;
+  parent = parent->get_parent ();
+
+  std::list<ref_variable_decl> m_parms = method->get_parameters ();
+  std::list<ref_variable_decl> p_parms = parent->get_parameters ();
+
+  std::list<ref_variable_decl>::const_iterator m_it = m_parms.begin ();
+  std::list<ref_variable_decl>::const_iterator p_it = p_parms.begin ();
+
+  while (m_it != m_parms.end () && p_it != p_parms.end ())
+    {
+      if ((*m_it)->type ()->erasure () != (*p_it)->type ()->erasure ())
+	return true;
+
+      ++m_it;
+      ++p_it;
+    }
+
+  return false;
+}
Index: bytecode/classwriter.cc
===================================================================
--- bytecode/classwriter.cc	(revision 107604)
+++ bytecode/classwriter.cc	(working copy)
@@ -27,6 +27,7 @@
 #include "bytecode/attribute.hh"
 #include "bytecode/generate.hh"
 #include "bytecode/byteutil.hh"
+#include "bytecode/bridge.hh"
 
 #include <fcntl.h>
 
@@ -155,13 +156,22 @@
 }
 
 void
-class_writer::write_method (model_method *meth, bytecode_attribute_list *attrs)
+class_writer::write_method (model_method *meth, bytecode_attribute_list *attrs,
+			    bool is_bridge)
 {
-  int mods = meth->get_modifiers ();
+  int mods;
+  if (is_bridge)
+    {
+      meth = meth->get_override ();
+      mods = ACC_BRIDGE | meth->get_modifiers ();
+    }
+  else
+    mods = meth->get_modifiers ();
+
   if (target_15)
     {
       if (meth->varargs_p ())
-	mods |= ACC_VARARGS;
+	mods |= ACC_VARARGS;	// FIXME: correct for bridge methods?
     }
   else
     mods &= ~ACC_SYNTHETIC;
@@ -235,11 +245,13 @@
 
   std::list<ref_method> methods = the_class->get_methods ();
   std::list<bytecode_attribute_list *> method_attrs;
+  int method_count = 0;
   for (std::list<ref_method>::const_iterator i = methods.begin ();
        i != methods.end ();
        ++i)
     {
       bytecode_attribute_list *attrs = new bytecode_attribute_list ();
+      ++method_count;
 
       // One last check on the method.
       std::list<ref_variable_decl> params = (*i)->get_parameters ();
@@ -284,6 +296,20 @@
       maybe_write_annotations ((*i).get (), attrs);
 
       method_attrs.push_back (attrs);
+
+      // If this method needs a bridge, create it and push it on the
+      // list here.
+      if (target_15 && bridge_method::required_p ((*i).get ()))
+	{
+	  attrs = new bytecode_attribute_list ();
+	  attrs->push_back (new bridge_method (pool, (*i).get ()));
+	  method_attrs.push_back (attrs);
+	  ++method_count;
+
+	  model_method *m = (*i)->get_override ();
+	  pool->add_utf (m->get_name ());
+	  pool->add_utf (m->get_descriptor ());
+	}
     }
 
   std::list<ref_field> fields = the_class->get_fields ();
@@ -378,10 +404,9 @@
     assert (attr_i == field_attrs.end ());
   }
 
-  int msize = methods.size ();
-  if (msize > 65535)
+  if (method_count > 65535)
     throw the_class->error ("class contains more than 65535 methods");
-  writer.put2 (msize);
+  writer.put2 (method_count);
   {
     std::list<bytecode_attribute_list *>::const_iterator attr_i
       = method_attrs.begin ();
@@ -393,6 +418,15 @@
 	write_method (m, *attr_i);
 	delete *attr_i;
 	++attr_i;
+
+	// When we made the 'method_attrs' list, we pushed a second
+	// entry for any method requiring a bridge.
+	if (target_15 && bridge_method::required_p (m))
+	  {
+	    write_method (m, *attr_i, true);
+	    delete *attr_i;
+	    ++attr_i;
+	  }
       }
     assert (attr_i == method_attrs.end ());
   }
Index: model/method.cc
===================================================================
--- model/method.cc	(revision 107975)
+++ model/method.cc	(working copy)
@@ -47,6 +47,7 @@
     IMember (enclosing),
     state (other->state),
     method_end (other->method_end),
+    override (NULL),		// FIXME
     parent (other)
 {
   set_name (other->name);
@@ -77,7 +78,6 @@
 
   varargs = other->varargs;
   used = false;
-  overrides = other->overrides;
   is_instance_initializer = other->is_instance_initializer;
 }
 
@@ -90,6 +90,7 @@
     IMember (enclosing),
     state (other->state),
     method_end (other->method_end),
+    override (NULL),
     parent (other)
 {
   set_name (other->name);
@@ -119,7 +120,6 @@
 
   varargs = other->varargs;
   used = false;
-  overrides = other->overrides;
   is_instance_initializer = other->is_instance_initializer;
 }
 
@@ -567,7 +567,7 @@
     other->check_deprecated (this);
 
   if (! static_p () && ! other->declaring_class->interface_p ())
-    overrides = true;
+    override = other;
 
   return true;
 }
@@ -843,7 +843,7 @@
 	std::cerr << error ("%<@Override%> applied to static method");
       else if (declaring_class->interface_p ())
 	std::cerr << error ("%<@Override%> applied to interface method");
-      else if (! overrides)
+      else if (! override)
 	std::cerr << error ("method marked %<@Override%> does not override "
 			    "another method");
     }
Index: model/method.hh
===================================================================
--- model/method.hh	(revision 107975)
+++ model/method.hh	(working copy)
@@ -80,10 +80,6 @@
   // True if this method was used.
   bool used;
 
-  // True if this method overrides a concrete (not interface) method.
-  // Meaningless for static methods and constructors.
-  bool overrides;
-
   // True if this is an instance initializer method, aka 'finit$'.
   bool is_instance_initializer;
 
@@ -96,6 +92,9 @@
   // this is used by GCC for debugging information.
   location method_end;
 
+  // The method this overrides, or NULL if none.
+  model_method *override;
+
   // If this is a generic instantiation, this points to the parent
   // method.
   model_method *parent;
@@ -130,11 +129,11 @@
       IMember (decl),
       varargs (false),
       used (false),
-      overrides (false),
       is_instance_initializer (false),
       state (NONE),
       // By default we set the end location to the start location.
       method_end (w),
+      override (NULL),
       parent (NULL)
   {
   }
@@ -409,6 +408,20 @@
   /// than going via the erasure of the method, as no enclosing
   /// context is needed.
   model_type *get_erased_return_type () const;
+
+  /// Return the method that this method overrides, or NULL if this
+  /// method does not override another.
+  model_method *get_override () const
+  {
+    return override;
+  }
+
+  /// Return the parent method if this method is a generic
+  /// instantiation, or the method itself if not.
+  model_method *get_parent ()
+  {
+    return parent ? parent : this;
+  }
 };
 
 /// This represents a method that is the result of merging multiple

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-12-12 16:51 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-12-12 16:51 [gcjx] Patch: FYI: create bridge methods Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).