Thursday, February 16, 2012

Java Fun: When 128 != 128

I didn't discover this, but I did think it was fun to share:

public class JavaWTF {
  public static void main(String[] args) {
    System.out.println(isSame(127, 127));  // true
    System.out.println(isSame(128, 128));  // false
  }

  private static boolean isSame(Integer i1, Integer i2) {
    return i1 == i2;
  }
}

This is still true as of JDK 1.6. Why is this so? I took a look at the bytecode to see what's going on, and here's what we have:

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

public static void main(java.lang.String[]);
  Code:
   0: bipush  127
   2: istore_1
   3: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   6: new #3; //class java/lang/Integer
   9: dup
   10:  iload_1
   11:  invokespecial #4; //Method java/lang/Integer."<init>":(I)V
   14:  new #3; //class java/lang/Integer
   17:  dup
   18:  iload_1
   19:  invokespecial #4; //Method java/lang/Integer."<init>":(I)V
   22:  if_acmpne 29
   25:  iconst_1
   26:  goto  30
   29:  iconst_0
   30:  invokevirtual #5; //Method java/io/PrintStream.println:(Z)V
   33:  getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   36:  iload_1
   37:  invokestatic  #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   40:  iload_1
   41:  invokestatic  #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   44:  if_acmpne 51
   47:  iconst_1
   48:  goto  52
   51:  iconst_0
   52:  invokevirtual #5; //Method java/io/PrintStream.println:(Z)V
   55:  return
}

(Incidentally, you can get this output by running javap -c JavaWTF.)

So basically, Integer.valueOf is being called to do the Integer boxing. From the 1.6 JavaDocs, I see:

public static Integer valueOf(int i)

Returns a Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values.

So sometimes it returns cached values, and sometimes it doesn't. If this functions returns an Integer via new Integer all the time, then all == comparisons will fail. However, if it returns the same object for some invocations, we'll get the observed behavior.

At this point, I was stuck - I didn't know where to go to look at some real Java 6 source code, but I bet the Apache Harmony guys knew a thing or two about all the quirks of the Java platform, so I took a peak at their Integer.java class:

public static Integer valueOf(int i) {
    if (i < -128 || i > 127) {
        return new Integer(i);
    }
    return valueOfCache.CACHE [i+128];
}

static class valueOfCache {
    /**
     * <p>
     * A cache of instances used by {@link Integer#valueOf(int)} and auto-boxing.
     */
    static final Integer[] CACHE = new Integer[256];
   
    static {
        for(int i=-128; i<=127; i++) {
            CACHE[i+128] = new Integer(i);
        }
    }
}

Ha! So I guess "most frequently used" integers means any integer between -128 and 127 (not integers your program has used before). No wonder!

Wednesday, December 21, 2011

Goodbye wmii. Hello i3!

A colleague recently recommend i3 to me, and I thought it was a rather good idea considering the problems I've been having with wmii (weirdly complicated configuration syntax, and problems with AWT).

wmii


(Notice the dialog box is not rendered correctly on the bottom right)

i3



The Swing problems are fixed in the HEAD of wmii's development branch, but I didn't notice that before I already committed to i3 (which is quite similar to wmii, but is less complicated to configure).

In the Debian/Ubuntu repositories, the latest version of i3 is 3.e (I think), but due to the configuration changes between 3 and 4, there may be some confusion about how to set up a status bar. The way to do it is to use i3status with the bar configuration directive with a 4.x+ release. You'll have to grab both i3wm and i3status from their respective repos and build the packages yourself. On Squeeze, apply this patch to i3 version 4.1 to make sure it builds correctly:

diff -rupN a/debian/control b/debian/control
--- a/debian/control    2011-11-11 14:40:38.000000000 -0800
+++ b/debian/control    2012-03-12 17:26:12.809273870 -0700
@@ -3,7 +3,7 @@ Section: utils
 Priority: extra
 Maintainer: Michael Stapelberg <michael@stapelberg.de>
 DM-Upload-Allowed: yes   
