Apakah tumpukan adalah satu-satunya cara yang masuk akal untuk menyusun program?

74

Sebagian besar arsitektur yang saya lihat mengandalkan tumpukan panggilan untuk menyimpan / mengembalikan konteks sebelum panggilan fungsi. Ini adalah paradigma umum yang mendorong operasi pop dan built-in untuk sebagian besar prosesor. Apakah ada sistem yang berfungsi tanpa tumpukan? Jika demikian, bagaimana cara kerjanya, dan untuk apa mereka digunakan?

ConditionRacer
sumber
5
Mengingat bagaimana fungsi diharapkan berperilaku dalam bahasa seperti-C (yaitu Anda dapat membuat sarang panggilan sedalam yang Anda suka, dan dapat kembali keluar dalam urutan terbalik), tidak jelas bagi saya bagaimana lagi orang dapat mengimplementasikan panggilan fungsi tanpa menjadi luar biasa tidak efisien. Anda dapat misalnya memaksa programmer untuk menggunakan gaya kelanjutan-lewat atau bentuk pemrograman aneh lainnya, tetapi tampaknya tidak ada yang benar-benar bekerja dengan CPS pada level rendah karena suatu alasan.
Kevin
5
GLSL bekerja tanpa tumpukan (seperti halnya bahasa lain di braket tertentu). Itu hanya menolak panggilan rekursif.
Leushenko
3
Anda mungkin juga ingin melihat ke dalam Daftar jendela , yang digunakan oleh beberapa arsitektur RISC.
Mark Booth
2
@Kevin: "Kompiler FORTRAN awal tidak mendukung rekursi dalam subrutin. Arsitektur komputer awal tidak mendukung konsep stack, dan ketika mereka secara langsung mendukung panggilan subrutin, lokasi pengembalian sering disimpan di satu lokasi tetap yang berdekatan dengan kode subrutin, yang tidak tidak mengizinkan subrutin untuk dipanggil lagi sebelum panggilan subrutin sebelumnya telah kembali. Meskipun tidak ditentukan dalam Fortran 77, banyak penyusun F77 mendukung rekursi sebagai opsi, sementara itu menjadi standar di Fortran 90. " en.wikipedia.org/wiki/Fortran#FORTRAN_II
Mooing Duck
3
Mikrokontroler P8X32A ("Propeller") tidak memiliki konsep stack dalam bahasa assembly standar (PASM). Instruksi yang bertanggung jawab untuk melompat juga memodifikasi sendiri instruksi pengembalian dalam RAM untuk menentukan ke mana harus kembali - yang dapat dipilih secara sewenang-wenang. Menariknya, bahasa "Spin" (bahasa tingkat tinggi yang ditafsirkan yang berjalan pada chip yang sama) memang memiliki semantik stack tradisional.
Wossname

Jawaban:

50

Alternatif (agak) populer untuk tumpukan panggilan adalah lanjutan .

Parrot VM berbasiskan kelanjutan, misalnya. Ini sepenuhnya stackless: data disimpan dalam register (seperti Dalvik atau LuaVM, Parrot berbasis register), dan aliran kontrol diwakili dengan kelanjutan (tidak seperti Dalvik atau LuaVM, yang memiliki panggilan stack).

Struktur data populer lainnya, yang biasanya digunakan oleh Smalltalk dan Lisp VM adalah tumpukan spageti, yang seperti jaringan tumpukan.

Seperti @rwong tunjukkan , gaya kelanjutan-kelanjutan adalah alternatif dari tumpukan panggilan. Program yang ditulis dengan (atau ditransformasikan ke) gaya kelanjutan-lewat tidak pernah kembali, sehingga tidak perlu ada tumpukan.

Menjawab pertanyaan Anda dari perspektif yang berbeda: dimungkinkan untuk memiliki panggilan stack tanpa memiliki tumpukan terpisah, dengan mengalokasikan frame tumpukan di heap. Beberapa implementasi Lisp dan Skema melakukan ini.

