This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[gcjx] Patch: FYI: constructor accessors
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 12 Mar 2005 13:46:50 -0700
- Subject: [gcjx] Patch: FYI: constructor accessors
- Reply-to: tromey at redhat dot com
I'm checking this in on the gcjx branch.
gcjx didn't create accessors for constructors. This patch adds that.
An accessor is needed when a private (and sometimes a protected)
constructor is used from another class. This is allowed in various
nested class situations.
Tom
Index: ChangeLog
from Tom Tromey <tromey@redhat.com>
* model/constructor.cc (model_constructor): New constructor.
(model_constructor): Correctly set this0.
* model/constructor.hh (model_constructor): Declare.
* bytecode/generate.cc (visit_new): Use accessor constructor if
needed.
(visit_type_qualified_invocation): Handle accessor.
(visit_super_invocation): Likewise.
* model/invoke.cc (handle_resolve): Add extra arguments when
calling constructor accessor.
(resolve): Handle class in static context.
* model/method.hh (model_method::get_parameter_count): New
method.
* model/class.cc (get_accessor): Create accessor constructor.
Index: bytecode/generate.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/bytecode/Attic/generate.cc,v
retrieving revision 1.1.2.9
diff -u -r1.1.2.9 generate.cc
--- bytecode/generate.cc 13 Feb 2005 03:39:44 -0000 1.1.2.9
+++ bytecode/generate.cc 12 Mar 2005 20:41:53 -0000
@@ -3146,6 +3146,11 @@
const std::list<ref_expression> &args,
bool super)
{
+ // FIXME: duplicate code.
+ model_class *accessed;
+ if (trampoline_required_p (meth, method->get_declaring_class (), &accessed))
+ meth = accessed->get_accessor (const_cast<model_method *> (meth));
+
if (! meth->static_p ())
emit_load (meth->get_declaring_class (), this_index);
handle_invocation (super ? op_invokespecial : op_invokestatic,
@@ -3159,6 +3164,11 @@
const model_method *meth,
const std::list<ref_expression> &args)
{
+ // FIXME: duplicate code.
+ model_class *accessed;
+ if (trampoline_required_p (meth, method->get_declaring_class (), &accessed))
+ meth = accessed->get_accessor (const_cast<model_method *> (meth));
+
emit_load (method->get_declaring_class (), this_index);
handle_invocation (op_invokespecial, inv->get_qualifying_class (),
meth, args, inv->get_expression () != NULL);
@@ -3170,6 +3180,7 @@
const model_method *meth,
const std::list<ref_expression> &args)
{
+ // Note: an accessor can never be needed here.
emit_load (method->get_declaring_class (), this_index);
handle_invocation (op_invokespecial, inv->get_qualifying_class (),
meth, args, inv->get_expression () != NULL);
@@ -3253,9 +3264,16 @@
}
// Stack: ... NEW-INITIALIZED
emit (op_invokespecial);
- // FIXME: cast
+
+ // If we need an accessor constructor, use it instead.
+ model_class *accessed;
+ if (trampoline_required_p (init_meth, method->get_declaring_class (),
+ &accessed))
+ init_meth
+ = accessed->get_accessor (const_cast<model_method *> (init_meth));
+
int mindex = cpool->add (init_meth->get_declaring_class (),
- (model_method *) init_meth);
+ const_cast<model_method *> (init_meth));
emit2 (mindex);
// Pop all the arguments and the class reference.
Index: model/class.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/model/Attic/class.cc,v
retrieving revision 1.1.2.7
diff -u -r1.1.2.7 class.cc
--- model/class.cc 8 Mar 2005 17:27:37 -0000 1.1.2.7
+++ model/class.cc 12 Mar 2005 20:41:54 -0000
@@ -2192,25 +2192,39 @@
{
location where = meth->get_location ();
+ std::string name;
+ ref_method accm;
+ // This is only used in the constructor case.
+ int added_args = 0;
+
// Note that constructors are special since we can't create one
// with a new name. So, we are forced to add dummy arguments to
// differentiate our constructors from ones that the user might
// declare.
if (meth->constructor_p ())
{
- if (global->get_compiler ()->warn_enclosing_access ())
- std::cerr << meth->warn (global->get_compiler ()->warn_enclosing_access (),
- "constructor %1 requires accessor")
- % meth;
- // FIXME: we need to make a new constructor (that is
- // disambiguated) here.
- return meth;
- }
+ model_constructor *cons = assert_cast<model_constructor *> (meth);
+ name = "<init>";
+ std::string descriptor = cons->get_descriptor ();
+ std::string::size_type it = descriptor.find(')');
+
+ // Unlike other compilers, we simply add 'boolean' arguments
+ // until the result is disambiguated. This can be defeated
+ // by having a constructor with many arguments, but cases
+ // like that are pathological anyway.
+ do
+ {
+ ++added_args;
+ descriptor.insert (it, "Z");
+ ++it;
+ }
+ while (has_method_with_descriptor_p (name, descriptor));
- ref_method accm = new model_method (where, this);
+ accm = new model_constructor (cons);
+ }
+ else
+ accm = new model_method (where, this);
- // FIXME: it might be better to always emit a static method
- // here.
modifier_t mods = 0;
if (meth->static_p ())
mods |= ACC_STATIC;
@@ -2219,6 +2233,8 @@
accm->set_return_type (new model_forwarding_resolved (get_location (),
meth->get_return_type ()));
+ // Compute the new formal arguments and actual arguments to the
+ // forwarding method call we create.
std::list<ref_variable_decl> args, old_args = meth->get_parameters ();
std::list<ref_expression> actual;
for (std::list<ref_variable_decl>::const_iterator i = old_args.begin ();
@@ -2236,7 +2252,54 @@
arg.get ()));
}
- ref_method_invocation inv = new model_method_invocation (where, actual);
+ // For a constructor we added arguments, so add those to the
+ // actual parameters.
+ if (added_args)
+ {
+ assert (meth->constructor_p ());
+ ref_forwarding_type booltype
+ = new model_forwarding_resolved (where, primitive_boolean_type);
+ for (int i = 0; i < added_args; ++i)
+ {
+ char buffer[10];
+ sprintf (buffer, "%d", i);
+ ref_variable_decl arg
+ = new model_variable_decl (where,
+ // FIXME: duplicate name?
+ "added$" + std::string (buffer),
+ booltype,
+ this);
+ args.push_back (arg);
+ }
+
+ // If the class is an inner class, then resolving the
+ // 'this()' invocation will push a new 'this$0' argument at
+ // the front. So, eliminate that here.
+ if (inner_p () && ! static_context_p ())
+ {
+ args.pop_front ();
+ // FIXME: this is a hack: we pop the this$0 parameter if
+ // the original constructor has been resolved. There
+ // has to be a better way.
+ model_constructor *c = assert_cast<model_constructor *> (meth);
+ if (c->get_this0_parameter ())
+ actual.pop_front ();
+ }
+ }
+
+ ref_invocation_base inv;
+ if (meth->constructor_p ())
+ {
+ // Generate 'this(actual args)'.
+ inv = new model_this_invocation (where);
+ // Sigh.
+ model_this_invocation *thi
+ = assert_cast<model_this_invocation *> (inv.get ());
+ thi->set_enclosing_class (this);
+ }
+ else
+ inv = new model_method_invocation (where);
+ inv->set_arguments (actual);
inv->set_method (meth->get_name ());
std::list<ref_stmt> statements;
@@ -2252,8 +2315,9 @@
accm->set_throws (meth->get_throws ());
// FIXME: copy type parameters?
- std::string name
- = generate_synthetic_method_name ("call$" + meth->get_name (), accm);
+ if (! meth->constructor_p ())
+ name = generate_synthetic_method_name ("call$" + meth->get_name (),
+ accm);
accm->set_name (name);
add (accm);
Index: model/constructor.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/model/Attic/constructor.cc,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 constructor.cc
--- model/constructor.cc 13 Jan 2005 03:18:36 -0000 1.1.2.1
+++ model/constructor.cc 12 Mar 2005 20:41:54 -0000
@@ -1,6 +1,6 @@
// Represent a constructor.
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -27,7 +27,20 @@
model_class *enclosing)
: model_method (other, type_map, enclosing)
{
- this0 = other->this0;
+ if (other->this0)
+ {
+ this0 = new model_variable_decl (get_location (),
+ // FIXME: construct new name
+ "arg$this$0",
+ other->this0->get_declared_type (),
+ declaring_class);
+ }
+}
+
+model_constructor::model_constructor (model_constructor *other)
+ : model_method (get_location (), other->get_declaring_class ()),
+ other_this (NULL)
+{
}
void
Index: model/constructor.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/model/Attic/constructor.hh,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 constructor.hh
--- model/constructor.hh 13 Jan 2005 03:18:36 -0000 1.1.2.1
+++ model/constructor.hh 12 Mar 2005 20:41:54 -0000
@@ -1,6 +1,6 @@
// Represent a constructor.
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -58,6 +58,9 @@
{
}
+ // This constructor is used only when creating an accessor.
+ model_constructor (model_constructor *);
+
bool constructor_p () const
{
return true;
Index: model/invoke.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/model/Attic/invoke.cc,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 invoke.cc
--- model/invoke.cc 13 Jan 2005 03:18:36 -0000 1.1.2.1
+++ model/invoke.cc 12 Mar 2005 20:41:54 -0000
@@ -1,6 +1,6 @@
// Method invocation.
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -324,7 +324,7 @@
if (trampoline_required_p (method, scope->get_current_class (), &accessed))
{
// Ensure that the required accessor exists.
- accessed->get_accessor (method);
+ model_method *accessor = accessed->get_accessor (method);
if (scope->warn_enclosing_access ())
{
std::cerr << warn (global->get_compiler ()->warn_enclosing_access (),
@@ -334,6 +334,19 @@
<< method->warn (global->get_compiler ()->warn_enclosing_access (),
"method is defined here");
}
+ if (method->constructor_p ())
+ {
+ // Constructors are handled by adding extra 'boolean'
+ // arguments.
+ int extra = (accessor->get_parameter_count ()
+ - method->get_parameter_count ());
+ // It is ok to share substructure here.
+ ref_expression narg = new model_boolean_literal (get_location (),
+ true);
+ narg->resolve (scope);
+ for (int i = 0; i < extra; ++i)
+ arguments.push_back (narg);
+ }
}
method->propagate_throws (scope);
@@ -578,7 +591,7 @@
model_constructor *curr_cons
= assert_cast<model_constructor *> (scope->get_current_method ());
- if (curr->inner_p ())
+ if (curr->inner_p () && ! curr->static_context_p ())
{
// We need to also pass the 'this$0' parameter to the other
// constructor.
Index: model/method.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/model/Attic/method.hh,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 method.hh
--- model/method.hh 13 Feb 2005 03:46:45 -0000 1.1.2.2
+++ model/method.hh 12 Mar 2005 20:41:54 -0000
@@ -198,6 +198,11 @@
return parameters;
}
+ int get_parameter_count () const
+ {
+ return parameters.size ();
+ }
+
void set_type_parameters (const std::list<ref_type_variable> &ts)
{
type_parameters.set_type_parameters (ts);