protected override void AllocManagedToNative(ILCodeStream codeStream) { ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeLabel lNull = emitter.NewCodeLabel(); ILLocalVariable lSize = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); LoadManagedValue(codeStream); codeStream.Emit(ILOpcode.brfalse, lNull); MethodDesc getNativeSizeHelper = Context.GetHelperEntryPoint("InteropHelpers", "AsAnyGetNativeSize"); LoadManagedValue(codeStream); codeStream.Emit(ILOpcode.call, emitter.NewToken(getNativeSizeHelper)); codeStream.Emit(ILOpcode.dup); codeStream.EmitStLoc(lSize); codeStream.Emit(ILOpcode.localloc); codeStream.Emit(ILOpcode.dup); StoreNativeValue(codeStream); codeStream.EmitLdc(0); codeStream.EmitLdLoc(lSize); codeStream.Emit(ILOpcode.initblk); codeStream.EmitLabel(lNull); }
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)); MethodDesc setLatchedExitCode = startup.GetMethod("SetLatchedExitCode", null); MethodDesc shutdown = startup.GetMethod("Shutdown", null); // The class library either supports "advanced shutdown", or doesn't. No half-implementations allowed. Debug.Assert((setLatchedExitCode != null) == (shutdown != null)); if (setLatchedExitCode != null) { // If the main method has a return value, save it if (!_mainMethod.Signature.ReturnType.IsVoid) { codeStream.Emit(ILOpcode.call, emitter.NewToken(setLatchedExitCode)); } // Ask the class library to shut down and return exit code. codeStream.Emit(ILOpcode.call, emitter.NewToken(shutdown)); } else { // This is a class library that doesn't have SetLatchedExitCode/Shutdown. // If the main method returns void, we simply use 0 exit code. if (_mainMethod.Signature.ReturnType.IsVoid) { codeStream.EmitLdc(0); } } codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); codeStream.MarkDebuggerStepThroughPoint(); // Allow the class library to run explicitly ordered class constructors first thing in start-up. if (_libraryInitializers != null) { foreach (MethodDesc method in _libraryInitializers) { codeStream.Emit(ILOpcode.call, emitter.NewToken(method)); } } 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)); } // Initialize the entrypoint assembly if the class library supports this MethodDesc initEntryAssembly = startup.GetMethod("InitializeEntryAssembly", null); if (initEntryAssembly != null) { ModuleDesc entrypointModule = ((MetadataType)_mainMethod.WrappedMethod.OwningType).Module; codeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(entrypointModule.GetGlobalModuleType())); codeStream.Emit(ILOpcode.call, emitter.NewToken(initEntryAssembly)); } // 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.MarkDebuggerStepInPoint(); codeStream.Emit(ILOpcode.call, emitter.NewToken(_mainMethod)); MethodDesc setLatchedExitCode = startup.GetMethod("SetLatchedExitCode", null); MethodDesc shutdown = startup.GetMethod("Shutdown", null); // The class library either supports "advanced shutdown", or doesn't. No half-implementations allowed. Debug.Assert((setLatchedExitCode != null) == (shutdown != null)); if (setLatchedExitCode != null) { // If the main method has a return value, save it if (!_mainMethod.Signature.ReturnType.IsVoid) { codeStream.Emit(ILOpcode.call, emitter.NewToken(setLatchedExitCode)); } // Ask the class library to shut down and return exit code. codeStream.Emit(ILOpcode.call, emitter.NewToken(shutdown)); } else { // This is a class library that doesn't have SetLatchedExitCode/Shutdown. // If the main method returns void, we simply use 0 exit code. if (_mainMethod.Signature.ReturnType.IsVoid) { codeStream.EmitLdc(0); } } codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
protected override void EmitMarshalFieldNativeToManaged() { ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeStream codeStream = _ilCodeStreams.UnmarshallingCodestream; // It generates the following IL: // ManagedArg.s = new ElementType[Length]; // // for (uint index = 0u; index < Length; index += 1u) // { // ManagedArg.s[index] = NativeArg.s[index]; // } // ILCodeLabel lRangeCheck = emitter.NewCodeLabel(); ILCodeLabel lLoopHeader = emitter.NewCodeLabel(); Debug.Assert(ManagedType is ArrayType); var nativeArrayType = NativeType as InlineArrayType; Debug.Assert(nativeArrayType != null); var managedElementType = ((ArrayType)ManagedType).ElementType; ILLocalVariable vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); codeStream.EmitLdArg(1); // load the length EmitElementCount(codeStream, MarshalDirection.Reverse); codeStream.EmitStLoc(vLength); codeStream.EmitLdLoc(vLength); codeStream.Emit(ILOpcode.newarr, emitter.NewToken(managedElementType)); codeStream.Emit(ILOpcode.stfld, emitter.NewToken(_managedField)); var vIndex = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); // index = 0 codeStream.EmitLdc(0); codeStream.EmitStLoc(vIndex); codeStream.Emit(ILOpcode.br, lRangeCheck); codeStream.EmitLabel(lLoopHeader); // load managed type codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(_managedField)); codeStream.EmitLdLoc(vIndex); // load native type codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldflda, emitter.NewToken(_nativeField)); codeStream.EmitLdLoc(vIndex); codeStream.Emit(ILOpcode.call, emitter.NewToken( nativeArrayType.GetInlineArrayMethod(InlineArrayMethodKind.Getter))); // generate marshalling IL for the element GetElementMarshaller(MarshalDirection.Reverse) .EmitMarshallingIL(new PInvokeILCodeStreams(_ilCodeStreams.Emitter, codeStream)); codeStream.EmitStElem(managedElementType); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdc(1); codeStream.Emit(ILOpcode.add); codeStream.EmitStLoc(vIndex); codeStream.EmitLabel(lRangeCheck); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdLoc(vLength); codeStream.Emit(ILOpcode.blt, lLoopHeader); }
protected override void EmitMarshalFieldManagedToNative() { // It generates the following code //if (ManagedArg.Field != null) //{ // // fixed (InlineArray* pUnsafe = &NativeArg.Field) // { // uint index = 0u; // while ((ulong)index < (ulong)((long)ManagedArg.Field.Length)) // { // NativeArg.s[index] = ManagedArg.Field[(int)index]; // index += 1u; // } // } //} ILEmitter emitter = _ilCodeStreams.Emitter; ILCodeStream codeStream = _ilCodeStreams.MarshallingCodeStream; var nativeArrayType = NativeType as InlineArrayType; Debug.Assert(nativeArrayType != null); Debug.Assert(ManagedType is ArrayType); var managedElementType = ((ArrayType)ManagedType).ElementType; ILCodeLabel lDone = emitter.NewCodeLabel(); ILCodeLabel lRangeCheck = emitter.NewCodeLabel(); ILCodeLabel lLoopHeader = emitter.NewCodeLabel(); ILLocalVariable vIndex = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable vLength = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable vNative = emitter.NewLocal(NativeType.MakeByRefType(), isPinned: true); // check if ManagedType == null, then return codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(_managedField)); codeStream.Emit(ILOpcode.brfalse, lDone); codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.ldflda, emitter.NewToken(_nativeField)); codeStream.EmitStLoc(vNative); EmitElementCount(codeStream, MarshalDirection.Forward); codeStream.EmitStLoc(vLength); codeStream.EmitLdc(0); codeStream.EmitStLoc(vIndex); codeStream.Emit(ILOpcode.br, lRangeCheck); codeStream.EmitLabel(lLoopHeader); codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.ldflda, emitter.NewToken(_nativeField)); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(_managedField)); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdElem(managedElementType); // generate marshalling IL for the element GetElementMarshaller(MarshalDirection.Forward) .EmitMarshallingIL(new PInvokeILCodeStreams(_ilCodeStreams.Emitter, codeStream)); codeStream.Emit(ILOpcode.call, emitter.NewToken( nativeArrayType.GetInlineArrayMethod(InlineArrayMethodKind.Setter))); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdc(1); codeStream.Emit(ILOpcode.add); codeStream.EmitStLoc(vIndex); codeStream.EmitLabel(lRangeCheck); codeStream.EmitLdLoc(vIndex); codeStream.EmitLdLoc(vLength); codeStream.Emit(ILOpcode.blt, lLoopHeader); codeStream.EmitLabel(lDone); }
/// <summary> /// Generates IL for the IsSupported property that reads this information from a field initialized by the runtime /// at startup. Returns null for hardware intrinsics whose support level is known at compile time /// (i.e. they're known to be always supported or always unsupported). /// </summary> public static MethodIL EmitIsSupportedIL(MethodDesc method, FieldDesc isSupportedField) { Debug.Assert(IsIsSupportedMethod(method)); Debug.Assert(isSupportedField.IsStatic && isSupportedField.FieldType.IsWellKnownType(WellKnownType.Int32)); TargetDetails target = method.Context.Target; MetadataType owningType = (MetadataType)method.OwningType; // Check for case of nested "X64" types if (owningType.Name == "X64") { if (target.Architecture != TargetArchitecture.X64) { return(null); } // Un-nest the type so that we can do a name match owningType = (MetadataType)owningType.ContainingType; } int flag; if ((target.Architecture == TargetArchitecture.X64 || target.Architecture == TargetArchitecture.X86) && owningType.Namespace == "System.Runtime.Intrinsics.X86") { switch (owningType.Name) { case "Aes": flag = XArchIntrinsicConstants.Aes; break; case "Pclmulqdq": flag = XArchIntrinsicConstants.Pclmulqdq; break; case "Sse3": flag = XArchIntrinsicConstants.Sse3; break; case "Ssse3": flag = XArchIntrinsicConstants.Ssse3; break; case "Lzcnt": flag = XArchIntrinsicConstants.Lzcnt; break; // NOTE: this switch is complemented by IsKnownSupportedIntrinsicAtCompileTime // in the method below. default: return(null); } } else { return(null); } var emit = new ILEmitter(); ILCodeStream codeStream = emit.NewCodeStream(); codeStream.Emit(ILOpcode.ldsfld, emit.NewToken(isSupportedField)); codeStream.EmitLdc(flag); codeStream.Emit(ILOpcode.and); codeStream.EmitLdc(0); codeStream.Emit(ILOpcode.cgt_un); codeStream.Emit(ILOpcode.ret); return(emit.Link(method)); }