Local variables as refs?

Oct 6, 2010 at 6:53 PM

Is there a reason for not support local variables as refs? I assume there is one, and it's me just not realizing it. This will not work, throwing an exception "System.ArgumentException: Variable 'ref intRef' uses unsupported type 'System.Int32'. Reference types are not supported for variables."

var intRef = System.Linq.Expressions.Expression.Parameter((typeof(int)).MakeByRefType(), "intRef");
System.Linq.Expressions.Expression.Block(new[] { intRef }, new[] { System.Linq.Expressions.Expression.Default(typeof(object)) });

Oct 6, 2010 at 7:45 PM

For ByRef variables to be useful, you’d need a way to assign to both the value and the reference. I had a proposal for ByRefAssign and ByRef variables, but we didn’t have a concrete use case for it, and thus couldn’t justify adding it. I’m curious what you’re thinking of using it for?

Depending on what you’re trying to do, you might be able to fake it by creating a lambda with ByRef parameter and invoking it in place with Expression.Invoke. That should cause the lambda body to be inlined, so you effectively get a new scope with a ByRef variable.

- John

Oct 6, 2010 at 8:55 PM

What I'm doing is related to how IronJS internally represents values. I know the default DLR usage is boxing everything as object, but this is pretty slow (especially boxing) when doing heavy math operations involving a lot of doubles/ints that needs to be boxed/unboxed. IronJS uses a tagged union (StructLayout.Explicit) to represent values instead which lets me read/write doubles/ints/bools without boxing them. This is faster then using boxing, even with the current overhead of copying the struct (which is 20 bytes, could not get it aligned at 16 because you can't overlay a reference type with a value type in a struct, I could make it 17 bytes just using 1 byte for the type tag but that seems worse then 20 bytes tbh.), it's however not fast enough to compete with V8/JM/IE9 so I'm trying to find a way to get around the copying of the struct.

I thought of the lambda "hack" but I have a feeling it's going to be even slower, will test it though.

Oct 6, 2010 at 9:42 PM

I'll be damned, doing an inline-lambda with byref parameters is ~35-40% faster than copying the struct to temp-parameters, I'm very glad I tried this, here's an example of what I'm doing (it's written with the F# DLR wrapper I've built, but it should be clear whats going on, the calls to the Dlr module is the generic DLR wrapper and the calls to the Expr. module is IronJS specific DLR stuff). This gave me a very nice performance boost, will have to explore it more over the weekend.

let left = Dlr.param "left" (typeof<Box>.MakeByRefType())
let right = Dlr.param "right" (typeof<Box>.MakeByRefType())
let store = Dlr.param "store" (typeof<Box>.MakeByRefType())
(Dlr.invoke
  (Dlr.lambdaAuto [left; right; store] (Dlr.blockSimple [
    (Dlr.ifElse
      (Dlr.and'
        (Expr.containsNumber left)
        (Expr.containsNumber right)
      )
      (Dlr.blockSimple [
        (Expr.assignBoxValue
          (store)
          (Dlr.add
            (Expr.unboxNumber left)
            (Expr.unboxNumber right)
          )
        )
      ])
      (Dlr.void') //placeholder for fallback if both are not numbers
    )
  ]))
  [getLeftValue(); getRightvalue(); getResultStoragE()]
)