This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[gcjx] Patch: FYI: String '+' and '+='
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 26 Mar 2005 19:53:41 -0700
- Subject: [gcjx] Patch: FYI: String '+' and '+='
- Reply-to: tromey at redhat dot com
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