[gcjx] Patch: FYI: constructor accessors

Tom Tromey tromey@redhat.com
Sun Mar 13 09:55:00 GMT 2005


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



More information about the Java-patches mailing list