[Andreas]

Hi all,

For starters: it's not really a pressing matter ATM, but it may become of relevance if we want to strive for a production-release. The matter is somewhat related to the distinction between developer- and user-directed logging.

It concerns the numerous log.debug() and log.trace() messages scattered around. Just recently, I was reminded of a little Java trick that emulates C's conditional compilation, which inspired me to pop this question here.

As you are most likely well aware, every log.debug() generates bytecode at compile-time, which leads to compiled classes being unnecessarily large for general usage. In Java, there exists this little trick to define a final debug() method:

final void debug(String msg) {
  if (DEBUG) {
    log.debug(msg);
  }
}

The DEBUG boolean constant being defined in a central, easily accessible place.

If subsequently, all log.debug() calls are replaced by mere debug(), and one sets DEBUG to false, then the result at compile-time is that:
- there is no bytecode generated for the debug() methods (empty body)

That is true.

- since the method is final, and it has an empty body, the compiler can optimize further and no bytecode will be generated for any call to it.

Not true for javac from jdk1.4.2. A call to the debug method is included in the byte code. Perhaps other compilers does it differently.

Meaning also: possible string literals in the message do not take up space in the internalized string-table, which in turn would be beneficial for eventual runtime-calls to String.intern() (smaller table => decreased lookup-time)

Also not true for 1.4.2.

public class x {
    public static final boolean DEBUG = false;

    public static void main(String[] args) throws Exception {
        new x();
    }

    public x() {
        int i = 55;
        debug("hello " + i + " world");
    }

    final void debug(String msg) {
        if (DEBUG) {
            System.out.println(msg);
        }
    }
}

Compiled from "x.java"
public class x extends java.lang.Object{
public static final boolean DEBUG;

public static void main(java.lang.String[]);
   throws java/lang/Exception
  Code:
   0:   new     #1; //class x
   3:   dup
   4:   invokespecial   #2; //Method "<init>":()V
   7:   pop
   8:   return

public x();
  Code:
   0:   aload_0
   1:   invokespecial   #3; //Method java/lang/Object."<init>":()V
   4:   bipush  55
   6:   istore_1
   7:   aload_0
   8:   new     #4; //class StringBuffer
   11:  dup
   12:  invokespecial   #5; //Method java/lang/StringBuffer."<init>":()V
   15:  ldc     #6; //String hello
17: invokevirtual #7; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
   20:  iload_1
21: invokevirtual #8; //Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;
   24:  ldc     #9; //String  world
26: invokevirtual #7; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 29: invokevirtual #10; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
   32:  invokevirtual   #11; //Method debug:(Ljava/lang/String;)V
   35:  return

final void debug(java.lang.String);
  Code:
   0:   return

}

All the string litterals and string concatination still exists in the byte code.

Perhaps the JIT will detect the empty method and avoid the string concatination, I have not tested that, but I doubt it.

regards,
finn

Reply via email to