2014-11-20 21 views
13

Vì vậy, I've read many times before về mặt kỹ thuật .NET không hỗ trợ tối ưu hóa cuộc gọi đuôi (TCO) vì nó có mã opcode cho nó và chỉ C# không tạo ra nó.Tại sao tối ưu hóa cuộc gọi đuôi cần mã op?

Tôi không chắc chắn lý do tại sao TCO cần mã opcode hoặc nó sẽ làm gì. Theo như tôi biết, yêu cầu để có thể thực hiện TCO là kết quả của một cuộc gọi đệ quy không được kết hợp với bất kỳ biến nào trong phạm vi chức năng hiện tại. Nếu bạn không có điều đó, sau đó tôi không thấy làm thế nào một opcode ngăn cản bạn phải giữ một khung stack mở. Nếu bạn có điều đó, thì trình biên dịch không thể dễ dàng biên dịch nó thành một cái gì đó lặp đi lặp lại?

Vậy điểm opcode là gì? Rõ ràng là có một cái gì đó tôi đang mất tích. Trong trường hợp TCO là có thể ở tất cả, không phải nó luôn luôn được xử lý ở cấp độ trình biên dịch hơn ở cấp opcode? Ví dụ về nơi nó không thể là gì?

+2

Dự đoán không suy đoán của tôi là mã op này được dự định giống như một gợi ý từ trình biên dịch cao cấp đến JITter sao cho sau này có biên dịch nhanh là một trong những tính năng chính của nó - được giải phóng khỏi thời gian có thể -Phân tích nhiệm vụ phân tích IL để xem liệu tối ưu hóa cuộc gọi đuôi có thực sự khả thi trong bất kỳ kịch bản cụ thể nào không. –

Trả lời

8

Tiếp theo các liên kết mà bạn đã cung cấp thì đây là phần mà dường như với tôi, câu trả lời câu hỏi của bạn khá chặt chẽ ..


Source

> Các CLR và đuôi gọi

Khi bạn đang xử lý ngôn ngữ do CLR quản lý, có hai ki các trình biên dịch trong vở kịch. Có trình biên dịch đi từ mã nguồn ngôn ngữ của bạn xuống IL (các nhà phát triển C# biết điều này là csc.exe), và sau đó có trình biên dịch từ IL sang mã gốc (các trình biên dịch bit JIT 32/64 được gọi lúc chạy) hoặc NGEN thời gian). Cả hai trình biên dịch nguồn gốc -> IL và IL-> đều hiểu được tối ưu hóa cuộc gọi đuôi. Nhưng trình biên dịch gốc IL -> mà tôi chỉ gọi là JIT - có câu nói cuối cùng về việc tối ưu hóa cuộc gọi đuôi có được sử dụng hay không. Trình biên dịch nguồn-> IL có thể giúp tạo ra IL có lợi cho việc thực hiện các cuộc gọi đuôi, bao gồm cả việc sử dụng "đuôi". Tiền tố IL (xem thêm sau). Bằng cách này, trình biên dịch nguồn-> IL có thể cấu trúc IL nó tạo ra để thuyết phục JIT thực hiện cuộc gọi đuôi. Nhưng JIT luôn có tùy chọn để làm bất cứ điều gì nó muốn.

Khi nào JIT thực hiện cuộc gọi đuôi?

Tôi hỏi Fei Chen và Grant Richins, hàng xóm ở dưới hành lang của tôi, những người tình cờ làm việc trên JIT, dưới điều kiện nào các JIT khác nhau sẽ sử dụng tối ưu hóa cuộc gọi đuôi. Câu trả lời đầy đủ là khá chi tiết. Tóm tắt nhanh là JITs cố gắng sử dụng tối ưu hóa cuộc gọi đuôi bất cứ khi nào họ có thể, nhưng có rất nhiều lý do tại sao tối ưu hóa cuộc gọi đuôi không thể được sử dụng.Một số lý do tại sao gọi đuôi là một tổ chức phi-option:

  • Caller không trả lại ngay lập tức sau khi cuộc gọi (duh :-))
  • luận Ngăn xếp giữa người gọi và callee không phù hợp trong một cách mà sẽ yêu cầu thay đổi những thứ xung quanh trong khung của người gọi trước khi callee có thể thực hiện
  • Caller và callee trở lại các loại khác nhau
  • Chúng nội tuyến các cuộc gọi thay vì (nội tuyến là cách tốt hơn so với gọi điện thoại đuôi, và mở ra cánh cửa cho nhiều tối ưu hơn)
  • an ninh được trong cách
  • Các debugger/profiler tắt JIT tối ưu hóa

Phần thú vị nhất trong bối cảnh của câu hỏi của bạn, mà làm cho nó siêu rõ ràng trong quan điểm của tôi, trong số nhiều trường hợp, là ví dụ về bảo mật được đề cập ở trên ...

Bảo mật trong .NET trong nhiều trường hợp phụ thuộc vào ngăn xếp chính xác ... tại thời điểm chạy .. Đó là lý do tại sao, như được nêu ở trên, gánh nặng được chia sẻ bởi cả hai nguồn tới trình biên dịch CIL và (thời gian chạy) trình biên dịch JIT CIL-đến-bản địa, với câu nói cuối cùng là sau.

+0

Nhưng tại sao opcode đuôi lại cần thiết? JIT chỉ có thể thử TCO. – usr

1

Đoán: Trong một ngôn ngữ đơn giản như trình biên tập x86 nơi bạn quản lý ngăn xếp "theo cách thủ công", bạn không cần mã hóa - bạn chỉ có thể thiết lập ngăn xếp cuộc gọi một cách thích hợp.

Nhưng ở cấp cao hơn như .NET CIL, ngăn xếp được quản lý một phần cho bạn và toàn bộ hành động gọi hàm là một mã duy nhất (ví dụ: gọi). Vì vậy, bạn cần một opcode khác nhau để thực hiện TCO - một trong đó có "vượt qua dòng điều khiển đến chức năng này, nhưng không tạo ra một khung ngăn xếp mới".

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