Skip to content

Implement MethodImplOptions.AggressiveInlining flag - fixes #1637 #3154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/absil/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,7 @@ type ILMethodBody =
{ IsZeroInit: bool;
MaxStack: int32;
NoInlining: bool;
AggressiveInlining: bool;
Locals: ILLocals;
Code: ILCode;
SourceMarker: ILSourceMarker option }
Expand Down Expand Up @@ -1374,6 +1375,7 @@ type ILMethodDef =
IsPreserveSig: bool;
IsMustRun: bool;
IsNoInline: bool;
IsAggressiveInline : bool
GenericParams: ILGenericParameterDefs;
CustomAttrs: ILAttributes; }
member x.ParameterTypes = typesOfILParams x.Parameters
Expand Down Expand Up @@ -2279,6 +2281,7 @@ let mkILMethodBody (zeroinit,locals,maxstack,code,tag) : ILMethodBody =
{ IsZeroInit=zeroinit
MaxStack=maxstack
NoInlining=false
AggressiveInlining=false
Locals= locals
Code= code
SourceMarker=tag }
Expand Down Expand Up @@ -2314,6 +2317,7 @@ let mkILCtor (access,args,impl) =
IsUnmanagedExport=false;
IsSynchronized=false;
IsNoInline=false;
IsAggressiveInline=false
IsMustRun=false;
IsPreserveSig=false;
CustomAttrs = emptyILCustomAttrs; }
Expand Down Expand Up @@ -2367,6 +2371,7 @@ let mkILStaticMethod (genparams,nm,access,args,ret,impl) =
IsUnmanagedExport=false;
IsSynchronized=false;
IsNoInline=false;
IsAggressiveInline=false;
IsMustRun=false;
IsPreserveSig=false; }

Expand Down Expand Up @@ -2396,6 +2401,7 @@ let mkILClassCtor impl =
IsUnmanagedExport=false;
IsSynchronized=false;
IsNoInline=false;
IsAggressiveInline=false
IsMustRun=false;
IsPreserveSig=false; }

Expand Down Expand Up @@ -2436,6 +2442,7 @@ let mkILGenericVirtualMethod (nm,access,genparams,actual_args,actual_ret,impl) =
IsUnmanagedExport=false;
IsSynchronized=false;
IsNoInline=false;
IsAggressiveInline=false
IsMustRun=false;
IsPreserveSig=false; }

Expand Down Expand Up @@ -2465,6 +2472,7 @@ let mkILGenericNonVirtualMethod (nm,access,genparams, actual_args,actual_ret, im
IsUnmanagedExport=false;
IsSynchronized=false;
IsNoInline=false;
IsAggressiveInline=false
IsMustRun=false;
IsPreserveSig=false; }

Expand Down
4 changes: 3 additions & 1 deletion src/absil/il.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -804,9 +804,10 @@ type ILLocals = list<ILLocal>
[<RequireQualifiedAccess; NoComparison; NoEquality>]
type ILMethodBody =
{ IsZeroInit: bool;
/// strictly speakin should be a uint16
/// strictly speaking should be a uint16
MaxStack: int32;
NoInlining: bool;
AggressiveInlining: bool;
Locals: ILLocals;
Code: ILCode;
SourceMarker: ILSourceMarker option }
Expand Down Expand Up @@ -1054,6 +1055,7 @@ type ILMethodDef =
/// .NET 2.0 feature: SafeHandle finalizer must be run.
IsMustRun: bool;
IsNoInline: bool;
IsAggressiveInline: bool;

GenericParams: ILGenericParameterDefs;
CustomAttrs: ILAttributes; }
Expand Down
9 changes: 5 additions & 4 deletions src/absil/ilprint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -846,10 +846,11 @@ let goutput_mdef env os md =
output_string os " ";
(goutput_params menv) os md.Parameters;
output_string os " ";
if md.IsSynchronized then output_string os "synchronized ";
if md.IsMustRun then output_string os "/* mustrun */ ";
if md.IsPreserveSig then output_string os "preservesig ";
if md.IsNoInline then output_string os "noinlining ";
if md.IsSynchronized then output_string os "synchronized "
if md.IsMustRun then output_string os "/* mustrun */ "
if md.IsPreserveSig then output_string os "preservesig "
if md.IsNoInline then output_string os "noinlining "
if md.IsAggressiveInline then output_string os "aggressiveinlining "
(goutput_mbody is_entrypoint menv) os md;
output_string os "\n"

