Szubrutin
a szubrutin ötletét azután dolgozták ki, hogy a számítástechnikai gépek már egy ideje léteztek.Az aritmetikai és feltételes ugrási utasításokat előre megtervezték, és viszonylag keveset változtak, de az eljáráshívásokhoz használt speciális utasítások jelentősen megváltoztak az évek során.A legkorábbi számítógépek és mikroprocesszorok, mint például a Manchester Baby és az RCA 1802, nem rendelkeztek egyetlen szubrutinhívási utasítással sem.A szubrutinok megvalósíthatók voltak, de megkövetelték a programozóktól, hogy minden híváshelyen használják a hívássorozatot—utasítások sorozatát.
a szubrutinokat Konrad Zuse Z4-ben hajtották végre 1945-ben.
1945-ben Alan M. Turing a “bury” és a “unbury” kifejezéseket használta a szubrutinok hívására és visszatérésére.
1947 januárjában John Mauchly bemutatott általános megjegyzések ‘A Symposium of Large Scale Digital Calculating Machinery’ keretében közös szponzori Harvard Egyetem és a Bureau of Ordnance, Egyesült Államok Haditengerészete. Itt a Soros és párhuzamos működést tárgyalja, ami
javaslatot tesz…a szerkezet a gép nem kell bonyolult egy kicsit. Mivel az eljáráshoz szükséges összes logikai jellemző rendelkezésre áll, lehetséges kifejleszteni egy kódolási utasítást a szubrutinok memóriába helyezésére a gép által ismert helyeken, oly módon, hogy azok könnyen használatba vehetők legyenek.
más szavakkal, az A szubrutint osztásként, a B szubrutint komplex szorzásként, a C szubrutint pedig egy számsorozat standard hibájának értékeléseként lehet kijelölni, és így tovább az adott problémához szükséges szubrutinok listáján keresztül. … Ezeket a szubrutinokat ezután a gép tárolja, és mindössze annyit kell tennie, hogy rövid hivatkozást tesz rájuk szám szerint, amint azt a kódolás jelzi.
Kay McNulty szorosan együttműködött John Mauchly-val az ENIAC csapatában, és kifejlesztett egy ötletet az ENIAC számítógép számára, amelyet a második világháború alatt programozott. ő és a többi ENIAC programozó a szubrutinokat használta a rakéták pályájának kiszámításához.
Goldstine és von Neumann írt egy papírt kelt augusztus 16-án 1948 megvitatása használata szubrutinok.
néhány nagyon korai számítógép és mikroprocesszor, mint például az IBM 1620, az Intel 4004 és az Intel 8008, valamint a PIC mikrovezérlők, egy utasításos szubrutinhívással rendelkeznek, amely egy dedikált hardverköteget használ a visszatérési címek tárolására-ezek a hardverek csak néhány szintű szubrutin beágyazást támogatnak, de támogatják a rekurzív szubrutinokat. Az 1960-as évek közepe előtti gépek—például az UNIVAC I, A PDP-1 és az IBM 1130—általában olyan hívási konvenciót használnak, amely az utasításszámlálót a hívott szubrutin első memóriahelyére mentette. Ez lehetővé teszi a szubrutin fészkelésének önkényesen mély szintjeit, de nem támogatja a rekurzív szubrutinokat. A PDP-11 (1970) az egyik első számítógép, amely verem-toló szubrutinhívási utasítással rendelkezik; ez a funkció támogatja mind az önkényesen mély szubrutin fészkelést, mind a rekurzív szubrutinokat.
Language supportEdit
a nagyon korai összeszerelőkben a szubrutin támogatás korlátozott volt. A szubrutinokat nem különítették el kifejezetten egymástól vagy a főprogramtól, sőt egy szubrutin forráskódja átfedhető más alprogramok forráskódjával. Egyes assemblerek előre definiált makrókat kínálnak a hívási és visszatérési szekvenciák létrehozásához. Az 1960-as évekre az összeszerelők általában sokkal kifinomultabb támogatást nyújtottak mind az inline, mind a külön összeállított szubrutinok számára, amelyek összekapcsolhatók voltak.
Subrutine librariesEdit
még ezzel a nehézkes megközelítéssel is, a szubrutinok nagyon hasznosnak bizonyultak. Egyrészt lehetővé tették ugyanazon kód használatát számos különböző programban. Sőt, a memória nagyon szűkös erőforrás volt a korai számítógépeken, a szubrutinok pedig jelentős megtakarítást tettek lehetővé a programok méretében.
sok korai számítógép lyukasztott papírszalagról töltötte be a program utasításait a memóriába. Ezután minden szubrutint külön szalagdarab biztosíthat, amelyet a főprogram (vagy a “fővonal”) előtt vagy után töltöttek be vagy illesztettek; és ugyanazt a szubrutinszalagot ezután sok különböző program használhatja. Hasonló megközelítést alkalmaztak azokban a számítógépekben is, amelyek lyukasztott kártyákat használtak a fő bemenetükhöz. A név szubrutin könyvtár eredetileg könyvtárat jelentett, szó szerinti értelemben, amely indexelt szalaggyűjteményeket vagy kártyacsomagokat tartott kollektív használatra.
return by indirect jumpEdit
az önmódosító kód szükségességének kiküszöbölése érdekében a számítógép-tervezők végül közvetett ugrási utasítást adtak, amelynek operandusa ahelyett, hogy maga a visszatérési cím lenne, egy változó vagy processzor regiszter helye volt, amely tartalmazza a visszatérési címet.
ezeken a számítógépeken a szubrutin visszatérési ugrásának módosítása helyett a hívó program a visszatérési címet egy változóban tárolja, így amikor a szubrutin befejeződött, közvetett ugrást hajt végre, amely a végrehajtást az előre meghatározott változó által megadott helyre irányítja.
ugrás a subrutineedit
egy másik előrelépés volt a ugrás a subrutine utasítás, amely egyesítette a Mentés a visszatérési címet a hívó ugrás, ezáltal minimalizálva rezsi jelentősen.
az IBM System/360-ban például az eljáráshívásra tervezett bal vagy BALR elágazási utasítások a visszatérési címet az utasításban meghatározott processzor regiszterbe mentenék, a 14.konvenciós regiszter szerint. A visszatéréshez a szubrutinnak csak egy közvetett elágazási utasítást (BR) kellett végrehajtania ezen a regiszteren keresztül. Ha a szubrutinnak valamilyen más célra szüksége volt erre a regiszterre (például egy másik szubrutin meghívására), akkor a regiszter tartalmát egy privát memóriahelyre vagy egy regiszter verembe menti.
olyan rendszerekben, mint a HP 2100, a JSB utasítás hasonló feladatot hajtana végre, azzal a különbséggel, hogy a visszatérési címet abban a memóriahelyen tárolták, amely az ág célpontja volt. Az eljárás végrehajtása valójában a következő memóriahelyen kezdődik. A HP 2100 assembly nyelven például írnánk
... JSB MYSUB (Calls subroutine MYSUB.) BB ... (Will return here after MYSUB is done.)
a mysub nevű alprogram meghívására a főprogramból. A szubrutin kódolása:
MYSUB NOP (Storage for MYSUB's return address.) AA ... (Start of MYSUB's body.) ... JMP MYSUB,I (Returns to the calling program.)
a JSB utasítás elhelyezte a következő utasítás címét (nevezetesen BB) az operandusként megadott helyre (nevezetesen MYSUB), majd ezt követően elágazik a következő helyre (nevezetesen AA = MYSUB + 1). A szubrutin ezután visszatérhet a főprogramhoz a közvetett ugrás végrehajtásával JMP MYSUB, I amely elágazik a helyen tárolt helyre mysub.
a Fortran és más nyelvek fordítói könnyen használhatják ezeket az utasításokat, ha rendelkezésre állnak. Ez a megközelítés többszintű hívásokat támogatott; mivel azonban egy szubrutin visszatérési címét, paramétereit és visszatérési értékeit rögzített memóriahelyekhez rendelték, nem tette lehetővé a rekurzív hívásokat.
egyébként hasonló módszert használt a Lotus 1-2-3, az 1980-as évek elején, hogy felfedezzék az újraszámítási függőségeket egy táblázatban. Nevezetesen, minden cellában helyet foglaltak el a visszatérési cím tárolására. Mivel a körkörös hivatkozások nem engedélyezettek a természetes újraszámítási sorrendhez, ez lehetővé teszi a fa sétát anélkül, hogy helyet foglalna a memóriában lévő verem számára, ami nagyon korlátozott volt olyan kis számítógépeken, mint az IBM PC.
Call stackEdit
a szubrutinhívások legtöbb modern implementációja egy hívásköteget, a verem adatstruktúrájának egy speciális esetét használja a szubrutinhívások és-visszatérések végrehajtására. Minden eljáráshívás létrehoz egy új bejegyzést, amelyet veremkeretnek hívnak, a verem tetején; amikor az eljárás visszatér, a verem kerete törlődik a veremből, és a hely felhasználható más eljáráshívásokhoz. Minden verem keret tartalmazza a megfelelő hívás személyes adatait, amelyek jellemzően tartalmazzák az eljárás paramétereit és belső változóit, valamint a visszatérési címet.
a hívássorozat végrehajtható közönséges utasítások sorozatával (ezt a megközelítést még mindig használják csökkentett utasításkészlet-számítás (RISC) és nagyon hosszú utasításszó (VLIW) architektúrák), de sok, az 1960-as évek vége óta tervezett hagyományos gép tartalmaz speciális utasításokat erre a célra.
a hívási verem általában összefüggő memóriaterületként valósul meg. Tetszőleges tervezési választás, hogy a verem alja a legalacsonyabb vagy a legmagasabb cím-e ezen a területen, így a verem előre vagy hátra nőhet a memóriában; sok architektúra azonban az utóbbit választotta.
egyes tervek, nevezetesen néhány Forth megvalósítások, használt két különálló Stack, az egyik elsősorban a vezérlő információkat (mint a visszatérési címek és hurok számlálók), a másik az adatok. Az előbbi volt, vagy úgy működött, mint egy hívási verem, és csak közvetetten volt elérhető a programozó számára más nyelvi konstrukciókon keresztül,míg az utóbbi közvetlenebb volt.
amikor a verem alapú eljáráshívásokat először vezették be, fontos motiváció volt az értékes memória megtakarítása. Ezzel a sémával a fordítónak nem kell külön helyet foglalnia a memóriában az egyes eljárások személyes adatai (paraméterek, visszatérési cím és helyi változók) számára. A verem bármikor csak a jelenleg aktív hívások személyes adatait tartalmazza (nevezetesen azokat, amelyeket meghívtak, de még nem tértek vissza). Mivel a programokat általában könyvtárakból állították össze, nem volt (és még mindig van) ritka olyan programokat találni, amelyek több ezer szubrutint tartalmaznak, amelyek közül csak egy maroknyi aktív egy adott pillanatban. Az ilyen programok esetében a hívásköteg mechanizmus jelentős mennyiségű memóriát takaríthat meg. Valójában a hívásköteg mechanizmus tekinthető a legkorábbi és legegyszerűbb módszernek az automatikus memóriakezeléshez.
a call stack metódus másik előnye azonban, hogy lehetővé teszi a rekurzív szubrutinhívásokat, mivel minden egyes beágyazott hívás ugyanahhoz az eljáráshoz külön példányt kap a személyes adataiból.
késleltetett halmozás Szerkesztés
a hívásköteg mechanizmus egyik hátránya az eljáráshívás megnövekedett költsége és annak megfelelő visszatérése. A többletköltség magában foglalja a veremmutató növelését és csökkentését (és egyes architektúrákban a verem túlcsordulásának ellenőrzését), valamint a helyi változók és paraméterek elérését frame-relative címekkel, az abszolút címek helyett. A költségek megnövelt végrehajtási időben, vagy megnövekedett processzor komplexitásban, vagy mindkettőben realizálhatók.
Ez a rezsi a legnyilvánvalóbb és leginkább kifogásolható a levélfolyamatokban vagy a levélfunkciókban, amelyek anélkül térnek vissza, hogy bármilyen eljárást hívnának maguknak.Ennek a rezsinek a csökkentése érdekében sok modern fordító megpróbálja késleltetni a hívásköteg használatát, amíg valóban szükség van rá. Például egy P eljárás meghívása tárolhatja a hívott eljárás visszatérési címét és paramétereit bizonyos processzor regiszterekben, és egy egyszerű ugrással átviheti a vezérlést az eljárás testébe. Ha a P eljárás más hívás kezdeményezése nélkül tér vissza, a hívásköteg egyáltalán nem kerül felhasználásra. Ha P – nek meg kell hívnia egy másik eljárást Q, akkor a hívási verem segítségével elmenti a regiszterek tartalmát (például a visszatérési címet), amelyekre a Q visszatérése után szükség lesz.