There's nothing wrong. The key to understanding what is happening is the need to fully understand how the static memory segment is managed, which is intimately tied to how variables are mapped to RAM locations by the assembler.
Recall that the assembler makes two passes through the code. The first pass identifies all of the code labels, which are mapped to memory locations in ROM. On the next pass, as identifiers are encountered they are first checked to see if they have already been mapped (either to ROM or to RAM). If they have not yet been mapped, then they are mapped to RAM locations starting with address 16. So they get mapped in the order they are first encountered.
Now consider what the VM translator does. When it sees a reference to a static memory location, it translates it to a unique variable name in the assembly language, so 'static 5' might become "Foo.static.5". These are inserted into the assembly in whatever order they are translated. When you have multiple files in a VM program, they are translated in no particular order into a single assembly code file.
The description in the text assumes that no static variables have been created before reaching that code snippet. The variable "static 5" is then mapped to RAM because it is the first static reference encountered, while "static 2" is mapped to RAM because it is the second one encountered. The key point that is being made is that the numerical value of the index in the static memory segment has no meaning -- it is just a way to create unique variable names for the assembler to map.
So in the code you ran in the translator, index 2 in the Foo class was the third distinct reference to static memory that was encountered by the assembler, while index 5 was the sixth.
Look at your Foo.vm file and you should find that static 5 is initially referenced, either in a push or a pop command, before static 2 is, and that between the initial references to each are two other initial static memory references.
I was thinking that you ran the VM Translator, but see that you were running the VM emulator (which is exactly what you stated originally, I just didn't pay close enough attention). I forget that the toolset doesn't even provide a VM Translator.
The VM emulator emulates the specified behaviors, but the implementations are not specified. The behavior is that each index (that is used) in the static memory segment for each class be accessible by all members of the class and that they hold the contents from one reference to the next, regardless of who is doing the referring. How that behavior comes about is up to the implementer.
It's actually quite hard for a VM emulator to match what the VM translator will produce because the idea behind a VM emulator is that it emulates VM commands, not the low-level code on a particular platform. The supplied VM emulator attempts to show hardware level information, which it really shouldn't. It should show the segments and the stacks and other VM-specified things only.
You can run very large programs in the VM emulator -- much larger ones than even the best VM Translator could fit into the available ROM.
As long as the VM Emulator maps foo static 5 to a distinct memory location that no other static reference is mapped to, the implementation is conforming. This particular VM Emulator maps them to RAM locations in the range 16 through 255, which is certainly allowed, but not required -- the VM language spec has no notion of all of these memory segments being physically located within the same overall memory space. In fact, it assumes that they are all separate and completely isolated from each other. I'd have to delve into the Java code to see how it is actually done, but it's quite possible that the emulator uses a hash table to map the static references to RAM locations.
When I was reading the paragraph in question, I wanted to make sure I understood it correctly. That's when I tried the VM Emulator to test my understanding. I was surprised that the results did not match the text!
Perhaps the emulator is a valid implementation as you suggest; I might have to think that through a little more.
Regardless, I'd expect the behavior of the emulator to match the text. The text describes the management of static variables as "somewhat devious" and indeed I had to read it a few times. Not being able to validate my understanding with the emulator was disappointing.
Having said that, kudos to you and all involved with the book and web site. Overall everything is very nicely done and I'm having a great time with it!
The distinction between behavior and implementation can be rather subtle and elusive, particular at first.
The text most definitely steers the reader toward a particular approach to implementing the specified behaviors. This is particularly true with regards to the software API that it presents.
But their own tools don't necessarily follow that same implementation path. In some cases, that's because the tool they provide simply isn't one of the tools they are asking you to write. The emulators are perfect cases in point. You are never asked to emulate the VM commands directly, but rather to write something that translates them into assembly language code snippets that implement the behaviors of those commands. The VM emulator simply doesn't take this approach, but rather implements the behavior of the VM commands in Java code. It certainly could do this by having an embedded translator and then running the translated code, but the resulting execution would be annoyingly slow.
The same is true with the CPU Emulator. It emulates the execution of the assembly instructions without simulating them on any particular hardware implementation. As a result, if you try to execute any of the forty-six C-type instructions that do not map to one of the eighteen specified ALU instructions, the CPU Emulator gives unexpected results because no effort was made to have it behave the same way as the usual hardware ALU implementation would behave. I found that annoying because some of those instructions are actually rather useful, so I had to write my own CPU Emulator in order to run programs that use them.
There are also some behaviors that the VM Emulator has that are designed to be helpful but that are not part of the specified behavior and also get in the way of using some implementation tricks. For instance, if you try to access memory outside of the Heap and Screen memory segments, the emulator throws an error. But the hardware wouldn't behave that way (though the hardware spec doesn't say that it can't behave that way, either).