Expand Down
10 changes: 7 additions & 3 deletions src/absil/ilread.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2301,6 +2301,7 @@ and seekReadMethod ctxt numtypars (idx:int) =
let internalcall = (implflags &&& 0x1000) <> 0x0
let synchronized = (implflags &&& 0x0020) <> 0x0
let noinline = (implflags &&& 0x0008) <> 0x0
let aggressiveinline = (implflags &&& 0x0100) <> 0x0
let mustrun = (implflags &&& 0x0040) <> 0x0
let cctor = (nm = ".cctor")
let ctor = (nm = ".ctor")
Expand Down Expand Up @@ -2338,6 +2339,7 @@ and seekReadMethod ctxt numtypars (idx:int) =
IsUnmanagedExport=export
IsSynchronized=synchronized
IsNoInline=noinline
IsAggressiveInline=aggressiveinline
IsMustRun=mustrun
IsPreserveSig=preservesig
IsManaged = not unmanaged
Expand All @@ -2358,7 +2360,7 @@ and seekReadMethod ctxt numtypars (idx:int) =
//if codeRVA <> 0x0 then dprintn "non-IL or abstract method with non-zero RVA"
mkMethBodyLazyAux (notlazy MethodBody.Abstract)
else
seekReadMethodRVA ctxt (idx,nm,internalcall,noinline,numtypars) codeRVA
seekReadMethodRVA ctxt (idx,nm,internalcall,noinline,aggressiveinline,numtypars) codeRVA
}


Expand Down Expand Up @@ -2877,9 +2879,9 @@ and seekReadTopCode ctxt numtypars (sz:int) start seqpoints =
instrs,rawToLabel, lab2pc, raw2nextLab

#if FX_NO_PDB_READER
and seekReadMethodRVA ctxt (_idx,nm,_internalcall,noinline,numtypars) rva =
and seekReadMethodRVA ctxt (_idx,nm,_internalcall,noinline,aggressiveinline,numtypars) rva =
#else
and seekReadMethodRVA ctxt (idx,nm,_internalcall,noinline,numtypars) rva =
and seekReadMethodRVA ctxt (idx,nm,_internalcall,noinline,aggressiveinline,numtypars) rva =
#endif
mkMethBodyLazyAux
(lazy
Expand Down Expand Up @@ -2965,6 +2967,7 @@ and seekReadMethodRVA ctxt (idx,nm,_internalcall,noinline,numtypars) rva =
{ IsZeroInit=false
MaxStack= 8
NoInlining=noinline
AggressiveInlining=aggressiveinline
Locals=List.empty
SourceMarker=methRangePdbInfo
Code=code }
Expand Down Expand Up @@ -3090,6 +3093,7 @@ and seekReadMethodRVA ctxt (idx,nm,_internalcall,noinline,numtypars) rva =
{ IsZeroInit=initlocals
MaxStack= maxstack
NoInlining=noinline
AggressiveInlining=aggressiveinline
Locals = locals
Code=code
SourceMarker=methRangePdbInfo}
Expand Down
1 change: 1 addition & 0 deletions src/absil/ilreflect.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1466,6 +1466,7 @@ let convMethodImplFlags mdef =
||| flagsIf mdef.IsPreserveSig MethodImplAttributes.PreserveSig
||| flagsIf mdef.IsSynchronized MethodImplAttributes.Synchronized
||| flagsIf (match mdef.mdBody.Contents with MethodBody.IL b -> b.NoInlining | _ -> false) MethodImplAttributes.NoInlining
||| flagsIf (match mdef.mdBody.Contents with MethodBody.IL b -> b.AggressiveInlining | _ -> false) MethodImplAttributes.AggressiveInlining

//----------------------------------------------------------------------------
// buildMethodPass2
Expand Down
4 changes: 3 additions & 1 deletion src/absil/ilwrite.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2539,6 +2539,7 @@ let GenMethodDefAsRow cenv env midx (md: ILMethodDef) =
| _ -> false) then 0x1000 else 0x0) ||| // RTSpecialName
(if md.IsReqSecObj then 0x8000 else 0x0) |||
(if md.HasSecurity || not md.SecurityDecls.AsList.IsEmpty then 0x4000 else 0x0)