Jörg W Mittag
sumber
4
Itu tergantung pada definisi Anda tentang tumpukan. Saya tidak yakin bahwa memiliki daftar tautan (atau array pointer ke atau ...) dari tumpukan frame sangat "bukan tumpukan" sebagai "representasi tumpukan yang berbeda"; dan program dalam bahasa CPS (dalam praktiknya) cenderung untuk membangun apa yang secara efektif terkait dengan daftar kelanjutan yang sangat mirip dengan tumpukan (jika belum, Anda mungkin melihat GHC, yang mendorong apa yang disebutnya "kelanjutan" ke tumpukan linear untuk efisiensi).
Jonathan Cast
6
" Program yang ditulis dengan (atau diubah menjadi) gaya kelanjutan tidak pernah kembali " ... terdengar tidak menyenangkan.
Rob Penridge
5
@RobPenridge: agak samar, saya setuju. CPS berarti bahwa alih-alih kembali, fungsi mengambil sebagai argumen tambahan fungsi lain untuk dipanggil ketika pekerjaan mereka selesai. Jadi, ketika Anda memanggil fungsi dan Anda memiliki beberapa pekerjaan lain yang perlu Anda lakukan setelah Anda memanggil fungsi, alih-alih menunggu fungsi kembali dan kemudian melanjutkan pekerjaan Anda, Anda membungkus pekerjaan yang tersisa ("kelanjutan" ) ke dalam suatu fungsi, dan meneruskan fungsi itu sebagai argumen tambahan. Fungsi yang Anda panggil lalu memanggil fungsi itu alih-alih kembali, dan seterusnya dan seterusnya. Tidak ada fungsi yang kembali, hanya
Jörg W Mittag
3
... memanggil fungsi berikutnya. Oleh karena itu, Anda tidak perlu tumpukan panggilan, karena Anda tidak perlu kembali dan mengembalikan keadaan mengikat fungsi yang sebelumnya disebut. Alih-alih membawa sekitar kondisi masa lalu sehingga Anda dapat kembali ke sana, Anda membawa sekitar kondisi masa depan , jika Anda mau.
Jörg W Mittag
1
@ siaran: Fitur penentu tumpukan adalah IMO yang hanya dapat Anda akses elemen paling atas. Daftar kelanjutan, OTOH, akan memberi Anda akses ke semua kelanjutan dan bukan hanya stackframe teratas. Jika Anda memiliki pengecualian yang dapat dilanjutkan dengan gaya Smalltalk, misalnya, Anda harus dapat melintasi tumpukan tanpa muncul. Dan memiliki kelanjutan dalam bahasa sementara masih ingin menjaga gagasan akrab dari tumpukan panggilan mengarah ke tumpukan spageti, yang pada dasarnya adalah pohon tumpukan di mana kelanjutan "garpu" tumpukan.
Jörg W Mittag
36

Di masa lalu, prosesor tidak memiliki instruksi tumpukan, dan bahasa pemrograman tidak mendukung rekursi. Seiring waktu, semakin banyak bahasa memilih untuk mendukung rekursi, dan perangkat keras mengikuti paket dengan kemampuan alokasi bingkai tumpukan. Dukungan ini sangat bervariasi selama bertahun-tahun dengan prosesor yang berbeda. Beberapa prosesor mengadopsi stack frame dan / atau register stack pointer; beberapa instruksi yang diadopsi akan menyelesaikan alokasi frame tumpukan dalam satu instruksi.

Saat prosesor maju dengan level tunggal, lalu cache multi-level, satu keuntungan penting dari stack adalah lokalitas cache. Bagian atas tumpukan hampir selalu ada dalam cache. Setiap kali Anda dapat melakukan sesuatu yang memiliki tingkat hit cache yang besar, Anda berada di jalur yang benar dengan prosesor modern. Cache yang diterapkan ke tumpukan berarti bahwa variabel lokal, parameter, dll. Hampir selalu ada dalam cache, dan menikmati tingkat kinerja tertinggi.

Singkatnya, penggunaan stack berevolusi baik dalam perangkat keras maupun perangkat lunak. Ada model lain (misalnya komputasi aliran data dicoba untuk jangka waktu yang lama), namun, lokalitas tumpukan membuatnya berfungsi dengan sangat baik. Lebih lanjut, kode prosedural adalah apa yang prosesor inginkan, untuk kinerja: satu instruksi mengatakan apa yang harus dilakukan setelah yang lain. Ketika instruksi keluar dari urutan linier, prosesor melambat sangat, setidaknya sampai sekarang, karena kita belum menemukan cara untuk membuat akses acak secepat akses berurutan. (Btw, ada masalah serupa di setiap level memori, dari cache, ke memori utama, ke disk ...)

Antara kinerja yang ditunjukkan dari instruksi akses sekuensial dan perilaku cache yang menguntungkan dari tumpukan panggilan, kami memiliki, setidaknya saat ini, model kinerja yang unggul.

