쓰다말음


위의 경우처럼 함수의 인자를 줄이기 위해서 람다식을 사용하는 경우가 있다.
c++의 std::bind 같은 메소드가 제공되면 편하겠지만, C#은 그러한 메소드를 제공하지는 않는다. 정상적인 코드라면 그러한 메소드를 사용하는것보다 람다함수의 캡쳐를 쓰는게 훨씬 낫기 때문에.

하지만 런타임에 위 코드처럼 어떤 메소드의 인자를 줄이고 싶은 상황에서는 상당히 불편하다.

따라하기 위해서는 먼저 C# 컴파일러가 람다와 캡처를 어떻게 처리하는지를 알아야 할 필요가 있다. (보고 배끼기 위해서)


위와같은 코드를 디컴파일하면 아래와같은 IL 코드가 생성된다.

주목할 점은 캡처를 클래스 필드를 이용해서 수행한다는 점인데, 코드중 string message 부분이다.
실제 람다 본문인 b__0 에서는 ldfld를 이용해 필드에 접근한다.


이를 Emit 으로 따라한 코드


caller side

callee side





'C# > MSIL' 카테고리의 다른 글

[MSIL] 람다식의 캡쳐 구현하기  (0) 2016.09.01
CLR에서 돌아가는 언어를 뭔가를 만들어 보면서  (1) 2015.11.17
[MSIL] 런타임 property 구현하기  (1) 2015.11.05
[MSIL] beforefieldinit  (1) 2015.11.02
[MSIL] for loop  (1) 2015.11.02
Posted by pjc0247
TAG C#, MSIL

https://github.com/pjc0247/ILIL

얼마 전에 ILIL이라는 이름으로, CLR환경에서 돌아가고 CIL로 컴파일되는 언어를 만들어보고자 하는 프로젝트를 진행했었다(개인적으로). 이번 프로젝트의 제작 의의는, 단순히 컴파일러 그 자체를 만들어보고, 결과물을 CIL로 출력해서, C# 또는 C++에서 콜해보는게 목적이었고, 어느 정도 작성한후에는 코드도 같이 Github에 공개할 예정이었다. (깃허브에 올려도 바다-나무님밖에 안보긴함)

그리고 최종적으로는 완성된 ILIL 컴파일러를 이용해 아래 코드와 같이 Reflection.Emit을 대체할 물건을 만드려고 했다.


대충 쉐이더 언어들처럼 돌아가는데, 런타임에 컴파일되고, 런타임에 바인딩된다. 기존 C#에서 런타임 메소드를 만드려면 Emit을 이용해서 바이트코드를 한땀한땀 작성하던것을 런타임 컴파일러가 돌아서 스크립트를 바이트코드로 대신 만들어주는것이다. 


어쨌든, 프로젝트는 하다가 접었는데, 요런 언어적인 물건은 처음 만들어보는거라 초창기부터 굉장히 이상한 구조로 작성하게 되었고, 언어 스펙을 구현하면서 굉장히 많은 예외케이스를 만났는데, 베이스 구조가 굉장히 이상하다보니 이러한 예외들을 깔끔하게 처리하지 못하고 코드가 완전히 엉켜버렸다. 
총체적 경험 부족이었고, 몇번 더 엎고, 처음부터 다시 하다보면 좀더 깔끔하게 만들 수 있을 것 같다는 생각이 든다. 
( 지금은 ILIL 프로젝트와는 별도로 Roslyn을 이용하여 Reflection.Emit을 대체하는 물건을 만드는데 성공했다. 사실 Roslyn이 워낙 사기라 내가 한건 없고, 그냥 사소한 코드만 몇줄 작성했다. )


이 프로젝트를 진행하면서 느낀 점은, CLR/CLI를 선택한것은 굉장히 멋진 선택이었다는 것인데, CLR/CLI 기반으로 언어를 작성하면 공짜로 얻을 수 있는것이 굉장히 많다. 요즘 어디선가 몇번씩 이름이 들려오는 scala, clojure등의 언어도 동일한 원리로 JVM에서 돌아가는 언어라고 한다.

아래는 이번 프로젝트를 진행해보면서 느낀, 중간 언어와/중간 언어로 컴파일되는 언어를 만들었을때의 장점이라고 생각되는 부분들이다. 


* VM

공짜로 VM이 제공된다, 이는 언어를 구현함에 있어서 VM 부분에는 신경쓰지 않고 순수하게 언어 그 자체 구현에 집중할 수 있음을 뜻한다. 

* 이미 설계된 instruction set

이런걸 만듬에 있어서 instruction set 설계부터 시작하는것이 또다른 재미요소일수도 있겠지만, 나같은경우는 그렇지 않다고 생각했고, 그냥 이미 다 만들어서 풀스펙 문서까지 작성되어 있는 CIL 명령어들을 가져다 썼다, 이는 엄청난 시간 절약이 되었다고 생각한다.

CIL Insruction set spec 문서