let implflags =
(match md.mdCodeKind with
| MethodCodeKind.Native -> 0x0001
Expand All @@ -2550,7 +2551,8 @@ let GenMethodDefAsRow cenv env midx (md: ILMethodDef) =
(if md.IsPreserveSig then 0x0080 else 0x0000) |||
(if md.IsSynchronized then 0x0020 else 0x0000) |||
(if md.IsMustRun then 0x0040 else 0x0000) |||
(if (md.IsNoInline || (match md.mdBody.Contents with MethodBody.IL il -> il.NoInlining | _ -> false)) then 0x0008 else 0x0000)
(if (md.IsNoInline || (match md.mdBody.Contents with MethodBody.IL il -> il.NoInlining | _ -> false)) then 0x0008 else 0x0000) |||
(if (md.IsAggressiveInline || (match md.mdBody.Contents with MethodBody.IL il -> il.AggressiveInlining | _ -> false)) then 0x0100 else 0x0000)

if md.IsEntryPoint then
if cenv.entrypoint <> None then failwith "duplicate entrypoint"
Expand Down
17 changes: 11 additions & 6 deletions src/fsharp/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5061,13 +5061,16 @@ and ComputeMethodImplAttribs cenv (_v:Val) attrs =
// 0x80 - hasPreserveSigImplFlag
// 0x20 - synchronize
// (See ECMA 335, Partition II, section 23.1.11 - Flags for methods [MethodImplAttributes])
let attrs = attrs
|> List.filter (IsMatchingFSharpAttribute cenv.g cenv.g.attrib_MethodImplAttribute >> not)
|> List.filter (IsMatchingFSharpAttributeOpt cenv.g cenv.g.attrib_PreserveSigAttribute >> not)
let attrs =
attrs
|> List.filter (IsMatchingFSharpAttribute cenv.g cenv.g.attrib_MethodImplAttribute >> not)
|> List.filter (IsMatchingFSharpAttributeOpt cenv.g cenv.g.attrib_PreserveSigAttribute >> not)

let hasPreserveSigImplFlag = ((implflags &&& 0x80) <> 0x0) || hasPreserveSigAttr
let hasSynchronizedImplFlag = (implflags &&& 0x20) <> 0x0
let hasNoInliningImplFlag = (implflags &&& 0x08) <> 0x0
hasPreserveSigImplFlag, hasSynchronizedImplFlag, hasNoInliningImplFlag, attrs
let hasAggressiveInliningImplFlag = (implflags &&& 0x0100) <> 0x0
hasPreserveSigImplFlag, hasSynchronizedImplFlag, hasNoInliningImplFlag, hasAggressiveInliningImplFlag, attrs

and GenMethodForBinding
cenv cgbuf eenv
Expand Down Expand Up @@ -5152,7 +5155,7 @@ and GenMethodForBinding
| _ -> [],None

// check if the hasPreserveSigNamedArg and hasSynchronizedImplFlag implementation flags have been specified
let hasPreserveSigImplFlag, hasSynchronizedImplFlag, hasNoInliningFlag, attrs = ComputeMethodImplAttribs cenv v attrs
let hasPreserveSigImplFlag, hasSynchronizedImplFlag, hasNoInliningFlag, hasAggressiveInliningImplFlag, attrs = ComputeMethodImplAttribs cenv v attrs

let securityAttributes,attrs = attrs |> List.partition (fun a -> IsSecurityAttribute cenv.g cenv.amap cenv.casApplied a m)

Expand Down Expand Up @@ -5183,6 +5186,7 @@ and GenMethodForBinding
IsSynchronized = hasSynchronizedImplFlag
IsEntryPoint = isExplicitEntryPoint
IsNoInline = hasNoInliningFlag
IsAggressiveInline = hasAggressiveInliningImplFlag
HasSecurity = mdef.HasSecurity || (securityAttributes.Length > 0)
SecurityDecls = secDecls }

Expand Down Expand Up @@ -6012,7 +6016,7 @@ and GenAbstractBinding cenv eenv tref (vref:ValRef) =
let m = vref.Range
let memberInfo = Option.get vref.MemberInfo
let attribs = vref.Attribs
let hasPreserveSigImplFlag,hasSynchronizedImplFlag,hasNoInliningFlag,attribs = ComputeMethodImplAttribs cenv vref.Deref attribs
let hasPreserveSigImplFlag,hasSynchronizedImplFlag,hasNoInliningFlag,hasAggressiveInliningImplFlag,attribs = ComputeMethodImplAttribs cenv vref.Deref attribs
if memberInfo.MemberFlags.IsDispatchSlot && not memberInfo.IsImplemented then
let ilAttrs =
[ yield! GenAttrs cenv eenv attribs
Expand All @@ -6033,6 +6037,7 @@ and GenAbstractBinding cenv eenv tref (vref:ValRef) =
IsPreserveSig=hasPreserveSigImplFlag
IsSynchronized=hasSynchronizedImplFlag
IsNoInline=hasNoInliningFlag
IsAggressiveInline=hasAggressiveInliningImplFlag
mdKind=match mdef.mdKind with
| MethodKind.Virtual vinfo ->
MethodKind.Virtual {vinfo with IsFinal=memberInfo.MemberFlags.IsFinal
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/symbols/Symbols.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,7 @@ and FSharpInlineAnnotation =
| AlwaysInline
| OptionalInline
| NeverInline
| AggressiveInline

and FSharpMemberOrValData =
| E of EventInfo
Expand Down
12 changes: 7 additions & 5 deletions src/fsharp/symbols/Symbols.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -694,14 +694,16 @@ and [<RequireQualifiedAccess>] FSharpInlineAnnotation =
#else
and [<RequireQualifiedAccess>] internal FSharpInlineAnnotation =
#endif
/// Indictes the value is inlined and compiled code for the function does not exist
/// Indicates the value is inlined and compiled code for the function does not exist
| PseudoValue
/// Indictes the value is inlined but compiled code for the function still exists, e.g. to satisfy interfaces on objects, but that it is also always inlined
/// Indicates the value is inlined but compiled code for the function still exists, e.g. to satisfy interfaces on objects, but that it is also always inlined
| AlwaysInline
/// Indictes the value is optionally inlined
/// Indicates the value is optionally inlined
| OptionalInline
/// Indictes the value is never inlined
| NeverInline
/// Indicates the value is never inlined
| NeverInline
/// Indicates the value is aggressively inlined by the .NET runtime
| AggressiveInline

/// A subtype of F# symbol that represents an F# method, property, event, function or value, including extension members.
#if COMPILER_PUBLIC_API
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Regression test for DevDiv:212424
// "NoInlining attribute not emitted into IL"
module M
[<System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)>]
let getUnit (f : unit -> unit) = f()
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17295
// Copyright (c) Microsoft Corporation. All rights reserved.



// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern FSharp.Core
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 4:3:0:0
}
.assembly MethodImplAttribute.AggressiveInlining
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
int32,
int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )

// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 01 01 00 00 00 00 )

.hash algorithm 0x00008004
.ver 0:0:0:0
}
.mresource public FSharpSignatureData.MethodImplAttribute.AggressiveInlining
{
// Offset: 0x00000000 Length: 0x0000035A
}
.mresource public FSharpOptimizationData.MethodImplAttribute.AggressiveInlining
{
// Offset: 0x00000360 Length: 0x0000007D
}
.module MethodImplAttribute.AggressiveInlining.dll
// MVID: {4E66F6A9-F47B-58B3-A745-0383A9F6664E}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x0000000000180000


// =============== CLASS MEMBERS DECLARATION ===================

.class public abstract auto ansi sealed M
extends [mscorlib]System.Object
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
.method public static void getUnit(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [FSharp.Core]Microsoft.FSharp.Core.Unit> f) cil managed aggressiveinlining
{
// Code size 10 (0xa)
.maxstack 8
.language '{AB4F38C9-B6E6-43BA-BE3B-58080B2CCCE3}', '{994B45C4-E6E9-11D2-903F-00C04FA302A1}', '{5A869D0B-6611-11D3-BD2A-0000F80849BD}'
.line 5,5 : 34,37
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldnull
IL_0003: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [FSharp.Core]Microsoft.FSharp.Core.Unit>::Invoke(!0)
IL_0008: pop
IL_0009: ret
} // end of method M::getUnit

} // end of class M

.class private abstract auto ansi sealed '<StartupCode$MethodImplAttribute-AggressiveInlining>'.$M
extends [mscorlib]System.Object
{
} // end of class '<StartupCode$MethodImplAttribute-AggressiveInlining>'.$M


// =============================================================

// *********** DISASSEMBLY COMPLETE ***********************
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
SOURCE=MethodImplAttribute.ForwardRef.fs SCFLAGS="-a -g --optimize-" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd MethodImplAttribute.ForwardRef.dll" # MethodImplAttribute.ForwardRef.fs
SOURCE=MethodImplAttribute.InternalCall.fs SCFLAGS="-a -g --optimize-" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd MethodImplAttribute.InternalCall.dll" # MethodImplAttribute.InternalCall.fs
SOURCE=MethodImplAttribute.NoInlining.fs SCFLAGS="-a -g --optimize-" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd MethodImplAttribute.NoInlining.dll" # MethodImplAttribute.NoInlining.fs
SOURCE=MethodImplAttribute.AggressiveInlining.fs SCFLAGS="-a -g --optimize-" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd MethodImplAttribute.AggressiveInlining.dll" # MethodImplAttribute.AggressiveInlining.fs
SOURCE=MethodImplAttribute.NoOptimization.fs SCFLAGS="-a -g --optimize-" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd MethodImplAttribute.NoOptimization.dll" # MethodImplAttribute.NoOptimization.fs
SOURCE=MethodImplAttribute.PreserveSig.fs SCFLAGS="-a -g --optimize-" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd MethodImplAttribute.PreserveSig.dll" # MethodImplAttribute.PreserveSig.fs
SOURCE=MethodImplAttribute.Synchronized.fs SCFLAGS="-a -g --optimize-" COMPILE_ONLY=1 POSTCMD="..\\CompareIL.cmd MethodImplAttribute.Synchronized.dll" # MethodImplAttribute.Synchronized.fs
Expand Down