- Tail Call: การเรียกฟังก์ชันที่เกิดขึ้นทันที ก่อนที่ฟังก์ชันจะคืนค่า หากเกิดการปรับแต่ง Tail Call จะใช้คำสั่ง
jmp เพื่อลดการใช้ call stack
- ข้อดี:
- ลดการใช้หน่วยความจำสแตกจาก O(n) เหลือ O(1)
- ตัด performance overhead ของการเรียกฟังก์ชันออก ทำให้ใช้เป็นโครงสร้างควบคุมการวนซ้ำที่มีประสิทธิภาพได้
ปัญหาของลูปอินเทอร์พรีเตอร์
- ปัญหา:
- ยิ่งฟังก์ชันมีขนาดใหญ่ขึ้นและ control flow ซับซ้อนขึ้น ก็ยิ่งยากที่จะเก็บข้อมูลสำคัญไว้ในรีจิสเตอร์
- หากเส้นทางแบบเร็วและเส้นทางแบบช้าปะปนกัน คุณภาพของโค้ดจะลดลง
การปรับปรุงลูปอินเทอร์พรีเตอร์ด้วย Tail Call
- วิธีแก้: ใช้ Tail Call แยกแต่ละงานออกเป็นฟังก์ชันย่อย ๆ และให้แต่ละฟังก์ชันเรียกงานถัดไปด้วย Tail Call
- ข้อดี:
- ควบคุมการจัดสรรรีจิสเตอร์ได้
- แยกเส้นทางแบบเร็วและแบบช้าออกจากกันเพื่อรักษาคุณภาพของโค้ด
- สามารถปรับแต่งลำดับคำสั่งที่เป็นอิสระต่อกันได้
ข้อจำกัด
- ปัญหาเมื่อมี non-tail call: หากมี non-tail call จะเกิด stack frame และข้อมูลถูกเก็บลงสแตก ทำให้ประสิทธิภาพลดลง
- การจัดการข้อยกเว้นที่ซับซ้อน: หากการจัดการข้อยกเว้นซับซ้อน จะทำให้โค้ดซ้ำซ้อนและความซับซ้อนเพิ่มขึ้น
- ปัญหาด้านการพกพา: แอททริบิวต์
musttail ไม่ใช่มาตรฐาน จึงไม่ได้รับการรองรับจากคอมไพเลอร์ทุกตัว
สรุปโดย GN⁺
- การปรับแต่ง Tail Call มีบทบาทสำคัญต่อการเพิ่มประสิทธิภาพ และให้ผลลัพธ์ที่โดดเด่นโดยเฉพาะในการแยกวิเคราะห์ Protobuf
- เทคนิคนี้สามารถนำไปใช้กับอินเทอร์พรีเตอร์ของภาษาหลักที่เขียนด้วย C ได้ด้วย เช่น Python, Ruby, PHP, Lua เป็นต้น
- ปัญหาด้านการพกพาของแอททริบิวต์
musttail เป็นโจทย์ที่ยังต้องแก้
- โปรเจ็กต์ที่มีความสามารถคล้ายกัน ได้แก่ LuaJIT, อินเทอร์พรีเตอร์ WebAssembly อย่าง wasm3 เป็นต้น
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ในข้อเสนอของมาตรฐาน C มีรูปแบบการรวม tail call แบบ
return goto (expression);[[musttail]]เป็นมาตรฐาน วิธีนี้รับประกันอายุการใช้งานของอ็อบเจ็กต์ภายในสโคป และไม่ต้องอาศัยการวิเคราะห์ escape อย่างกว้างขวางสำหรับแฟน Rust เคยมี RFC เก่าเกี่ยวกับการเพิ่มคีย์เวิร์ด
becomeใน C++ วิธีที่ interpreter ใช้เพิ่มความเร็วโดยหลักคือการใช้ computed goto
ปัญหาของการสลับ context ด้วย tail call คือจำเป็นต้องมีฟังก์ชันที่ใช้ calling convention
หวังว่าแอตทริบิวต์
[[musttail]]จะแพร่ไปยัง GCC, Visual C++ และคอมไพเลอร์ยอดนิยมอื่น ๆ[[musttail]]เข้า GCC กำลังดำเนินอยู่มีการกล่าวถึงการรองรับใน C++ พร้อมชี้ว่า C++ แทบไม่มี tail call เลย
สงสัยว่าจะเกิดอะไรขึ้นหากโยน exception จากฟังก์ชัน C++
[[musttail]]มีการกล่าวว่าตัวอย่างง่าย ๆ ไม่จำเป็นต้องใช้
__attribute__((musttail))เพื่อให้ได้การสร้างโค้ดที่ดีสงสัยเรื่องความเร็วของการใช้ trampoline โดยให้ฟังก์ชันคืนค่า function pointer แล้วไปเรียกจากลูปภายนอก
มีคำขอให้ยกตัวอย่างเส้นทาง exception ที่ครอบด้วย
[[musttail]]ให้ชัดเจนขึ้น[[musttail]]จึงป้องกันการสร้าง stack frame และการ spill รีจิสเตอร์