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: String '+' and '+='


I'm checking this in on the gcjx branch.

Now we at least try to lower String '+' and '+=' operations.

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	* builtins.cc (lay_out_class): Resolve class members.
	* tree.hh (tree_generator::stringbuffer_append): Declare.
	(tree_generator::handle_string_plus): Likewise.
	(tree_generator::find_method): Likewise.
	(tree_generator::create_stringbuffer): Likewise.
	(tree_generator::finish_stringbuffer): Likewise.
	* tree.cc (stringbuffer_append): New method.
	(handle_string_plus): Likewise.
	(visit_arith_binary): Handle String '+'.
	(visit_op_assignment): Added assertion.
	(find_method): New method.
	(create_stringbuffer): Likewise.
	(finish_stringbuffer): Likewise.

Index: builtins.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/builtins.cc,v
retrieving revision 1.1.2.25
diff -u -r1.1.2.25 builtins.cc
--- builtins.cc 25 Mar 2005 01:56:32 -0000 1.1.2.25
+++ builtins.cc 27 Mar 2005 02:51:27 -0000
@@ -579,6 +579,9 @@
 
   tree klass_record = TREE_TYPE (klass_tree);
 
+  // The class itself must be resolved for layout to work.
+  klass->resolve_members ();
+
   // Lay out superclasses and interfaces.
   tree super_record = NULL_TREE;
   if (klass->get_superclass () != NULL)
Index: tree.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/tree.cc,v
retrieving revision 1.1.2.28
diff -u -r1.1.2.28 tree.cc
--- tree.cc 27 Mar 2005 02:50:27 -0000 1.1.2.28
+++ tree.cc 27 Mar 2005 02:51:27 -0000
@@ -1099,13 +1099,182 @@
   binary_operator (elt, BIT_XOR_EXPR, lhs, rhs);
 }
 
+// FIXME: this is copied from bytecode_generator.
+model_method *
+tree_generator::find_method (const char *mname, model_class *klass,
+			     model_type *argtype, model_type *result_type,
+			     model_element *request)
+{
+  std::set<model_method *> methods;
+  klass->find_members (mname, methods, method->get_declaring_class (), klass);
+  model_method *result = NULL;
+  for (std::set<model_method *>::const_iterator i = methods.begin ();
+       i != methods.end ();
+       ++i)
+    {
+      model_method *meth = *i;
+      std::list<ref_variable_decl> params = meth->get_parameters ();
+      int len = params.size ();
+      if (! argtype && len == 0)
+	{
+	  result = meth;
+	  break;
+	}
+      if (! argtype || len != 1)
+	continue;
+      ref_variable_decl var = params.front ();
+      if (var->type () == argtype)
+	{
+	  result = meth;
+	  break;
+	}
+    }
+
+  if (! result)
+    {
+      throw request->error ("couldn't find method %1 with argument of type "
+			    "%2 in class %3 -- perhaps you have the wrong "
+			    "class library?")
+	% mname % argtype % klass;
+    }
+
+  if (result->get_return_type () != result_type)
+    {
+      throw request->error ("method %1 doesn't have expected return type"
+			    " of %2")
+	% result % result_type;
+    }
+  return result;
+}
+
+void
+tree_generator::stringbuffer_append (model_expression *expr,
+				     tree &buffer_tree,
+				     model_class *sb_class,
+				     tree expr_override)
+{
+  if (! expr->type ()->primitive_p () && dynamic_cast<model_plus *> (expr))
+    {
+      assert (! expr_override);
+      // We have another String '+'.  So recurse, using the same
+      // StringBuffer.  Note that it is simpler to handle this
+      // recursion explicitly here than it is to do more bookkeeping
+      // so we can reuse visitor.
+      model_plus *plus = assert_cast<model_plus *> (expr);
+      handle_string_plus (plus, plus->get_lhs (), plus->get_rhs (),
+			  buffer_tree, sb_class);
+    }
+  else
+    {
+      // Generate code for the expression.
+      tree expr_tree;
+      if (expr_override)
+	expr_tree = expr_override;
+      else
+	{
+	  expr->visit (this);
+	  expr_tree = current;
+	}
+
+      // Maybe promote the expression -- StringBuffer doesn't have
+      // every possible overload.
+      model_type *expr_type = expr->type ();
+      if (expr_type == primitive_byte_type
+	  || expr_type == primitive_short_type)
+	{
+	  expr_type = primitive_int_type;
+	  expr_tree = convert (type_jint, expr_tree);
+	}
+      else if (! expr_type->primitive_p ()
+	       && expr_type != global->get_compiler ()->java_lang_String ())
+	{
+	  expr_type = global->get_compiler ()->java_lang_Object ();
+	  expr_tree = convert (type_object_ptr, expr_tree);
+	}
+
+      tree args = build_tree_list (NULL_TREE, expr_tree);
+
+      model_method *append = find_method ("append", sb_class, expr_type,
+					  sb_class, expr);
+      tree ap_tree = gcc_builtins->map_method_call (class_wrapper,
+						    buffer_tree, args,
+						    append, false);
+      buffer_tree = save_expr (ap_tree);
+    }
+}
+
+void
+tree_generator::handle_string_plus (model_plus *model,
+				    const ref_expression &lhs,
+				    const ref_expression &rhs,
+				    tree &buffer_tree,
+				    model_class *sb_class)
+{
+  stringbuffer_append (lhs.get (), buffer_tree, sb_class);
+  stringbuffer_append (rhs.get (), buffer_tree, sb_class);
+}
+
+tree
+tree_generator::create_stringbuffer (model_class **sb_class_r,
+				     model_element *model)
+{
+  // Our StringBuffer is unsynchronized, but unlike StringBuilder does
+  // not allocate any garbage.
+  model_class *sb_class
+    = global->get_compiler ()->gnu_gcj_runtime_StringBuffer ();
+  gcc_builtins->lay_out_class (sb_class);
+
+  // Create the StringBuffer.
+  // FIXME: could optimize ""+foo if we wanted ...
+  // 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);
+  buffer_tree = save_expr (buffer_tree);
+
+  *sb_class_r = sb_class;
+  return buffer_tree;
+}
+
+tree
+tree_generator::finish_stringbuffer (model_class *sb_class,
+				     tree buffer_tree,
+				     model_element *model)
+{
+  // At this point we have a big expression to create a StringBuffer
+  // and append all the contents.  So now we just convert it into a
+  // String.
+  model_method *tostring
+    = find_method ("toString", sb_class, NULL,
+		   global->get_compiler ()->java_lang_String (),
+		   model);
+  tree result = gcc_builtins->map_method_call (class_wrapper, buffer_tree,
+					       NULL_TREE, tostring, false);
+  TREE_SIDE_EFFECTS (result) = 1;
+  return result;
+}
+
 void
 tree_generator::visit_arith_binary (model_plus *model,
 				    const ref_expression &lhs,
 				    const ref_expression &rhs)
 {
-  //  FIXME: String '+'.
-  binary_operator (model, PLUS_EXPR, lhs, rhs);
+  if (model->type ()->primitive_p ())
+    {
+      binary_operator (model, PLUS_EXPR, lhs, rhs);
+      return;
+    }
+
+  // String '+'.
+  model_class *sb_class;
+  tree buffer_tree = create_stringbuffer (&sb_class, model);
+  handle_string_plus (model, lhs, rhs, buffer_tree, sb_class);
+  current = finish_stringbuffer (sb_class, buffer_tree, model);
+  TREE_SIDE_EFFECTS (current) = 1;
+  annotate (current, model);
 }
 
 tree