(Kami mungkin juga melemparkan keterputusan struktur data ke dalam karya ...)

Ini tidak berarti bahwa model pemrograman lain tidak dapat berfungsi, terutama ketika mereka dapat diterjemahkan ke dalam instruksi berurutan dan memanggil model tumpukan perangkat keras saat ini. Tetapi ada keuntungan berbeda untuk model yang mendukung di mana perangkat keras berada. Namun, hal-hal tidak selalu tetap sama, jadi kita bisa melihat perubahan di masa depan karena teknologi memori dan transistor yang berbeda memungkinkan untuk lebih paralelisme. Selalu ada olok-olok antara bahasa pemrograman dan kemampuan perangkat keras, jadi, kita akan lihat!

Erik Eidt
sumber
9
Faktanya, GPU masih tidak memiliki tumpukan sama sekali. Anda dilarang mengulangi di GLSL / SPIR-V / OpenCL (tidak yakin tentang HLSL, tapi mungkin, saya tidak melihat alasan mengapa itu akan berbeda). Cara mereka benar-benar menangani pemanggilan fungsi "tumpukan" adalah dengan menggunakan sejumlah besar register yang tidak masuk akal.
LinearZoetrope
@ Jan: Itu detail implementasi tingkat besar, seperti dapat dilihat dari arsitektur SPARC. Seperti GPU Anda, SPARC memiliki set register yang sangat besar, tetapi unik karena memiliki jendela geser yang pada sampulnya menumpahkan register yang sangat lama ke tumpukan dalam RAM. Jadi ini benar-benar hibrida antara kedua model. Dan SPARC tidak menentukan secara pasti berapa banyak register fisik yang ada, seberapa besar jendela registernya, sehingga implementasi yang berbeda dapat terletak di mana saja pada skala "jumlah register yang sangat besar" hingga "cukup untuk satu jendela, pada setiap panggilan fungsi tumpah langsung ke tumpukan "
MSalters
Sisi bawah dari model tumpukan panggilan adalah array itu, dan / atau alamat overflow harus diawasi dengan sangat hati-hati, karena program modifikasi diri sebagai exploit dimungkinkan jika bit sewenang-wenang dari tumpukan dapat dieksekusi.
BenPen
14

