2012-06-22 7 views
21

Muchos métodos en el BCL están marcados con el atributo [MethodImpl(MethodImplOptions.InternalCall)]. Esto indicates que el "método se implementa dentro del tiempo de ejecución de lenguaje común".¿Cuál es el punto de MethodImplOptions.InternalCall?

¿Cuál era el sentido de diseñar el marco de esta manera sobre tener instrucciones CIL explícitas especificadas que el tiempo de ejecución estaría forzado a implementar? En última instancia, el atributo crea obligaciones contractuales para el tiempo de ejecución, pero de una manera que me parece confusa y no inmediatamente obvia.

Por ejemplo, Math.Pow podría haber sido escrita esta manera (excusa mi mezcla informal de C# + IL y el propio si es malo IL; esto es sólo una muestra de explicar mi punto):

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

en lugar de la forma actual:

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

¿Por qué existe MethodImplOptions.InternalCall?

+6

No es que eso no funcione, simplemente aumenta horriblemente. Las transacciones de la pila están implícitas para los códigos de operación IL, muchas herramientas tendrían que actualizarse para tratar con las firmas de función. Es gratis cuando la declaración está en los metadatos. Y fácilmente extensible más allá del estándar Ecma-335. –

+0

@Hans: ¿se trataba de agregar compatibilidad con las nuevas instrucciones de IL? Entendí que Ani quería saber por qué los métodos 'InternalCall' estaban ahí en primer lugar. Solo preguntando ... –

+1

@thecoon - '// Instrucción CIL dedicada' es una buena pista. –

Respuesta

7

Creo que una razón importante es que es bastante difícil crear una nueva instrucción IL y podría afectar a muchas herramientas, incluidas las externas (ILGenerator, ilasm, ildasm, PEVerify, Reflector, PostSharp, ...).

¿Pero creando un nuevo método InternalCall? Eso es casi tan simple como escribir el método en C# (supongo que no miré a Rotor para verificarlo) y no afecta nada.

Y no se trata solo de crearlo, creo que lo mismo se aplica al mantenimiento.

+0

Disculpa, publiqué un comentario pero respondiste correctamente, +1. –

+0

@svick: suficiente. ¿Cómo explicarías que Math.Pow esté presente desde la primera versión de .NET? ¿Sería entonces el motivo de Hans el no querer complicar demasiado el estándar ECMA? – Ani

+0

@Ani Todavía significaría más trabajo para la mayoría de las personas que hacen algo con IL. El hecho de que ese trabajo debería incluirse en las primeras versiones de las herramientas no cambia mucho. – svick

3

Creo que no fue para complicar demasiado el CLR. Cuando analicé por primera vez CIL, no pude evitar advertir las similitudes con un lenguaje ensamblador, y más que eso, las instrucciones limitadas establecidas, casi como si hubieran llegado a ejecutarse directamente en un procesador.

En teoría, cuando el JIT CLR ese código de muestra para Pow que incluyó en su publicación, debería emitirse el código nativo para la instrucción pow, ya que no hay instrucciones nativas (¿o no? actualizado con los nuevos juegos de instrucciones x86 desde hace algunos años). Desde el punto de vista del rendimiento, pero también desde el punto de vista de la implementación, es mucho más fácil simplemente llamar a mscorlib para el código pow, que simplemente "pegar" en línea.

O bien, podrían haber tenido una tabla de búsqueda para funciones comunes de mscorlib que son InternalCall y sustituir la instrucción con una llamada a la función en sí. Pero, de nuevo, no todos los InternalCall son tan fáciles como eso.

Creo que fue una compensación por conveniencia; ambos de su lado, para el mantenimiento de CLR, un estándar de CLI más uniforme y para permitir cierta flexibilidad a quienes llaman.

La conclusión es que no he desarrollado el CLR y esto está fuera de mi cabeza. Algo que hubiera hecho, supongo.

1

El método es nativo, VERDADERO nativo, implementado en el tiempo de ejecución en sí. No olvides que, después de todo, CLR proviene de C++. Es como en el compilador. En el mundo real, CIL no se ejecuta realmente. Está JIT-ted y luego se ejecuta, como un compilador, por un tiempo de ejecución de C/C++. Math.Pow probablemente sea [especulación] una llamada al método nativo C/C++ math.h pow, y está definido por la implementación, ahora NET y Mono implementan el CLR.

En UnityEngine.dll, [MethodImpl(MethodImplOptions.InternalCall)] se usa en la mayoría de los métodos externos nativos. Sin embargo, estos métodos de C++ utilizan directamente la biblioteca CLR de Mono C++ y pueden cooperar con C# de una manera mucho más íntima que P/INVOKE. Y mucho más rendimiento (PInvoke oculta algunos detalles de implementación y hace que algunos sean difíciles de entender)

Sin embargo, la única forma de usar [MethodImpl(MethodImplOptions.InternalCall)] es si usted es el tiempo de ejecución de CLR en sí; sin embargo, solo probé Mono así. No sé si es posible alterar la implementación de CLR de Microsoft, pero con Mono es libre de abusar de esta característica.

Además, no ensucie esto con [MethodImpl(MethodImplOptions.Unmanaged)] - es una historia completamente diferente.

Más sobre las llamadas internas y cómo funciona Mono, aquí: http://www.mono-project.com/docs/advanced/embedding/

Negación: no estoy relacionado a la Unidad o Mono!