อ่าน 6 นาที
ไบต์โค้ด JVM
ไบต์โค้ด JVM คือ สถาปัตยกรรมชุดคำสั่ง (ISA) ของ เครื่องเสมือน Java (JVM) ซึ่งเป็นภาษาที่ ใช้คอม ไพล์ Java และ ซอร์สโค้ด อื่นๆ ที่เข้ากันได้ กับJVM [ 1 ] แต่ละคำสั่งจะถูกแทนด้วย...
ไบต์โค้ด JVM
ไบต์โค้ด JVMคือสถาปัตยกรรมชุดคำสั่ง (ISA) ของเครื่องเสมือน Java (JVM) ซึ่งเป็นภาษาที่ใช้คอม ไพล์ Java และ ซอร์สโค้ด อื่นๆ ที่เข้ากันได้ กับJVM [ 1 ]แต่ละคำสั่งจะถูกแทนด้วยไบต์ หนึ่งไบต์ จึงเรียกว่าไบต์โค้ดทำให้เป็นรูปแบบข้อมูลที่ กระชับ [ 2 ]
เนื่องจากคุณสมบัติของเครื่องเสมือน และไบต์โค้ด โปรแกรมไบต์โค้ด JVM จึงสามารถทำงานได้บนเครื่องใดก็ได้ที่มี JVM ที่เข้ากันได้ โดยไม่ต้องผ่านกระบวนการคอมไพล์จากซอร์สโค้ดที่ยุ่งยากและใช้เวลานาน
ไบต์โค้ดของ JVM จะถูกนำไปใช้ในขณะรันไทม์โดยอาจถูกตีความโดย JVM หรือถูกคอมไพล์เป็นโค้ดเครื่องจักรผ่าน การคอมไพล์ แบบทันเวลา (JIT) และรันเป็นแอปพลิเคชันเนทีฟ
เนื่องจาก JVM bytecode ได้รับการออกแบบมาเพื่อ ความเข้ากันได้และความปลอดภัย ของซอฟต์แวร์ข้ามแพลตฟอร์ม แอปพลิเคชัน JVM bytecode จึงมีแนวโน้มที่จะทำงานได้อย่างสม่ำเสมอในฮาร์ดแวร์และการกำหนดค่าซอฟต์แวร์ ต่างๆ [ 3 ]
ความสัมพันธ์กับภาษาจาวา
โดยทั่วไปโปรแกรมเมอร์ Java ไม่จำเป็นต้องเข้าใจไบต์โค้ดของ JVM หรือแม้กระทั่งต้องรับรู้ถึงมัน อย่างไรก็ตาม ตามที่แนะนำใน วารสาร IBM developerWorks ว่า "การเข้าใจไบต์โค้ดและไบต์โค้ดที่น่าจะถูกสร้างขึ้นโดยคอมไพเลอร์ Javaจะช่วยโปรแกรมเมอร์ Java ในลักษณะเดียวกับที่ความรู้เกี่ยวกับภาษาแอสเซมบลีช่วย โปรแกรมเมอร์ CหรือC++ " [ 4 ]
สถาปัตยกรรมชุดคำสั่ง
ไบต์โค้ดประกอบด้วยคำสั่งประเภทต่างๆ รวมถึงการจัดการข้อมูล การถ่ายโอนการควบคุม การสร้างและการจัดการวัตถุ และการเรียกใช้เมธอด ซึ่งทั้งหมดนี้เป็นส่วนสำคัญของแบบจำลองการเขียนโปรแกรมเชิงวัตถุ ของ Java [ 1 ]
JVM เป็นทั้งเครื่องสแต็กและเครื่องรีจิสเตอร์แต่ละเฟรมสำหรับการเรียกเมธอดจะมี "สแต็กตัวถูกดำเนินการ" และอาร์เรย์ของ "ตัวแปรโลคัล" [ 5 ] : 2.6 [ 2 ]สแต็กตัวถูกดำเนินการใช้สำหรับส่งตัวถูกดำเนินการไปยังการคำนวณและรับค่าส่งคืนของเมธอดที่ถูกเรียก ในขณะที่ตัวแปรโลคัลทำหน้าที่เช่นเดียวกับรีจิสเตอร์และใช้สำหรับส่งอาร์กิวเมนต์ของเมธอดด้วย ขนาดสูงสุดของสแต็กตัวถูกดำเนินการและอาร์เรย์ตัวแปรโลคัล ซึ่งคำนวณโดยคอมไพเลอร์ เป็นส่วนหนึ่งของแอตทริบิวต์ของแต่ละเมธอด[ 5 ] : 4.7.3 แต่ละเมธอดสามารถกำหนดขนาดได้อย่างอิสระตั้งแต่ 0 ถึง 65535 ค่า โดยแต่ละค่ามีขนาด 32 บิตlongและdoubleชนิดข้อมูล ซึ่งมีขนาด 64 บิต จะใช้ตัวแปรโลคัลสองตัวที่ต่อเนื่องกัน[ 5 ] : 2.6.1 (ซึ่งไม่จำเป็นต้องจัดเรียงแบบ 64 บิตในอาร์เรย์ตัวแปรโลคัล) หรือหนึ่งค่าในสแต็กตัวถูกดำเนินการ (แต่จะนับเป็นสองหน่วยในความลึกของสแต็ก) [ 5 ] : 2.6.2
ชุดคำสั่ง
ไบต์โค้ดแต่ละตัวประกอบด้วยไบต์หนึ่งไบต์ที่แสดงถึงโอเปอเรเตอร์โค้ดพร้อมด้วยไบต์ศูนย์ไบต์หรือมากกว่าสำหรับโอเปแรนด์[ 5 ] : 2.11
จากโอเปรนด์โค้ด ความยาวไบต์ที่เป็นไปได้ 256 รายการ ณ ปี 2015 มีการใช้งานอยู่ 202 รายการ (~79%) สงวนไว้ 51 รายการสำหรับการใช้งานในอนาคต (~20%) และสงวนคำสั่งไว้ถาวร 3 รายการ (~1%) สำหรับการใช้งานในระบบ JVM [ 5 ] : 6.2 สองรายการนี้ ( impdep1และimpdep2) ใช้สำหรับดักจับข้อผิดพลาดสำหรับซอฟต์แวร์และฮาร์ดแวร์เฉพาะระบบตามลำดับ ส่วนรายการที่สามใช้สำหรับดีบักเกอร์เพื่อใช้งานเบรกพอยต์
คำแนะนำต่างๆ สามารถแบ่งออกเป็นกลุ่มใหญ่ๆ ได้หลายกลุ่ม:
- โหลดและจัดเก็บ (เช่น
aload_0,istore) - เลขคณิตและตรรกศาสตร์ (เช่น
ladd,fcmpl) - การแปลงประเภท (เช่น
i2b,d2i) - การสร้างและการจัดการวัตถุ (
new,putfield) - การจัดการสแต็กตัวดำเนินการ (เช่น
swap,dup2) - การถ่ายโอนการควบคุม (เช่น
ifeq,goto) - การเรียกใช้เมธอดและการส่งคืนค่า (เช่น
invokespecial,areturn)
นอกจากนี้ยังมีคำแนะนำเพิ่มเติมสำหรับงานเฉพาะทางอีกหลายอย่าง เช่น การจัดการข้อผิดพลาด การซิงโครไนซ์ เป็นต้น
คำสั่งหลายคำสั่งมีคำนำหน้าและ/หรือคำต่อท้ายที่อ้างอิงถึงประเภทของตัวถูกดำเนินการ[ 5 ] : 2.11.1 ดังต่อไปนี้:
| คำนำหน้า/คำต่อท้าย | ประเภทตัวดำเนินการ |
|---|---|
i | จำนวนเต็ม |
l | ยาว |
s | สั้น |
b | ไบต์ |
c | อักขระ |
f | ลอย |
d | สองเท่า |
a | อ้างอิง |
ตัวอย่างเช่นiaddจะบวกจำนวนเต็มสองจำนวน ในขณะที่daddจะบวกจำนวนทศนิยมสองจำนวนconstคำ สั่ง load, และstoreอาจมีคำต่อท้ายในรูปแบบโดยที่nคือตัวเลขตั้งแต่ 0–3 สำหรับและ ค่า nสูงสุดสำหรับจะแตกต่างกันไปตามประเภท _nloadstoreconst
คำconstสั่งเหล่านี้จะผลักค่าของชนิดที่ระบุลงบนสแต็ก ตัวอย่างเช่น คำสั่ง ` iconst_5push` จะผลักค่าจำนวนเต็ม (ค่า 32 บิต) ที่มีค่า 5 ลงบนสแต็ก ในขณะที่คำสั่ง ` dconst_1push` จะผลักค่าทศนิยม (ค่าจุดลอยตัว 64 บิต) ที่มีค่า 1 ลงบนสแต็ก นอกจากนี้ยังมี คำสั่ง aconst_null`push` ซึ่ง ใช้สำหรับผลักค่า nullอ้างอิง ค่าnสำหรับ คำสั่ง `push` loadและ `push` storeระบุถึงดัชนีในอาร์เรย์ตัวแปรโลคอลที่จะโหลดหรือจัดเก็บaload_0คำสั่ง `push` จะผลักอ็อบเจ็กต์ในตัวแปรโลคอล 0 ลงบนสแต็ก (โดยปกติจะเป็นอ็อบเจ็กต์ ` thisin`) คำสั่ง `push` istore_1จะจัดเก็บจำนวนเต็มที่อยู่บนสุดของสแต็กไปยังตัวแปรโลคอล 1 สำหรับตัวแปรโลคอลที่มากกว่า 3 จะละคำต่อท้ายและต้องใช้ตัวถูกดำเนินการ
ตัวอย่าง
พิจารณาโค้ด Java ต่อไปนี้:
วงนอก: สำหรับ( int i = 2 ; i < 1000 ; i ++ ) { สำหรับ( int j = 2 ; j < i ; j ++ ) { ถ้า( i % j == 0 ) ให้ข้ามวงนอกไป} System.out.println ( i ) ; }คอมไพเลอร์ของ Java อาจแปลงโค้ด Java ข้างต้นเป็นไบต์โค้ดได้ดังนี้ โดยสมมติว่าโค้ดข้างต้นอยู่ในเมธอด:
0 : Iconst_2 1 : istore_1 2 : iload_1 3 : sipush 1,000 6 : if_icmpge 44 9 : Iconst_2 10 : istore_2 11 : iload_2 12 : iload_1 13 : if_icmpge 31 16 : iload_1 17 : iload_2 18 : irem 19 : ifne 25 22 : ข้ามไป38 25 : iinc 2, 1 28 : ข้ามไป11 31 : getstatic #84; // ฟิลด์java/lang/System.out : Ljava/io/PrintStream; 34 : iload_1 35 : เรียกใช้เสมือน#85 ; // วิธีการ java/io/PrintStream.println:(I)V 38 : iinc 1, 1 41 : ไปที่2 44 : returnรุ่น
ภาษาที่ใช้กันมากที่สุดในการ สร้างไบต์โค้ด JVM สำหรับ เครื่องเสมือน Javaคือภาษา Java เดิมทีมีคอมไพเลอร์เพียงตัวเดียวคือjavacจากSun Microsystemsซึ่งคอมไพล์ซอร์สโค้ด Javaไปเป็นไบต์โค้ด JVM แต่เนื่องจากปัจจุบันมีข้อกำหนดทั้งหมดสำหรับไบต์โค้ด JVM แล้ว จึงมีผู้พัฒนาคอมไพเลอร์รายอื่นที่สร้างไบต์โค้ด JVM ตัวอย่างของคอมไพเลอร์อื่นๆ ได้แก่:
- คอมไพเลอร์ Eclipse สำหรับ Java (ECJ)
- Jikesคือโปรแกรมที่คอมไพล์โค้ด Java ไปเป็นไบต์โค้ด JVM (พัฒนาโดยIBMและเขียนด้วยภาษาC++ )
- Espresso คอมไพล์จาก Java เป็นไบต์โค้ดของ JVM (เฉพาะ Java 1.0 เท่านั้น)
- GNU Compiler for Java (GCJ) ทำหน้าที่คอมไพล์จาก Java ไปเป็นไบต์โค้ดของ JVM นอกจากนี้ยังสามารถคอมไพล์เป็นโค้ดเครื่องจักร แบบเนทีฟได้ และเคยเป็นส่วนหนึ่งของGNU Compiler Collection (GCC) จนถึงเวอร์ชัน 6
บางโปรเจกต์มีตัวสร้างแอสเซมบลีของ Java เพื่อให้สามารถเขียนไบต์โค้ด JVM ด้วยตนเองได้ นอกจากนี้ โค้ดแอสเซมบลีอาจถูกสร้างขึ้นโดยเครื่องจักร เช่น โดยคอมไพเลอร์ที่กำหนดเป้าหมายไปยังเครื่องเสมือน Java ตัวสร้างแอสเซมบลีของ Java ที่น่าสนใจ ได้แก่:
- จัสมินใช้คำอธิบายข้อความสำหรับคลาส Java ซึ่งเขียนด้วยไวยากรณ์คล้ายแอสเซมบลีอย่างง่ายโดยใช้ชุดคำสั่งเครื่องเสมือน Java และสร้างไฟล์คลาส Java [ 6 ]
- จาเมกาภาษาแอสเซมบลีมาโคร สำหรับเครื่องเสมือน Java ไวยากรณ์ Java ใช้สำหรับการกำหนดคลาสหรืออินเทอร์เฟซ เนื้อหาเมธอดระบุโดยใช้คำสั่งไบต์โค้ด[ 7 ]
- ปัจจุบัน Krakatau Bytecode Tools ประกอบด้วยเครื่องมือสามอย่าง ได้แก่ ตัวถอดรหัสและตัวแยกส่วนประกอบสำหรับไฟล์คลาส Java และตัวประกอบเพื่อสร้างไฟล์คลาส[ 8 ]
- Lilac ซึ่งเป็นแอสเซมเบลอร์และดีแอสเซมเบลอร์สำหรับเครื่องเสมือน Java [ 9 ]
มีผู้พัฒนาคอมไพเลอร์สำหรับภาษาโปรแกรมต่างๆ เพื่อใช้งานกับเครื่องเสมือน Java เช่น:
- โคลด์ฟิวชั่น
- JRubyและJython เป็น ภาษาสคริปต์สอง ภาษา ที่พัฒนามาจากRubyและPython
- Apache Groovy เป็นภาษาโปรแกรมอเนกประสงค์แบบไดนามิกที่สามารถเลือกกำหนดชนิดข้อมูลได้ พร้อมทั้งมีความสามารถในการกำหนดชนิดข้อมูลแบบคงที่และการคอมไพล์แบบคงที่
- Scala เป็น ภาษาโปรแกรมอเนกประสงค์ที่ปลอดภัยต่อชนิด ข้อมูล รองรับทั้งการเขียนโปรแกรมเชิงวัตถุและเชิงฟังก์ชัน
- JGNATและ AppletMagic คอมไพล์จากภาษาAdaไปเป็นไบต์โค้ดของ JVM
- คอมไพเลอร์ C เป็นไบต์โค้ด Java
- Clojureเป็นภาษาโปรแกรมเชิงฟังก์ชันที่ไม่สามารถเปลี่ยนแปลงได้ และใช้งานได้ทั่วไปใน ตระกูล Lispโดยเน้นหนักไปที่การทำงานพร้อมกัน
- Kawaคือการนำ ภาษา Scheme มาใช้ ซึ่งเป็นภาษาถิ่นหนึ่งของLisp เช่นกัน
- มิดเล็ตปาสคาล
- โค้ดJavaFX Script จะถูกคอมไพล์เป็นไบต์โค้ดของ JVM
- Kotlinเป็นภาษาโปรแกรมอเนกประสงค์แบบกำหนดประเภทข้อมูลคงที่ (statically typed) พร้อมระบบอนุมานประเภทข้อมูล (type inference)
- โค้ดต้นฉบับของ Object Pascalจะถูกคอมไพล์เป็นไบต์โค้ดของ JVM โดยใช้ คอมไพเลอร์ Free Pascal 3.0+ [ 10 ] [ 11 ]
การประหารชีวิต
ปัจจุบันมี Java Virtual Machine (JVM) หลายตัวที่สามารถใช้ในการประมวลผล JVM bytecode ได้ ทั้งแบบฟรีและแบบเสียเงิน หากไม่ต้องการประมวลผล bytecode ใน Virtual Machine นักพัฒนาสามารถคอมไพล์ซอร์สโค้ดหรือ bytecode ของ Java โดยตรงเป็นโค้ดเครื่องจักรแบบเนทีฟได้ด้วยเครื่องมือต่างๆ เช่นGNU Compiler for Java (GCJ) นอกจากนี้ โปรเซสเซอร์บางตัวยังสามารถประมวลผล JVM bytecode ได้โดยตรง โปรเซสเซอร์เหล่านี้เรียกว่าJava Processor
รองรับภาษาแบบไดนามิก
เครื่องเสมือน Javaให้การสนับสนุนบางส่วนสำหรับภาษาที่มีประเภทแบบไดนามิกชุดคำสั่ง JVM ที่มีอยู่ส่วนใหญ่เป็นแบบคงที่กล่าวคือ การเรียกใช้เมธอดจะมีการตรวจสอบประเภทของลายเซ็นในเวลาคอมไพล์ โดย ไม่มีกลไกที่จะเลื่อนการตัดสินใจนี้ไปยังเวลารันไทม์หรือเลือกการเรียกใช้เมธอดด้วยวิธีการอื่น[ 12 ]
Java Specification Request ( JSR ) 292 ( การสนับสนุนภาษาที่มีประเภทแบบไดนามิกบนแพลตฟอร์ม Java ) [ 13 ]ได้เพิ่มคำสั่งใหม่invokedynamicในระดับ JVM เพื่ออนุญาตให้เรียกใช้เมธอดโดยอาศัยการตรวจสอบประเภทแบบ ไดนามิก (แทนที่จะเป็นinvokevirtualคำสั่งตรวจสอบประเภทแบบคงที่ที่มีอยู่) Da Vinci Machineเป็นต้นแบบการใช้งานเครื่องเสมือนที่โฮสต์ส่วนขยาย JVM ที่มุ่งเน้นการสนับสนุนภาษาแบบไดนามิก JVM ทั้งหมดที่รองรับJava Platform, Standard Editioninvokedynamic (JSE) 7 ยังรวมถึง โอเปรนด์โค้ด ด้วย
ดูเพิ่มเติม
- ไลบรารีวิศวกรรมไบต์โค้ด
- ภาษา Common Intermediate Language (CIL) ซึ่งเป็นคู่แข่งของ JVM bytecode นั้นพัฒนาโดย Microsoft
- เครื่องมือสำหรับการย้อนกลับของ Java
- ไฟล์คลาส Java
- เครื่องเสมือน Java
- เจเอสติก
- อ็อบเจ็กต์เว็บ ASM
- รายการคำสั่งไบต์โค้ด JVM
- รายชื่อภาษา JVM
ลิงก์ภายนอก
- ข้อกำหนดเครื่องเสมือน Java ของ Oracle
- ภาษาโปรแกรมสำหรับเครื่องเสมือนจาวา (Java Virtual Machine)
- Bytecode Visualizer – โปรแกรมดูและดีบักไบต์โค้ด (ปลั๊กอิน Eclipse ฟรี)
- AdaptJ StackTrace – เครื่องมือดีบักระดับไบต์โค้ดที่ควบคุมสแต็ก ตัวแปรโลคอล และการไหลของการทำงานได้อย่างสมบูรณ์
- Java Class Unpacker – ปลั๊กอินสำหรับ Total Commander ช่วยให้เปิดไฟล์คลาสในรูปแบบไฟล์บีบอัด และดูฟิลด์และเมธอดในรูปแบบไฟล์ได้ สามารถดูไบต์โค้ดในรูปแบบข้อความได้โดยใช้ปุ่ม F3
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ ไบต์โค้ด JVM
ไบต์โค้ด JVM คือ สถาปัตยกรรมชุดคำสั่ง (ISA) ของ เครื่องเสมือน Java (JVM) ซึ่งเป็นภาษาที่ ใช้คอม ไพล์ Java และ ซอร์สโค้ด อื่นๆ ที่เข้ากันได้ กับJVM [ 1 ] แต่ละคำสั่งจะถูกแทนด้วย...
ความสัมพันธ์กับภาษาจาวา
โดยทั่วไป โปรแกรมเมอร์ Java ไม่จำเป็นต้องเข้าใจไบต์โค้ดของ JVM หรือแม้กระทั่งต้องรับรู้ถึงมัน อย่างไรก็ตาม ตามที่แนะนำใน วารสาร IBM developerWorks ว่า "การเข้าใจไบต์โค้ดและไบต์โค้ดที่น่าจะถูกสร้างขึ้นโดย คอมไพเลอร์ Java จะช่วยโปรแกรมเมอร์ Java...
สถาปัตยกรรมชุดคำสั่ง
ไบต์โค้ดประกอบด้วยคำสั่งประเภทต่างๆ รวมถึงการจัดการข้อมูล การถ่ายโอนการควบคุม การสร้างและการจัดการวัตถุ และการเรียกใช้เมธอด ซึ่งทั้งหมดนี้เป็นส่วนสำคัญของแบบจำลอง การเขียนโปรแกรมเชิงวัตถุ ของ Java [ 1 ]
ชุดคำสั่ง
ไบต์โค้ด แต่ละตัวประกอบด้วยไบต์หนึ่งไบต์ที่แสดงถึง โอเปอเรเตอร์โค้ด พร้อมด้วยไบต์ศูนย์ไบต์หรือมากกว่าสำหรับโอเปแรนด์ [ 5 ] : 2.11