C# .Net and Java


This article compares the same program written in the C# and Java languages and then compares the dissembled code of both languages.

Java Hello Program:


class Hello
{
	public static void main(String args[])
	{
	System.out.println("Hello");
	}
}

Disassembled Java Hello Program:


class Hello
{
	Hello()
	{
	// 0 0:aload_0
	// 1 1:invokespecial #1 <Method void Object()>
	// 2 4:return
	}

public static void main(String args[])
{
	System.out.println("Hello");
	// 0 0:getstatic #2 <Field PrintStream System.out>
	// 1 3:ldc1 #3 <String "Hello">
	// 2 5:invokevirtual #4 <Method void PrintStream.println(String)>
	// 3 8:return
	}
}

Explanation of Java program:

To understand this you must have some knowledge of computer internals concepts for eg. Opcodes, instruction templates etc. I assume that you already know them.

As usual this code will also start with main method. The first line tells that print ?Hello? it is a normal print statement. A specific instruction, with type information, is built by replacing the ?T? in the instruction template in the opcode column by the letter in the type column. In this case it is a load instruction for type reference.

Invokespecial instruction must name an instance initialization method, a method in the current class, or a method in a superclass of the current class. Class and interface initialization methods are invoked implicitly by the Java virtual machine; they are never invoked directly from any Java virtual machine instruction, but are invoked only indirectly as part of the class initialization process.

invokevirtual or invokespecial is used to access a protected method of a superclass, then the type of the class instance being accessed must be the same as or a subclass of the current class.

The Java virtual machine uses local variables to pass parameters on method invocation. On class method invocation any parameters are passed in consecutive local variables starting from local variable 0.

C# Hello Program:


using System; 

class Hello
{
	public static void Main(string[] args)
	{
		Console.WriteLine("Hello");
	}
}

Disassembled C# Hello Program :


.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr "Hello"
IL_0005: call void [mscorlib]System.Console::WriteLine(class System.String)
IL_000a: ret
} // end of method Hello::Main

Explanation of C# .Net Program:

The first line defines the Main method by using the .method MSIL keyword. Note that the method is defined as being public and static, which are the default modifiers for the Main method. Also note that this method is defined as managed.

The next line of code uses the MSIL .entrypoint keyword to designate this particular method as the entry point to the application. When the .NET runtime executes this application, this is where control will be passed to the program.

Next, look at the MSIL opcodes on lines IL_0000 and IL_0005. The first uses the the ldstr (Load String) opcode to load a hard-coded literal (“Hello”) onto the stack.

The next line of code calls the System.Console.WriteLine method. Notice that the MSIL prefixes the method name with the name of the assembly that defines the method. This line also tells us the number of arguments (and their types) that are expected by the method. Here, the method will expect a System.String object to be on the stack when it’s called. Finally, line IL_000a is a simple ret MSIL opcode to return from the method.