This is the mail archive of the
java@gcc.gnu.org
mailing list for the Java project.
Re: -fno-cast-check ?!
- From: Bryce McKinlay <bryce at waitaki dot otago dot ac dot nz>
- To: Norman Hendrich <hendrich at informatik dot uni-hamburg dot de>
- Cc: java at gcc dot gnu dot org
- Date: Wed, 07 Aug 2002 01:01:51 +1200
- Subject: Re: -fno-cast-check ?!
- References: <200208061041.g76Afs4Z004693@rzdspc1.informatik.uni-hamburg.de>
Norman Hendrich wrote:
Hello,
with the ugly hack outlined below, I got my simulator to run
as fast under gcj as it does under Hotspot Client (even
without method inlining).
As it turned out, my code executes multiple type casts in the
inner loop. Unfortunately, the very simple class hierarchy
involved is somewhat of a "worst case" for _Jv_CheckCast.
Eliminating the cast check results in more than 10% speedup.
Cool, thats very interesting. FYI I have long had a plan to improve
GCJ's type checking. In many cases where GCJ currently always does a
_Jv_CheckCast there is enough compile time knowledge of the type to
replace it with a very simple inline check or even eliminate it
completely. I agree that the type checks are currently a big performance
sink for many applications, and its good to know that your tests confirm
this.
Many applications, including every application that uses
the Java Collections API, will execute frequent downcasts.
It might therefore be useful to add another "overclocker"
command line option to gcj,
gcj -fno-cast-check
that totally eliminates the type checking overhead for those
classes that are believed to be type-safe. What do you think?
Yes I agree ;-)
---- diagnosis: frequently called code sequence in my code
public class A { ... } // base class
public class AA extends A { ... } // direct subclass
public class App {
void innerLoop() {
Iterator iterator = collection.iterator();
while(!done) {
A tmp1 = (A) iterator.next(); // actually gets AA: slow
A tmp2 = (A) iterator.next(); // actually gets AA: slow
...
result = calculateResult( tmp1, tmp2, ... );
}
}
}
Unfortunately, the situation sketched above is a "worst case"
scenario for the current implementation of type cast checking
in libjava/java/lang/natClass.cc.
Each cast results in a call to _Jv_CheckCast(), which checks for
a non-null argument and then falls through to _Jv_isAssignableFrom().
This method includes a short-circuit test that checks whether
the target and source classes are the same. But here, they are
not (target=A vs. source=AA). This means that the full method is
traversed, until finally Per's constant time type checking trick
is executed:
// _Jv_isAssignableFrom()
...
else if (source->ancestors != NULL
&& target->ancestors != NULL
&& source->depth >= target->depth
&& source->ancestors[source->depth - target->depth] == target)
return true;
...
Question 2: Is the ordering of the different tests (for array,
object, interfaces, primitive types) in _Jv_CheckCast necessary?
Perhaps a little reordering would already speed up the frequent
case (here, unpacking things from collections).
There are a few subtle ordering dependencies in there. Its possible that
there is room for improvement, but we'd have to be careful not to break
something. The best solution is to make the compiler smarter because
many of those tests can be avoided with compile time knowledge. ie: we
know at compile time when we're casting to an interface, etc.
---- gcc/java/expr.c:
static void
expand_java_CHECKCAST (type)
tree type;
{
tree value = pop_value (ptr_type_node);
value = build (CALL_EXPR, promote_type (type),
build_address_of (soft_checkcast_node),
tree_cons (NULL_TREE, build_class_ref (type),
build_tree_list (NULL_TREE, value)),
NULL_TREE);
push_value (value);
}
Question 3: Is this the right place to substitute the tree
when trying to disable the type checks? How do I get a
"no operation" tree instead of the checkcast?
Just make it return a NOP_EXPR instead of the CALL_EXPR. See
build_java_arraystore_check for an example of a function which does
something similar.
regards
Bryce.