Jawaban:
Kompiler JIT mengkompilasi kode dengan cepat, tepat sebelum eksekusi atau bahkan ketika mereka sudah mengeksekusi. Dengan cara ini, VM tempat kode berjalan dapat memeriksa pola dalam eksekusi kode untuk memungkinkan optimasi yang hanya mungkin dengan informasi run-time. Lebih lanjut, jika VM memutuskan bahwa versi yang dikompilasi tidak cukup baik untuk alasan apa pun (misalnya, terlalu banyak cache yang terlewat, atau kode yang sering melempar pengecualian tertentu), ia mungkin memutuskan untuk mengkompilasi ulangnya dengan cara yang berbeda, yang mengarah ke cara yang jauh lebih cerdas kompilasi.
Di sisi lain, kompiler C dan C ++ secara tradisional bukan JIT. Mereka mengkompilasi dalam sekali tembakan hanya sekali pada mesin pengembang dan kemudian dieksekusi.
JIT adalah kependekan dari just-in-time compiler, dan namanya misson: selama runtime, ia menentukan optimisasi kode yang berharga dan menerapkannya. Itu tidak menggantikan kompiler biasa tetapi merupakan bagian dari penerjemah. Perhatikan bahwa bahasa seperti Java yang menggunakan kode perantara memiliki keduanya : kompiler normal untuk terjemahan kode sumber ke perantara, dan JIT yang disertakan dalam juru bahasa untuk peningkatan kinerja.
Optimalisasi kode tentu saja dapat dilakukan oleh kompiler "klasik", tetapi perhatikan perbedaan utama: kompiler JIT memiliki akses ke data saat runtime. Ini adalah keuntungan besar ; mengeksploitasinya dengan benar mungkin sulit, jelas.
Pertimbangkan, misalnya, kode seperti ini:
m(a : String, b : String, k : Int) {
val c : Int;
switch (k) {
case 0 : { c = 7; break; }
...
case 17 : { c = complicatedMethod(k, a+b); break; }
}
return a.length + b.length - c + 2*k;
}
Kompiler normal tidak dapat melakukan terlalu banyak tentang hal ini. Kompiler JIT, bagaimanapun, dapat mendeteksi bahwa m
hanya pernah dipanggil dengan k==0
beberapa alasan (hal-hal seperti itu dapat terjadi karena perubahan kode dari waktu ke waktu); kemudian dapat membuat versi kode yang lebih kecil (dan mengkompilasinya ke kode asli, meskipun saya menganggap ini sebagai hal kecil, secara konsep):
m(a : String, b : String) {
return a.length + b.length - 7;
}
Pada titik ini, bahkan mungkin akan sebaris panggilan metode karena sepele sekarang.
Rupanya, Matahari menolak sebagian besar optimisasi yang javac
biasa dilakukan di Jawa 6; Saya telah diberitahu bahwa optimisasi tersebut menyulitkan JIT untuk melakukan banyak hal, dan kode yang dikompilasi secara naif berjalan lebih cepat pada akhirnya. Sosok pergi.
m
dengan versi yang tidak memeriksa k
karena tidak akan dapat membuktikan bahwa tidakm
akan pernah dipanggil dengan yang bukan nol k
, tetapi bahkan tanpa dapat membuktikan bahwa itu dapat menggantikan dengan static miss_count; if (k==0) return a.length+b.length-7; else if (miss_count++ < 16) { ... unoptimized code for
m ...} else { ... consider other optimizations...}
.
k=0
selalu , yang berarti itu bukan fungsi input atau lingkungan, apakah aman untuk membatalkan tes - tetapi menentukan ini memerlukan analisis statis, yang sangat mahal dan dengan demikian hanya terjangkau pada waktu kompilasi. JIT dapat menang ketika satu jalur melalui blok kode diambil lebih sering daripada yang lain, dan versi kode khusus untuk jalur ini akan jauh lebih cepat. Tetapi JIT masih akan memancarkan tes untuk memeriksa apakah jalur cepat berlaku , dan mengambil "jalur lambat" jika tidak.
Base* p
parameter, dan memanggil fungsi virtual melaluinya; Analisis runtime menunjukkan bahwa objek aktual yang menunjuk selalu (atau hampir selalu) tampaknya Derived1
bertipe. JIT dapat menghasilkan versi baru dari fungsi dengan pemanggilan Derived1
metode yang diselesaikan secara statis (atau bahkan inline) . Kode ini akan didahului oleh kondisional yang memeriksa apakah p
pointer vtable menunjuk ke Derived1
tabel yang diharapkan ; jika tidak, ia akan melompat ke versi asli fungsi dengan panggilan metode yang lebih lambat diselesaikan secara dinamis.