2012-06-22 22 views
21

Wiele metod w BCL jest oznaczonych atrybutem [MethodImpl(MethodImplOptions.InternalCall)]. Ten indicates, że "metoda jest zaimplementowana w samym środowisku wykonawczym języka wspólnego".Jaki jest sens MethodImplOptions.InternalCall?

Po co projektować tę platformę, mając określone instrukcje CIL, które będą musiały zostać uruchomione w środowisku wykonawczym? Ostatecznie atrybutem jest tworzenie zobowiązań umownych dla środowiska wykonawczego, ale w sposób, który wydaje mi się mylący i nie od razu oczywisty.

Na przykład Math.Pow mógł zostać napisany w ten sposób (usprawiedliwienia mój nieformalny mieszankę C# + IL, a sam, jeśli jest zły IL; to tylko próby, aby wyjaśnić mój punkt):

public static double Pow(double x, double y) 
{ 
    ldarg.0 
    ldarg.1 
    pow // Dedicated CIL instruction 
    ret 
} 

zamiast aktualnej:

[MethodImpl(MethodImplOptions.InternalCall)] 
public static double Pow(double x, double y); 

Dlaczego istnieje MethodImplOptions.InternalCall?

+6

To nie tak, że nie może działać, to po prostu strasznie się skaluje. Transakcje na stosach są niejawne dla opkodów IL, wiele narzędzi musiałoby zostać zaktualizowanych, aby radzić sobie z sygnaturami funkcji. Jest za darmo, gdy deklaracja znajduje się w metadanych. Łatwo rozszerzalny poza standard Ecma-335. –

+0

@Hans: było pytanie o dodanie teraz obsługi nowych instrukcji IL? Zrozumiałem, że Ani chciała wiedzieć, dlaczego metody "InternalCall" były na pierwszym miejscu. Po prostu prosząc ... –

+1

@teoon - '// Dedykowane instrukcje CIL' to dobra wskazówka. –

Odpowiedz

7

Myślę, że dużym powodem jest to, że tworzenie nowej instrukcji IL jest dość trudne i może wpłynąć na wiele narzędzi, w tym zewnętrznych (ILGenerator, ilasm, ildasm, PEVerify, Reflector, PostSharp, ...).

Ale tworzenie nowej metody InternalCall? To prawie tak proste, jak napisanie metody w języku C# (zakładam, nie patrzyłem na Rotor, aby to zweryfikować) i nie ma to wpływu na nic.

I nie chodzi tylko o tworzenie, myślę, że to samo dotyczy konserwacji.

+0

Przepraszamy, napisałem komentarz, ale odpowiedziałeś poprawnie, +1. –

+0

@svick: Wystarczająco fair. Jak byś wyjaśnił Math.Power będąc w pobliżu od pierwszej wersji .NET? Czy zatem powód, dla którego Hans nie chce zbytnio komplikować standardu ECMA? – Ani

+0

@Ani Wciąż oznaczałoby to więcej pracy dla wszystkich, którzy robią cokolwiek z IL. Fakt, że ta praca musiałaby przejść do pierwszych wersji narzędzi, nie zmienia się zbytnio. – svick

3

Myślę, że to nie było zbyt skomplikowane CLR. Kiedy po raz pierwszy przyjrzałem się CIL, nie mogłem nie zauważyć podobieństw z językiem asemblerowym, a także ograniczonego zestawu instrukcji, prawie tak, jakby uruchomiły go bezpośrednio na procesorze.

Teoretycznie, gdy JIT CLR ma ten przykładowy kod dla Pow, który zawarłeś w swoim wpisie, musiałby wydać własny kod dla instrukcji pow, ponieważ nie ma natywnej instrukcji (lub jest to? na bieżąco z nowymi zestawami instrukcji x86 od kilku lat wstecz). Patrząc z punktu widzenia wydajności, ale także z punktu widzenia implementacji, o wiele łatwiej jest po prostu wywołać mscorlib dla kodu pow, niż po prostu wkleić go w linii.

Lub, mogliby mieć tabelę odnośników dla wspólnych funkcji mscorlib, które są InternalCall i zastąpić instrukcję wywołaniem samej funkcji. Ale znowu nie wszystkie są tak proste.

Myślę, że był to kompromis dla wygody; zarówno po ich stronie, w celu utrzymania CLR, bardziej jednolitego standardu CLI i umożliwienia pewnej elastyczności dla dzwoniących.

Najważniejsze jest to, że nie opracowałem CLR i jest to tuż poza moją głową. Coś, co bym zrobił, tak myślę.

1

Metoda jest natywna, bardzo oryginalna, zaimplementowana w samym środowisku wykonawczym. Nie zapominaj, że CLR pochodzi z C++. To jest jak w kompilatorze. W prawdziwym świecie CIL nie jest naprawdę wykonany. Jest JIT-ted, a następnie wykonywany, jak kompilator, przez środowisko wykonawcze C/C++. Math.Pow to najprawdopodobniej [spekulacja] wywołanie do natywnej metody math.h pow C/C++, i to jest zdefiniowane przez implementację - teraz NET i Mono implementują CLR.

W UnityEngine.dll, [MethodImpl(MethodImplOptions.InternalCall)] jest używany na większości natywnych metod zewnętrznych. Te metody C++ wykorzystują jednak bibliotekę CLR Mono C++ bezpośrednio i mogą współpracować z C# w sposób bardziej intymny niż sam P/INVOKE. I o wiele bardziej wydajne (PInvoke ukrywa pewne szczegóły implementacji i sprawia, że ​​niektóre są trudne do zrozumienia). Jednak jedynym sposobem na użycie [MethodImpl(MethodImplOptions.InternalCall)] jest samo środowisko CLR - testowałem tylko Mono w ten sposób. Nie wiem, czy możliwa jest nawet zmiana implementacji CLR Microsoftu, ale z Mono możesz nadużywać tej funkcji.

Nie rób tego z [MethodImpl(MethodImplOptions.Unmanaged)] - to zupełnie inna historia.

Więcej informacji na temat połączeń wewnętrznych i jak Mono działa tutaj: http://www.mono-project.com/docs/advanced/embedding/

Oświadczenie: Nie jestem związany z Jedności lub mono!