-Build-Depends: debhelper (>= 7.0.50~), libx11-dev, libxcb-util0-dev (>= 0.3.8), libxcb-ke
ysyms1-dev, libxcb-xinerama0-dev (>= 1.1), libxcb-randr0-dev, libxcb-icccm4-dev, libxcurso
r-dev, asciidoc (>= 8.4.4), xmlto, docbook-xml, pkg-config, libev-dev, flex, bison, libyaj
l-dev, texlive-latex-base, texlive-latex-recommended, texlive-latex-extra, libpcre3-dev, l
ibstartup-notification0-dev (>= 0.10)
+Build-Depends: debhelper (>= 7.0.50~), libx11-dev, libxcb-aux0-dev, libxcb-atom1-dev, lib
xcb-keysyms1-dev, libxcb-xinerama0-dev (>= 1.1), libxcb-randr0-dev, libxcb-icccm1-dev, lib
xcursor-dev, asciidoc (>= 8.4.4), xmlto, docbook-xml, pkg-config, libev-dev, flex, bison,
libyajl-dev, texlive-latex-base, texlive-latex-recommended, texlive-latex-extra, libpcre3-
dev, libstartup-notification0-dev (>= 0.10)
 Standards-Version: 3.9.2
 Homepage: http://i3wm.org/

You can apply this patch and build with:

cd i3-4.1
patch -p0 < /path/to/i3.patch
dpkg-buildpackage -uc -us

One other thing to note is that the i3status bar will not display correctly if there any errors; you also won't get any notification of errors if the font you specify is not correct (or missing).

Here is the result of switching to i3:


You can find my i3 configuration here.

Sunday, September 18, 2011

Ditz bash completion

I just had an "Oh, so that's how you do it" moment. The boss likes ditz for issue management; but for a while, I've been agonizing about how to do bash completion in ditz. The answer is you have to source this file: /var/lib/gems/1.8/gems/ditz-0.5/contrib/completion/ditz.bash. Oh, so that's how you do it!

Thursday, July 28, 2011

Getting my Logitech headset to work in Debian

I'm on Debian Squeeze at work, and I don't have any external speakers, but I do want to use a USB headset for pair programming and meetings and such. Getting the headset to work with Skype actually pretty easy; you just do some clicky click GUI monkey business and you're set. But having sound play for Youtube and other video sites (you know, stuff to do when NOT in meeting or pair programming), is trickier than I thought.

Here's what I did. First figure out which number the headset is:

$ cat /proc/asound/cards
 0 [Headset        ]: USB-Audio - Logitech USB Headset
                      Logitech Logitech USB Headset at usb-0000:00:1d.1-1, full speed
 1 [Intel          ]: HDA-Intel - HDA Intel
                      HDA Intel at 0xfebdc000 irq 16
 2 [HDMI           ]: HDA-Intel - HDA ATI HDMI
                      HDA ATI HDMI at 0xfe9ec000 irq 17

Okay, so it's index 0. Then I made a new file called /etc/modprobe.d/sound and jammed this text in it:

options snd-usb-audio index=0

And then bingo bango bongo, there is sound in my Youtubes.

Sunday, May 8, 2011

Using adb to copy files from your android device over wireless

Actually, I don't know why this is so hard. I poked around in various forums and the android docs to deduce this process:

  1. Install android SDK.
  2. Run tools/android and install the platform tools.
  3. The adb tool will be under platform-tools/adb.
  4. Run the following as root: adb kill-server && adb start-server.
  5. Download the adb wireless app and click the big green button.
  6. Run adb connect xxx.xxx.xxx.xxx:5555, and put the IP of your android device in there (the adb wireless app will show you what it is).
  7. Push and pull stuff willy nilly! Here's a list of pertinent commands.
  8. Run adb disconnect and press the big red button.

The main commands you'll be interested in are:

adb shell ls / 
adb pull REMOTE LOCAL
adb push LOCAL REMOTE