• Advertisement
Sign in to follow this  

J2ME, dead code not removed

This topic is 4209 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi again everyone. I've been using a 'debug' class with a static final boolean so i can switch between outputting debug data (simple println) and not. The problem is that when I set the debug boolean to false it seems as though code that shold be removed, since the boolean is false and the code can never be reached, is not removed. Heres some code to explain a little better.
public class Debug {
	public static final boolean ON = false;
}

and in my main code I try 'switching' by doing this:
if (Debug.ON) {
    System.out.println("The code is still here!");
}

Ok thats fairly standard stuff as far as I'm aware, but the code that should be removed remains after compilation and obfuscation using Proguard. On a related note, in an attempt to figure this out myself (if nobody has the answer) how do I use the 'argument' nested element in the WTKObfuscate task in Antenna? I would like to use the arguments -printusage and/or -whyareyoukeeping to try to get more information about what Proguard is doing while shrinking/obfuscating. Thanks for reading!

Share this post


Link to post
Share on other sites
Advertisement
This won't work, unfortunately. I'm not sure why, but it'd save us a lot of work, indeed.

Your only option is probably using a source code preprocessor.


Here's how you use arguments in wtkobfusacte:

<wtkobfuscate jarfile="${deploydir}/${jar-name}"
jadfile="${deploydir}/${jad-name}"
bootclasspath="${bootclasspath}">
<argument value="-defaultpackage de.mef -ignorewarnings" />
<argument value="-dontobfuscate" />
</wtkobfuscate>


Share this post


Link to post
Share on other sites
Quote:
Original post by Thygrrr
This won't work, unfortunately. I'm not sure why, but it'd save us a lot of work, indeed.

Your only option is probably using a source code preprocessor.



Thats rather strange. Although I have no reason to doubt what you say, since you are a trusted and respected (maybe even famous?) member of the community, I really hope that you've got this one wrong! :P

But i fear that once again, you are correct. :(

I've been told to do it that way (by people who are supposed to know better than me) so that the debug code would be switchable and removable at compile time.
Another thing they told me is that I'm not allowed to use any preprocessing, so that leaves me between a rock and a hard place. *sigh*

Thanks for the info on using the arguments, although now I probably won't need them for the reason i was intending to use them for (to find out what was going wrong). But it will probably come in handy some point down the line!

Thanks once again!

Share this post


Link to post
Share on other sites
never had such problems - used the same code as you did, all the code in if (DEBUG) branches dissapeared after obfuscation if DEBUG was false. actually, it's easy to test: just search the obfuscated classes for "The code is still here!" string [wink] if it didnt dissapeared, it's possible that you send -dontoptimize to the proguard.

Share this post


Link to post
Share on other sites
Ah, darnit... i forgot something. The wtkbuild task sometimes omits Compiler side optimization. I do think that what you initially posted counts as a "dead code block".

I have never been able to reliably remove those, though; but admittedly, I never tried really hard.


You may need to activate optimization for the compiler; and deactivate debug info. I'm also a little doubtful whether this is what needs to happen or not; but for example, the following is legal:


if (true) return;
doSomething();





while the following is illegal:


return;
doSomething();






So basically what I'm saying is that Java needs to make some kind of distinction there at compile time.

Share this post


Link to post
Share on other sites
I checked your example by putting the class Debug containing the flag and a class Main containing the println() into a package debug.

Compilation with eclipse java compiler 3.1 and sun jdk 1.4 removed the dead code. A disassembly with javac confirmed that:

$ javap -c debug/Main
Compiled from "Main.java"
public class debug.Main extends java.lang.Object{
public debug.Main();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

void foo();
Code:
0: return

}


Share this post


Link to post
Share on other sites
Ok, that helps a lot, nmi! (rating++ :)

Then it probably means that wtkbuild doesn't optimize (I think I remember it didn't).

However, we now use the javac task here and our own packaging, so probably that's why dead code blocks never came up again as a topic - they were silently optimized away and we had no incentive to look for them.


Could you do me a favor, nmi? Compile the classes with source compatibility 1.2 or lower, and class file compatibility Java 1.1 ... this is what's used for J2ME.

Share this post


Link to post
Share on other sites
you may "force" the wtkbuild task to do optimization using optimize="on" (which is, actually, a parameter of javac). by default, optimization is off in javac task.

Share this post


Link to post
Share on other sites
Hey guys,

I have to explain myself here, and perhaps even apologise.

First of all we suffered a power cut yesterday which was why I didnt reply earlier.

My 'problem' didn't actually exist, my Debug java file, with ON set to false, was being overwritten by a backup Debug file which was being copied during the build process, and yes you guessed it, On was set to true. So its all my fault guys, I'm sorry. :(

Hopefully this hasn't been a complete waste of everyones time, at least I learned to be more careful in future.

Thanks for all your efforts to help and I apologise once more!

Cheers

Share this post


Link to post
Share on other sites
Preprocessing really sucks, too. I'm trying to get away from it, but apparently, it's not completely possible unless you can live with code bloat.

Here is an example I compiled. In fact, I read that javac doesn't optimize, and Sun even documents it that way. nmi wasn't precisely right; it was just a lucky exception. For example, Switch statements won't work gracefully. In short, that means you will either end up with really long if/then/elseif/... statements, or you need to do without any kind of "sophisticated" configuration of your bytecode by means of final fields.


public class Config
{
public static final int VALUE1 = 0;
public static final int VALUE2 = 1;
public static final int VALUE3 = 2;


public static void test()
{
switch (VALUE1)
{
case VALUE2:
System.out.println("final int switch statement");
default:
System.out.println("nothing");
}
}
}






As you see, the switch statement remains entirely intact...




public class de.mef.auto.Config extends java.lang.Object{
public static final int VALUE1;

public static final int VALUE2;

public static final int VALUE3;

public de.mef.auto.Config();
Code:
0: aload_0
1: invokespecial #16; //Method java/lang/Object."<init>":()V
4: return

public static void test();
Code:
0: iconst_0
1: tableswitch{ //1 to 1
1: 20;
default: 28 }
20: getstatic #23; //Field java/lang/System.out:Ljava/io/PrintStream;
23: ldc #29; //String final int switch statement
25: invokevirtual #31; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: getstatic #23; //Field java/lang/System.out:Ljava/io/PrintStream;
31: ldc #37; //String nothing
33: invokevirtual #31; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
36: return

}








However, good news: Here's what jikes did:

public class de.mef.auto.Config extends java.lang.Object{
public static final int VALUE1;

public static final int VALUE2;

public static final int VALUE3;

public static void test();
Code:
0: getstatic #22; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #24; //String nothing
5: invokevirtual #30; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return

public de.mef.auto.Config();
Code:
0: aload_0
1: invokespecial #33; //Method java/lang/Object."<init>":()V
4: return

}


[Edited by - Thygrrr on August 11, 2006 9:06:20 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
In fact, I read that javac doesn't optimize


Java is a JIT language...it isn't fully compiled until runtime when it is compiled for the specific device in which it is running on.

Share this post


Link to post
Share on other sites
I know, and I also know that Java, at runtime, can perform breathtaking optimizations specifically adapted to the platform the VM is running on. Optimal register and cache usage determined at runtime, from observing program behaviour, for example. Object creation path is somewhere around 50 instructions in Java 1.6, which is totally awesome. Commonplace C++ heap managers require much more than that.

Still, I do believe that some moderate, trivial optimizations should be made at compile time.

Furthermore, please note that this is for mobile devices - Java VM 1.1, hardly any HI implementations out yet, etc. pp. These VMs mostly interpret the byte code rather dumbly.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement