#118 DupDown (dup_x1) in .NET

brian Sat 18 Nov 2006

This is how I'm thinking we should handle DupDown(dup_x1) in .NET. For this discussion my stack is left (bottom) to right (top).

Start: A B 
DupDown: B A B
Field Set: B  // pops top two, leaving result

Note I only use DupDown for setting an instance field when I need to leave the result on the stack. Since .NET has such lame stack manipulating opcodes I think we are pretty much forced to use an extra local variable. Although except in the postfix cases I could also just re-read the field pretty cleanly - it's "return x++" that causes problems since I'm returning the old field value.

I don't want to just always use a local variable because then Java has to take the performance hit. So to keep it efficient in Java I'm thinking that DupDown gets broken up into two opcodes: DupDownStore and DupDownLoad which give you the hooks to store/load from the local variable:

Start: A B
DupDownStore: A B  // B stored in local
FieldSet: empty    // pops top two
DupDownLoad: B     // load from local, leaving result

The Java code continues work like it does and just ignores the DupDownLoad since DupDownStore would be manipulating the stack directly.

I think that should solve the problem fairly elegantly. The key question is how to deal with the local variables cleanly, we definitely need to support a stack of multiple DupDowns for example "a += (b++)" where a and b are instance fields. I don't know enough about how the CLR works, can we get away with a generic set of locals simply typed as Obj? In that case I would simply tell you the depth of DupDowns and you could allocate them. Or do we really need to create a typed local? That would be a pain in the ass - although if the CLR verifier works like Java then I could just give you the type and you could emit a cast operation. But at that point DupDown is starting to look so complicated that maybe we ought to just use locals all the time. So you need to let me know how sophisticated we need to be with allocating the temporary locals.

brian Mon 20 Nov 2006

After sleeping on it, I figured that any DupDown solution would be so freaking complicated that I just needed to go back and use local variables all the time for both Java and .NET. So I updated the Fan compiler so that it uses a temporary local variable and never emits the DupDown opcode. The Java compiler continues to use DupDown, so I won't actually remove DupDown until we completely switch to the new compiler.

class Foo
{
  Int prefix() { return ++a }
  Int postfix() { return a++ }
  private Int a := 2
}

Now compiles into the following fcode:

sys::Int prefix() -> sys::Int [0x1000]
  [Local 1] $temp1 -> sys::Int
  [Code]
    0: LoadVar          0
    3: Dup
    4: LoadInstance     compiler_ExprTest00::Foo.a -> sys::Int
    7: CallVirtual      sys::Int.increment() -> sys::Int
   10: Dup
   11: StoreVar         1
   14: StoreInstance    compiler_ExprTest00::Foo.a -> sys::Int
   17: LoadVar          1
   20: ReturnObj

sys::Int postfix() -> sys::Int [0x1000]
  [Local 1] $temp1 -> sys::Int
  [Code]
    0: LoadVar          0
    3: Dup
    4: LoadInstance     compiler_ExprTest00::Foo.a -> sys::Int
    7: Dup
    8: StoreVar         1
   11: CallVirtual      sys::Int.increment() -> sys::Int
   14: StoreInstance    compiler_ExprTest00::Foo.a -> sys::Int
   17: LoadVar          1
   20: ReturnObj

Login or Signup to reply.