This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[gcjx] Patch: FYI: enhanced for and boxing
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 11 Sep 2005 19:33:07 -0600
- Subject: [gcjx] Patch: FYI: enhanced for and boxing
- Reply-to: tromey at redhat dot com
I'm checking this in on the gcjx branch.
This updates the enhanced 'for' code to handle automatic boxing and
unboxing as needed.
Tom
Index: ChangeLog
from Tom Tromey <tromey@redhat.com>
* model/forenhanced.hh (model_for_enhanced::elt_type): New field.
(model_for_enhanced): Initialize it.
(model_for_enhanced::get_element_type): New method.
* bytecode/generate.hh
(bytecode_generator::emit_cast_maybe_boxing): Declare.
* bytecode/generate.cc (emit_cast_maybe_boxing): New method.
(visit_cast): Use it.
(visit_for_enhanced): Likewise.
* model/forenhanced.cc (resolve): Removed error for primitive
type; do assignment conversion in both cases.
(find_method): New function.
Index: bytecode/generate.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/bytecode/Attic/generate.cc,v
retrieving revision 1.1.2.19
diff -u -r1.1.2.19 generate.cc
--- bytecode/generate.cc 12 Jul 2005 17:34:59 -0000 1.1.2.19
+++ bytecode/generate.cc 12 Sep 2005 01:34:38 -0000
@@ -684,7 +684,11 @@
increase_stack (container->type ()->element_type ());
// If needed, emit a cast to the iteration variable type.
- emit_cast (var->type (), container->type ()->element_type ());
+ {
+ push_expr_target push (this, ON_STACK);
+ emit_cast_maybe_boxing (fstmt, var->type (),
+ container->type ()->element_type ());
+ }
emit_store (var->type (), user_var);
target_map[fstmt] = std::make_pair (update, done);
@@ -718,6 +722,7 @@
model_method *has_next_meth
= find_method ("hasNext", iterator_type, NULL,
primitive_boolean_type, fstmt);
+ // FIXME: wrong for generics?
model_method *next_meth
= find_method ("next", iterator_type, NULL, object_type,
fstmt);
@@ -759,9 +764,11 @@
increase_stack (object_type);
// Cast to the user's type.
- // FIXME: this doesn't work for unboxing. In that case we
- // must first cast to the iterator's element type.
- emit_cast (var->type (), object_type);
+ {
+ push_expr_target push (this, ON_STACK);
+ emit_cast_maybe_boxing (fstmt, var->type (),
+ fstmt->get_element_type ());
+ }
emit_store (var->type (), user_var);
body->visit (this);
@@ -2214,21 +2221,11 @@
}
void
-bytecode_generator::visit_cast (model_cast *cast_expr,
- const ref_forwarding_type &dest,
- const ref_expression &expr)
+bytecode_generator::emit_cast_maybe_boxing (model_element *request,
+ model_type *dest_type,
+ model_type *expr_type)
{
- assert (expr_target == ON_STACK || expr_target == STRING
- || expr_target == CONDITIONAL || expr_target == IGNORE);
- {
- push_expr_target push (this, (expr_target == CONDITIONAL
- ? CONDITIONAL
- : ON_STACK));
- expr->visit (this);
- }
-
- model_type *dest_type = dest->type ();
- if (dest_type->primitive_p () != expr->type ()->primitive_p ())
+ if (dest_type->primitive_p () != expr_type->primitive_p ())
{
if (dest_type->primitive_p ())
{
@@ -2237,26 +2234,23 @@
// get_pretty_name here is a bit of an abuse. Note that
// Character doesn't have all the methods from Number, so we
// need a special case here.
- std::string method_name;
- bool is_char = false;
model_type *tmp_dest_type = dest_type;
- if (expr->type () == global->get_compiler ()->java_lang_Character ())
- {
- is_char = true;
- method_name = "charValue";
- tmp_dest_type = primitive_char_type;
- }
- else
- method_name = dest_type->get_pretty_name () + "Value";
+ if (expr_type == global->get_compiler ()->java_lang_Character ())
+ tmp_dest_type = primitive_char_type;
+ std::string method_name = (tmp_dest_type->get_pretty_name ()
+ + "Value");
model_method *call
= find_method (method_name.c_str (),
- assert_cast<model_class *> (expr->type ()),
- NULL, tmp_dest_type, cast_expr);
+ assert_cast<model_class *> (expr_type),
+ NULL, tmp_dest_type, request);
std::list<ref_expression> args;
handle_invocation (op_invokevirtual, call->get_declaring_class (),
call, args);
- if (is_char)
- emit_cast (dest_type, primitive_char_type);
+ if (tmp_dest_type != dest_type)
+ {
+ assert (tmp_dest_type == primitive_char_type);
+ emit_cast (dest_type, primitive_char_type);
+ }
}
else
{
@@ -2265,21 +2259,21 @@
// conversion.
model_class *dest_class = assert_cast<model_class *> (dest_type);
model_method *call = find_method ("valueOf", dest_class,
- expr->type (), dest_class,
- cast_expr);
+ expr_type, dest_class,
+ request);
// We do pass an argument, but sneakily: we pushed it up
// above.
std::list<ref_expression> args;
handle_invocation (op_invokestatic, dest_class, call, args);
// We have to pop this ourselves due to lying to
// handle_invocation.
- reduce_stack (expr->type ());
+ reduce_stack (expr_type);
}
}
else
{
- class_writer::check_type (cast_expr, dest_type);
- emit_cast (dest_type, expr->type ());
+ class_writer::check_type (request, dest_type);
+ emit_cast (dest_type, expr_type);
if (expr_target == IGNORE)
{
// This can only happen when accessing a static member with
@@ -2291,6 +2285,23 @@
}
void
+bytecode_generator::visit_cast (model_cast *cast_expr,
+ const ref_forwarding_type &dest,
+ const ref_expression &expr)
+{
+ assert (expr_target == ON_STACK || expr_target == STRING
+ || expr_target == CONDITIONAL || expr_target == IGNORE);
+ {
+ push_expr_target push (this, (expr_target == CONDITIONAL
+ ? CONDITIONAL
+ : ON_STACK));
+ expr->visit (this);
+ }
+
+ emit_cast_maybe_boxing (cast_expr, dest->type (), expr->type ());
+}
+
+void
bytecode_generator::visit_class_ref (model_class_ref *ref,
const ref_forwarding_type &req)
{
Index: bytecode/generate.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/bytecode/Attic/generate.hh,v
retrieving revision 1.1.2.8
diff -u -r1.1.2.8 generate.hh
--- bytecode/generate.hh 11 Jul 2005 16:41:48 -0000 1.1.2.8
+++ bytecode/generate.hh 12 Sep 2005 01:34:38 -0000
@@ -280,6 +280,7 @@
const ref_expression &);
void emit_cast (model_type *, model_type *);
+ void emit_cast_maybe_boxing (model_element *, model_type *, model_type *);
void handle_comparison (java_opcode,
const ref_expression &,
Index: model/forenhanced.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/model/Attic/forenhanced.cc,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 forenhanced.cc
--- model/forenhanced.cc 13 Jan 2005 03:18:36 -0000 1.1.2.1
+++ model/forenhanced.cc 12 Sep 2005 01:34:38 -0000
@@ -1,6 +1,6 @@
// Enhanced for loop.
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -21,6 +21,37 @@
#include "typedefs.hh"
+// A helper function to find a no-argument method in a class.
+// Issues error and returns null if no match or ambiguous match.
+static model_method *
+find_method (resolution_scope *scope, model_element *where, model_class *klass,
+ const std::string &name)
+{
+ std::set<model_method *> methods;
+ klass->find_members (name, methods, scope->get_current_class (), klass);
+ if (methods.empty ())
+ {
+ std::cerr << where->error ("couldn't find method %1 for type %2")
+ % name % klass;
+ return NULL;
+ }
+
+ model_method *candidate = NULL;
+ for (std::set<model_method *>::const_iterator i = methods.begin ();
+ i != methods.end ();
+ ++i)
+ {
+ if ((*i)->get_parameter_count () == 0)
+ {
+ if (candidate != NULL)
+ abort (); // FIXME
+ candidate = *i;
+ }
+ }
+ if (! candidate) abort (); // FIXME
+ return candidate;
+}
+
void
model_for_enhanced::resolve (resolution_scope *scope)
{
@@ -35,14 +66,7 @@
// Ok. We pull this out so we don't try to load Iterable unless
// really necessary. This is a little strange but it does let
// users iterate over arrays even with an older class library.
-
- if (! assignment_conversion (variable->type (),
- expression->type ()->element_type ()))
- std::cerr << expression->error ("%<for%> expression of type %1"
- " is not assignment compatible with"
- " variable of type %2")
- % expression->type ()->element_type ()
- % variable->type ();
+ elt_type = expression->type ()->element_type ();
}
else
{
@@ -54,13 +78,38 @@
" implement %<java.lang.Iterable%>")
% expression->type ();
- if (! variable->type ()->reference_p ())
- std::cerr << variable->error ("%<for%> variable has primitive type");
-
- // FIXME: generics: if expression has parameterized type, the
- // variable must be compatible with the parameter.
+ // Find the type of the iterator. This is fairly roundabout --
+ // we find the 'iterator' method, then look at its return type
+ // for the 'next' method. This seems robust, if lengthy.
+ model_class *expr_class
+ = assert_cast<model_class *> (expression->type ());
+ model_method *iterator = find_method (scope, expression.get (),
+ expr_class, "iterator");
+ if (iterator)
+ {
+ model_type *rtype = iterator->get_return_type ();
+ if (! rtype->reference_p ())
+ {
+ // FIXME
+ abort ();
+ }
+ model_class *rclass = assert_cast<model_class *> (rtype);
+ model_method *next = find_method (scope, expression.get (),
+ rclass, "next");
+ if (next)
+ elt_type = next->get_return_type ();
+ }
}
+ // If ELT_TYPE is NULL, we have already issued an error.
+ if (elt_type != NULL
+ && ! assignment_conversion (variable->type (), elt_type))
+ std::cerr << expression->error ("%<for%> expression of type %1"
+ " is not assignment compatible with"
+ " variable of type %2")
+ % elt_type
+ % variable->type ();
+
scope->add_binding (variable.get ());
body->resolve (scope);
}
Index: model/forenhanced.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/model/Attic/forenhanced.hh,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 forenhanced.hh
--- model/forenhanced.hh 13 Jan 2005 03:18:36 -0000 1.1.2.1
+++ model/forenhanced.hh 12 Sep 2005 01:34:38 -0000
@@ -1,6 +1,6 @@
// The enhanced for statement.
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -30,6 +30,9 @@
// Variable declaration.
ref_variable_decl variable;
+ // Type of the elements of the collection.
+ model_type *elt_type;
+
public:
model_for_enhanced (const location &w,
@@ -37,7 +40,8 @@
const ref_expression &e)
: model_for_base (w),
expression (e),
- variable (v)
+ variable (v),
+ elt_type (NULL)
{
}
@@ -46,6 +50,11 @@
void compute_normal_completion (normal_completion_state &);
void visit (visitor *v);
+
+ model_type *get_element_type () const
+ {
+ return elt_type;
+ }
};
#endif // GCJX_MODEL_FORENHANCED_HH