public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Name == "EETypePtrOf"); Debug.Assert(target.Signature.Length == 0 && target.Signature.ReturnType == target.OwningType); Debug.Assert(target.Instantiation.Length == 1); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); TypeSystemContext context = target.Context; TypeDesc runtimeTypeHandleType = context.GetWellKnownType(WellKnownType.RuntimeTypeHandle); MethodDesc getValueInternalMethod = runtimeTypeHandleType.GetKnownMethod("GetValueInternal", null); MethodDesc eetypePtrCtorMethod = context.SystemModule .GetKnownType("System", "EETypePtr") .GetKnownMethod(".ctor", new MethodSignature(0, 0, context.GetWellKnownType(WellKnownType.Void), new TypeDesc[] { context.GetWellKnownType(WellKnownType.IntPtr) })); // The sequence of these instructions is important. JIT is able to optimize out // the LDTOKEN+GetValueInternal call into "load EEType pointer onto the evaluation stack". codeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(context.GetSignatureVariable(0, true))); codeStream.Emit(ILOpcode.call, emitter.NewToken(getValueInternalMethod)); codeStream.Emit(ILOpcode.newobj, emitter.NewToken(eetypePtrCtorMethod)); codeStream.Emit(ILOpcode.ret); return emitter.Link(target); }
public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Name == "Call"); Debug.Assert(target.Signature.Length > 0 && target.Signature[0] == target.Context.GetWellKnownType(WellKnownType.IntPtr)); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); // Load all the arguments except the first one (IntPtr address) for (int i = 1; i < target.Signature.Length; i++) { codeStream.EmitLdArg(i); } // now load IntPtr address codeStream.EmitLdArg(0); // Create a signature for the calli by copying the signature of the containing method // while skipping the first argument MethodSignature template = target.Signature; TypeDesc returnType = template.ReturnType; TypeDesc[] parameters = new TypeDesc[template.Length - 1]; for (int i = 1; i < template.Length; i++) { parameters[i - 1] = template[i]; } var signature = new MethodSignature(template.Flags, 0, returnType, parameters); codeStream.Emit(ILOpcode.calli, emitter.NewToken(signature)); codeStream.Emit(ILOpcode.ret); return emitter.Link(); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); MetadataType startup = Context.GetHelperType("StartupCodeHelpers"); // Initialize command line args string initArgsName = (Context.Target.OperatingSystem == TargetOS.Windows) ? "InitializeCommandLineArgsW" : "InitializeCommandLineArgs"; MethodDesc initArgs = startup.GetKnownMethod(initArgsName, null); codeStream.Emit(ILOpcode.ldarg_0); // argc codeStream.Emit(ILOpcode.ldarg_1); // argv codeStream.Emit(ILOpcode.call, emitter.NewToken(initArgs)); // Call program Main if (_mainMethod.Signature.Length > 0) { codeStream.Emit(ILOpcode.call, emitter.NewToken(startup.GetKnownMethod("GetMainMethodArguments", null))); } codeStream.Emit(ILOpcode.call, emitter.NewToken(_mainMethod)); if (_mainMethod.Signature.ReturnType.IsVoid) { codeStream.EmitLdc(0); } codeStream.Emit(ILOpcode.ret); return emitter.Link(this); }
public static MethodIL EmitIL(MethodDesc method) { ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); MethodDesc typeLoadExceptionHelper = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowTypeLoadException"); codeStream.EmitCallThrowHelper(emit, typeLoadExceptionHelper); return emit.Link(); }
private PInvokeMarshallingILEmitter(MethodDesc targetMethod) { Debug.Assert(targetMethod.IsPInvoke); Debug.Assert(RequiresMarshalling(targetMethod)); _targetMethod = targetMethod; _importMetadata = targetMethod.GetPInvokeMethodMetadata(); _emitter = null; _marshallingCodeStream = null; }
private static MethodIL EmitSizeOf(MethodDesc method) { Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 0); TypeSystemContext context = method.Context; ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.Emit(ILOpcode.sizeof_, emit.NewToken(context.GetSignatureVariable(0, method: true))); codeStream.Emit(ILOpcode.ret); return emit.Link(method); }
public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Name == "Call"); Debug.Assert(target.Signature.Length > 0 && target.Signature[0] == target.Context.GetWellKnownType(WellKnownType.IntPtr)); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); // Load all the arguments except the first one (IntPtr address) for (int i = 1; i < target.Signature.Length; i++) { codeStream.EmitLdArg(i); } // now load IntPtr address codeStream.EmitLdArg(0); // Create a signature for the calli by copying the signature of the containing method // while skipping the first argument MethodSignature template = target.Signature; TypeDesc returnType = template.ReturnType; TypeDesc[] parameters = new TypeDesc[template.Length - 1]; for (int i = 1; i < template.Length; i++) { parameters[i - 1] = template[i]; } var signature = new MethodSignature(template.Flags, 0, returnType, parameters); bool useTransformedCalli = true; if ((signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask) != 0) { // Fat function pointer only ever exist for managed targets. useTransformedCalli = false; } if (((MetadataType)target.OwningType).Name == "RawCalliHelper") { // RawCalliHelper doesn't need the transform. useTransformedCalli = false; } if (useTransformedCalli) EmitTransformedCalli(emitter, codeStream, signature); else codeStream.Emit(ILOpcode.calli, emitter.NewToken(signature)); codeStream.Emit(ILOpcode.ret); return emitter.Link(target); }
private PInvokeILEmitter(MethodDesc targetMethod) { Debug.Assert(targetMethod.IsPInvoke); _targetMethod = targetMethod; _context = _targetMethod.Context; _importMetadata = targetMethod.GetPInvokeMethodMetadata(); _emitter = null; _marshallingCodeStream = null; _returnValueMarshallingCodeStream = null; _unmarshallingCodestream = null; }
private ArrayMethodILEmitter(ArrayMethod method) { _method = method; ArrayType arrayType = (ArrayType)method.OwningType; _rank = arrayType.Rank; _elementType = arrayType.ElementType; _emitter = new ILEmitter(); // This helper field is needed to generate proper GC tracking. There is no direct way // to create interior pointer. _helperFieldToken = _emitter.NewToken(_method.Context.GetWellKnownType(WellKnownType.Object).GetField("m_pEEType")); }
/// <summary> /// Emits a call to a throw helper. Use this to emit calls to static parameterless methods that don't return. /// The advantage of using this extension method is that you don't have to deal with what code to emit after /// the call (e.g. do you need to make sure the stack is balanced?). /// </summary> public static void EmitCallThrowHelper(this ILCodeStream codeStream, ILEmitter emitter, MethodDesc method) { Debug.Assert(method.Signature.Length == 0 && method.Signature.IsStatic); // Emit a call followed by a branch to the call. // We are emitting this instead of emitting a tight loop that jumps to itself // so that the JIT doesn't generate extra GC checks within the loop. ILCodeLabel label = emitter.NewCodeLabel(); codeStream.EmitLabel(label); codeStream.Emit(ILOpcode.call, emitter.NewToken(method)); codeStream.Emit(ILOpcode.br, label); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } codeStream.Emit(ILOpcode.call, emitter.NewToken(_target)); codeStream.Emit(ILOpcode.ret); return emitter.Link(); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); ModuleDesc developerExperience = Context.ResolveAssembly(new AssemblyName("System.Private.DeveloperExperience.Console"), false); if (developerExperience != null) { TypeDesc connectorType = developerExperience.GetKnownType("Internal.DeveloperExperience", "DeveloperExperienceConnectorConsole"); MethodDesc initializeMethod = connectorType.GetKnownMethod("Initialize", null); codeStream.Emit(ILOpcode.call, emitter.NewToken(initializeMethod)); } MetadataType startup = Context.GetHelperType("StartupCodeHelpers"); // Initialize command line args if the class library supports this string initArgsName = (Context.Target.OperatingSystem == TargetOS.Windows) ? "InitializeCommandLineArgsW" : "InitializeCommandLineArgs"; MethodDesc initArgs = startup.GetMethod(initArgsName, null); if (initArgs != null) { codeStream.Emit(ILOpcode.ldarg_0); // argc codeStream.Emit(ILOpcode.ldarg_1); // argv codeStream.Emit(ILOpcode.call, emitter.NewToken(initArgs)); } // Call program Main if (_mainMethod.Signature.Length > 0) { // TODO: better exception if (initArgs == null) throw new Exception("Main() has parameters, but the class library doesn't support them"); codeStream.Emit(ILOpcode.call, emitter.NewToken(startup.GetKnownMethod("GetMainMethodArguments", null))); } codeStream.Emit(ILOpcode.call, emitter.NewToken(_mainMethod)); if (_mainMethod.Signature.ReturnType.IsVoid) { codeStream.EmitLdc(0); } codeStream.Emit(ILOpcode.ret); return emitter.Link(this); }
public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Name == "AddrOf"); Debug.Assert(target.Signature.Length == 1 && target.Signature.ReturnType == target.Context.GetWellKnownType(WellKnownType.IntPtr)); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); codeStream.EmitLdArg(0); var fptrField = target.Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType.GetKnownField("m_extraFunctionPointerOrData"); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(fptrField)); codeStream.Emit(ILOpcode.ret); return emitter.Link(); }
public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Name == "CompareExchange" || target.Name == "Exchange"); // // Find non-generic method to forward the generic method to. // int parameterCount = target.Signature.Length; Debug.Assert(parameterCount == 3 || parameterCount == 2); var objectType = target.Context.GetWellKnownType(WellKnownType.Object); var parameters = new TypeDesc[parameterCount]; parameters[0] = objectType.MakeByRefType(); for (int i = 1; i < parameters.Length; i++) parameters[i] = objectType; MethodSignature nonGenericSignature = new MethodSignature(MethodSignatureFlags.Static, 0, objectType, parameters); MethodDesc nonGenericMethod = target.OwningType.GetMethod(target.Name, nonGenericSignature); // TODO: Better exception type. Should be: "CoreLib doesn't have a required thing in it". if (nonGenericMethod == null) throw new NotImplementedException(); // // Emit the forwarder // ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); // Reload all arguments for (int i = 0; i < parameterCount; i++) codeStream.EmitLdArg(i); codeStream.Emit(ILOpcode.call, emitter.NewToken(nonGenericMethod)); codeStream.Emit(ILOpcode.ret); return emitter.Link(); }
public static MethodIL EmitIL(MethodDesc method) { Debug.Assert(method.OwningType.IsDelegate); Debug.Assert(method.IsRuntimeImplemented); if (method.Name == "BeginInvoke" || method.Name == "EndInvoke") { // BeginInvoke and EndInvoke are not supported on .NET Core ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); MethodDesc notSupportedExceptionHelper = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException"); codeStream.EmitCallThrowHelper(emit, notSupportedExceptionHelper); return emit.Link(method); } if (method.Name == ".ctor") { TypeSystemContext context = method.Context; ILEmitter emit = new ILEmitter(); TypeDesc delegateType = context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType; MethodDesc objectCtorMethod = context.GetWellKnownType(WellKnownType.Object).GetDefaultConstructor(); FieldDesc functionPointerField = delegateType.GetKnownField("m_functionPointer"); FieldDesc firstParameterField = delegateType.GetKnownField("m_firstParameter"); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.call, emit.NewToken(objectCtorMethod)); codeStream.EmitLdArg(0); codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.stfld, emit.NewToken(firstParameterField)); codeStream.EmitLdArg(0); codeStream.EmitLdArg(2); codeStream.Emit(ILOpcode.stfld, emit.NewToken(functionPointerField)); codeStream.Emit(ILOpcode.ret); return emit.Link(method); } return null; }
public static MethodIL EmitIL(MethodDesc method) { Debug.Assert(method.OwningType.IsDelegate); Debug.Assert(method.IsRuntimeImplemented); if (method.Name == "BeginInvoke" || method.Name == "EndInvoke") { // BeginInvoke and EndInvoke are not supported on .NET Core ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); MethodDesc notSupportedExceptionHelper = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException"); codeStream.EmitCallThrowHelper(emit, notSupportedExceptionHelper); return emit.Link(method); } if (method.Name == ".ctor") { // TODO: this should be an assert that codegen never asks for this. // This is just a workaround for https://github.com/dotnet/corert/issues/2102 // The code below is making a wild guess that we're creating a closed // instance delegate. Without shared generics, this should only happen // for virtual method (so we're fine there). With shared generics, this can // happen for anything and might be pretty wrong. TypeSystemContext context = method.Context; ILEmitter emit = new ILEmitter(); TypeDesc delegateType = context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType; MethodDesc initializeMethod = delegateType.GetKnownMethod("InitializeClosedInstanceSlow", null); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.EmitLdArg(0); codeStream.EmitLdArg(1); codeStream.EmitLdArg(2); codeStream.Emit(ILOpcode.call, emit.NewToken(initializeMethod)); codeStream.Emit(ILOpcode.ret); return emit.Link(method); } return null; }
private void EmitCalli(PInvokeILCodeStreams ilCodeStreams, CalliMarshallingMethodThunk calliThunk) { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } MethodSignature nativeSig = new MethodSignature( calliThunk.TargetSignature.Flags, 0, nativeReturnType, nativeParameterTypes); callsiteSetupCodeStream.EmitLdArg(calliThunk.TargetSignature.Length); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); }
public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Name == "CreateInstanceIntrinsic"); Debug.Assert(target.Instantiation.Length == 1); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); // TODO: This won't work for shared generics // https://github.com/dotnet/corert/issues/368 TypeDesc type = target.Instantiation[0]; MethodDesc ctorMethod = type.GetDefaultConstructor(); if (ctorMethod == null) { if (type.IsValueType) { var loc = emitter.NewLocal(type); codeStream.EmitLdLoca(loc); codeStream.Emit(ILOpcode.initobj, emitter.NewToken(type)); codeStream.EmitLdLoc(loc); } else { var missingCtor = type.Context.SystemModule.GetKnownType("System", "Activator"). GetNestedType("ClassWithMissingConstructor").GetDefaultConstructor(); codeStream.Emit(ILOpcode.newobj, emitter.NewToken(missingCtor)); } } else { codeStream.Emit(ILOpcode.newobj, emitter.NewToken(ctorMethod)); } codeStream.Emit(ILOpcode.ret); return(emitter.Link(target)); }
public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Name == "CreateInstanceIntrinsic"); Debug.Assert(target.Instantiation.Length == 1); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); // TODO: This won't work for shared generics // https://github.com/dotnet/corert/issues/368 TypeDesc type = target.Instantiation[0]; MethodDesc ctorMethod = type.GetDefaultConstructor(); if (ctorMethod == null) { if (type.IsValueType) { var loc = emitter.NewLocal(type); codeStream.EmitLdLoca(loc); codeStream.Emit(ILOpcode.initobj, emitter.NewToken(type)); codeStream.EmitLdLoc(loc); } else { var missingCtor = type.Context.SystemModule.GetKnownType("System", "Activator"). GetNestedType("ClassWithMissingConstructor").GetDefaultConstructor(); codeStream.Emit(ILOpcode.newobj, emitter.NewToken(missingCtor)); } } else { codeStream.Emit(ILOpcode.newobj, emitter.NewToken(ctorMethod)); } codeStream.Emit(ILOpcode.ret); return emitter.Link(target); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); // InstantiateAsOpen covers the weird case of generic enums TypeDesc owningTypeAsOpen = _owningType.InstantiateAsOpen(); ILCodeLabel lNotEqual = emitter.NewCodeLabel(); // if (!(obj is {enumtype})) // return false; codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.isinst, emitter.NewToken(owningTypeAsOpen)); codeStream.Emit(ILOpcode.dup); codeStream.Emit(ILOpcode.brfalse, lNotEqual); // return ({underlyingtype})this == ({underlyingtype})obj; // PREFER: ILOpcode.unbox, but the codegen for that is pretty bad codeStream.Emit(ILOpcode.ldflda, emitter.NewToken(Context.GetWellKnownType(WellKnownType.Object).GetKnownField("m_pEEType"))); codeStream.EmitLdc(Context.Target.PointerSize); codeStream.Emit(ILOpcode.add); codeStream.EmitLdInd(owningTypeAsOpen); codeStream.EmitLdArg(0); codeStream.EmitLdInd(owningTypeAsOpen); codeStream.Emit(ILOpcode.ceq); codeStream.Emit(ILOpcode.ret); codeStream.EmitLabel(lNotEqual); codeStream.Emit(ILOpcode.pop); codeStream.EmitLdc(0); codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); ILLocalVariable returnValue = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); TypeDesc startup = Context.SystemModule.GetType("Internal.Runtime.CompilerHelpers", "StartupCodeHelpers"); codeStream.Emit(ILOpcode.call, emitter.NewToken(startup.GetMethod("Initialize", null))); // Initialize command line args // TODO: For Windows change to "InitializeCommandLineArgsW" with wmain wchar_t change. string initArgsName = (Context.Target.OperatingSystem == TargetOS.Windows) ? "InitializeCommandLineArgs" : "InitializeCommandLineArgs"; MethodDesc initArgs = startup.GetMethod(initArgsName, null); codeStream.Emit(ILOpcode.ldarg_0); // argc codeStream.Emit(ILOpcode.ldarg_1); // argv codeStream.Emit(ILOpcode.call, emitter.NewToken(initArgs)); // Call program Main if (_mainMethod.Signature.Length > 0) { TypeDesc environ = Context.SystemModule.GetType("System", "Environment"); codeStream.Emit(ILOpcode.call, emitter.NewToken(environ.GetMethod("GetCommandLineArgs", null))); } codeStream.Emit(ILOpcode.call, emitter.NewToken(_mainMethod)); if (_mainMethod.Signature.ReturnType.IsVoid) { codeStream.EmitLdc(0); } codeStream.EmitStLoc(returnValue); codeStream.Emit(ILOpcode.call, emitter.NewToken(startup.GetMethod("Shutdown", null))); codeStream.EmitLdLoc(returnValue); codeStream.Emit(ILOpcode.ret); return emitter.Link(); }
private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams) { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeSystemContext context = _targetMethod.Context; TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; MetadataType stubHelpersType = InteropTypes.GetStubHelpers(context); // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_importMetadata.Flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( stubHelpersType.GetKnownMethod("ClearLastError", null))); } for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); var rawTargetMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(rawTargetMethod)); // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastError // so that last error can be used later by calling Marshal.GetLastPInvokeError if (_importMetadata.Flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( stubHelpersType.GetKnownMethod("SetLastError", null))); } }
private MethodIL EmitCleanupIL(PInvokeILCodeStreams pInvokeILCodeStreams) { ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream codeStream = pInvokeILCodeStreams.MarshallingCodeStream; IEnumerator <FieldDesc> nativeEnumerator = NativeType.GetFields().GetEnumerator(); for (int i = 0; i < _marshallers.Length; i++) { bool valid = nativeEnumerator.MoveNext(); Debug.Assert(valid); if (_marshallers[i].CleanupRequired) { LoadFieldValueFromArg(0, nativeEnumerator.Current, pInvokeILCodeStreams); _marshallers[i].EmitElementCleanup(codeStream, emitter); } } pInvokeILCodeStreams.UnmarshallingCodestream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public static MethodIL EmitIL( #if READYTORUN ILCompiler.CompilationModuleGroup compilationModuleGroup, #endif // READYTORUN MethodDesc method) { Debug.Assert(((MetadataType)method.OwningType).Name == "Interlocked"); if (method.HasInstantiation && method.Name == "CompareExchange") { #if READYTORUN // Check to see if the tokens needed to describe the CompareExchange are naturally present within // the compilation. The current implementation of stable tokens used by cross module inlining is not // compatible with rewriting the IL of a compiler generated intrinsic. Fortunately, it turns out // that the managed implementation of this intrinsic is correct, just a few more IL instructions. if (compilationModuleGroup.ContainsType(method.OwningType)) #endif // READYTORUN { TypeDesc objectType = method.Context.GetWellKnownType(WellKnownType.Object); MethodDesc compareExchangeObject = method.OwningType.GetKnownMethod("CompareExchange", new MethodSignature( MethodSignatureFlags.Static, genericParameterCount: 0, returnType: objectType, parameters: new TypeDesc[] { objectType.MakeByRefType(), objectType, objectType })); ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.EmitLdArg(0); codeStream.EmitLdArg(1); codeStream.EmitLdArg(2); codeStream.Emit(ILOpcode.call, emit.NewToken(compareExchangeObject)); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); } } return(null); }
public override MethodIL EmitIL() { ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); Debug.Assert(Signature[0] == _helperMethod.Signature[0]); codeStream.EmitLdArg(0); Debug.Assert(_helperMethod.Signature[1].IsString); codeStream.Emit(ILOpcode.ldstr, emit.NewToken(DefaultAssemblyName)); for (int i = 2; i < _helperMethod.Signature.Length; i++) { // The helper method could be expecting more arguments than what we have - check for that // The thunk represents one of the 6 possible overloads: // (String), (String, bool), (String, bool, bool) // (String, Func<...>, Func<...>), (String, Func<...>, Func<...>, bool), (String, Func<...>, Func<...>, bool, bool) // We only need 2 helpers to support all 6 overloads. The default value for the bools is false. if (i - 1 < Signature.Length) { // Pass user's parameter Debug.Assert(_helperMethod.Signature[i] == Signature[i - 1]); codeStream.EmitLdArg(i - 1); } else { // Pass a default value Debug.Assert(_helperMethod.Signature[i].IsWellKnownType(WellKnownType.Boolean)); codeStream.EmitLdc(0); } } codeStream.Emit(ILOpcode.call, emit.NewToken(_helperMethod)); codeStream.Emit(ILOpcode.ret); return(emit.Link(this)); }
private static MethodIL EmitReadWrite(MethodDesc method, bool write, bool unaligned = false) { Debug.Assert(method.Signature.IsStatic && method.Signature.Length == (write ? 2 : 1)); TypeSystemContext context = method.Context; ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.EmitLdArg(0); if (write) { codeStream.EmitLdArg(1); } if (unaligned) { codeStream.EmitUnaligned(); } codeStream.Emit(write ? ILOpcode.stobj : ILOpcode.ldobj, emit.NewToken(context.GetSignatureVariable(0, method: true))); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); }
public static MethodIL EmitIL(MethodDesc method) { Debug.Assert(((MetadataType)method.OwningType).Name == "MemoryMarshal"); string methodName = method.Name; if (method.Instantiation.Length != 1) { return(null); // we only handle the generic method GetArrayDataReference<T>(T[]) } if (methodName == "GetArrayDataReference") { ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldflda, emit.NewToken(method.Context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "RawArrayData").GetField("Data"))); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); } // unknown method return(null); }
private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams) { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeSystemContext context = _targetMethod.Context; TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); var rawTargetMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(rawTargetMethod)); }
public override MethodIL EmitIL() { TypeDesc[] targetMethodParameters = new TypeDesc[Signature.Length + 1]; targetMethodParameters[0] = Context.GetWellKnownType(WellKnownType.Object); for (int i = 0; i < Signature.Length; i++) { targetMethodParameters[i + 1] = Signature[i]; } var targetMethodSignature = new MethodSignature( Signature.Flags | MethodSignatureFlags.Static, 0, Signature.ReturnType, targetMethodParameters); var emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); // Load the stored 'this' codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField)); // Load all arguments except 'this' for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } // Indirectly call the delegate target static method. codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(ExtraFunctionPointerOrDataField)); EmitTransformedCalli(emitter, codeStream, targetMethodSignature); //codeStream.Emit(ILOpcode.calli, emitter.NewToken(targetMethodSignature)); codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Name == "Call"); Debug.Assert(target.Signature.Length > 0 && target.Signature[0] == target.Context.GetWellKnownType(WellKnownType.IntPtr)); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); // Load all the arguments except the first one (IntPtr address) for (int i = 1; i < target.Signature.Length; i++) { codeStream.EmitLdArg(i); } // now load IntPtr address codeStream.EmitLdArg(0); // Create a signature for the calli by copying the signature of the containing method // while skipping the first argument MethodSignature template = target.Signature; TypeDesc returnType = template.ReturnType; TypeDesc[] parameters = new TypeDesc[template.Length - 1]; for (int i = 1; i < template.Length; i++) { parameters[i - 1] = template[i]; } var signature = new MethodSignature(template.Flags, 0, returnType, parameters); codeStream.Emit(ILOpcode.calli, emitter.NewToken(signature)); codeStream.Emit(ILOpcode.ret); return(emitter.Link(target)); }
public override MethodIL EmitIL() { // Target has the same signature as the Invoke method, except it's static. MethodSignatureBuilder builder = new MethodSignatureBuilder(Signature); builder.Flags = Signature.Flags | MethodSignatureFlags.Static; var emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); // Load all arguments except 'this' for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } // Indirectly call the delegate target static method. codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(ExtraFunctionPointerOrDataField)); codeStream.Emit(ILOpcode.calli, emitter.NewToken(builder.ToSignature())); codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Name == "AddrOf"); Debug.Assert(target.Signature.Length == 1 && target.Signature.ReturnType == target.Context.GetWellKnownType(WellKnownType.IntPtr)); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); codeStream.EmitLdArg(0); var fptrField = target.Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType.GetField("m_extraFunctionPointerOrData"); if (fptrField == null) { // TODO: Better exception type. Should be: "CoreLib doesn't have a required thing in it". throw new NotImplementedException(); } codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(fptrField)); codeStream.Emit(ILOpcode.ret); return emitter.Link(); }
private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams) { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream fnptrLoadStream = ilCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeSystemContext context = _targetMethod.Context; bool isHRSwappedRetVal = !_flags.PreserveSig && !_targetMethod.Signature.ReturnType.IsVoid; TypeDesc nativeReturnType = _flags.PreserveSig ? _marshallers[0].NativeParameterType : context.GetWellKnownType(WellKnownType.Int32); TypeDesc[] nativeParameterTypes = new TypeDesc[isHRSwappedRetVal ? _marshallers.Length : _marshallers.Length - 1]; // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastError", null))); } for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } if (isHRSwappedRetVal) { nativeParameterTypes[_marshallers.Length - 1] = _marshallers[0].NativeParameterType; } if (!_pInvokeILEmitterConfiguration.GenerateDirectCall(_targetMethod, out _)) { MetadataType lazyHelperType = context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = _interopStateManager.GetPInvokeLazyFixupField(_targetMethod); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType .GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallingConvention = _flags.UnmanagedCallingConvention; if (unmanagedCallingConvention == MethodSignatureFlags.None) { unmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConvention; } EmbeddedSignatureData[] embeddedSignatureData = null; if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "SuppressGCTransitionAttribute")) { embeddedSignatureData = new EmbeddedSignatureData[] { new EmbeddedSignatureData() { index = MethodSignature.IndexOfCustomModifiersOnReturnType, kind = EmbeddedSignatureDataKind.OptionalCustomModifier, type = context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "CallConvSuppressGCTransition") } }; } MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags | unmanagedCallingConvention, 0, nativeReturnType, nativeParameterTypes, embeddedSignatureData); ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(context .GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); } else { // Eager call MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod)); } if (!_flags.PreserveSig) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetMarshal(context) .GetKnownMethod("ThrowExceptionForHR", null))); } // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastError // so that last error can be used later by calling Marshal.GetLastPInvokeError if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context) .GetKnownMethod("SaveLastError", null))); } }
public MethodIL EmitIL() { MethodSignature targetMethodSignature = _targetMethod.Signature; // We have 4 code streams: // - _marshallingCodeStream is used to convert each argument into a native type and // store that into the local // - callsiteSetupCodeStream is used to used to load each previously generated local // and call the actual target native method. // - _returnValueMarshallingCodeStream is used to convert the native return value // to managed one. // - _unmarshallingCodestream is used to propagate [out] native arguments values to // managed ones. _emitter = new ILEmitter(); _marshallingCodeStream = _emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = _emitter.NewCodeStream(); _returnValueMarshallingCodeStream = _emitter.NewCodeStream(); _unmarshallingCodestream = _emitter.NewCodeStream(); TypeDesc[] nativeParameterTypes = new TypeDesc[targetMethodSignature.Length]; // // Parameter marshalling // // // Convert each argument to something we can pass to native and store it in a local. // Then load the local in the second code stream. // for (int i = 0; i < targetMethodSignature.Length; i++) { // TODO: throw if there's custom marshalling _marshallingCodeStream.EmitLdArg(i); TypeDesc nativeType = MarshalArgument(targetMethodSignature[i]); nativeParameterTypes[i] = nativeType; ILLocalVariable vMarshalledTypeTemp = _emitter.NewLocal(nativeType); _marshallingCodeStream.EmitStLoc(vMarshalledTypeTemp); callsiteSetupCodeStream.EmitLdLoc(vMarshalledTypeTemp); } // // Return value marshalling // // TODO: throw if SetLastError is true // TODO: throw if there's custom marshalling TypeDesc nativeReturnType = MarshalReturnValue(targetMethodSignature.ReturnType); MethodSignature nativeSig = new MethodSignature( targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, _importMetadata); // Call the native method callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); _unmarshallingCodestream.Emit(ILOpcode.ret); return(_emitter.Link()); }
public override MethodIL EmitIL() { var emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); // Load the stored 'this' codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField)); // Load all arguments except 'this' for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } // Indirectly call the delegate target codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(ExtraFunctionPointerOrDataField)); CalliIntrinsic.EmitTransformedCalli(emitter, codeStream, Signature); //codeStream.Emit(ILOpcode.calli, emitter.NewToken(Signature)); codeStream.Emit(ILOpcode.ret); return emitter.Link(this); }
public MethodIL EmitIL() { MethodSignature targetMethodSignature = _targetMethod.Signature; // We have 4 code streams: // - _marshallingCodeStream is used to convert each argument into a native type and // store that into the local // - callsiteSetupCodeStream is used to used to load each previously generated local // and call the actual target native method. // - _returnValueMarshallingCodeStream is used to convert the native return value // to managed one. // - _unmarshallingCodestream is used to propagate [out] native arguments values to // managed ones. _emitter = new ILEmitter(); ILCodeStream fnptrLoadStream = _emitter.NewCodeStream(); _marshallingCodeStream = _emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = _emitter.NewCodeStream(); _returnValueMarshallingCodeStream = _emitter.NewCodeStream(); _unmarshallingCodestream = _emitter.NewCodeStream(); TypeDesc[] nativeParameterTypes = new TypeDesc[targetMethodSignature.Length]; // // Parameter marshalling // // // Convert each argument to something we can pass to native and store it in a local. // Then load the local in the second code stream. // for (int i = 0; i < targetMethodSignature.Length; i++) { // TODO: throw if there's custom marshalling _marshallingCodeStream.EmitLdArg(i); TypeDesc nativeType = MarshalArgument(targetMethodSignature[i]); nativeParameterTypes[i] = nativeType; ILLocalVariable vMarshalledTypeTemp = _emitter.NewLocal(nativeType); _marshallingCodeStream.EmitStLoc(vMarshalledTypeTemp); callsiteSetupCodeStream.EmitLdLoc(vMarshalledTypeTemp); } // // Return value marshalling // // TODO: throw if SetLastError is true // TODO: throw if there's custom marshalling TypeDesc nativeReturnType = MarshalReturnValue(targetMethodSignature.ReturnType); if (UseLazyResolution(_targetMethod, _importMetadata.Module)) { MetadataType lazyHelperType = _targetMethod.Context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = new PInvokeLazyFixupField((DefType)_targetMethod.OwningType, _importMetadata); fnptrLoadStream.Emit(ILOpcode.ldsflda, _emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, _emitter.NewToken(lazyHelperType.GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = PInvokeMetadata.GetUnmanagedCallingConvention(_importMetadata.Attributes); MethodSignature nativeCalliSig = new MethodSignature( targetMethodSignature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); ILLocalVariable vNativeFunctionPointer = _emitter.NewLocal(_targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, _emitter.NewToken(nativeCalliSig)); } else { // Eager call PInvokeMetadata nativeImportMetadata = new PInvokeMetadata(_importMetadata.Module, _importMetadata.Name ?? _targetMethod.Name, _importMetadata.Attributes); MethodSignature nativeSig = new MethodSignature( targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, nativeImportMetadata); callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); } _unmarshallingCodestream.Emit(ILOpcode.ret); return _emitter.Link(_targetMethod); }
private MethodIL EmitIL() { if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "LCIDConversionAttribute")) { throw new NotSupportedException(); } PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream marshallingCodestream = pInvokeILCodeStreams.MarshallingCodeStream; ILCodeStream unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream; ILCodeStream cleanupCodestream = pInvokeILCodeStreams.CleanupCodeStream; // Marshalling is wrapped in a finally block to guarantee cleanup ILExceptionRegionBuilder tryFinally = emitter.NewFinallyRegion(); marshallingCodestream.BeginTry(tryFinally); cleanupCodestream.BeginHandler(tryFinally); // Marshal the arguments bool isHRSwappedRetVal = !_flags.PreserveSig && !_targetMethod.Signature.ReturnType.IsVoid; for (int i = isHRSwappedRetVal ? 1 : 0; i < _marshallers.Length; i++) { _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams); } if (isHRSwappedRetVal) { _marshallers[0].EmitMarshallingIL(pInvokeILCodeStreams); } // make the call switch (_targetMethod) { case DelegateMarshallingMethodThunk delegateMethod: EmitDelegateCall(delegateMethod, pInvokeILCodeStreams); break; case CalliMarshallingMethodThunk calliMethod: EmitCalli(pInvokeILCodeStreams, calliMethod); break; default: EmitPInvokeCall(pInvokeILCodeStreams); break; } ILCodeLabel lReturn = emitter.NewCodeLabel(); unmarshallingCodestream.Emit(ILOpcode.leave, lReturn); unmarshallingCodestream.EndTry(tryFinally); cleanupCodestream.Emit(ILOpcode.endfinally); cleanupCodestream.EndHandler(tryFinally); cleanupCodestream.EmitLabel(lReturn); _marshallers[0].LoadReturnValue(cleanupCodestream); cleanupCodestream.Emit(ILOpcode.ret); return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired())); }
public override MethodIL EmitIL() { // We will generate the following code: // // object ret; // object[] args = new object[parameterCount]; // args[0] = param0; // args[1] = param1; // ... // try { // ret = ((Func<object[], object>)dlg.m_helperObject)(args); // } finally { // param0 = (T0)args[0]; // only generated for each byref argument // } // return (TRet)ret; ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); TypeDesc objectType = Context.GetWellKnownType(WellKnownType.Object); TypeDesc objectArrayType = objectType.MakeArrayType(); ILLocalVariable argsLocal = emitter.NewLocal(objectArrayType); bool hasReturnValue = !Signature.ReturnType.IsVoid; bool hasRefArgs = false; if (Signature.Length > 0) { codeStream.EmitLdc(Signature.Length); codeStream.Emit(ILOpcode.newarr, emitter.NewToken(objectType)); codeStream.EmitStLoc(argsLocal); for (int i = 0; i < Signature.Length; i++) { TypeDesc paramType = Signature[i]; bool paramIsByRef = false; if (paramType.IsByRef) { hasRefArgs |= paramType.IsByRef; paramIsByRef = true; paramType = ((ByRefType)paramType).ParameterType; } hasRefArgs |= paramType.IsByRef; codeStream.EmitLdLoc(argsLocal); codeStream.EmitLdc(i); codeStream.EmitLdArg(i + 1); TypeDesc boxableParamType = DelegateDynamicInvokeThunk.ConvertToBoxableType(paramType); ILToken boxableParamToken = emitter.NewToken(boxableParamType); if (paramIsByRef) { codeStream.Emit(ILOpcode.ldobj, boxableParamToken); } codeStream.Emit(ILOpcode.box, boxableParamToken); codeStream.Emit(ILOpcode.stelem_ref); } } else { MethodDesc emptyObjectArrayMethod = Context.GetHelperEntryPoint("DelegateHelpers", "GetEmptyObjectArray"); codeStream.Emit(ILOpcode.call, emitter.NewToken(emptyObjectArrayMethod)); codeStream.EmitStLoc(argsLocal); } if (hasRefArgs) { // we emit a try/finally to update the args array even if an exception is thrown // ilgen.BeginTryBody(); } codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField)); MetadataType funcType = Context.SystemModule.GetKnownType("System", "Func`2"); TypeDesc instantiatedFunc = funcType.MakeInstantiatedType(objectArrayType, objectType); codeStream.Emit(ILOpcode.castclass, emitter.NewToken(instantiatedFunc)); codeStream.EmitLdLoc(argsLocal); MethodDesc invokeMethod = instantiatedFunc.GetKnownMethod("Invoke", null); codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod)); ILLocalVariable retLocal = (ILLocalVariable)(-1); if (hasReturnValue) { retLocal = emitter.NewLocal(objectType); codeStream.EmitStLoc(retLocal); } else { codeStream.Emit(ILOpcode.pop); } if (hasRefArgs) { // ILGeneratorLabel returnLabel = new ILGeneratorLabel(); // ilgen.Emit(OperationCode.Leave, returnLabel); // copy back ref/out args //ilgen.BeginFinallyBlock(); for (int i = 0; i < Signature.Length; i++) { TypeDesc paramType = Signature[i]; if (paramType.IsByRef) { paramType = ((ByRefType)paramType).ParameterType; TypeDesc boxableParamType = DelegateDynamicInvokeThunk.ConvertToBoxableType(paramType); ILToken boxableParamToken = emitter.NewToken(boxableParamType); // Update parameter codeStream.EmitLdArg(i + 1); codeStream.EmitLdLoc(argsLocal); codeStream.EmitLdc(i); codeStream.Emit(ILOpcode.ldelem_ref); codeStream.Emit(ILOpcode.unbox_any, boxableParamToken); codeStream.Emit(ILOpcode.stobj, boxableParamToken); } } // ilgen.Emit(OperationCode.Endfinally); // ilgen.EndTryBody(); // ilgen.MarkLabel(returnLabel); } if (hasReturnValue) { TypeDesc boxableReturnType = DelegateDynamicInvokeThunk.ConvertToBoxableType(Signature.ReturnType); codeStream.EmitLdLoc(retLocal); codeStream.Emit(ILOpcode.unbox_any, emitter.NewToken(boxableReturnType)); } codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public static MethodIL EmitIL(MethodDesc method) { Debug.Assert(((MetadataType)method.OwningType).Name == "RuntimeHelpers"); string methodName = method.Name; if (methodName == "GetRawSzArrayData") { ILEmitter emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldflda, emit.NewToken(method.Context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "RawArrayData").GetField("Data"))); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); } // All the methods handled below are per-instantiation generic methods if (method.Instantiation.Length != 1 || method.IsTypicalMethodDefinition) { return(null); } TypeDesc elementType = method.Instantiation[0]; // Fallback to non-intrinsic implementation for universal generics if (elementType.IsCanonicalSubtype(CanonicalFormKind.Universal)) { return(null); } bool result; if (methodName == "IsReferenceOrContainsReferences") { result = elementType.IsGCPointer || (elementType is DefType defType && defType.ContainsGCPointers); } else if (methodName == "IsReference") { result = elementType.IsGCPointer; } else if (methodName == "IsBitwiseEquatable") { // Ideally we could detect automatically whether a type is trivially equatable // (i.e., its operator == could be implemented via memcmp). But for now we'll // do the simple thing and hardcode the list of types we know fulfill this contract. // n.b. This doesn't imply that the type's CompareTo method can be memcmp-implemented, // as a method like CompareTo may need to take a type's signedness into account. switch (elementType.UnderlyingType.Category) { case TypeFlags.Boolean: case TypeFlags.Byte: case TypeFlags.SByte: case TypeFlags.Char: case TypeFlags.UInt16: case TypeFlags.Int16: case TypeFlags.UInt32: case TypeFlags.Int32: case TypeFlags.UInt64: case TypeFlags.Int64: case TypeFlags.IntPtr: case TypeFlags.UIntPtr: result = true; break; default: var mdType = elementType as MetadataType; if (mdType != null && mdType.Name == "Rune" && mdType.Namespace == "System.Text") { result = true; } else if (mdType != null && mdType.Name == "Char8" && mdType.Namespace == "System") { result = true; } else { result = false; } break; } } else { return(null); } ILOpcode opcode = result ? ILOpcode.ldc_i4_1 : ILOpcode.ldc_i4_0; return(new ILStubMethodIL(method, new byte[] { (byte)opcode, (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), Array.Empty <object>())); }
private void EmitDelegateCall(DelegateMarshallingMethodThunk delegateMethod, PInvokeILCodeStreams ilCodeStreams) { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream fnptrLoadStream = ilCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeSystemContext context = _targetMethod.Context; Debug.Assert(delegateMethod != null); if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind.ReverseOpenStatic) { // // For Open static delegates call // InteropHelpers.GetCurrentCalleeOpenStaticDelegateFunctionPointer() // which returns a function pointer. Just call the function pointer and we are done. // TypeDesc[] parameters = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { parameters[i - 1] = _marshallers[i].ManagedParameterType; } MethodSignature managedSignature = new MethodSignature( MethodSignatureFlags.Static, 0, _marshallers[0].ManagedParameterType, parameters); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken( delegateMethod.Context.GetHelperType("InteropHelpers").GetKnownMethod( "GetCurrentCalleeOpenStaticDelegateFunctionPointer", null))); ILLocalVariable vDelegateStub = emitter.NewLocal( delegateMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vDelegateStub); callsiteSetupCodeStream.EmitLdLoc(vDelegateStub); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(managedSignature)); } else if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind.ReverseClosed) { // // For closed delegates call // InteropHelpers.GetCurrentCalleeDelegate<Delegate> // which returns the delegate. Do a CallVirt on the invoke method. // MethodDesc instantiatedHelper = delegateMethod.Context.GetInstantiatedMethod( delegateMethod.Context.GetHelperType("InteropHelpers") .GetKnownMethod("GetCurrentCalleeDelegate", null), new Instantiation((delegateMethod.DelegateType))); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(instantiatedHelper)); ILLocalVariable vDelegateStub = emitter.NewLocal(delegateMethod.DelegateType); fnptrLoadStream.EmitStLoc(vDelegateStub); fnptrLoadStream.EmitLdLoc(vDelegateStub); MethodDesc invokeMethod = delegateMethod.DelegateType.GetKnownMethod("Invoke", null); callsiteSetupCodeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod)); } else if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind .ForwardNativeFunctionWrapper) { // if the SetLastError flag is set in UnmanagedFunctionPointerAttribute, clear the error code before doing P/Invoke if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null))); } // // For NativeFunctionWrapper we need to load the native function and call it // fnptrLoadStream.EmitLdArg(0); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(InteropTypes .GetNativeFunctionPointerWrapper(context) .GetMethod("get_NativeFunctionPointer", null))); var fnPtr = emitter.NewLocal( context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(fnPtr); callsiteSetupCodeStream.EmitLdLoc(fnPtr); TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } MethodSignature nativeSig = new MethodSignature( MethodSignatureFlags.Static | _flags.UnmanagedCallingConvention, 0, nativeReturnType, nativeParameterTypes); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); // if the SetLastError flag is set in UnmanagedFunctionPointerAttribute, call the PInvokeMarshal. // SaveLastWin32Error so that last error can be used later by calling // PInvokeMarshal.GetLastWin32Error if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context) .GetKnownMethod("SaveLastWin32Error", null))); } } else { Debug.Fail("Unexpected DelegateMarshallingMethodThunkKind"); } }
public PInvokeILCodeStreams(ILEmitter emitter, ILCodeStream codeStream) { Emitter = emitter; MarshallingCodeStream = codeStream; }
private MethodIL EmitIL() { PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream fnptrLoadStream = pInvokeILCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = pInvokeILCodeStreams.CallsiteSetupCodeStream; ILCodeStream unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream; TypeSystemContext context = _targetMethod.Context; // Marshal the arguments for (int i = 0; i < _marshallers.Length; i++) { _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams); } // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_importMetadata.Flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null))); } // make the call DelegateMarshallingMethodThunk delegateMethod = _targetMethod as DelegateMarshallingMethodThunk; if (delegateMethod != null) { EmitDelegateCall(delegateMethod, pInvokeILCodeStreams); } else { TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } if (MarshalHelpers.UseLazyResolution(_targetMethod, _importMetadata.Module, _pInvokeILEmitterConfiguration)) { MetadataType lazyHelperType = _targetMethod.Context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = new PInvokeLazyFixupField(_targetMethod); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType .GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = _importMetadata.Flags.UnmanagedCallingConvention; MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(_targetMethod.Context .GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); } else { // Eager call MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod)); } } // if the SetLastError flag is set in DllImport, call the PInvokeMarshal. // SaveLastWin32Error so that last error can be used later by calling // PInvokeMarshal.GetLastWin32Error if (_importMetadata.Flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context) .GetKnownMethod("SaveLastWin32Error", null))); } unmarshallingCodestream.Emit(ILOpcode.ret); return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired())); }
public MethodIL EmitIL() { MethodSignature targetMethodSignature = _targetMethod.Signature; // We have 4 code streams: // - _marshallingCodeStream is used to convert each argument into a native type and // store that into the local // - callsiteSetupCodeStream is used to used to load each previously generated local // and call the actual target native method. // - _returnValueMarshallingCodeStream is used to convert the native return value // to managed one. // - _unmarshallingCodestream is used to propagate [out] native arguments values to // managed ones. _emitter = new ILEmitter(); _marshallingCodeStream = _emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = _emitter.NewCodeStream(); _returnValueMarshallingCodeStream = _emitter.NewCodeStream(); _unmarshallingCodestream = _emitter.NewCodeStream(); TypeDesc[] nativeParameterTypes = new TypeDesc[targetMethodSignature.Length]; // // Parameter marshalling // // // Convert each argument to something we can pass to native and store it in a local. // Then load the local in the second code stream. // for (int i = 0; i < targetMethodSignature.Length; i++) { // TODO: throw if there's custom marshalling _marshallingCodeStream.EmitLdArg(i); TypeDesc nativeType = MarshalArgument(targetMethodSignature[i]); nativeParameterTypes[i] = nativeType; ILLocalVariable vMarshalledTypeTemp = _emitter.NewLocal(nativeType); _marshallingCodeStream.EmitStLoc(vMarshalledTypeTemp); callsiteSetupCodeStream.EmitLdLoc(vMarshalledTypeTemp); } // // Return value marshalling // // TODO: throw if SetLastError is true // TODO: throw if there's custom marshalling TypeDesc nativeReturnType = MarshalReturnValue(targetMethodSignature.ReturnType); MethodSignature nativeSig = new MethodSignature( targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, _importMetadata); // Call the native method callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); _unmarshallingCodestream.Emit(ILOpcode.ret); return _emitter.Link(); }
public MethodIL EmitIL() { MethodSignature targetMethodSignature = _targetMethod.Signature; // We have two code streams - one is used to convert each argument into a native type // and store that into the local. The other is used to load each previously generated local // and call the actual target native method. _emitter = new ILEmitter(); _marshallingCodeStream = _emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = _emitter.NewCodeStream(); _returnValueMarshallingCodeStream = _emitter.NewCodeStream(); TypeDesc[] nativeParameterTypes = new TypeDesc[targetMethodSignature.Length]; // // Parameter marshalling // // // Convert each argument to something we can pass to native and store it in a local. // Then load the local in the second code stream. // for (int i = 0; i < targetMethodSignature.Length; i++) { // TODO: throw if there's custom marshalling TypeDesc parameterType = targetMethodSignature[i]; _marshallingCodeStream.EmitLdArg(i); TypeDesc nativeType; if (parameterType.IsSzArray) { nativeType = EmitArrayMarshalling((ArrayType)parameterType); } else if (parameterType.IsByRef) { nativeType = EmitByRefMarshalling((ByRefType)parameterType); } else if (parameterType.IsString) { nativeType = EmitStringMarshalling(); } else if (parameterType.Category == TypeFlags.Boolean) { nativeType = EmitBooleanMarshalling(); } else { if (!IsBlittableType(parameterType)) throw new NotSupportedException(); nativeType = parameterType.UnderlyingType; } nativeParameterTypes[i] = nativeType; ILLocalVariable vMarshalledTypeTemp = _emitter.NewLocal(nativeType); _marshallingCodeStream.EmitStLoc(vMarshalledTypeTemp); callsiteSetupCodeStream.EmitLdLoc(vMarshalledTypeTemp); } // // Return value marshalling // // TODO: throw if SetLastError is true // TODO: throw if there's custom marshalling TypeDesc returnType = targetMethodSignature.ReturnType; TypeDesc nativeReturnType; if (returnType.IsVoid) { nativeReturnType = returnType; } else if (returnType.Category == TypeFlags.Boolean) { nativeReturnType = EmitBooleanReturnValueMarshalling(); } else { if (!IsBlittableType(returnType)) throw new NotSupportedException(); nativeReturnType = returnType; } MethodSignature nativeSig = new MethodSignature( targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, _importMetadata); // Call the native method callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); callsiteSetupCodeStream.Emit(ILOpcode.ret); return _emitter.Link(); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream argSetupStream = emitter.NewCodeStream(); ILCodeStream thisCallSiteSetupStream = emitter.NewCodeStream(); ILCodeStream staticCallSiteSetupStream = emitter.NewCodeStream(); // This function will look like // // !For each parameter to the method // !if (parameter is In Parameter) // localX is TypeOfParameterX& // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperIn(RuntimeTypeHandle) // stloc localX // !else // localX is TypeOfParameter // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperRef(RuntimeTypeHandle) // stloc localX // ldarg.2 // call DynamicInvokeArgSetupComplete(ref ArgSetupState) // *** Thiscall instruction stream starts here *** // ldarg.3 // Load targetIsThisCall // brfalse Not_this_call // ldarg.0 // Load this pointer // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType thiscall(TypeOfParameter1, ...) // !if ((ReturnType == void) // ldnull // !elif (ReturnType is pointer) // System.Reflection.Pointer.Box(ReturnType) // !else // box ReturnType // ret // *** Static call instruction stream starts here *** // Not_this_call: // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType (TypeOfParameter1, ...) // !if ((ReturnType == void) // ldnull // !elif (ReturnType is pointer) // System.Reflection.Pointer.Box(ReturnType) // !else // box ReturnType // ret ILCodeLabel lStaticCall = emitter.NewCodeLabel(); thisCallSiteSetupStream.EmitLdArg(3); // targetIsThisCall thisCallSiteSetupStream.Emit(ILOpcode.brfalse, lStaticCall); staticCallSiteSetupStream.EmitLabel(lStaticCall); thisCallSiteSetupStream.EmitLdArg(0); // thisPtr ILToken tokDynamicInvokeParamHelperRef = emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null)); ILToken tokDynamicInvokeParamHelperIn = emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null)); TypeDesc[] targetMethodSignature = new TypeDesc[_targetSignature.Length]; for (int paramIndex = 0; paramIndex < _targetSignature.Length; paramIndex++) { TypeDesc paramType = Context.GetSignatureVariable(paramIndex, true); DynamicInvokeMethodParameterKind paramKind = _targetSignature[paramIndex]; if (paramKind == DynamicInvokeMethodParameterKind.Pointer) { for (int i = 0; i < _targetSignature.GetNumberOfParameterPointerIndirections(paramIndex); i++) { paramType = paramType.MakePointerType(); } } ILToken tokParamType = emitter.NewToken(paramType); ILLocalVariable local = emitter.NewLocal(paramType.MakeByRefType()); thisCallSiteSetupStream.EmitLdLoc(local); staticCallSiteSetupStream.EmitLdLoc(local); argSetupStream.Emit(ILOpcode.ldtoken, tokParamType); if (paramKind == DynamicInvokeMethodParameterKind.Reference) { argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperRef); targetMethodSignature[paramIndex] = paramType.MakeByRefType(); } else { argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperIn); thisCallSiteSetupStream.Emit(ILOpcode.ldobj, tokParamType); staticCallSiteSetupStream.Emit(ILOpcode.ldobj, tokParamType); targetMethodSignature[paramIndex] = paramType; } argSetupStream.EmitStLoc(local); } argSetupStream.EmitLdArg(2); // argSetupState argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null))); thisCallSiteSetupStream.EmitLdArg(1); // methodToCall staticCallSiteSetupStream.EmitLdArg(1); // methodToCall DynamicInvokeMethodParameterKind returnKind = _targetSignature.ReturnType; TypeDesc returnType = returnKind != DynamicInvokeMethodParameterKind.None ? Context.GetSignatureVariable(_targetSignature.Length, true) : Context.GetWellKnownType(WellKnownType.Void); if (returnKind == DynamicInvokeMethodParameterKind.Pointer) { for (int i = 0; i < _targetSignature.GetNumerOfReturnTypePointerIndirections(); i++) { returnType = returnType.MakePointerType(); } } MethodSignature thisCallMethodSig = new MethodSignature(0, 0, returnType, targetMethodSignature); thisCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(thisCallMethodSig)); MethodSignature staticCallMethodSig = new MethodSignature(MethodSignatureFlags.Static, 0, returnType, targetMethodSignature); staticCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(staticCallMethodSig)); if (returnKind == DynamicInvokeMethodParameterKind.None) { thisCallSiteSetupStream.Emit(ILOpcode.ldnull); staticCallSiteSetupStream.Emit(ILOpcode.ldnull); } else if (returnKind == DynamicInvokeMethodParameterKind.Pointer) { thisCallSiteSetupStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnType)); staticCallSiteSetupStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnType)); MethodDesc getTypeFromHandleMethod = Context.SystemModule.GetKnownType("System", "Type").GetKnownMethod("GetTypeFromHandle", null); thisCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod)); staticCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod)); MethodDesc pointerBoxMethod = Context.SystemModule.GetKnownType("System.Reflection", "Pointer").GetKnownMethod("Box", null); thisCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod)); staticCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod)); } else { Debug.Assert(returnKind == DynamicInvokeMethodParameterKind.Value); ILToken tokReturnType = emitter.NewToken(returnType); thisCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType); staticCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType); } thisCallSiteSetupStream.Emit(ILOpcode.ret); staticCallSiteSetupStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream argSetupStream = emitter.NewCodeStream(); ILCodeStream callSiteSetupStream = emitter.NewCodeStream(); // This function will look like // // !For each parameter to the delegate // !if (parameter is In Parameter) // localX is TypeOfParameterX& // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperIn(RuntimeTypeHandle) // stloc localX // !else // localX is TypeOfParameter // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperRef(RuntimeTypeHandle) // stloc localX // ldarg.3 // call DynamicInvokeArgSetupComplete(ref ArgSetupState) // *** Second instruction stream starts here *** // ldarg.1 // Load this pointer // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType thiscall(TypeOfParameter1, ...) // !if ((ReturnType == void) // ldnull // !else if (ReturnType is a byref) // ldobj StripByRef(ReturnType) // box StripByRef(ReturnType) // !else // box ReturnType // ret callSiteSetupStream.EmitLdArg(1); MethodSignature delegateSignature = _delegateInfo.Signature; TypeDesc[] targetMethodParameters = new TypeDesc[delegateSignature.Length]; for (int paramIndex = 0; paramIndex < delegateSignature.Length; paramIndex++) { TypeDesc paramType = delegateSignature[paramIndex]; TypeDesc localType = paramType; targetMethodParameters[paramIndex] = paramType; if (localType.IsByRef) { // Strip ByRef localType = ((ByRefType)localType).ParameterType; } else { // Only if this is not a ByRef, convert the parameter type to something boxable. // Everything but pointer types are boxable. localType = ConvertToBoxableType(localType); } ILLocalVariable local = emitter.NewLocal(localType.MakeByRefType()); callSiteSetupStream.EmitLdLoc(local); argSetupStream.Emit(ILOpcode.ldtoken, emitter.NewToken(localType)); if (paramType.IsByRef) { argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null))); } else { argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null))); callSiteSetupStream.Emit(ILOpcode.ldobj, emitter.NewToken(paramType)); } argSetupStream.EmitStLoc(local); } argSetupStream.EmitLdArg(3); argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null))); callSiteSetupStream.EmitLdArg(2); MethodSignature targetMethodSig = new MethodSignature(0, 0, delegateSignature.ReturnType, targetMethodParameters); callSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(targetMethodSig)); if (delegateSignature.ReturnType.IsVoid) { callSiteSetupStream.Emit(ILOpcode.ldnull); } else if (delegateSignature.ReturnType.IsByRef) { TypeDesc targetType = ((ByRefType)delegateSignature.ReturnType).ParameterType; callSiteSetupStream.Emit(ILOpcode.ldobj, emitter.NewToken(targetType)); callSiteSetupStream.Emit(ILOpcode.box, emitter.NewToken(targetType)); } else { callSiteSetupStream.Emit(ILOpcode.box, emitter.NewToken(delegateSignature.ReturnType)); } callSiteSetupStream.Emit(ILOpcode.ret); return emitter.Link(this); }
internal ILCodeStream(ILEmitter emitter) { _instructions = Array.Empty <byte>(); _startOffsetForLinking = -1; _emitter = emitter; }
/// <summary> /// Generates a calli sequence that is aware of fat function pointers and can unwrap them into /// a function pointer + instantiation argument if necessary. /// </summary> public static void EmitTransformedCalli(ILEmitter emitter, ILCodeStream codestream, MethodSignature targetSignature) { TypeSystemContext context = targetSignature.ReturnType.Context; int thisPointerParamDelta = 0; if (!targetSignature.IsStatic) { thisPointerParamDelta = 1; } // Start by saving the pointer to call and all the args into locals ILLocalVariable vPointerToCall = emitter.NewLocal(context.GetWellKnownType(WellKnownType.IntPtr)); codestream.EmitStLoc(vPointerToCall); ILLocalVariable[] vParameters = new ILLocalVariable[targetSignature.Length + thisPointerParamDelta]; for (int i = thisPointerParamDelta; i < vParameters.Length; i++) { vParameters[vParameters.Length - i - 1 + thisPointerParamDelta] = emitter.NewLocal(targetSignature[targetSignature.Length - (i - thisPointerParamDelta) - 1]); codestream.EmitStLoc(vParameters[vParameters.Length - i - 1 + thisPointerParamDelta]); } if (!targetSignature.IsStatic) { vParameters[0] = emitter.NewLocal(context.GetWellKnownType(WellKnownType.Object)); codestream.EmitStLoc(vParameters[0]); } // Is this a fat pointer? codestream.EmitLdLoc(vPointerToCall); Debug.Assert(((FatFunctionPointerConstants.Offset - 1) & FatFunctionPointerConstants.Offset) == 0); codestream.EmitLdc(FatFunctionPointerConstants.Offset); codestream.Emit(ILOpcode.and); ILCodeLabel notAFatPointer = emitter.NewCodeLabel(); codestream.Emit(ILOpcode.brfalse, notAFatPointer); // // Fat pointer case // codestream.EmitLdLoc(vPointerToCall); codestream.EmitLdc(FatFunctionPointerConstants.Offset); codestream.Emit(ILOpcode.sub); // Get the pointer to call from the fat pointer codestream.Emit(ILOpcode.dup); codestream.Emit(ILOpcode.ldind_i); codestream.EmitStLoc(vPointerToCall); // Get the instantiation argument codestream.EmitLdc(context.Target.PointerSize); codestream.Emit(ILOpcode.add); codestream.Emit(ILOpcode.ldind_i); codestream.Emit(ILOpcode.ldind_i); ILLocalVariable instArg = emitter.NewLocal(context.GetWellKnownType(WellKnownType.IntPtr)); codestream.EmitStLoc(instArg); // Load this int firstRealParameter = 0; if (!targetSignature.IsStatic) { codestream.EmitLdLoc(vParameters[0]); firstRealParameter = 1; } // Load hidden arg codestream.EmitLdLoc(instArg); // Load rest of args for (int i = firstRealParameter; i < vParameters.Length; i++) { codestream.EmitLdLoc(vParameters[i]); } codestream.EmitLdLoc(vPointerToCall); // The signature has a hidden argument TypeDesc[] newParameters = new TypeDesc[targetSignature.Length + 1]; for (int i = 0; i < targetSignature.Length; i++) { newParameters[i + 1] = targetSignature[i]; } newParameters[0] = context.GetWellKnownType(WellKnownType.IntPtr); MethodSignature newMethodSignature = new MethodSignature(targetSignature.Flags, targetSignature.GenericParameterCount, targetSignature.ReturnType, newParameters); codestream.Emit(ILOpcode.calli, emitter.NewToken(newMethodSignature)); ILCodeLabel done = emitter.NewCodeLabel(); codestream.Emit(ILOpcode.br, done); // // Not a fat pointer case // codestream.EmitLabel(notAFatPointer); for (int i = 0; i < vParameters.Length; i++) { codestream.EmitLdLoc(vParameters[i]); } codestream.EmitLdLoc(vPointerToCall); codestream.Emit(ILOpcode.calli, emitter.NewToken(targetSignature)); codestream.EmitLabel(done); // Workaround for https://github.com/dotnet/corert/issues/2073 codestream.Emit(ILOpcode.nop); }
public static MethodIL EmitIL(MethodDesc methodThatShouldThrow, TypeSystemException exception) { TypeSystemContext context = methodThatShouldThrow.Context; MethodDesc helper; Type exceptionType = exception.GetType(); if (exceptionType == typeof(TypeSystemException.TypeLoadException)) { // // There are two ThrowTypeLoadException helpers. Find the one which matches the number of // arguments "exception" was initialized with. // helper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowTypeLoadException"); if (helper.Signature.Length != exception.Arguments.Count + 1) { helper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowTypeLoadExceptionWithArgument"); } } else if (exceptionType == typeof(TypeSystemException.MissingFieldException)) { helper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowMissingFieldException"); } else if (exceptionType == typeof(TypeSystemException.MissingMethodException)) { helper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowMissingMethodException"); } else if (exceptionType == typeof(TypeSystemException.FileNotFoundException)) { helper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowFileNotFoundException"); } else if (exceptionType == typeof(TypeSystemException.InvalidProgramException)) { // // There are two ThrowInvalidProgramException helpers. Find the one which matches the number of // arguments "exception" was initialized with. // helper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowInvalidProgramException"); if (helper.Signature.Length != exception.Arguments.Count + 1) { helper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowInvalidProgramExceptionWithArgument"); } } else if (exceptionType == typeof(TypeSystemException.BadImageFormatException)) { helper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowBadImageFormatException"); } else { throw new NotImplementedException(); } Debug.Assert(helper.Signature.Length == exception.Arguments.Count + 1); var emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); var infinityLabel = emitter.NewCodeLabel(); codeStream.EmitLabel(infinityLabel); codeStream.EmitLdc((int)exception.StringID); foreach (var arg in exception.Arguments) { codeStream.Emit(ILOpcode.ldstr, emitter.NewToken(arg)); } codeStream.Emit(ILOpcode.call, emitter.NewToken(helper)); // The call will never return, but we still need to emit something. Emit a jump so that // we don't have to bother balancing the stack if the method returns something. codeStream.Emit(ILOpcode.br, infinityLabel); return(emitter.Link(methodThatShouldThrow)); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); ILCodeLabel returnNullLabel = emitter.NewCodeLabel(); bool hasDynamicInvokeThunk = (_delegateInfo.SupportedFeatures & DelegateFeature.DynamicInvoke) != 0 && DynamicInvokeMethodThunk.SupportsSignature(_delegateInfo.Signature); ILCodeLabel[] labels = new ILCodeLabel[(int)DelegateThunkCollection.MaxThunkKind]; for (DelegateThunkKind i = 0; i < DelegateThunkCollection.MaxThunkKind; i++) { MethodDesc thunk = _delegateInfo.Thunks[i]; if (thunk != null || (i == DelegateThunkKind.DelegateInvokeThunk && hasDynamicInvokeThunk)) { labels[(int)i] = emitter.NewCodeLabel(); } else { labels[(int)i] = returnNullLabel; } } codeStream.EmitLdArg(1); codeStream.EmitSwitch(labels); codeStream.Emit(ILOpcode.br, returnNullLabel); for (DelegateThunkKind i = 0; i < DelegateThunkCollection.MaxThunkKind; i++) { MethodDesc targetMethod = null; // Dynamic invoke thunk is special since we're calling into a shared helper if (i == DelegateThunkKind.DelegateInvokeThunk && hasDynamicInvokeThunk) { Debug.Assert(_delegateInfo.Thunks[i] == null); var sig = new DynamicInvokeMethodSignature(_delegateInfo.Signature); MethodDesc thunk = Context.GetDynamicInvokeThunk(sig); if (thunk.HasInstantiation) { TypeDesc[] inst = DynamicInvokeMethodThunk.GetThunkInstantiationForMethod(_delegateInfo.Type.InstantiateAsOpen().GetMethod("Invoke", null)); targetMethod = Context.GetInstantiatedMethod(thunk, new Instantiation(inst)); } else { targetMethod = thunk; } } else { MethodDesc thunk = _delegateInfo.Thunks[i]; if (thunk != null) { targetMethod = thunk.InstantiateAsOpen(); } } if (targetMethod != null) { codeStream.EmitLabel(labels[(int)i]); codeStream.Emit(ILOpcode.ldftn, emitter.NewToken(targetMethod)); codeStream.Emit(ILOpcode.ret); } } codeStream.EmitLabel(returnNullLabel); codeStream.EmitLdc(0); codeStream.Emit(ILOpcode.conv_i); codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public static MethodIL EmitIL(MethodDesc method) { if (!RequiresMarshalling(method)) return null; try { return new PInvokeMarshallingILEmitter(method).EmitIL(); } catch (NotSupportedException) { ILEmitter emitter = new ILEmitter(); string message = "Method '" + method.ToString() + "' requires non-trivial marshalling that is not yet supported by this compiler."; TypeSystemContext context = method.Context; MethodSignature ctorSignature = new MethodSignature(0, 0, context.GetWellKnownType(WellKnownType.Void), new TypeDesc[] { context.GetWellKnownType(WellKnownType.String) }); MethodDesc exceptionCtor = method.Context.GetWellKnownType(WellKnownType.Exception).GetKnownMethod(".ctor", ctorSignature); ILCodeStream codeStream = emitter.NewCodeStream(); codeStream.Emit(ILOpcode.ldstr, emitter.NewToken(message)); codeStream.Emit(ILOpcode.newobj, emitter.NewToken(exceptionCtor)); codeStream.Emit(ILOpcode.throw_); codeStream.Emit(ILOpcode.ret); return emitter.Link(); } }
public override MethodIL EmitIL() { // Target has the same signature as the Invoke method, except it's static. MethodSignatureBuilder builder = new MethodSignatureBuilder(Signature); builder.Flags = Signature.Flags | MethodSignatureFlags.Static; var emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); // Load all arguments except 'this' for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } // Indirectly call the delegate target static method. codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(ExtraFunctionPointerOrDataField)); codeStream.Emit(ILOpcode.calli, emitter.NewToken(builder.ToSignature())); codeStream.Emit(ILOpcode.ret); return emitter.Link(this); }
private MethodIL EmitMarshallingIL(PInvokeILCodeStreams pInvokeILCodeStreams) { Marshaller[] marshallers = InitializeMarshallers(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; IEnumerator <FieldDesc> nativeEnumerator = NativeType.GetFields().GetEnumerator(); int index = 0; foreach (var managedField in ManagedType.GetFields()) { if (managedField.IsStatic) { continue; } bool notEmpty = nativeEnumerator.MoveNext(); Debug.Assert(notEmpty == true); var nativeField = nativeEnumerator.Current; Debug.Assert(nativeField != null); bool isInlineArray = nativeField.FieldType is InlineArrayType; // // Field marshallers expects the value of the fields to be // loaded on the stack. We load the value on the stack // before calling the marshallers. // Only exception is ByValArray marshallers. Since they can // only be used for field marshalling, they load/store values // directly from arguments. // if (isInlineArray) { var byValMarshaller = marshallers[index++] as ByValArrayMarshaller; Debug.Assert(byValMarshaller != null); byValMarshaller.EmitMarshallingIL(pInvokeILCodeStreams, managedField, nativeField); } else { if (ThunkType == StructMarshallingThunkType.ManagedToNative) { LoadFieldValueFromArg(0, managedField, pInvokeILCodeStreams); } else if (ThunkType == StructMarshallingThunkType.NativeToManaged) { LoadFieldValueFromArg(0, nativeField, pInvokeILCodeStreams); } marshallers[index++].EmitMarshallingIL(pInvokeILCodeStreams); if (ThunkType == StructMarshallingThunkType.ManagedToNative) { StoreFieldValueFromArg(1, nativeField, pInvokeILCodeStreams); } else if (ThunkType == StructMarshallingThunkType.NativeToManaged) { StoreFieldValueFromArg(1, managedField, pInvokeILCodeStreams); } } } Debug.Assert(!nativeEnumerator.MoveNext()); pInvokeILCodeStreams.UnmarshallingCodestream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public override MethodIL EmitIL() { TypeDesc[] targetMethodParameters = new TypeDesc[Signature.Length + 1]; targetMethodParameters[0] = Context.GetWellKnownType(WellKnownType.Object); for (int i = 0; i < Signature.Length; i++) { targetMethodParameters[i + 1] = Signature[i]; } var targetMethodSignature = new MethodSignature( Signature.Flags | MethodSignatureFlags.Static, 0, Signature.ReturnType, targetMethodParameters); var emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); // Load the stored 'this' codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField)); // Load all arguments except 'this' for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } // Indirectly call the delegate target static method. codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(ExtraFunctionPointerOrDataField)); codeStream.Emit(ILOpcode.calli, emitter.NewToken(targetMethodSignature)); codeStream.Emit(ILOpcode.ret); return emitter.Link(this); }
private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams) { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream fnptrLoadStream = ilCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeSystemContext context = _targetMethod.Context; TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null))); } for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } if (MarshalHelpers.UseLazyResolution(_targetMethod, _importMetadata.Module, _pInvokeILEmitterConfiguration)) { MetadataType lazyHelperType = context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = _interopStateManager.GetPInvokeLazyFixupField(_targetMethod); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType .GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = _flags.UnmanagedCallingConvention; MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(context .GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); } else { // Eager call MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod)); } // if the SetLastError flag is set in DllImport, call the PInvokeMarshal. // SaveLastWin32Error so that last error can be used later by calling // PInvokeMarshal.GetLastWin32Error if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context) .GetKnownMethod("SaveLastWin32Error", null))); } }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); ArrayType invocationListArrayType = SystemDelegateType.MakeArrayType(); ILLocalVariable delegateArrayLocal = emitter.NewLocal(invocationListArrayType); ILLocalVariable invocationCountLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable iteratorLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable delegateToCallLocal = emitter.NewLocal(SystemDelegateType); ILLocalVariable returnValueLocal = 0; if (Signature.ReturnType is SignatureVariable || !Signature.ReturnType.IsVoid) { returnValueLocal = emitter.NewLocal(Signature.ReturnType); } // Fill in delegateArrayLocal // Delegate[] delegateArrayLocal = (Delegate[])this.m_helperObject // ldarg.0 (this pointer) // ldfld Delegate.HelperObjectField // castclass Delegate[] // stloc delegateArrayLocal codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField)); codeStream.Emit(ILOpcode.castclass, emitter.NewToken(invocationListArrayType)); codeStream.EmitStLoc(delegateArrayLocal); // Fill in invocationCountLocal // int invocationCountLocal = this.m_extraFunctionPointerOrData // ldarg.0 (this pointer) // ldfld Delegate.m_extraFunctionPointerOrData // stloc invocationCountLocal codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(ExtraFunctionPointerOrDataField)); codeStream.EmitStLoc(invocationCountLocal); // Fill in iteratorLocal // int iteratorLocal = 0; // ldc.0 // stloc iteratorLocal codeStream.EmitLdc(0); codeStream.EmitStLoc(iteratorLocal); // Loop across every element of the array. ILCodeLabel startOfLoopLabel = emitter.NewCodeLabel(); codeStream.EmitLabel(startOfLoopLabel); // Implement as do/while loop. We only have this stub in play if we're in the multicast situation // Find the delegate to call // Delegate = delegateToCallLocal = delegateArrayLocal[iteratorLocal]; // ldloc delegateArrayLocal // ldloc iteratorLocal // ldelem System.Delegate // stloc delegateToCallLocal codeStream.EmitLdLoc(delegateArrayLocal); codeStream.EmitLdLoc(iteratorLocal); codeStream.Emit(ILOpcode.ldelem, emitter.NewToken(SystemDelegateType)); codeStream.EmitStLoc(delegateToCallLocal); // Call the delegate // returnValueLocal = delegateToCallLocal(...); // ldloc delegateToCallLocal // ldfld System.Delegate.m_firstParameter // ldarg 1, n // ldloc delegateToCallLocal // ldfld System.Delegate.m_functionPointer // calli returnValueType thiscall (all the params) // IF there is a return value // stloc returnValueLocal codeStream.EmitLdLoc(delegateToCallLocal); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FirstParameterField)); for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } codeStream.EmitLdLoc(delegateToCallLocal); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FunctionPointerField)); codeStream.Emit(ILOpcode.calli, emitter.NewToken(Signature)); if (returnValueLocal != 0) codeStream.EmitStLoc(returnValueLocal); // Increment iteratorLocal // ++iteratorLocal; // ldloc iteratorLocal // ldc.i4.1 // add // stloc iteratorLocal codeStream.EmitLdLoc(iteratorLocal); codeStream.EmitLdc(1); codeStream.Emit(ILOpcode.add); codeStream.EmitStLoc(iteratorLocal); // Check to see if the loop is done codeStream.EmitLdLoc(invocationCountLocal); codeStream.EmitLdLoc(iteratorLocal); codeStream.Emit(ILOpcode.bne_un, startOfLoopLabel); // Return to caller. If the delegate has a return value, be certain to return that. // return returnValueLocal; // ldloc returnValueLocal // ret if (returnValueLocal != 0) codeStream.EmitLdLoc(returnValueLocal); codeStream.Emit(ILOpcode.ret); return emitter.Link(this); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); ArrayType invocationListArrayType = SystemDelegateType.MakeArrayType(); ILLocalVariable delegateArrayLocal = emitter.NewLocal(invocationListArrayType); ILLocalVariable invocationCountLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable iteratorLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable delegateToCallLocal = emitter.NewLocal(SystemDelegateType); ILLocalVariable returnValueLocal = 0; if (!Signature.ReturnType.IsVoid) { returnValueLocal = emitter.NewLocal(Signature.ReturnType); } // Fill in delegateArrayLocal // Delegate[] delegateArrayLocal = (Delegate[])this.m_helperObject // ldarg.0 (this pointer) // ldfld Delegate.HelperObjectField // castclass Delegate[] // stloc delegateArrayLocal codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField)); codeStream.Emit(ILOpcode.castclass, emitter.NewToken(invocationListArrayType)); codeStream.EmitStLoc(delegateArrayLocal); // Fill in invocationCountLocal // int invocationCountLocal = this.m_extraFunctionPointerOrData // ldarg.0 (this pointer) // ldfld Delegate.m_extraFunctionPointerOrData // stloc invocationCountLocal codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(ExtraFunctionPointerOrDataField)); codeStream.EmitStLoc(invocationCountLocal); // Fill in iteratorLocal // int iteratorLocal = 0; // ldc.0 // stloc iteratorLocal codeStream.EmitLdc(0); codeStream.EmitStLoc(iteratorLocal); // Loop across every element of the array. ILCodeLabel startOfLoopLabel = emitter.NewCodeLabel(); codeStream.EmitLabel(startOfLoopLabel); // Implement as do/while loop. We only have this stub in play if we're in the multicast situation // Find the delegate to call // Delegate = delegateToCallLocal = delegateArrayLocal[iteratorLocal]; // ldloc delegateArrayLocal // ldloc iteratorLocal // ldelem System.Delegate // stloc delegateToCallLocal codeStream.EmitLdLoc(delegateArrayLocal); codeStream.EmitLdLoc(iteratorLocal); codeStream.Emit(ILOpcode.ldelem, emitter.NewToken(SystemDelegateType)); codeStream.EmitStLoc(delegateToCallLocal); // Call the delegate // returnValueLocal = delegateToCallLocal(...); // ldloc delegateToCallLocal // ldfld System.Delegate.m_firstParameter // ldarg 1, n // ldloc delegateToCallLocal // ldfld System.Delegate.m_functionPointer // calli returnValueType thiscall (all the params) // IF there is a return value // stloc returnValueLocal codeStream.EmitLdLoc(delegateToCallLocal); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FirstParameterField)); for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } codeStream.EmitLdLoc(delegateToCallLocal); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FunctionPointerField)); codeStream.Emit(ILOpcode.calli, emitter.NewToken(Signature)); if (returnValueLocal != 0) { codeStream.EmitStLoc(returnValueLocal); } // Increment iteratorLocal // ++iteratorLocal; // ldloc iteratorLocal // ldc.i4.1 // add // stloc iteratorLocal codeStream.EmitLdLoc(iteratorLocal); codeStream.EmitLdc(1); codeStream.Emit(ILOpcode.add); codeStream.EmitStLoc(iteratorLocal); // Check to see if the loop is done codeStream.EmitLdLoc(invocationCountLocal); codeStream.EmitLdLoc(iteratorLocal); codeStream.Emit(ILOpcode.bne_un, startOfLoopLabel); // Return to caller. If the delegate has a return value, be certain to return that. // return returnValueLocal; // ldloc returnValueLocal // ret if (returnValueLocal != 0) { codeStream.EmitLdLoc(returnValueLocal); } codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public override MethodIL EmitIL() { const DelegateThunkKind maxThunkKind = DelegateThunkKind.ObjectArrayThunk; ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); ILCodeLabel returnNullLabel = emitter.NewCodeLabel(); ILCodeLabel[] labels = new ILCodeLabel[(int)maxThunkKind]; for (DelegateThunkKind i = 0; i < maxThunkKind; i++) { MethodDesc thunk = _delegateInfo.Thunks[i]; if (thunk != null) labels[(int)i] = emitter.NewCodeLabel(); else labels[(int)i] = returnNullLabel; } codeStream.EmitLdArg(1); codeStream.EmitSwitch(labels); codeStream.Emit(ILOpcode.br, returnNullLabel); for (DelegateThunkKind i = 0; i < maxThunkKind; i++) { MethodDesc thunk = _delegateInfo.Thunks[i]; if (thunk != null) { codeStream.EmitLabel(labels[(int)i]); codeStream.Emit(ILOpcode.ldftn, emitter.NewToken(thunk.InstantiateAsOpen())); codeStream.Emit(ILOpcode.ret); } } codeStream.EmitLabel(returnNullLabel); codeStream.EmitLdc(0); codeStream.Emit(ILOpcode.conv_i); codeStream.Emit(ILOpcode.ret); return emitter.Link(this); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream argSetupStream = emitter.NewCodeStream(); ILCodeStream callSiteSetupStream = emitter.NewCodeStream(); // This function will look like // // !For each parameter to the delegate // !if (parameter is In Parameter) // localX is TypeOfParameterX& // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperIn(RuntimeTypeHandle) // stloc localX // !else // localX is TypeOfParameter // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperRef(RuntimeTypeHandle) // stloc localX // ldarg.3 // call DynamicInvokeArgSetupComplete(ref ArgSetupState) // *** Second instruction stream starts here *** // ldarg.1 // Load this pointer // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType thiscall(TypeOfParameter1, ...) // !if ((ReturnType == void) // ldnull // !else if (ReturnType is a byref) // ldobj StripByRef(ReturnType) // box StripByRef(ReturnType) // !else // box ReturnType // ret callSiteSetupStream.EmitLdArg(1); MethodSignature delegateSignature = _delegateInfo.Signature; TypeDesc[] targetMethodParameters = new TypeDesc[delegateSignature.Length]; for (int paramIndex = 0; paramIndex < delegateSignature.Length; paramIndex++) { TypeDesc paramType = delegateSignature[paramIndex]; TypeDesc localType = paramType; targetMethodParameters[paramIndex] = paramType; if (localType.IsByRef) { // Strip ByRef localType = ((ByRefType)localType).ParameterType; } else { // Only if this is not a ByRef, convert the parameter type to something boxable. // Everything but pointer types are boxable. localType = ConvertToBoxableType(localType); } ILLocalVariable local = emitter.NewLocal(localType.MakeByRefType()); callSiteSetupStream.EmitLdLoc(local); argSetupStream.Emit(ILOpcode.ldtoken, emitter.NewToken(localType)); if (paramType.IsByRef) { argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null))); } else { argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null))); callSiteSetupStream.Emit(ILOpcode.ldobj, emitter.NewToken(paramType)); } argSetupStream.EmitStLoc(local); } argSetupStream.EmitLdArg(3); argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null))); callSiteSetupStream.EmitLdArg(2); MethodSignature targetMethodSig = new MethodSignature(0, 0, delegateSignature.ReturnType, targetMethodParameters); callSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(targetMethodSig)); if (delegateSignature.ReturnType.IsVoid) { callSiteSetupStream.Emit(ILOpcode.ldnull); } else if (delegateSignature.ReturnType.IsByRef) { TypeDesc targetType = ((ByRefType)delegateSignature.ReturnType).ParameterType; callSiteSetupStream.Emit(ILOpcode.ldobj, emitter.NewToken(targetType)); callSiteSetupStream.Emit(ILOpcode.box, emitter.NewToken(targetType)); } else { callSiteSetupStream.Emit(ILOpcode.box, emitter.NewToken(delegateSignature.ReturnType)); } callSiteSetupStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
/// <summary> /// Generates a calli sequence that is aware of fat function pointers and can unwrap them into /// a function pointer + instantiation argument if necessary. /// </summary> public static void EmitTransformedCalli(ILEmitter emitter, ILCodeStream codestream, MethodSignature targetSignature) { TypeSystemContext context = targetSignature.ReturnType.Context; int thisPointerParamDelta = 0; if (!targetSignature.IsStatic) thisPointerParamDelta = 1; // Start by saving the pointer to call and all the args into locals ILLocalVariable vPointerToCall = emitter.NewLocal(context.GetWellKnownType(WellKnownType.IntPtr)); codestream.EmitStLoc(vPointerToCall); ILLocalVariable[] vParameters = new ILLocalVariable[targetSignature.Length + thisPointerParamDelta]; for (int i = thisPointerParamDelta; i < vParameters.Length; i++) { vParameters[vParameters.Length - i - 1 + thisPointerParamDelta] = emitter.NewLocal(targetSignature[targetSignature.Length - (i - thisPointerParamDelta) - 1]); codestream.EmitStLoc(vParameters[vParameters.Length - i - 1 + thisPointerParamDelta]); } if (!targetSignature.IsStatic) { vParameters[0] = emitter.NewLocal(context.GetWellKnownType(WellKnownType.Object)); codestream.EmitStLoc(vParameters[0]); } // Is this a fat pointer? codestream.EmitLdLoc(vPointerToCall); Debug.Assert(((FatFunctionPointerConstants.Offset - 1) & FatFunctionPointerConstants.Offset) == 0); codestream.EmitLdc(FatFunctionPointerConstants.Offset); codestream.Emit(ILOpcode.and); ILCodeLabel notAFatPointer = emitter.NewCodeLabel(); codestream.Emit(ILOpcode.brfalse, notAFatPointer); // // Fat pointer case // codestream.EmitLdLoc(vPointerToCall); codestream.EmitLdc(FatFunctionPointerConstants.Offset); codestream.Emit(ILOpcode.sub); // Get the pointer to call from the fat pointer codestream.Emit(ILOpcode.dup); codestream.Emit(ILOpcode.ldind_i); codestream.EmitStLoc(vPointerToCall); // Get the instantiation argument codestream.EmitLdc(context.Target.PointerSize); codestream.Emit(ILOpcode.add); codestream.Emit(ILOpcode.ldind_i); codestream.Emit(ILOpcode.ldind_i); ILLocalVariable instArg = emitter.NewLocal(context.GetWellKnownType(WellKnownType.IntPtr)); codestream.EmitStLoc(instArg); // Load this int firstRealParameter = 0; if (!targetSignature.IsStatic) { codestream.EmitLdLoc(vParameters[0]); firstRealParameter = 1; } // Load hidden arg codestream.EmitLdLoc(instArg); // Load rest of args for (int i = firstRealParameter; i < vParameters.Length; i++) { codestream.EmitLdLoc(vParameters[i]); } codestream.EmitLdLoc(vPointerToCall); // The signature has a hidden argument TypeDesc[] newParameters = new TypeDesc[targetSignature.Length + 1]; for (int i = 0; i < targetSignature.Length; i++) newParameters[i + 1] = targetSignature[i]; newParameters[0] = context.GetWellKnownType(WellKnownType.IntPtr); MethodSignature newMethodSignature = new MethodSignature(targetSignature.Flags, targetSignature.GenericParameterCount, targetSignature.ReturnType, newParameters); codestream.Emit(ILOpcode.calli, emitter.NewToken(newMethodSignature)); ILCodeLabel done = emitter.NewCodeLabel(); codestream.Emit(ILOpcode.br, done); // // Not a fat pointer case // codestream.EmitLabel(notAFatPointer); for (int i = 0; i < vParameters.Length; i++) { codestream.EmitLdLoc(vParameters[i]); } codestream.EmitLdLoc(vPointerToCall); codestream.Emit(ILOpcode.calli, emitter.NewToken(targetSignature)); codestream.EmitLabel(done); }