RSS 2.0

Personal Info:

Joe Send mail to the author(s) leads the architecture of an experimental OS's developer platform, where he is also chief architect of its programming language. His current mission is to enable writing large-scale software that is reliable, secure, and scalable by-construction. Before this, Joe founded the Parallel Extensions to .NET project. He has been granted 19 patents, with 49 pending. When not working, Joe enjoys travelling with his wife, writing books, writing music, studying music theory & mathematics, and doing anything involving food & wine.

My books

My music

Disclaimer:
The content of this site are my own personal opinions and do not represent my employer's view in anyway.

© 2012, Joe Duffy

 
 Thursday, January 20, 2005

I'm ashamed.

Well, the good news is, Sencha compiles simple programs like this:

(let ((sq (lambda (x) (* x x)))
      (dbl (lambda (x y) (x (x y)))))
  (dbl sq 10))

Which demonstrates nothing but good old environment modification and free variable binding.

But it also compiles this:

(letrec ((fib (lambda (x)
             (if (<= x 1)
                1
                (+ (fib (- x 1)) (fib (- x 2)))))))
     (fib 12))

Which demonstrates, of course, recurisve let bindings. This isn't what I'm ashamed of.

What I am ashamed of is the nasty IL that gets generated from the latter.

First, the top-level execution:

.method public hidebysig static void  Main(string[] A_0) cil managed
{
  .entrypoint
  // Code size       69 (0x45)
  .maxstack  3
  IL_0000:  newobj     instance void __lambda0::.ctor()
  IL_0005:  dup
  IL_0006:  ldvirtftn  instance object __lambda0::Apply1(object)
  IL_000c:  newobj     instance void class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object>::.ctor(object,
                                                                                                                native int)
  IL_0011:  stsfld     class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object> Program::fib
  IL_0016:  ldsfld     class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object> Program::fib
  IL_001b:  dup
  IL_001c:  ldc.i4.1
  IL_001d:  call       void [SenchaRuntimeLibrary]Sencha.Runtime.RuntimeHelper::AssertCompatableFunctionType(object,
                                                                                                             int32)
  IL_0022:  castclass  class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object>
  IL_0027:  ldc.r8     12.
  IL_0030:  box        [mscorlib]System.Double
  IL_0035:  call       instance !0 class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object>::Invoke(!1)
  IL_003a:  call       string [SenchaRuntimeLibrary]Sencha.Runtime.RuntimeHelper::ToString(object)
  IL_003f:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0044:  ret
} // end of method Program::Main

Notice the obvious areas for optimization... For example, if I construct a new Func1`2 delegate right before I call it... well... do I really need all that crap about reloading and type checking? Likely not.

But it gets worse. Check out the actual fib function IL:

.method public hidebysig virtual instance object
        Apply1([in] object x) cil managed
{
  .override  method instance !0 class [SenchaRuntimeLibrary]Sencha.Runtime.'Closure1`2'<object,object>::Apply1(!1)
  // Code size       189 (0xbd)
  .maxstack  10
  .locals init ([0] object[] V_0,
           [1] object[] V_1,
           [2] object[] V_2)
  IL_0000:  ldarg.1
  IL_0001:  ldc.r8     1.
  IL_000a:  box        [mscorlib]System.Double
  IL_000f:  call       bool [SenchaRuntimeLibrary]Sencha.Runtime.StandardSchemeFunctions::op_LessThanOrEqual(object,
                                                                                                             object)
  IL_0014:  box        [mscorlib]System.Boolean
  IL_0019:  call       bool [SenchaRuntimeLibrary]Sencha.Runtime.StandardSchemeFunctions::IsTrue(object)
  IL_001e:  brfalse.s  IL_0033
  IL_0020:  ldc.r8     1.
  IL_0029:  box        [mscorlib]System.Double
  IL_002e:  br         IL_00bc
  IL_0033:  ldc.i4.1
  IL_0034:  newarr     [mscorlib]System.Object
  IL_0039:  stloc      V_0
  IL_003d:  nop
  IL_003e:  nop
  IL_003f:  ldsfld     class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object> Program::fib
  IL_0044:  dup
  IL_0045:  ldc.i4.1
  IL_0046:  call       void [SenchaRuntimeLibrary]Sencha.Runtime.RuntimeHelper::AssertCompatableFunctionType(object,
                                                                                                             int32)
  IL_004b:  castclass  class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object>
  IL_0050:  ldc.i4.1
  IL_0051:  newarr     [mscorlib]System.Object
  IL_0056:  stloc      V_1
  IL_005a:  nop
  IL_005b:  nop
  IL_005c:  ldarg.1
  IL_005d:  ldloc.1
  IL_005e:  ldc.i4.0
  IL_005f:  ldc.r8     1.
  IL_0068:  box        [mscorlib]System.Double
  IL_006d:  stelem.ref
  IL_006e:  ldloc.1
  IL_006f:  call       object [SenchaRuntimeLibrary]Sencha.Runtime.StandardSchemeFunctions::op_Sub(object,
                                                                                                   object[])
  IL_0074:  call       instance !0 class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object>::Invoke(!1)
  IL_0079:  ldloc.0
  IL_007a:  ldc.i4.0
  IL_007b:  ldsfld     class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object> Program::fib
  IL_0080:  dup
  IL_0081:  ldc.i4.1
  IL_0082:  call       void [SenchaRuntimeLibrary]Sencha.Runtime.RuntimeHelper::AssertCompatableFunctionType(object,
                                                                                                             int32)
  IL_0087:  castclass  class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object>
  IL_008c:  ldc.i4.1
  IL_008d:  newarr     [mscorlib]System.Object
  IL_0092:  stloc      V_2
  IL_0096:  nop
  IL_0097:  nop
  IL_0098:  ldarg.1
  IL_0099:  ldloc.2
  IL_009a:  ldc.i4.0
  IL_009b:  ldc.r8     2.
  IL_00a4:  box        [mscorlib]System.Double
  IL_00a9:  stelem.ref
  IL_00aa:  ldloc.2
  IL_00ab:  call       object [SenchaRuntimeLibrary]Sencha.Runtime.StandardSchemeFunctions::op_Sub(object,
                                                                                                   object[])
  IL_00b0:  call       instance !0 class [SenchaRuntimeLibrary]Sencha.Runtime.'Func1`2'<object,object>::Invoke(!1)
  IL_00b5:  stelem.ref
  IL_00b6:  ldloc.0
  IL_00b7:  call       object [SenchaRuntimeLibrary]Sencha.Runtime.StandardSchemeFunctions::op_Add(object,
                                                                                                   object[])
  IL_00bc:  ret
} // end of method __lambda0::Apply1

Ouch! You mean I have to generate verifiable code and optimize it?!? As each day passes, I respect commercial compiler teams a little more.

In case you're wondering, the roughly equivalent C# code would be:

using System;

class Program
{

  delegate double fibfunc(double x);
 
static fibfunc fib;

  static void Main()
  {
    fib = delegate (double x) {
      if (x <= 1)
        return 1;
      else
        return fib(x - 1) + fib(x - 2);
    };
    Console.WriteLine(fib(12));
  }

}

Believe me -- the IL generated is a bit nicer. :)

1/20/2005 12:10:47 AM (Pacific Standard Time, UTC-08:00)  #   
Tracked by:
"work from home jobs online" (work from home jobs online) [Trackback]
"online business" (online business) [Trackback]
"doxycycline" (doxycycline) [Trackback]

 

Recent Entries:

Search:

Browse by Date:
<January 2005>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
303112345

Browse by Category:

Notables: