قرارداد فراخوانی

در علومهای رایانه ای، یک قرارداد فراخوانی یک طرح در سطح پیاده‌سازی است برای نشان دادن آن که در یک زیرروال نحوه گرفتن پارامترها از صدا زنندهٔ آن‌ها و نحوه برگرداندن نتیجه به چه صورت است
تفاوت‌ها در پیاده‌سازی‌های مختلف شامل مکان پارامترها، مقادیر بازگشتی، آدرس‌های بازگشت و نحوه وظایف آماده‌سازی برای فراخوانی تابع و بازگرداندن محیط پس از آن بین صدا زننده (caller)و صدا زده شده(callee) می‌شود.
قراردادهای فراخوانی ممکن است به یک استراتژی ارزیابی زبان برنامه‌نویسی خاص مربوط باشند، اما اغلب آن‌ها بخشی از آن (یا برعکس) نیستند، زیرا استراتژی ارزیابی معمولاً در سطح انتزاعی تری (بالاتری) تعریف شده‌است و به عنوان بخشی از زبان دیده می‌شود به جای جزئیات پیاده‌سازی (سطح پایین) یک زبان خاص کامپایلر.

تنوع کامپایلر

اگر چه برخی زبان در واقع ممکن است این تا حدی در مشخص زبان برنامه‌نویسی مشخصات (یا در برخی اجرای محوری)، پیاده‌سازی‌های مختلف از جمله زبان (به عنوان مثال مختلف کامپایلر) به‌طور معمول ممکن است هنوز هم استفاده از کنوانسیون‌های مختلف تماس، اغلب انتخاب. دلایل این کار عملکرد، سازگاری مکرر با توافقنامه‌های دیگر زبان‌های محبوب (با توجه به یا بدون دلایل فنی)، و محدودیت‌ها یا قراردادهای اعمال شده توسط «سیستم عامل‌های مختلف» (ترکیبی از معماری CPU و سیستم عامل) است.

تنوع معماری

معماری‌های CPU همیشه دارای بیش از یک قرارداد فراخوانی ممکن هستند. با تعداد زیادی از ثبات‌های کلی و سایر ویژگی‌ها، پتانسیل چند قرارداد فراخوانی زیاد است، اگر چه برخی معماری به‌طور رسمی مشخص شده‌است که فقط از یک قرارداد فراخوانی استفاده کند که توسط معمار ارائه شده‌است.

x86 (32 بیتی)

معماری x86 از قراردادهای فراخوانی مختلفی استفاده می‌کند. با توجه به کم بودن ثبات‌ها، قراردادهای فراخوانی x86 اغلب آرگومان را در پشته منتقل می‌کنند، در حالی که مقدار بازگشتی (یا اشاره گر به آن) در یک ثبات منتقل می‌شود. برخی از قراردادها از ثبات‌ها برای چند پارامتر اول استفاده می‌کنند که ممکن است باعث بهبود عملکرد و سریعتر شدن برای زیرروال - برگ (یعنی روال‌هایی که با روشی دیگر تماس نداشته‌اند و نیازی به بازنگری ندارند) که مکرراً استفاده می‌شود شود.
مثال فراخوانی: 
 push EAX            ; pass some register result
 push byte[EBP+20]   ; pass some memory variable (FASM/TASM syntax)
 push 3              ; pass some constant
 call calc           ; the returned result is now in EAX
 
ساختار callee معمولی: (برخی یا همه (به جز ret) دستورالعمل‌های زیر ممکن است در روش‌های ساده بهینه‌سازی شوند) 
calc:
  push EBP            ; save old frame pointer
  mov EBP,ESP         ; get new frame pointer
  sub ESP,localsize   ; reserve place for locals
  .
  .                   ; perform calculations, leave result in EAX
  .
  mov ESP,EBP         ; free space for locals
  pop EBP             ; restore old frame pointer
  ret paramsize       ; free parameter space and return

PowerPC

معماری PowerPC دارای تعداد زیادی از ثبات‌ها است، بنابراین اکثر توابع می‌توانند تمام آرگومنت‌ها را در رجیسترها برای فراخوانی‌های تک مرحله ای منتقل کنند. آرگومانت‌های اضافی در پشته منتقل می‌شوند و برای آرگومنت‌های رجیستر-پایه (مقادیری باید در رجیستر ذخیره شود) همیشه فضای مناسب در پشته تخصیص داده می‌شود تا فراخوانی تابع در موارد فراخوانی چند مرحله ای (بازگشتی) راحت‌تر شودو ثبات‌ها باید ذخیره شوند. همچنین در توابع variadic مانند printf()، جایی که پارامترهای تابع باید به صورت آرایه قابل دسترسی باشند. تنها یک قرارد فراخوانی برای تمام زبان‌های رویه ای استفاده می‌شود.

SPARC

معماری SPARC، بر خلاف اکثر معماری‌های RISC، بر روی ثبات‌های پنجره ای ساخته شده‌است. ۲۴ ثبات قابل دسترسی در هر پنجره ثبات وجود دارد: ۸ ثبات در (in) , 8 ثبات ثبات محلی هستند و ۸ تا ثبات (out).
ثبات "in" برای ارسال آرگومنت‌ها به تابع مورد نظر استفاده می‌شود و هر آرگومنت اضافی باید بر روی پشته قرار گیرد. با این حال، فضا همیشه توسط تابع صدا زده شده اختصاص داده می‌شود برای مدیریت سرریز احتمالی ثبات پنجره ای، متغیرهای محلی، و (در SPARC 32 بیتی) بازگشت ساختار بر اساس ارزش(by value). برای فراخوانی یک تابع، یک مکان که در آن آرگومنت‌ها قرار می‌گیرد ثبات‌های پنجره ای out هستند؛ هنگامی که تابع نامیده می‌شود، ثبات "out" تبدیل به ثبات"in" می‌شود و تابع فراخوانی شده به آرگومنت‌های موجود در ثبات "in" دسترسی دارد. هنگامی که تابع صدا زده شده تمام می‌شود، مقدار برگشتی را در اولین ثبات "in" قرار می‌دهد، که تبدیل به اولیت ثبات "out " می‌شود هنگام برگشتن از تابع فراخوانی شده.

ملاحظات پیاده‌سازی

این تغییرپذیری باید در هنگام ترکیب ماژول‌های نوشته شده در چندین زبان یا هنگام فراخوانی سیستم عامل یا کتابخانهAPI‌ها از یک زبان غیر از آن که در آن نوشته شده باشد، در نظر گرفته شود. در این موارد، باید مراقبت‌های ویژه ای را برای هماهنگ‌کردن قراردادهای فراخوانی مورد استفاده توسط صدا زننده و صدا زده شده انجام شود. حتی یک برنامه که از یک زبان برنامه‌نویسی استفاده می‌کند، می‌تواند از قراردادهای فراخوانی چندگانه یا انتخاب شده توسط کامپایلر، برای بهینه‌سازی کد یا برنامه‌نویس مشخص شده‌استفاده کند.

کد ریسه ای

کد ریسه ای همه مسئولیت را برای تنظیم و تمیز کردن کد پس از فراخوانی تابع بر روی کد صدا زده شده دارد. کد صدا زده شده چیزی نیست جز فهرست زیرروال‌هایی که باید فراخوانی شوند. این باعث می‌شود تمام تابع تنظیم و تمیز کردن در یک مکان - prolog و epilog تابع - و نه در بسیاری از مکان‌هایی که عملکرد نامیده می‌شود. این باعث می‌شود کد رشته کمترین قرارداد تماس.
کد ریسه ای تمام آرگومنت‌های مربوط به پشته را منتقل می‌کند. تمام مقادیر برگشتی در پشته بازگشته‌اند. این باعث می‌شود پیاده‌سازی ساده از قرارداد فراخوانی‌هایی که مقادیرهای بیشتری در ثبات‌ها دارند، کندتر شود. با این حال، پیاده‌سازی کد ریسه ای که چندین مقدار پشته بالا را در رجیسترها ذخیره می‌کند - به ویژه، آدرس بازگشت - معمولاً سریع تر از قراردادهای فراخوانی است که همیشه آدرس بازگشت به پشته را push و popمی‌کند.

PL / I

قرارداد فراخوانی پیش فرض برای برنامه‌های نوشته شده در زبان PL / I تمام آرگومان را با مرجع منتقل می‌کند (by reference)، هرچند ممکن است قراردادهای دیگر مشخص شود. رفتار کردن با آرگومنت‌ها برای کامپایلرها و سیستم عامل‌ها مختلف متفاوت است، اما معمولاً آدرس‌های آرگومنت‌ها توسط یک لیست آرگومنت در حافظه منتقل می‌شوند. یک آدرس نهایی یا پنهان ممکن است به یک منطقه منتقل شود تا حاوی مقدار بازگشتی باشد. به دلیل طیف گسترده‌ای از داده‌های پشتیبانی شده توسط PL / I، توصیفگر داده نیز ممکن است برای تعریف پاس داده شود، به عنوان مثال، طول رشته‌های کاراکتر یا بیت، ابعاد و طول آرایه‌ها. آرگومنت‌های ساختگی آرگومنت‌هایی هستند که یا ثابت هستند یا با نوع ورودی ای که انتظار می‌رود متفاوت‌اند.