( 나는 위에 문서는 안보고 MSDN쪽에 C# API 문서를 보면서 만들었다. )

* 퍼포먼스

직접 만들어서 재보진 않았지만, MS의 절대고수님들이 만든 검증된 VM과 내가 조잡하게 만든 VM이 속도면에서 비교가 되지 않을 거라고 확신한다. 게다가 이렇게 만들면 CLR 버전이 올라감에 따라 공짜로 속도 업그레이드도 받을 수 있다.

* stdlib

새로 만드는 언어에서 stdlib로 .Net을 그대로 가져다 사용할 수 있다. 개인적으로는 C++, Ruby, Python의 stdlib가 아무리 날뛰어봤자 그 위에 군림하는게 .Net이라고 생각하는데, 과연 내가 아무리 언어를 만들고 나서 stdlib도 신경써서 만든다 해도 이거보다 잘 만들 수 있을까?

* 활용성 (호환성)

이렇게 빌드된 프로그램들은 곧바로 기존 C#, VB, Managed C++들과 호환된다.

기존에 진행중인 C# 프로젝트에 자신이 새로 만든 언어로 모듈을 만들어 붙이는것, 혹은 그 반대의 일이 가능하다는 것이다. 이건 좀 멋지다.

* 멀티 플랫폼

Mono!

사실 난 멀티 플랫폼에 별 관심이 없다. 이부분은 잘 모르겠다.

* 가비지 콜렉터

공짜로 가비지 컬렉터가 제공된다, 가비지 컬렉터를 직접 만들 필요도, 가비지 컬렉팅을 위한 내부적인 추가 코드를 생성할 일(ARC 처럼)도 없다. 

* 객체 지향

객체 지향 역시 공짜로 제공된다, CIL은 객체지향을 염두에 두고 만들어진 중간언어이다. 만약 x86 어셈블리등으로 출력되는 프로그램을 만든다고 하면, 객체지향 지원을 위해서 언어 레벨에서의 처리 이외에, 어셈블리를 빌드할때도 추가적인 처리가 필요할것이다. 

'C# > MSIL' 카테고리의 다른 글

[MSIL] 람다식의 캡쳐 구현하기  (0) 2016.09.01
CLR에서 돌아가는 언어를 뭔가를 만들어 보면서  (1) 2015.11.17
[MSIL] 런타임 property 구현하기  (1) 2015.11.05
[MSIL] beforefieldinit  (1) 2015.11.02
[MSIL] for loop  (1) 2015.11.02
Posted by pjc0247


1. '_propertyName' 이름을 가지는 backing field를 만든다. ( C# 컴파일러가 만들어내는 실제 backing field 이름은 이것과 다르다 )

2. 'get_propertyName' 이름을 가지는 getter 메소드를 만든다. 메소드가 MethodAttributes.SpecialName 속성을 가지는것을 기억하자.

3. 'set_propertyName' 이름을 가지는 setter 메소드를 만든다. setter는 1개의 파라미터를 가진다. (value)



'C# > MSIL' 카테고리의 다른 글

[MSIL] 람다식의 캡쳐 구현하기  (0) 2016.09.01
CLR에서 돌아가는 언어를 뭔가를 만들어 보면서  (1) 2015.11.17
[MSIL] 런타임 property 구현하기  (1) 2015.11.05
[MSIL] beforefieldinit  (1) 2015.11.02
[MSIL] for loop  (1) 2015.11.02
Posted by pjc0247
TAG EMIT

[MSIL] beforefieldinit

C#/MSIL 2015.11.02 23:20

beforefieldinit는 타입이 초기화(정적 생성자, cctor)되는 시점을 슈퍼-레이지하게 만들어준다.

슈퍼 레이지하다는것은, 스태틱 메소드중에 필드에 접근하지 않는 애는 호출이 되어도 초기화를 스킵한다는 뜻이다.

위 코드에서 PrintHello는 그냥 HelloWorld만 출력한다.
반면에 PrintHelloWithField는 HelloWorld를 찍은 뒤, 굳이 필드에 일부러 접근하는 동작을 가진다.
마지막으로 정적 생성자가 호출되는 시점을 알 수 있도록 CCTOR라는 메세지를 출력하도록 했다.



위의 코드를 실행하면 단순히 HelloWorld가 출력되는 모습을 볼 수 있는데, 이는 Foo 클래스는 beforefieldinit 속성을 가지고있기 때문에 PrintHello를 불러도 정적 생성자가 호출되지 않기 때문이다.

PrintHello를 호출하는 부분을 PrintHelloWithField로 변경하면 HelloWorld가 출력되기 전에 타입이 초기화되어 CCTOR가 먼저 출력되는것을 볼 수 있다.


Foo 클래스에서 beforefieldinit 빼고 빌드하여 테스트해보면, 슈퍼-레이지 초기화는 없기 때문에 PrintHello를 부르던 PrintHelloWithField를 부르던 타입이 사용되면 무조건 초기화된다.

'C# > MSIL' 카테고리의 다른 글

[MSIL] 람다식의 캡쳐 구현하기  (0) 2016.09.01
CLR에서 돌아가는 언어를 뭔가를 만들어 보면서  (1) 2015.11.17
[MSIL] 런타임 property 구현하기  (1) 2015.11.05
[MSIL] beforefieldinit  (1) 2015.11.02
[MSIL] for loop  (1) 2015.11.02
Posted by pjc0247

[MSIL] for loop

C#/MSIL 2015.11.02 13:31


첫번째 인자로 넘어온 int 숫자만큼 반복하는 메소드

그냥 x86 어셈블리 지식을 더듬어 혼자 짠 코드라, 제대로된 C# 컴파일러가 빌드하는 코드와는 다를 수 있다.



'C# > MSIL' 카테고리의 다른 글

[MSIL] 람다식의 캡쳐 구현하기  (0) 2016.09.01
CLR에서 돌아가는 언어를 뭔가를 만들어 보면서  (1) 2015.11.17
[MSIL] 런타임 property 구현하기  (1) 2015.11.05
[MSIL] beforefieldinit  (1) 2015.11.02
[MSIL] for loop  (1) 2015.11.02
Posted by pjc0247