Velocity's long reliance on toString to render references means that toString() is expected to be called on references. This leads to a) the assumption that slow toString() methods will be called anyway and b) adaptation of fluent interfaces to take advantage of this behavior. The latter is the primary reason why we check whether toString() returns null. There are tools out there which resort to such behaviors because they are providing an API for Velocity, not for Java and did not feel constrained by Java conventions. Prior to 1.6 such null-returning behaved as expected in general VTL, but behaved differently in #if calls. r686428 evened this out. Since consistent behavior is generally more important than performance, and it is assumed that toString() will be called on most references anyway, this seemed the appropriate choice.
For most people, 1.6 provided drastic improvements in performance. I'm sorry this was not the case for you. If you provide some examples of the slow spots for you, i can probably help you clean those up. For instance, if you were doing something like this:
#if( $largeHashMap ) $largeHashMap.foobar #end
It would slow down in 1.6, but you can circumvent the toString() in such a situation by doing:
#if( !$largeHashMap.isEmpty() ) ...
or if you are setting values, not just retrieving:
#if( $largeHashMap.size() > -1 ) ...
As to whether these toString() calls can be removed... they will not be removed in the 1.6 branch. Changing this back to the previous null handling in 1.7 could be done, but i am not yet convinced that the performance penalty is worse than the inconsistency of that behavior.
In the 2.x branch, i do hope to eventually change this. I hope to alter Velocity to prioritize getAsString() methods and only use toString() when necessary. Once that is in place, Velocity should again insist that toString() never return null and act accordingly. But i'm not sure when that will happen, i've been swamped with other work for months now, and the end is not yet in sight.