- Tail Call: lời gọi hàm được thực hiện ngay trước khi hàm hiện tại trả về. Khi tối ưu hóa Tail Call xảy ra, lệnh
jmp sẽ được dùng để giảm ngăn xếp lời gọi.
- Ưu điểm:
- Giảm mức sử dụng bộ nhớ stack từ O(n) xuống O(1).
- Loại bỏ overhead hiệu năng của lời gọi hàm, nhờ đó có thể dùng như một cấu trúc điều khiển lặp hiệu quả.
Vấn đề của vòng lặp thông dịch
- Vấn đề:
- Khi hàm trở nên lớn hơn và luồng điều khiển phức tạp hơn, sẽ khó giữ dữ liệu quan trọng trong thanh ghi.
- Nếu đường đi nhanh và đường đi chậm bị trộn lẫn, chất lượng mã sẽ suy giảm.
Cải thiện vòng lặp thông dịch bằng Tail Call
- Giải pháp: dùng Tail Call để tách mỗi tác vụ thành các hàm nhỏ, và mỗi hàm gọi tác vụ kế tiếp bằng Tail Call.
- Ưu điểm:
- Có thể kiểm soát việc cấp phát thanh ghi.
- Tách riêng đường đi nhanh và đường đi chậm để duy trì chất lượng mã.
- Có thể tối ưu các chuỗi lệnh độc lập.
Giới hạn
- Vấn đề khi tồn tại non-tail call: nếu có non-tail call, stack frame sẽ được tạo ra và dữ liệu được lưu vào stack, làm giảm hiệu năng.
- Xử lý ngoại lệ phức tạp: khi xử lý ngoại lệ phức tạp, mã bị lặp lại và độ phức tạp tăng lên.
- Vấn đề tính di động: thuộc tính
musttail không phải là tiêu chuẩn, nên không được mọi trình biên dịch hỗ trợ.
Tóm tắt của GN⁺
- Tối ưu hóa Tail Call đóng vai trò quan trọng trong việc cải thiện hiệu năng, đặc biệt cho phân tích Protobuf.
- Kỹ thuật này cũng có thể áp dụng cho các trình thông dịch ngôn ngữ lớn được viết bằng C (Python, Ruby, PHP, Lua, v.v.).
- Vấn đề tính di động của thuộc tính
musttail là một thách thức cần được giải quyết.
- Các dự án cung cấp tính năng tương tự gồm có LuaJIT, trình thông dịch WebAssembly wasm3, v.v.
1 bình luận
Ý kiến trên Hacker News
Bản đề xuất tiêu chuẩn C có bao gồm tail call dưới dạng
return goto (expression);[[musttail]], cách này đảm bảo vòng đời của đối tượng cục bộ và không cần phân tích escape trên diện rộngVới những người yêu thích Rust, đã từng có một RFC cũ đề xuất thêm từ khóa
becomeTrong C++, cách các trình thông dịch tăng tốc chủ yếu là dùng computed goto
Vấn đề chuyển đổi ngữ cảnh bằng tail call đòi hỏi các hàm dùng calling convention
Hy vọng thuộc tính
[[musttail]]sẽ được phổ biến sang GCC, Visual C++ và các trình biên dịch phổ biến khác[[musttail]]đang trong quá trình được thêm vào GCCCó đề cập đến hỗ trợ C++, đồng thời chỉ ra rằng trong C++ hầu như không có tail call
Có người thắc mắc điều gì xảy ra nếu ném ngoại lệ trong hàm C++
[[musttail]]Có nhắc rằng với các ví dụ đơn giản thì không cần
__attribute__((musttail))để sinh mã tốtCó người tò mò về tốc độ của cách dùng trampoline để gọi con trỏ hàm được trả về trong một vòng lặp bên ngoài
Có yêu cầu làm rõ ví dụ về đường đi ngoại lệ được bọc bằng
[[musttail]][[musttail]]ngăn việc dựng stack frame và register spilling