2016-10-18 24 views
14

Thuộc tính System.Runtime.CompilerServices.MethodImplAttribute có thể được sử dụng để đưa ra gợi ý cho trình biên dịch JIT về cách xử lý phương thức được trang trí. Đặc biệt, tùy chọn MethodImplOptions.AggressiveInlining chỉ thị trình biên dịch nội tuyến phương thức bị ảnh hưởng nếu có thể. Thật không may trình biên dịch F # dường như đơn giản bỏ qua thuộc tính này khi tạo IL.Áp dụng MethodImplOptions.AggressiveInlining cho hàm F #

Ví dụ: C# code sau

[MethodImpl(MethodImplOptions.AggressiveInlining)] 
public static int Inc(int x) => x + 1; 

được phiên dịch sang

.method public hidebysig static int32 Inc(int32 x) cil managed aggressiveinlining 
{  
    .maxstack 8 
    IL_0000: ldarg.0 
    IL_0001: ldc.i4.1 
    IL_0002: add 
    IL_0003: ret 
} 

Lưu ý "aggressiveinlining" cờ.

# mã F này tuy nhiên

[<MethodImpl(MethodImplOptions.AggressiveInlining)>] 
let inc x = x + 1 

trở thành

.method public static int32 inc(int32 x) cil managed 
{ 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: ldc.i4.1 
    IL_0003: add 
    IL_0004: ret 
} 

Không "aggressiveinlining". Tôi cũng đã cố gắng áp dụng thuộc tính cho các phương thức tĩnh và không tĩnh của các lớp thích hợp (type ...), nhưng kết quả là như nhau.

Tuy nhiên, nếu tôi áp dụng nó vào một indexer tùy chỉnh, như vậy

type Dummy = 
    member self.Item 
     with [<MethodImpl(MethodImplOptions.AggressiveInlining)>] get x = x + 1 

kết quả IL là

.method public hidebysig specialname instance int32 get_Item(int32 x) cil managed 
{ 
    .custom instance void [mscorlib]System.Runtime.CompilerServices.MethodImplAttribute::.ctor(valuetype [mscorlib]System.Runtime.CompilerServices.MethodImplOptions) = (01 00 00 01 00 00 00 00) 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ldarg.1 
    IL_0002: ldc.i4.1 
    IL_0003: add 
    IL_0004: ret 
} 

... mặc dù tôi không chắc chắn cho dù đó là tương đương với " hung hăng "cờ được tạo bởi trình biên dịch C#.

Hành vi đó có được mong đợi/mong đợi không? Nó là một lỗi trong trình biên dịch F #?

(Lưu ý: Tôi nhận thức được F # inline từ khóa, nhưng điều đó chỉ làm việc cho F # khách hàng của thư viện của tôi, chứ không phải C# người tiêu dùng.)

+0

AFAIK thuộc tính này được sử dụng bởi JIT: er để gợi ý rằng phương pháp nên được gạch chân. Vì vậy, nếu đó là chính xác, bạn nên kiểm tra mã tạo ra máy.Chú thích; nó không đơn giản như xem tháo gỡ trong .NET như với trình gỡ lỗi chạy JIT: er ít tích cực hơn nhiều. – FuleSnabel

+0

Awww, tôi hiểu ý của bạn là gì. Dường như thiếu dữ liệu meta IL. Hãy để tôi kiểm tra điều này sau. – FuleSnabel

+3

Có vẻ như chỉ 'PreserveSig',' Synchronized', và 'NoInlining' được tôn trọng - xem' ComputeMethodImplAttribs' trong [IlxGen.fs] (https://github.com/Microsoft/visualfsharp/blob/master/src/fsharp /IlxGen.fs) – kvb

Trả lời

6

@kvb là đúng khi cho rằng có vẻ như trình biên dịch F# dường như dải ra khỏi số MethodImpl.

ComputeMethodImplAttribs trong IlxGen.fs được gọi để tính các thuộc tính phương pháp.

and ComputeMethodImplAttribs cenv (_v:Val) attrs = 
    let implflags = 
     match TryFindFSharpAttribute cenv.g cenv.g.attrib_MethodImplAttribute attrs with 
     | Some (Attrib(_,_,[ AttribInt32Arg flags ],_,_,_,_)) -> flags 
     | _ -> 0x0 

    let hasPreserveSigAttr = 
     match TryFindFSharpAttributeOpt cenv.g cenv.g.attrib_PreserveSigAttribute attrs with 
     | Some _ -> true 
     | _ -> false 

    // strip the MethodImpl pseudo-custom attribute  
    // The following method implementation flags are used here 
    // 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 hasPreserveSigImplFlag = ((implflags &&& 0x80) <> 0x0) || hasPreserveSigAttr 
    let hasSynchronizedImplFlag = (implflags &&& 0x20) <> 0x0 
    let hasNoInliningImplFlag = (implflags &&& 0x08) <> 0x0 
    hasPreserveSigImplFlag, hasSynchronizedImplFlag, hasNoInliningImplFlag, attrs 

Nhìn kỹ hơn xung quanh hàng: 4990:

let attrs = attrs 
        |> List.filter (IsMatchingFSharpAttribute cenv.g cenv.g.attrib_MethodImplAttribute >> not) 
         |> List.filter (IsMatchingFSharpAttributeOpt cenv.g cenv.g.attrib_PreserveSigAttribute >> not) 

Các filter bộ lọc đầu tiên đi MethodImplAttribute.

Hiện tại, tôi đang tìm kiếm một chút để tìm lý do nhưng mã này bắt nguồn từ cam kết ban đầu là latkin. Tôi nghĩ rằng nó có thể sai để loại bỏ các MethodImpl đặc biệt là cho AggressiveInlining mà tôi tin rằng ảnh hưởng đến JIT: ing do đó nó cần phải được lắp ráp.

Tôi khuyên bạn nên đăng ký issue. Có lẽ bạn có thể nhận được một giải thích ít nhất.

+3

Lọc ra thuộc tính có ý nghĩa bởi vì nó thực sự là một thuộc tính tùy chỉnh giả và không nên có mặt như một thuộc tính tùy chỉnh thực tế trong siêu dữ liệu (xem ví dụ: http://weblog.ikvm.net/2008/ 11/25/PseudoCustomAttributes.aspx). – kvb

+0

Tôi sẽ mở một vấn đề trên repo GitHub. – Frank

+2

c.f. https://github.com/Microsoft/visualfsharp/issues/1637 – Frank

Các vấn đề liên quan