Agus IL Code in the Eye of Runtime

Iseng-iseng abis baca blog dari om Agus (http://geeks.netindonesia.net/blogs/agus/archive/2006/11/20/_2300_1_3A00_Computing-is-Fun.aspx)

 

[TENTANG RECURSIVE]

Btw, nggak ada yg recursive dari kode itu walaupun baris pertama ngomonging recursive :)

 

Ah, now that you are part of the elite computer science group, read open once again your Discrete Maths book. A recursive function would have a base case, soalnya dari teori Proof-by-Induction. So this is recursive:

  static int Sigma(int index)

  {

    if (index == 0) // base case

       return 0;

    else

       return index + Sigma(--index);

  }

 

 

[PRINSIP RUNTIME STACK]

Anyway, karena aku dikasih tahu Ridi tentang posting ini sambil ngajarin bikin Interpreter dan pas ngomongin Runtime Stack, I thought I might disassemble the IL produced by Pak Agus's program. Here it is... hold tight, it's a long read :)

 

Ini IL yg dihasilkan oleh Perform(int32& index)

dengan menggunakan "csc.exe agus.cs /debug- /optimize+"

(matikan kode debugging, dan jalankan optimizer)

 

Setelah itu, gunakan ILDASM.EXE untuk dumping kode IL-nya:

 

    .maxstack  3

    .locals init (int32 V_0)

    IL_0000:  ldarg.0

    IL_0001:  dup

    IL_0002:  ldind.i4

    IL_0003:  ldc.i4.1

    IL_0004:  add

    IL_0005:  dup

    IL_0006:  stloc.0

    IL_0007:  stind.i4

    IL_0008:  ldloc.0

    IL_0009:  ret

 

IL_0000: Stack after ldarg.0 dgn index = 0

 

|________| [2]

|________| [1]

| &index | [0]

 

Kenapa saya gambar stack dari 0 sampai 2? Karena di kode IL untuk Perform tertulis ".maxstack  3"

 

 

IL_0001: Stack after dup

|________| [2]

| &index | [1]

| &index | [0]

 

Karena dup akan menduplikasi top of stack

 

 

IL_0002: Stack after ldind.i4

|________| [2]

|    0   | [1]

| &index | [0]

 

Karena ldind akan mengambil isi top of stack dan mem-push nilainya ke stack lagi

 

 

IL_0003: Stack after ldc.i4.1

|    1   | [2]

|    0   | [1]

| &index | [0]

 

Karena ldc.i4.1 akan mem-push 1 ke stack

 

 

IL_0004: Stack after add

|________| [2]

|    1   | [1]

| &index | [0]

 

Karena add akan mem-pop 2x dari stack, menambahkan dua value tadi, dan mem-push 1x.

 

 

IL_0005: Stack after dup

|    1   | [2]

|    1   | [1]

| &index | [0]

 

 

IL_0006: Stack after stloc.0

|________| [2]

|    1   | [1]

| &index | [0]

 

dengan V_0 = 1

Karena stloc.0 akan mem-pop stack dan menaruhnya ke V_0

 

 

IL_0007: Stack after stind.i4

|________| [2]

|________| [1]

|________| [0]

 

dengan V_0 = 1 dan index = 1

Karena stind akan:

   - pop pertama

   - taruh nilai yg di-pop ke variabel dgn address yg di pop kedua kali.

 

 

IL_0008: Stack after ldloc.0

|________| [2]

|________| [1]

|   1    | [0]

 

dengan V_0 = 1

Karena ldloc.0 akan mempush isi V_0 ke stack.

 

 

IL_0009: Stack after ret

|________| [2]

|________| [1]

|________| [0]

 

karena methodnya return int, maka 1 akan dikembalikan ke runtime stack caller (runtime stack method Main, lihat kode di bawah).

 

 

