ดูเหมือนจะมีคำถามที่แตกต่างกันอย่างน้อยสองคำถามที่นี่ หนึ่งในนั้นคือคอมไพเลอร์โดยทั่วไปโดยทั่วไปแล้ว Java เป็นเพียงตัวอย่างของประเภท อีกอันหนึ่งมีความเฉพาะเจาะจงมากขึ้นสำหรับ Java คือใช้รหัสไบต์เฉพาะที่ใช้
คอมไพเลอร์โดยทั่วไป
ลองพิจารณาคำถามทั่วไปก่อน: ทำไมคอมไพเลอร์จะใช้การเป็นตัวแทนขั้นกลางในกระบวนการรวบรวมซอร์สโค้ดเพื่อใช้กับโปรเซสเซอร์บางตัว
การลดความซับซ้อน
คำตอบเดียวนั้นค่อนข้างง่าย: มันแปลงปัญหา O (N * M) เป็นปัญหา O (N + M)
หากเราได้รับภาษาต้นฉบับ N ภาษาและเป้าหมาย M และคอมไพเลอร์แต่ละรายการมีความเป็นอิสระโดยสมบูรณ์เราจำเป็นต้องใช้โปรแกรมแปลภาษา N * M เพื่อแปลภาษาต้นฉบับทั้งหมดเหล่านั้นเป็นเป้าหมายทั้งหมด (โดยที่ "เป้าหมาย" เป็นสิ่งที่รวมกันของ โปรเซสเซอร์และระบบปฏิบัติการ)
อย่างไรก็ตามหากคอมไพเลอร์เหล่านั้นเห็นด้วยกับการเป็นตัวแทนระดับกลางทั่วไปเราสามารถมีส่วนหน้า N คอมไพเลอร์ที่แปลภาษาต้นฉบับเป็นตัวแทนระดับกลางและคอมไพเลอร์ M กลับด้านท้ายที่แปลการเป็นตัวแทนระดับกลางเป็นสิ่งที่เหมาะสมสำหรับเป้าหมายเฉพาะ
การแบ่งส่วนปัญหา
ยังดีกว่ามันแยกปัญหาออกเป็นสองโดเมนพิเศษมากหรือน้อย ผู้ที่รู้ / ใส่ใจเกี่ยวกับการออกแบบภาษาการแยกวิเคราะห์และสิ่งต่าง ๆ เช่นนั้นสามารถมุ่งเน้นไปที่ส่วนท้ายของคอมไพเลอร์ในขณะที่คนที่รู้เกี่ยวกับชุดคำสั่งการออกแบบตัวประมวลผลและสิ่งต่าง ๆ ที่สามารถมุ่งเน้นไปที่ส่วนท้าย
ตัวอย่างเช่นในบางกรณีเช่น LLVM เรามีส่วนหน้ามากมายสำหรับภาษาที่แตกต่างหลากหลาย เรามีแบ็คเอนด์สำหรับโปรเซสเซอร์ที่แตกต่างกันมากมาย ผู้ชายภาษาสามารถเขียนส่วนหน้าใหม่สำหรับภาษาของเขาและสนับสนุนเป้าหมายจำนวนมากได้อย่างรวดเร็ว นักประมวลผลสามารถเขียนแบ็คเอนด์ใหม่สำหรับเป้าหมายของเขาได้โดยไม่ต้องเกี่ยวข้องกับการออกแบบภาษาการแยกวิเคราะห์ ฯลฯ
การแยกคอมไพเลอร์เป็นส่วนหน้าและส่วนหลังโดยมีสื่อกลางในการสื่อสารระหว่างสองภาษานั้นไม่ได้เป็นต้นฉบับของ Java มันเป็นเรื่องธรรมดาที่ปฏิบัติกันมานาน (ตั้งแต่ก่อนที่ Java จะมาด้วย)
รูปแบบการกระจาย
ในกรณีที่ Java เพิ่มสิ่งใหม่ในแง่นี้มันอยู่ในรูปแบบการกระจาย โดยเฉพาะอย่างยิ่งถึงแม้ว่าคอมไพเลอร์จะถูกแยกเป็นส่วนหน้าและส่วนหลังภายในเป็นเวลานาน แต่โดยทั่วไปแล้วพวกมันจะถูกแจกจ่ายเป็นผลิตภัณฑ์ชิ้นเดียว ตัวอย่างเช่นหากคุณซื้อคอมไพเลอร์ Microsoft C ภายในจะมี "C1" และ "C2" ซึ่งเป็น front-end และ back-end ตามลำดับ - แต่สิ่งที่คุณซื้อคือ "Microsoft C" ที่รวมทั้ง ชิ้น (พร้อมกับ "ไดรเวอร์คอมไพเลอร์" ที่ประสานการทำงานระหว่างสอง) แม้ว่าคอมไพเลอร์จะถูกสร้างขึ้นเป็นสองชิ้น แต่สำหรับนักพัฒนาทั่วไปที่ใช้คอมไพเลอร์มันเป็นเพียงสิ่งเดียวที่แปลจากซอร์สโค้ดเป็นโค้ดออบเจ็กต์โดยไม่มีสิ่งใดปรากฏขึ้นระหว่างนั้น
Java แทนจำหน่าย front-end ใน Java Development Kit และ back-end ใน Java Virtual Machine ผู้ใช้ Java ทุกคนมีคอมไพเลอร์แบ็คเอนด์เพื่อกำหนดเป้าหมายสิ่งที่ระบบที่เขาใช้ ผู้พัฒนา Java แจกจ่ายรหัสในรูปแบบกลางดังนั้นเมื่อผู้ใช้โหลด JVM ทำสิ่งที่จำเป็นในการเรียกใช้งานบนเครื่องของตน
ทำนอง
โปรดทราบว่ารูปแบบการแจกจ่ายนี้ไม่ใช่เรื่องใหม่ทั้งหมด ตัวอย่างเช่นระบบ UCSD P ทำงานคล้ายกัน: คอมไพเลอร์ส่วนหน้าผลิตรหัส P และแต่ละสำเนาของระบบ P รวมเครื่องเสมือนที่ทำสิ่งที่จำเป็นในการดำเนินการรหัส P บนเป้าหมายเฉพาะ1นั้น
รหัส Java byte
รหัส Java byte ค่อนข้างคล้ายกับรหัส P มันเป็นคำแนะนำพื้นฐานสำหรับเครื่องที่ค่อนข้างง่าย เครื่องดังกล่าวมีจุดประสงค์เพื่อให้เป็นนามธรรมของเครื่องที่มีอยู่ดังนั้นจึงค่อนข้างง่ายที่จะแปลอย่างรวดเร็วไปยังเป้าหมายที่เฉพาะเจาะจง ความง่ายในการแปลมีความสำคัญในช่วงต้นเพราะเจตนาดั้งเดิมคือการตีความรหัสไบต์เช่นเดียวกับระบบ P-System ได้ทำ (และใช่นั่นคือวิธีการใช้งานในช่วงต้น)
จุดแข็ง
โค้ด Java byte นั้นง่ายสำหรับคอมไพเลอร์ส่วนหน้าในการสร้าง หาก (ตัวอย่าง) คุณมีต้นไม้ที่ค่อนข้างปกติที่ใช้แทนนิพจน์โดยปกติแล้วมันค่อนข้างง่ายที่จะสำรวจต้นไม้และสร้างรหัสโดยตรงจากสิ่งที่คุณพบในแต่ละโหนด
รหัส Java byte ค่อนข้างกะทัดรัด - ในกรณีส่วนใหญ่มีขนาดกะทัดรัดกว่าซอร์สโค้ดหรือรหัสเครื่องสำหรับโปรเซสเซอร์ทั่วไปส่วนใหญ่ (และโดยเฉพาะอย่างยิ่งสำหรับโปรเซสเซอร์ RISC ส่วนใหญ่เช่น SPARC ที่ Sun ขายเมื่อออกแบบ Java) นี่เป็นสิ่งสำคัญอย่างยิ่งในขณะนี้เพราะจุดประสงค์หลักประการหนึ่งของจาวาคือเพื่อสนับสนุนแอปเพล็ - รหัสที่ฝังอยู่ในหน้าเว็บที่จะดาวน์โหลดก่อนการประหารชีวิต - ในเวลาที่คนส่วนใหญ่เข้าถึงเราผ่านโมเด็มผ่านสายโทรศัพท์ประมาณ 28.8 กิโลบิตต่อวินาที (แน่นอนว่ายังมีคนไม่กี่คนที่ใช้โมเด็มที่เก่ากว่าและช้ากว่า)
จุดอ่อน
จุดอ่อนหลักของโค้ดไบต์ Java คือมันไม่ได้แสดงออกอย่างชัดเจน แม้ว่าพวกเขาจะสามารถแสดงแนวคิดใน Java ได้ค่อนข้างดี แต่พวกเขาก็ทำงานได้ไม่ดีนักสำหรับการแสดงแนวคิดที่ไม่ได้เป็นส่วนหนึ่งของ Java เช่นเดียวกันในขณะที่การเรียกใช้งานโค้ดไบต์บนเครื่องส่วนใหญ่นั้นเป็นเรื่องง่าย แต่ก็ยากกว่าที่จะใช้ประโยชน์จากเครื่องใด ๆ โดยเฉพาะ
ยกตัวอย่างเช่นมันเป็นประจำรักที่ถ้าคุณอยากที่จะเพิ่มประสิทธิภาพรหัสไบต์ Java คุณพื้นทำวิศวกรรมย้อนกลับบางอย่างที่จะแปลให้ถอยหลังจากเครื่องรหัสเช่นการแสดงและเปิดให้กลับเข้ามาในคำแนะนำ SSA (หรือบางสิ่งบางอย่างที่คล้ายกัน) 2 จากนั้นคุณปรับเปลี่ยนคำแนะนำ SSA เพื่อเพิ่มประสิทธิภาพของคุณจากนั้นแปลจากสิ่งนั้นเป็นสิ่งที่กำหนดเป้าหมายสถาปัตยกรรมที่คุณสนใจ แม้จะมีกระบวนการที่ค่อนข้างซับซ้อน แต่แนวคิดบางอย่างที่ต่างไปจาก Java นั้นยากพอที่จะบอกได้ว่าเป็นการยากที่จะแปลจากภาษาต้นฉบับบางภาษาไปเป็นรหัสเครื่องที่ทำงาน (แม้จะใกล้เคียง) อย่างเหมาะสมที่สุดบนเครื่องทั่วไปส่วนใหญ่
สรุป
หากคุณถามว่าทำไมต้องใช้การเป็นตัวแทนระดับกลางโดยทั่วไปปัจจัยหลักสองประการคือ:
- ลดปัญหา O (N * M) เป็นปัญหา O (N + M) และ
- แยกปัญหาออกเป็นส่วนที่จัดการได้มากขึ้น
หากคุณกำลังถามเกี่ยวกับรหัสเฉพาะของจาวาไบต์และทำไมพวกเขาถึงเลือกการแทนแบบนี้แทนที่จะเป็นแบบอื่นฉันก็จะบอกว่าคำตอบส่วนใหญ่กลับมาจากความตั้งใจดั้งเดิมและข้อ จำกัด ของเว็บในเวลานั้น นำไปสู่ลำดับความสำคัญต่อไปนี้:
- กระชับเป็นตัวแทน
- รวดเร็วและง่ายต่อการถอดรหัสและดำเนินการ
- รวดเร็วและง่ายต่อการใช้งานบนเครื่องทั่วไปส่วนใหญ่
ความสามารถในการแสดงหลายภาษาหรือดำเนินการอย่างเหมาะสมกับเป้าหมายที่หลากหลายนั้นมีความสำคัญน้อยกว่ามาก
- เหตุใดระบบ P จึงถูกลืมส่วนใหญ่? ส่วนใหญ่เป็นสถานการณ์การกำหนดราคา P-system ขายค่อนข้างดีใน Apple II ของ Commodore SuperPets ฯลฯ เมื่อ IBM PC ออกมา P-system เป็นระบบปฏิบัติการที่รองรับ แต่ MS-DOS ราคาถูกกว่า มีโปรแกรมเพิ่มเติมให้ใช้อย่างรวดเร็วเนื่องจากเป็นสิ่งที่ Microsoft และ IBM (อื่น ๆ ) เขียนไว้
- ตัวอย่างเช่นนี่คือการทำงานของSoot