(Ini adalah pertanyaan yang sangat pemula-ish).
Saya telah mempelajari sedikit tentang Mesin Virtual.
Ternyata banyak dari mereka dirancang sangat mirip dengan komputer fisik atau teoretis.
Saya membaca bahwa JVM misalnya, adalah 'mesin tumpukan'. Apa itu artinya (dan koreksi saya jika saya salah) adalah bahwa ia menyimpan semua 'memori sementara' di stack, dan melakukan operasi pada stack ini untuk semua opcode-nya.
Misalnya, kode sumber 2 + 3
akan diterjemahkan ke bytecode mirip dengan:
push 2
push 3
add
Pertanyaan saya adalah ini:
JVM mungkin ditulis menggunakan C / C ++ dan semacamnya. Jika demikian, mengapa JVM tidak menjalankan kode C berikut: 2 + 3
..? Maksud saya, mengapa perlu tumpukan, atau 'register' VM lainnya - seperti di komputer fisik?
CPU fisik yang mendasarinya mengurus semua ini. Mengapa penulis VM tidak hanya menjalankan bytecode yang ditafsirkan dengan instruksi 'biasa' dalam bahasa yang diprogram dengan VM?
Mengapa VM perlu meniru perangkat keras, ketika perangkat keras yang sebenarnya sudah melakukan ini untuk kita?
Sekali lagi, pertanyaan yang sangat pemula. Terima kasih atas bantuan Anda
sumber
printf("hi");
: apakah ini dianggap sebagai VM? Ia tidak memiliki 'tumpukan' atau 'register' dan atau apa pun.Jawaban:
Mesin, virtual atau tidak, membutuhkan model komputasi yang menggambarkan bagaimana komputasi dilakukan di dalamnya. Menurut definisi, segera setelah dihitung, ia mengimplementasikan beberapa model perhitungan. Pertanyaannya kemudian adalah: Model apa yang harus kita pilih untuk VM kita? Mesin fisik dibatasi oleh apa yang dapat dilakukan secara efektif dan efisien dalam perangkat keras. Tetapi, seperti yang Anda perhatikan, mesin virtual tidak memiliki kendala seperti itu, mereka didefinisikan dalam perangkat lunak menggunakan bahasa tingkat tinggi yang sewenang-wenang.
Sebenarnya, ada mesin virtual yang tingkat tinggi seperti yang Anda gambarkan. Mereka disebut bahasa pemrograman . Standar C misalnya mendedikasikan sebagian besar halamannya untuk mendefinisikan model untuk apa yang disebut "mesin abstrak C" yang menggambarkan bagaimana program C berperilaku, dan dengan ekstensi (as-jika aturan) bagaimana kompiler C yang sesuai (atau penerjemah) harus berperilaku.
Tentu saja, kita biasanya tidak menyebut itu mesin virtual. VM biasanya berarti tingkat yang lebih rendah, lebih dekat dengan perangkat keras, tidak dimaksudkan untuk diprogram secara langsung, dirancang untuk dieksekusi secara efisien. Bias pemilihan ini berarti bahwa sesuatu yang menerima kode komposer tingkat tinggi (seperti apa yang Anda jelaskan) tidak akan dianggap sebagai VM karena dieksekusi kode tingkat tinggi.
Tetapi untuk sampai pada intinya, berikut adalah beberapa alasan untuk membuat VM (seperti, sesuatu yang ditargetkan oleh kompiler bytecode) berbasis register atau sejenisnya. Stack dan mesin register sangat sederhana. Ada urutan instruksi, beberapa status, dan semantik untuk setiap instruksi (fungsi State -> State). Tidak ada pengurangan pohon yang rumit, tidak ada prioritas operator. Memilah, menganalisis, dan mengeksekusinya sangat sederhana, karena ini adalah bahasa minimal (gula sintaksis dikompilasi) dan dirancang untuk dibaca mesin daripada dibaca manusia.
Sebaliknya, mem-parsing bahasa C-seperti paling sederhana pun cukup sulit, dan mengeksekusinya memerlukan analisis non-lokal seperti memeriksa dan menyebarkan jenis, menyelesaikan kelebihan beban, mempertahankan tabel simbol, menyelesaikan pengidentifikasi string , mengubah teks linier menjadi AST yang digerakkan oleh prioritas. , dan seterusnya. Itu dibangun di atas konsep yang menjadi alami bagi manusia tetapi harus dengan susah payah direkayasa secara terbalik oleh mesin.
Bytecode JVM, misalnya, dipancarkan oleh
javac
. Ini hampir tidak pernah perlu dibaca atau ditulis oleh manusia, jadi itu wajar untuk membawanya ke konsumsi oleh mesin. Jika Anda dioptimalkan untuk manusia, JVM akan hanya pada setiap startup membaca kode, mengurai, menganalisis, dan kemudian mengubahnya menjadi representasi menengah menyerupai disederhanakan model mesin seperti pula . Mungkin juga memotong perantara.sumber
System.out.println("hi");
dikompilasi ke beberapa instruksi pada stack,int a = 7
dikompilasi dengan instruksi pada stack, dll.) Membuat menjalankan program sederhana dan lebih efisien?2 + 3
dikompilasipush 2 push 3 add
. Theadd
langkah pada akhirnya dieksekusi oleh JVM pula dengan menjalankan kode C2 + 3
. Tidak ada cara lain bagi programmer JVM untuk melakukan ini. Mengapa tidak mengkompilasinya2 + 3
, dan minta JVM mengeksekusi kode C2 + 3
(dengan asumsi kode itu ditulis dalam C) segera?2 + 3
dalam kode sumber JVM karena JVM harus bekerja dengan program apa pun yang melakukan operasi dalam urutan apa pun. Membangun kode sumber C dan menunda implementasi C hanya mendorong masalah yang sama ke dalam implementasi C (dan tidak dapat dilakukan dengan mudah, apalagi efisien). Harus ada beberapa struktur data yang menggambarkan program, sehingga dapat ditafsirkan dan JIT dikompilasi, dan "kode sumber yang dapat dibaca manusia" adalah pilihan struktur data yang mengerikan karena alasan yang diuraikan di atas.a + b
? Maka nilai yang ditambahkan tidak berasali.argument{1,2}
, mereka diambil dari variabel lokal. Bagaimana denganfrobnicate(x[i]) + (Foo.bar() * 2)
? Menggunakan desain ini, hanya ada satuadd
operasi (untukint
) dan bekerja secara independen dari bagaimana penambahan ditambahkan. Plus, instruksi yang hanya menambahkan literal bilangan bulat tidak ada gunanya: Hasilnya bisa juga sudah dihitung sebelumnya (yaitu bukannyaadd(2,3)
seharusnyapush(5)
).Jawaban ini berfokus pada JVM, tetapi pada kenyataannya itu berlaku untuk VM.
Mereka tidak, tetapi itu membuat VM jauh lebih sederhana dan portabel: VM yang mengemulasi perangkat keras dapat menggunakan model komputasi yang sama daripada CPU perangkat keras apa pun.
JVM khususnya dibangun dengan portabilitas dalam pikiran, pada kenyataannya itu dibangun sehingga bahkan dapat diimplementasikan dalam perangkat keras (mungkin sulit dipercaya hari ini, tetapi asal Jawa ada di dunia tertanam - khususnya, pengontrol untuk televisi interaktif ).
Jika Anda memiliki tujuan seperti ini, diharapkan VM beroperasi sedekat mungkin dengan mesin fisik, karena menerjemahkan ke kode mesin aktual menjadi lebih mudah dan dengan demikian lebih cepat. Setelah Anda memiliki opcodes dari VM, secara teori, yang harus Anda lakukan hanyalah menerjemahkan ke opcodes dari CPU yang sebenarnya dijalankan oleh program. Dalam praktiknya tidak sesederhana itu.
Menggunakan model mesin virtual berbasis stack memiliki keuntungan bahwa ia dapat dengan mudah ditransfer ke mesin register dan stack, sedangkan yang sebaliknya tidak selalu benar. VM berbasis register perlu membuat asumsi tentang jumlah register, ukuran register, dll. Dengan mesin stack, tidak ada asumsi seperti itu yang diperlukan.
Nah, itulah yang dilakukan VM seperti itu, mereka mengartikan bytecode. Bahkan JVM benar-benar melakukan itu, setidaknya sebelum JIT (just-in-time) mulai: ia mengartikan kode byte dan mengeksekusi pernyataan dalam bahasa yang digunakan JVM (biasanya C atau C ++, tetapi bahkan ada satu yang ditulis dalam JavaScript, Doppio ). Namun, perlu diketahui bahwa pernyataan seperti itu pun diterjemahkan ke kode mesin oleh kompiler dan benar-benar terlihat sangat mirip dengan apa yang dihasilkan oleh kompiler Java - yaitu, mereka menggunakan register dan stack untuk melakukan pekerjaan mereka. Perhatikan penggunaan bahasa "ditafsirkan" vs "dikompilasi" menjadi agak kabur pada saat ini.
sumber
Mengapa VM harus “mesin stack” atau “mesin register” dll.?
Mereka tidak. Jika Anda membutuhkan mesin virtual, itu bisa apa saja.
Mesin virtual yang ada telah muncul sebagai solusi untuk situasi seperti: Sebuah ide yang sangat brilian telah datang ke kepala saya, saya telah menemukan bahasa pemrograman baru! Tetapi saya harus membuat kode. (Tugas yang sangat membosankan!) Tetapi saya tidak ingin membuat kode i8086 karena jelek, dan saya tidak ingin menghasilkan kode 68k karena semua orang menggunakan Intel. Ada juga VAX, tapi saya tidak punya VAX, baik komputer maupun buku VAX. Oleh karena itu saya akan menghasilkan kode untuk beberapa prosesor yang tidak ada secara fisik dan mengimplementasikan prosesor itu dalam perangkat lunak. Spesifikasi VM itu akan membuat bab dalam tesis saya. Secara teori, adalah mungkin untuk mengkompilasinya ke kode asli dari prosesor apa pun, tetapi itu bukan saya.
Di sisi lain, notasi seperti "2 + 3" mungkin tidak akan digunakan oleh VM di masa mendatang karena itu menyiratkan melakukan banyak transformasi sebelum sesuatu dapat dieksekusi.
sumber
Untuk menjawab pertanyaan aktual yang ditanyakan. Istilah "MESIN virtual" berarti bahwa SEMUA perangkat lunak / perangkat keras disimulasikan / ditiru. Jika Anda menggunakan perangkat lunak / perangkat keras yang mendasari untuk menjalankan instruksi maka Anda tidak memiliki VM, Anda memiliki kompiler / juru bahasa.
sumber