Dan ini IL yg dihasilkan untuk Main

 

    .entrypoint

    .maxstack  2

    .locals init (int32 V_0,

            int32 V_1)

    IL_0000:  ldc.i4.0

    IL_0001:  stloc.0

    IL_0002:  br.s       IL_0026

 

    IL_0004:  ldstr      "nilai = "

    IL_0009:  ldloca.s   V_0

    IL_000b:  call       int32 Program::Perform(int32&)

    IL_0010:  stloc.1

    IL_0011:  ldloca.s   V_1

    IL_0013:  call       instance string [mscorlib]System.Int32::ToString()

    IL_0018:  call       string [mscorlib]System.String::Concat(string,

                                                                string)

    IL_001d:  call       void [mscorlib]System.Console::WriteLine(string)

    IL_0022:  ldloc.0

    IL_0023:  ldc.i4.1

    IL_0024:  add

    IL_0025:  stloc.0

    IL_0026:  ldloc.0

    IL_0027:  ldc.i4.s   10

    IL_0029:  blt.s      IL_0004

 

    IL_002b:  call       string [mscorlib]System.Console::ReadLine()

    IL_0030:  pop

    IL_0031:  ret

 

 

IL_0000: Stack setelah ldc.i4.0

|___| [1]

| 0 | [0]

 

Ingat, size stack = 2 dan ldc.i4.0 akan mem-push integer 0 (nol) ke stack

 

 

IL_0001: Stack setelah stloc.0

|___| [1]

|___| [0]

 

dengan V_0 = 0.

Karena stloc.0 akan mem-pop dan menaruh value-nya ke V_0

 

 

IL_0002: Stack setelah br.s IL_0026

Sama seperti sebelumnya, sekarang kita lompat ke kode 0026

 

 

IL_0026: Stack setelah ldloc.0

|___| [1]

| 0 | [0]

 

Karena ldloc.0 akan menaruh isi V_0 ke stack

 

 

IL_0027: Stack setelah ldc.i4.s 10

| 10 | [1]

|  0 | [0]

 

Karena ldc.i4.s akan menaruh 10 ke stack

 

 

IL_0029: Stack setelah blt.s IL_0004

|___| [1]

|___| [0]

 

Ini akan branch ke IL_0004 karena 0 LessThan 10

 

 

IL_0004: Stack setelah ldstr "nilai = "

| "nilai = " | [1]

|____________| [0]

 

 

IL_0009: Stack setelah ldloca.s V_0

|    &V_0    | [1]

| "nilai = " | [0]

 

dimana &V_0 = address of V_0

 

 

IL_000b: Stack setelah  call int32 Program::Perform(int32&)

|    1       | [1]

| "nilai = " | [0]

 

Karena Perform akan dipanggil dengan menggunakan top-of-stack sebagai argumen

Lihat penjelasan IL sebelumnya, dimana Perform(0) akan mengembalikan 1.

 

 

IL_0010: Stack setelah  stloc.1

|____________| [1]

| "nilai = " | [0]

 

dengan V_1 = 1

Karena stloc.1 akan mem-pop stack dan menaruh isinya ke V_1

 

 

IL_0011:  Stack setelah ldloca.s   V_1

|    &V_1    | [1]

| "nilai = " | [0]

 

 

IL_0013: Stack setelah call instance string [mscorlib]System.Int32::ToString()

|    "1"    | [1]

| "nilai = " | [0]

 

 

IL_0018: Stack setelah call string [mscorlib]System.String::Concat(string,string)

|_____________| [1]

| "nilai = 1" | [0]

 

IL_001d: Stack setelah call void [mscorlib]System.Console::WriteLine(string)

|_____________| [1]

|_____________| [0]

 

Akan ada output "nilai = 1"

 

 

IL_0022: Stack setelah ldloc.0

|___| [1]

| 0 | [0]

 

Karena ldloc.0 akan menaruh isi V_0 ke stack

 

IL_0023: Stack setelah ldc.i4.1

| 1 | [1]

| 0 | [0]

 

Karena ldc.i4.1 akan mem-push angka 1.

 

 