TL; DR

  • Tumpukan panggilan sebagai mekanisme panggilan fungsi:
    1. Biasanya disimulasikan oleh perangkat keras tetapi tidak mendasar untuk pembangunan perangkat keras
    2. Sangat penting untuk pemrograman imperatif
    3. Tidak mendasar untuk pemrograman fungsional
  • Stack sebagai abstraksi "last-in, first-out" (LIFO) adalah dasar untuk ilmu komputer, algoritma, dan bahkan beberapa domain non-teknis.
  • Beberapa contoh organisasi program yang tidak menggunakan tumpukan panggilan:
    • Gaya kelanjutan-kelanjutan (CPS)
    • Mesin negara - perulangan raksasa, dengan segala yang disematkan. (Dimaksudkan untuk terinspirasi oleh arsitektur firmware Saab Gripen, dan dikaitkan dengan komunikasi oleh Henry Spencer dan direproduksi oleh John Carmack.) (Catatan # 1)
    • Arsitektur dataflow - jaringan aktor yang terhubung oleh antrian (FIFO). Antrian kadang-kadang disebut saluran.

Sisa dari jawaban ini adalah kumpulan pikiran dan anekdot yang acak, dan karenanya agak tidak teratur.


Tumpukan yang telah Anda gambarkan (sebagai mekanisme panggilan fungsi) khusus untuk pemrograman imperatif.

Di bawah pemrograman imperatif, Anda akan menemukan kode mesin. Kode mesin dapat meniru tumpukan panggilan dengan mengeksekusi urutan kecil instruksi.

Di bawah kode mesin, Anda akan menemukan perangkat keras yang bertanggung jawab untuk menjalankan perangkat lunak. Sementara mikroprosesor modern terlalu rumit untuk dijelaskan di sini, orang dapat membayangkan bahwa ada desain yang sangat sederhana yang lambat tetapi masih mampu mengeksekusi kode mesin yang sama. Desain yang begitu sederhana akan memanfaatkan elemen dasar dari logika digital:

  1. Logika kombinasional, yaitu koneksi gerbang logika (dan, atau, tidak, ...) Perhatikan bahwa "logika kombinasional" tidak termasuk umpan balik.
  2. Memori, yaitu sandal jepit, kait, register, SRAM, DRAM, dll.
  3. Mesin negara yang terdiri dari beberapa logika kombinasi dan beberapa memori, cukup sehingga dapat mengimplementasikan "pengontrol" yang mengelola sisa perangkat keras.

Diskusi berikut berisi banyak contoh cara alternatif menyusun program penting.

Struktur program seperti ini akan terlihat seperti ini:

void main(void)
{
    do
    {
        // validate inputs for task 1
        // execute task 1, inlined, 
        // must complete in a deterministically short amount of time
        // and limited to a statically allocated amount of memory
        // ...
        // validate inputs for task 2
        // execute task 2, inlined
        // ...
        // validate inputs for task N
        // execute task N, inlined
    }
    while (true);
    // if this line is reached, tell the programmers to prepare
    // themselves to appear before an accident investigation board.
    return 0; 
}

Gaya ini akan sesuai untuk mikrokontroler, yaitu bagi mereka yang melihat perangkat lunak sebagai pendamping fungsi perangkat keras.


rwong
sumber
@Peteris: Tumpukan adalah struktur data LIFO.
Christopher Creutzig
1
Menarik. Saya akan berpikir sebaliknya. Misalnya, FORTRAN adalah bahasa pemrograman yang penting, dan versi awal tidak menggunakan tumpukan panggilan. Namun, rekursi merupakan hal mendasar untuk pemrograman fungsional, dan saya pikir itu tidak mungkin diterapkan dalam kasus umum tanpa menggunakan stack.
TED
@ TED - dalam implementasi bahasa fungsional ada struktur data stack (atau biasanya, pohon) di sana mewakili perhitungan yang tertunda tetapi Anda tidak perlu menjalankannya dengan instruksi menggunakan mode pengalamatan berorientasi-stack mesin atau bahkan instruksi panggilan / pengembalian (Dengan cara bersarang / rekursif - mungkin hanya sebagai bagian dari loop mesin negara).
davidbak
@davidbak - IIRC, algoritma rekursif cukup banyak harus ekor-rekursif agar dapat menyingkirkan tumpukan. Mungkin ada beberapa kasus lain di mana Anda dapat mengoptimalkannya, tetapi dalam kasus umum , Anda harus memiliki tumpukan . Bahkan, saya diberitahu ada bukti matematis dari benda ini. Jawaban ini mengklaim itu adalah teorema Gereja-Turing (saya pikir berdasarkan fakta bahwa mesin Turing menggunakan tumpukan?)
TED
1
@ TED - Saya setuju dengan Anda. Saya percaya miskomunikasi di sini adalah bahwa saya membaca posting OP untuk berbicara tentang arsitektur sistem yang berarti bagi saya arsitektur mesin . Saya pikir orang lain yang menjawab di sini memiliki pemahaman yang sama. Jadi kita yang mengerti bahwa konteksnya telah menjawab dengan menjawab bahwa Anda tidak memerlukan tumpukan pada level mode instruksi mesin / pengalamatan. Tetapi saya dapat melihat pertanyaannya juga dapat diartikan sebagai, semata-mata, apakah suatu sistem bahasa secara umum membutuhkan tumpukan panggilan. Jawaban itu juga tidak, tetapi karena berbagai alasan.
davidbak
11

Tidak, belum tentu.

Membaca koran lama Appel's Garbage Collection bisa lebih cepat dari Stack Allocation . Ini menggunakan gaya kelanjutan lewat dan menunjukkan implementasi stackless.

Perhatikan juga bahwa arsitektur komputer lama (mis. IBM / 360 ) tidak memiliki register tumpukan perangkat keras. Tetapi OS dan kompiler memesan register untuk penunjuk tumpukan dengan konvensi (terkait dengan konvensi panggilan ) sehingga mereka dapat memiliki stack panggilan perangkat lunak .

Pada prinsipnya, seluruh kompiler C program dan optimizer dapat mendeteksi case (agak umum untuk embedded system) di mana grafik panggilan dikenal secara statis dan tanpa rekursi (atau pointer fungsi). Dalam sistem seperti itu, setiap fungsi dapat menyimpan alamat kembalinya di lokasi statis tetap (dan itulah cara Fortran77 bekerja di komputer era 1970).

Saat ini, prosesor juga memiliki tumpukan panggilan (dan instruksi panggilan & pengembalian mesin) yang mengetahui cache CPU .

Basile Starynkevitch
sumber
1
Cukup yakin FORTRAN berhenti menggunakan lokasi pengembalian statis ketika FORTRAN-66 keluar dan membutuhkan dukungan untuk SUBROUTINEdan FUNCTION. Anda benar untuk versi sebelumnya, meskipun (FORTRAN-IV dan mungkin WATFIV).
TMN
Dan COBOL, tentu saja. Dan poin yang sangat baik tentang IBM / 360 - itu mendapat cukup banyak penggunaan meskipun tidak ada mode pengalamatan stack hardware. (R14, saya percaya itu?) Dan memiliki kompiler untuk bahasa berbasis stack, misalnya, PL / I, Ada, Algol, C.
davidbak
Memang, saya belajar 360 di perguruan tinggi dan merasa membingungkan pada awalnya.
JDługosz
1
@ JDługosz Cara terbaik bagi siswa modern arsitektur komputer untuk mempertimbangkan 360 adalah sebagai mesin RISC yang sangat sederhana ... walaupun dengan lebih dari satu format instruksi ... dan beberapa anomali seperti TRdan TRT.
davidbak
Bagaimana dengan "nol dan tambahkan dikemas" untuk memindahkan register? Tetapi "cabang dan tautan" daripada tumpukan untuk alamat pengirim telah membuat balik.
JDługosz
10

Sejauh ini Anda sudah mendapat jawaban yang bagus; izinkan saya memberi Anda sebuah contoh yang tidak praktis tetapi sangat mendidik tentang bagaimana Anda bisa mendesain bahasa tanpa gagasan tumpukan atau "aliran kontrol" sama sekali. Berikut adalah program yang menentukan faktorial:

function f(i) => if i == 0 then 1 else i * f(i - 1)
let x = f(3)

Kami menempatkan program ini dalam sebuah string, dan kami mengevaluasi program dengan substitusi teks. Jadi ketika kami mengevaluasi f(3), kami melakukan pencarian dan ganti dengan 3 untuk saya, seperti ini:

function f(i) => if i == 0 then 1 else i * f(i - 1)
let x = if 3 == 0 then 1 else 3 * f(3 - 1)

Bagus. Sekarang kita melakukan substitusi tekstual lain: kita melihat bahwa kondisi "jika" salah dan melakukan penggantian string lain, menghasilkan program:

function f(i) => if i == 0 then 1 else i * f(i - 1)
let x = 3 * f(3 - 1)

Sekarang kita lakukan penggantian string lain pada semua sub-ekspresi yang melibatkan konstanta:

function f(i) => if i == 0 then 1 else i * f(i - 1)
let x = 3 * f(2)

Dan Anda lihat bagaimana ini terjadi; Saya tidak akan memaksakan poin lebih jauh. Kita bisa terus melakukan serangkaian pergantian string sampai kita let x = 6selesai dan kita akan selesai.

Kami menggunakan tumpukan secara tradisional untuk variabel lokal dan informasi lanjutan; ingat, tumpukan tidak memberi tahu Anda dari mana Anda berasal, itu memberi tahu Anda di mana Anda akan pergi berikutnya dengan nilai pengembalian di tangan.

Dalam model substitusi string pemrograman, tidak ada "variabel lokal" pada stack; parameter formal disubstitusikan untuk nilai-nilai mereka ketika fungsi diterapkan pada argumennya, daripada dimasukkan ke dalam tabel pencarian pada stack. Dan tidak ada "pergi ke suatu tempat berikutnya" karena evaluasi program hanya menerapkan aturan sederhana untuk substitusi string untuk menghasilkan program yang berbeda tetapi setara.

Sekarang, tentu saja, benar-benar melakukan pergantian string mungkin bukan cara yang tepat. Tetapi bahasa pemrograman yang mendukung "penalaran kesetaraan" (seperti Haskell) secara logis menggunakan teknik ini.

Eric Lippert
sumber
3
Retina adalah contoh bahasa pemrograman berbasis-Regex yang menggunakan operasi string untuk perhitungan.
Andrew Piliser
2
@AndrewPiliser Dirancang dan diimplementasikan oleh Bung keren ini .
kucing
3

Sejak publikasi oleh Parnas pada tahun 1972 tentang kriteria yang akan digunakan dalam mendekomposisi sistem menjadi modul , telah diterima secara wajar bahwa menyembunyikan informasi dalam perangkat lunak adalah hal yang baik. Ini mengikuti debat panjang sepanjang 60-an tentang dekomposisi struktural dan pemrograman modular.

Modularitas

Hasil yang diperlukan dari hubungan black-box antara modul yang dilaksanakan oleh kelompok yang berbeda dalam sistem multi-threaded membutuhkan mekanisme untuk mengizinkan reentrancy dan sarana untuk melacak grafik panggilan dinamis sistem. Aliran eksekusi yang terkontrol harus melewati masuk dan keluar dari banyak modul.

Pelingkupan dinamis

Segera setelah pelingkupan leksikal tidak cukup untuk melacak perilaku dinamis, maka beberapa pembukuan runtime diperlukan untuk melacak perbedaannya.

Mengingat setiap utas (menurut definisi) hanya memiliki satu penunjuk instruksi saat ini, tumpukan LIFO sesuai untuk melacak setiap pemanggilan.

Pengecualian

Jadi, sementara model kelanjutan tidak mempertahankan struktur data secara eksplisit untuk stack, masih ada pemanggilan bersarang modul yang harus dipertahankan di suatu tempat!

Bahkan bahasa deklaratif mempertahankan riwayat evaluasi, atau sebaliknya meratakan rencana eksekusi untuk alasan kinerja dan mempertahankan kemajuan dengan cara lain.

Struktur loop tak berujung yang diidentifikasi oleh rwong adalah umum pada aplikasi dengan keandalan tinggi dengan penjadwalan statis yang melarang banyak struktur pemrograman umum tetapi menuntut agar seluruh aplikasi dianggap sebagai kotak putih tanpa menyembunyikan informasi yang signifikan.

Beberapa loop tak berujung bersamaan tidak memerlukan struktur apa pun untuk menahan alamat pengirim karena tidak memanggil fungsi, membuat pertanyaan dapat diperdebatkan. Jika mereka berkomunikasi menggunakan variabel bersama, maka ini dapat dengan mudah berubah menjadi analogi alamat pengirim gaya Fortran.

Pekka
sumber
1
Anda melukis diri sendiri di sudut dengan menganggap " sistem multi-utas". Mesin finite-state yang digabungkan mungkin memiliki beberapa utas dalam implementasinya, tetapi tidak memerlukan tumpukan LIFO. Tidak ada batasan dalam FSM bahwa Anda kembali ke keadaan sebelumnya, apalagi dalam urutan LIFO. Jadi itu adalah sistem multi-utas nyata yang tidak dipegangnya. Dan jika Anda membatasi diri Anda pada definisi multi-threaded sebagai "tumpukan fungsi panggilan paralel independen" Anda berakhir dengan definisi melingkar.
MSalters
Saya tidak membaca pertanyaan seperti itu. OP terbiasa dengan panggilan fungsi, tetapi bertanya tentang sistem lain .
MSalters
@MSalters Diperbarui untuk menggabungkan loop tak berujung bersamaan. Model ini valid, tetapi membatasi skalabilitas. Saya menyarankan bahwa bahkan mesin negara moderat menggabungkan pemanggilan fungsi untuk mengizinkan penggunaan kembali kode.
Pekka
2

Semua mainframe lama (IBM System / 360) tidak memiliki gagasan stack sama sekali. Pada 260, misalnya, parameter dibangun di lokasi tetap dalam memori dan ketika subrutin dipanggil, itu disebut dengan R1menunjuk ke blok parameter dan R14berisi alamat pengirim. Rutin yang dipanggil, jika ingin memanggil subrutin lain, harus menyimpan R14di lokasi yang diketahui sebelum melakukan panggilan itu.

Ini jauh lebih dapat diandalkan daripada tumpukan karena semuanya dapat disimpan di lokasi memori tetap yang ditetapkan pada waktu kompilasi dan dapat dijamin 100% bahwa proses tidak akan pernah kehabisan tumpukan. Tidak ada "Alokasikan 1MB dan silangkan jari Anda" yang harus kita lakukan saat ini.

Panggilan subrutin rekursif diizinkan dalam PL / I dengan menentukan kata kunci RECURSIVE. Mereka berarti bahwa memori yang digunakan oleh subrutin secara dinamis daripada dialokasikan secara statis. Tapi panggilan rekursif jarang terjadi seperti sekarang.

Operasi tanpa tumpukan juga membuat multi-threading masif menjadi jauh lebih mudah, itulah sebabnya upaya sering dilakukan untuk membuat bahasa modern menjadi tidak bertali. Tidak ada alasan sama sekali, misalnya, mengapa kompiler C ++ tidak dapat dimodifikasi back-end untuk menggunakan memori yang dialokasikan secara dinamis daripada tumpukan.

Martin Kochanski
sumber