Kompiler JIT untuk C, C ++, dan sejenisnya

33

Apakah ada kompiler just-in-time di luar sana untuk bahasa yang dikompilasi, seperti C dan C ++? (Nama pertama yang muncul di pikiran adalah Dentang dan LLVM! Tapi saya tidak berpikir mereka saat ini mendukungnya.)

Penjelasan:

Saya pikir perangkat lunak dapat mengambil manfaat dari umpan balik profil runtime dan secara agresif dioptimalkan kompilasi hotspot saat runtime, bahkan untuk bahasa yang dikompilasi-ke-mesin seperti C dan C ++.

Optimalisasi yang dipandu profil melakukan pekerjaan yang serupa, tetapi dengan perbedaan JIT akan lebih fleksibel dalam lingkungan yang berbeda. Di PGO Anda menjalankan biner Anda sebelum melepaskannya. Setelah Anda merilisnya, ia tidak akan menggunakan umpan balik lingkungan / input yang dikumpulkan saat runtime. Jadi jika pola input diubah, itu probe hukuman kinerja. Tetapi JIT bekerja dengan baik bahkan dalam kondisi seperti itu.

Namun saya pikir itu kontroversial apakah manfaat kinerja kompilasi JIT melebihi overhead sendiri.

Ebrahim Mohammadi
sumber
1
Sumber daya di luar topik di luar situs.
DeadMG
1
Tidak yakin apakah itu cocok dengan pertanyaan, tetapi untuk prospektif kegunaan, saya menemukan paket Cxx berguna dalam bahasa Julia .. ini memberi Anda prompt C ++ interaktif mirip dengan yang dijelaskan dalam jawaban @ PhilippClaßen.
Antonello
GCC 9 sekarang memiliki kompiler jit gcc.gnu.org/onlinedocs/jit/intro/index.html
user3071643

Jawaban:

33

[Lihat edit riwayat untuk jawaban yang sangat berbeda yang sekarang pada dasarnya sudah usang.]

Ya, ada beberapa kompiler JIT untuk C dan / atau C ++.

CLing (seperti yang Anda tebak dari game) didasarkan pada Dentang / LLVM. Kerjanya seperti seorang juru bahasa. Artinya, Anda memberinya beberapa kode sumber, memberikan perintah untuk menjalankannya, dan itu berjalan. Penekanan di sini terutama pada kenyamanan dan kompilasi cepat, bukan optimalisasi maksimal. Dengan demikian, meskipun secara teknis jawaban untuk pertanyaan itu sendiri, ini tidak benar-benar sesuai dengan niat OP.

Kemungkinan lain adalah NativeJIT . Ini cocok dengan pertanyaan yang agak berbeda. Secara khusus, ia tidak menerima kode sumber C atau C ++, dan kompilasi dan jalankan. Sebaliknya, ini adalah kompiler kecil yang dapat Anda kompilasi ke dalam program C ++ Anda. Ia menerima ekspresi yang pada dasarnya dinyatakan sebagai EDSL di dalam program C ++ Anda, dan menghasilkan kode mesin aktual dari itu, yang kemudian dapat Anda jalankan. Ini lebih cocok dengan kerangka kerja di mana Anda dapat mengkompilasi sebagian besar program Anda dengan kompiler normal, tetapi memiliki beberapa ekspresi yang Anda tidak akan tahu sampai run-time, yang ingin Anda jalankan dengan sesuatu yang mendekati kecepatan eksekusi optimal.

Adapun maksud yang jelas dari pertanyaan asli, saya pikir poin dasar dari jawaban asli saya masih berdiri: sementara kompiler JIT dapat beradaptasi dengan hal-hal seperti data yang bervariasi dari satu eksekusi ke yang berikutnya, atau bahkan bervariasi secara dinamis selama satu eksekusi, kenyataannya adalah bahwa ini membuat perbedaan yang relatif kecil setidaknya sebagai aturan umum. Dalam kebanyakan kasus, menjalankan compiler pada saat run time berarti Anda harus melepaskan sedikit optimisasi, jadi yang terbaik yang biasanya Anda harapkan adalah bahwa itu mendekati secepat kompilator konvensional akan menghasilkan.

Meskipun dimungkinkan untuk mendalilkan situasi di mana informasi yang tersedia untuk kompiler JIT dapat memungkinkannya untuk menghasilkan kode yang jauh lebih baik daripada kompiler konvensional, contoh-contoh kejadian ini dalam praktek tampaknya sangat tidak biasa (dan dalam kebanyakan kasus di mana saya dapat memverifikasi itu terjadi, itu benar-benar karena masalah dalam kode sumber, bukan dengan model kompilasi statis).