IL_0024: Stack setelah add

|___| [1]

| 1 | [0]

 

Karena add akan mem-pop 2x, dan mem-push hasil 0+1

 

 

IL_0025: Stack setelah stloc.0

|___| [1]

|___| [0]

 

dengan V_0 = 1

Karena stloc.0 akan mem-pop dan menaruh value ke V_0

 

 

IL_0026: Stack setelah ldloc.0

|___| [1]

| 1 | [0]

 

 

IL_0027: Stack setelah ldc.i4.s 10

| 10 | [1]

|  1 | [0]

 

 

IL_0029: Stack setelah blt.s IL_0004

|___| [1]

|___| [0]

 

Ini akan branch ke IL_0004 karena 1 LessThan 10

 

 

Dan seterusnya... baca lagi pembahasan kode IL_0004 sampai dapet 10 NOT LessThan 10 :)

 

 

[MEMBACA UNTUK MENCARI KODE YG EFISIEN]

Yang menarik adalah implementasi output string + int.

 

Kode ini 1)

Console.WriteLine("nilai = " + i.ToString());

 

akan menghasilkan IL:

  IL_0008:  ldstr      "nilai = "

  IL_000d:  ldloca.s   V_0

  IL_000f:  call       instance string [mscorlib]System.Int32::ToString()

  IL_0014:  call       string [mscorlib]System.String::Concat(string,

                                                              string)

  IL_0019:  call       void [mscorlib]System.Console::WriteLine(string)

 

Disini ada 2x stack access + 3x call method

Apakah String::Concat menghasilkan overhead yg signifikan? Itu perlu di-test dgn stop-watch...

 

 

Sedangkan kode berikut 2)

Console.WriteLine("nilai = {0}", i);

 

akan menghasilkan IL:

  IL_001e:  ldstr      "nilai = {0}"

  IL_0023:  ldloc.0

  IL_0024:  box        [mscorlib]System.Int32

  IL_0029:  call       void [mscorlib]System.Console::WriteLine(string,

                                                                object)

Disini ada 3x stack access + 1x call method

Tapi disini ada operasi boxing, yg mana sebuah object baru di-create, kemudian nilai integer akan dibungkus ke dalam object tadi. Dan tanpa di-test pun, kita sudah tahu bahwa boxing menghasilkan overhead yg signifikan. Kalo nggak, ngapain ada Generics di .Net 2.0 donk....

 

 

Sedangkan kode berikut 3)

Console.Write("nilai = ");

Console.WriteLine(i);

 

akan menghasilkan IL:

  IL_002e:  ldstr      "nilai = "

  IL_0033:  call       void [mscorlib]System.Console::Write(string)

  IL_0038:  ldloc.0

  IL_0039:  call       void [mscorlib]System.Console::WriteLine(int32)

 

Disini ada 2x stack access + 2x call method.

 

So silakan hitung-hitung kode mana yang paling efisien :)

 

 

[MEMBACA KODE IL]

