* [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).