Jerry Coffin
sumber
1
Mengapa JIT tidak menyimpan file seperti cache sehingga mereka dapat melewatkan mempelajari kembali semuanya dari awal?
JohnMudd
3
@ JohnMudd: Saya menduga alasannya adalah keamanan. Misalnya, memodifikasi kode yang di-cache, lalu pada saat VM memulai, ia mengeksekusi kode yang saya letakkan di sana alih-alih apa yang ditulisnya di sana.
Jerry Coffin
4
OTOH, jika Anda bisa memodifikasi cache, Anda juga bisa memodifikasi file sumber.
user3125367
1
@ user3125367: Ya, tetapi dalam banyak kasus kompiler melakukan berbagai pengecekan tipe dan semacamnya yang mungkin dilewati jika Anda memuat kode yang dikompilasi langsung dari cache. Tergantung pada JIT, tentu saja - Java melakukan banyak pekerjaan penegakan saat memuat file .class (dikompilasi), tetapi banyak lainnya melakukan jauh lebih sedikit (hampir tidak ada, dalam banyak kasus).
Jerry Coffin
11

Ya, ada kompiler JIT untuk C ++. Dari perspektif kinerja murni, saya pikir Profile Guided Optimization (PGO) masih lebih unggul.

Namun, itu tidak berarti bahwa kompilasi JIT belum digunakan dalam praktiknya. Misalnya, Apple menggunakan LLVM sebagai JIT untuk pipa OpenGL mereka. Itu adalah domain tempat Anda memiliki lebih banyak informasi saat runtime, yang dapat digunakan untuk menghapus banyak kode mati.

Aplikasi lain yang menarik dari JIT adalah Cling, interpreter C ++ interaktif berdasarkan LLVM dan Dentang: https://root.cern.ch/cling

Berikut adalah contoh sesi:

[cling]$ #include <iostream>
[cling]$ std::cout << "Hallo, world!" << std::endl;
Hallo, world!
[cling]$ 3 + 5
(int const) 8
[cling]$ int x = 3; x++
(int) 3
(int const) 3
[cling]$ x
(int) 4

Ini bukan proyek mainan tetapi sebenarnya digunakan di CERN, misalnya, untuk mengembangkan kode untuk Large Hadron Collider.

Philipp Claßen
sumber
7

C ++ / CLI dipasangkan. Memang, C ++ / CLI bukan C ++ tetapi cukup dekat. Yang mengatakan Microsoft JIT tidak melakukan optimisasi berbasis perilaku runtime yang super pintar / imut yang Anda tanyakan, setidaknya tidak sepengetahuan saya. Jadi ini benar-benar tidak membantu.

http://nestedvm.ibex.org/ mengubah MIPS menjadi bytecode Java yang kemudian akan dipasangkan. Masalah dengan pendekatan ini dari pertanyaan Anda adalah bahwa Anda membuang banyak informasi yang berguna pada saat sampai ke JIT.

Logan Capaldo
sumber
2

Pertama, saya menganggap Anda ingin melacak jit daripada metode jit.

Pendekatan terbaik untuk dilakukan adalah mengkompilasi kode ke llvm IR, kemudian menambahkan dalam kode tracing, sebelum menghasilkan executable asli. Setelah blok kode menjadi cukup baik digunakan dan sekali informasi yang cukup tentang nilai - nilai (bukan jenis seperti dalam bahasa dinamis) variabel telah dikumpulkan maka kode dapat dikompilasi ulang (dari IR) dengan penjaga berdasarkan nilai-nilai variabel.

Sepertinya saya ingat ada beberapa kemajuan dalam membuat ac / c ++ jit di dentang dengan nama libclang.

dan_waterworth
sumber
1
AFAIK, libclang adalah sebagian besar fungsi clang yang difaktorkan sebagai perpustakaan. jadi, Anda dapat menggunakannya untuk menganalisis kode sumber untuk membuat pewarnaan sintaksis yang canggih, serat, penelusuran kode, dll.
Javier
@ Javier, kedengarannya benar. Saya pikir ada fungsi di perpustakaan yang mengambil kode sumber * konstan dan menghasilkan llvm ir, tetapi berpikir sekarang, mungkin lebih baik untuk jit berdasarkan ir daripada sumbernya.
dan_waterworth