Kalo udah ngerti Prinsip Runtime Stack diatas, kagak usah ngapalin syntax MSIL atuh... download aja CIL Instruction Set dari spesifikasi Ecma (http://www.ecma-international.org/publications/standards/Ecma-335.htm). Ada di Partition 3 koq...

 

 

[UNDERSTANDING COMPILER INTERNALS]

Btw, dalam workshop saya, "Building PascalIndo Interpreter with Visual C++", kita juga membuat intermediate code(.icd) untuk bahasa pemrograman PascalIndo (Pascal dgn syntax bahasa Indonesia) dan .icd ini bisa di-load dan dijalankan oleh executor(interpreter) dengan menggunakan Runtime Stack. Jadi, .icd mirip .Net assembly atau Java .class, dan Runtime Stack nya mirip Evaluation Stack .Net dan Java. Mudah-mudahan ilmu yang mereka dapat dari membuat runtime stack bisa membuat mereka lebih mengerti kode berbasis stack seperti MSIL, Java ByteCode, bahkan Assembly.

 

Alas, minggu ini adalah minggu terakhir Roadshow "Bikin Bahasa Pemrograman Sendiri". Kalau menurut saya, mahasiswa kita masih kewalahan (tidak banyak yang mengerti C++, sehingga di hari pertama harus ada C++ 101 Refresher), dan juga mungkin materi terlalu "plain" (tidak semua kuat mengetik kode, mungkin kebiasaan drag-n-drop hehe). Jadi, untuk membuat semangat dan meng-highlight relevansi, saya harus mengkaitkannya dengan aplikasi yg ada dan bisa dijual (misal untuk membuat scripting engine game, membuat HTML-tidy, membuat file compressor, dsb).

 

But my guts says, if this is the level of our S1 students, then in general (and I'll say it again, IN GENERAL), our S1 students need more catching up-to-do with Indian, Chinese, and eve Singaporean(NUS) students.

 

On the other side, are the recent S2 students (Norman and Agus) interested in a 3-part series (Interpreter, Debugger, Compiler) Workshop di kampusnya? Hehe, jangan mau kalah sama mahasiswa-mahasiswa S2 Magister TI UGM yang udah duluan donk Stick out tongue

 

 

NB: Koq susah ya nyari warnet broadband di Jogja... tadi dapet luambat banget, pas balik ke hotel, eh malah dikasih bocoran SSID hidden network + passwordnya. Pancen Oye nih hotel Smile

Share this post: | | | |
Published Monday, November 20, 2006 5:00 PM by zeddy

Comments

# re: Agus IL Code in the Eye of Runtime

Tuesday, November 21, 2006 6:33 AM by alex

Om Z,

Boleh nih, ntar ilmu tentang compilernya dibawa ke TF-UAJY :-)

# re: Agus IL Code in the Eye of Runtime

Tuesday, November 21, 2006 9:16 AM by Agus Kurniawan

it's a great job, zed....btw, ada planning ke bogor gak ? kalau ada di prepare nih;)

# re: Agus IL Code in the Eye of Runtime

Tuesday, November 21, 2006 9:47 AM by dondy

Comment gw kok ilang ?

# re: Agus IL Code in the Eye of Runtime

Tuesday, November 21, 2006 10:43 AM by zeddy

Don, posting yg jam 11 keapus, salah pencet :)

Jadi gue re-posting jam 01.00 pagi...

Makanya jangan naruh comment sebelum RTM...

# re: Agus IL Code in the Eye of Runtime

Tuesday, November 21, 2006 1:07 PM by Erick Kurniawan

wah bagus zed penjelasan IL-nya, bisa buat bahan matkul kompiler nich..., kapan2 klo ke UKDW bawain topik ini aja zed :)

# re: Agus IL Code in the Eye of Runtime

Tuesday, November 21, 2006 2:23 PM by zeddy

Ini comment nya Dondy yg sempat "hilang". Untung tiap comment dikirim ke email:

---

Author: dondy

Status: Published

Spam Score: 0

Sumprit.. gw baca ini serius banget hahahah.. gila lu z.. masa lu bahas ampe detail gini hahahaa

---

# re: Agus IL Code in the Eye of Runtime

Tuesday, November 21, 2006 7:13 PM by MCA
Zeddy "Knuth" Iskandar huahahahehheheh bikin gw nggak napsu ambil gradute CS, mending information system ajah :D

# re: Agus IL Code in the Eye of Runtime

Wednesday, November 22, 2006 12:49 PM by Risman Adnan Mattotorang

Zeddy's posting remind me to one topic in memory management, Stack Free Recursion. In .NET (stack based virtual machine), Stack free recursion is impossible. But you can do that in C++. Take a look at this article:

http://www.olympus.net/personal/7seas/recurse.html

Leave a Comment

(required) 
(required) 
(optional)
(required) 

Enter the numbers above:
Powered by Community Server (Commercial Edition), by Telligent Systems