@@ -1364,7 +1533,32 @@
 				     const ref_expression &lhs,
 				     const ref_expression &rhs)
 {
-  handle_op_assignment (elt, PLUS_EXPR, lhs, rhs);
+  if (elt->type ()->primitive_p ())
+    {
+      handle_op_assignment (elt, PLUS_EXPR, lhs, rhs);
+      return;
+    }
+
+  // String '+='.
+  model_class *sb_class;
+  tree buffer_tree = create_stringbuffer (&sb_class, elt);
+
+  // Wrap the LHS in a SAVE_EXPR so we only evaluate it once.
+  lhs->visit (this);
+  tree lhs_tree = save_expr (current);
+
+  // Add the LHS and RHS to the StringBuffer.
+  stringbuffer_append (lhs.get (), buffer_tree, sb_class, lhs_tree);
+  stringbuffer_append (rhs.get (), buffer_tree, sb_class);
+
+  tree result = finish_stringbuffer (sb_class, buffer_tree, elt);
+
+  // Note that the LHS might not have String type.  So, we make sure
+  // to cast everything to the actual type.
+  current = build2 (MODIFY_EXPR, TREE_TYPE (lhs_tree), lhs_tree,
+		    convert (TREE_TYPE (lhs_tree), result));
+  TREE_SIDE_EFFECTS (current) = 1;
+  annotate (current, elt);
 }
 
 void
Index: tree.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/tree.hh,v
retrieving revision 1.1.2.8
diff -u -r1.1.2.8 tree.hh
--- tree.hh 27 Mar 2005 02:48:55 -0000 1.1.2.8
+++ tree.hh 27 Mar 2005 02:51:27 -0000
@@ -131,6 +131,15 @@
   tree build_array_reference (tree, tree, tree, bool = true);
   tree build_exception_object_ref (tree);
 
+  void stringbuffer_append (model_expression *, tree &, model_class *,
+			    tree = NULL_TREE);
+  void handle_string_plus (model_plus *, const ref_expression &,
+			   const ref_expression &, tree &, model_class *);
+  model_method *find_method (const char *, model_class *,
+			     model_type *, model_type *,
+			     model_element *);
+  tree create_stringbuffer (model_class **, model_element *);
+  tree finish_stringbuffer (model_class *, tree, model_element *);
 
   // This class also includes code to transform bytecode to trees.
   // This is kept in a separate file, lower.cc, because it makes the


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