-fno-cast-check ?!
Norman Hendrich
hendrich@informatik.uni-hamburg.de
Tue Aug 6 03:41:00 GMT 2002
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.
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?
- Norman
---- 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).
---- brutal mutilation in libjava/java/lang/natClass.cc
void *
_Jv_CheckCast (jclass c, jobject obj)
{
// HACK: simulate -fno-check-cast: always return obj
//
// if (__builtin_expect
// (obj != NULL && ! _Jv_IsAssignableFrom(c, JV_CLASS (obj)), false))
// throw new java::lang::ClassCastException
// ((new java::lang::StringBuffer
// (obj->getClass()->getName()))->append
// (JvNewStringUTF(" cannot be cast to "))->append
// (c->getName())->toString());
return obj;
}
This is ugly, but was the easiest to do...
---- relative performance for my simulator benchmark
GIJ ev/sec= 26
JDK 1.1.8 green threads (interpreter) ev/sec= 101
GCJ (options *1) ev/sec= 950
GCJ (options *2) ev/sec= 1072
GCJ (options *3) ev/sec= 1140
GCJ (options *4 -fno-cast-check HACK) ev/sec= 1275
JDK 1.3.1 Hotspot client VM ev/sec= 1303
JDK 1.3.0 IBM cx130-20010626 ev/sec= 1338
JDK 1.4.0 Hotspot client VM ev/sec= 1457
JDK 1.4.0 Hotspot server VM (UNSTABLE) ev/sec= 1995
gcj options:
*1 -O2 -fno-bounds-check -fno-store-check
*2 -static -O3 -fno-bounds-check -fno-store-check
*3 -static -O3 -fno-bounds-check -fno-store-check
Also, "manually inlined" two frequently called methods.
This helps gcj, but the Hotspot numbers do not improve.
*4 As *3, but with the _Jv_CheckCast() hack.
---- 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?
More information about the Java
mailing list