यहां कम से कम दो अलग-अलग संभावित प्रश्न प्रतीत होते हैं। एक वास्तव में संकलक के बारे में है, जावा मूल रूप से शैली का एक उदाहरण है। अन्य जावा के लिए विशिष्ट विशिष्ट बाइट कोड है जो इसका उपयोग करता है।
सामान्य रूप से संकलक
आइए पहले सामान्य प्रश्न पर विचार करें: किसी विशेष प्रोसेसर पर चलने के लिए संकलक स्रोत कोड की प्रक्रिया में एक संकलक कुछ मध्यवर्ती प्रतिनिधित्व का उपयोग क्यों करेगा?
जटिलता में कमी
इसका एक उत्तर काफी सरल है: यह एक O (N * M) समस्या को O (N + M) समस्या में परिवर्तित करता है।
यदि हमें N स्रोत भाषाएं, और M लक्ष्य दिए गए हैं, और प्रत्येक संकलक पूरी तरह से स्वतंत्र है, तो हमें N * M संकलक की आवश्यकता है उन सभी स्रोत भाषाओं को उन सभी लक्ष्यों (जहाँ "लक्ष्य" कुछ के संयोजन की तरह है) प्रोसेसर और ओएस)।
यदि, हालांकि, वे सभी कंपाइलर एक सामान्य मध्यवर्ती प्रतिनिधित्व पर सहमत हैं, तो हमारे पास एन कंपाइलर फ्रंट एंड्स हो सकते हैं जो स्रोत भाषाओं को मध्यवर्ती प्रतिनिधित्व में अनुवाद करते हैं, और एम कंपाइलर बैक एंड्स जो किसी विशिष्ट लक्ष्य के लिए उपयुक्त कुछ के लिए मध्यवर्ती प्रतिनिधित्व का अनुवाद करते हैं।
समस्या विभाजन
बेहतर अभी भी, यह समस्या को दो या अधिक अनन्य डोमेन में अलग करता है। जो लोग भाषा डिजाइन, पार्सिंग और उस तरह की चीजों के बारे में जानते हैं, वे संकलक सामने के छोर पर ध्यान केंद्रित कर सकते हैं, जबकि लोग जो निर्देश सेट, प्रोसेसर डिजाइन और इस तरह की चीजों के बारे में जानते हैं, वे पीछे के छोर पर ध्यान केंद्रित कर सकते हैं।
इसलिए, उदाहरण के लिए, LLVM जैसी कुछ चीज़ों को देखते हुए, हमारे पास विभिन्न विभिन्न भाषाओं के लिए बहुत सारे फ्रंट एंड हैं। हमारे पास कई अलग-अलग प्रोसेसर के लिए बैक-एंड भी हैं। एक भाषा आदमी अपनी भाषा के लिए एक नया फ्रंट-एंड लिख सकता है, और जल्दी से बहुत सारे लक्ष्यों का समर्थन कर सकता है। एक प्रोसेसर आदमी भाषा डिजाइन, पार्सिंग आदि से निपटने के बिना अपने लक्ष्य के लिए एक नया बैक-एंड लिख सकता है।
संकलक को फ्रंट एंड बैक एंड में अलग करना, एक मध्यवर्ती प्रतिनिधित्व के साथ दोनों के बीच संवाद जावा के साथ मूल नहीं है। यह लंबे समय से सामान्य व्यवहार रहा है (चूंकि जावा के साथ आने से पहले, वैसे भी)।
वितरण मॉडल
इस हद तक कि जावा ने इस संबंध में कुछ नया जोड़ा है, यह वितरण मॉडल में था। विशेष रूप से, भले ही कंपाइलरों को लंबे समय तक आंतरिक रूप से फ्रंट-एंड और बैक-एंड टुकड़ों में अलग किया गया हो, उन्हें आम तौर पर एकल उत्पाद के रूप में वितरित किया गया था। उदाहरण के लिए, यदि आपने एक Microsoft C कंपाइलर खरीदा है, तो आंतरिक रूप से इसमें "C1" और "C2" था, जो क्रमशः फ्रंट-एंड और बैक-एंड थे - लेकिन आपने जो खरीदा था वह "Microsoft C" था जिसमें दोनों शामिल थे टुकड़े (एक "संकलक चालक" के साथ जो दोनों के बीच संचालन को समन्वित करते हैं)। हालांकि कंपाइलर दो टुकड़ों में बनाया गया था, कंपाइलर का उपयोग करने वाले एक सामान्य डेवलपर के लिए यह सिर्फ एक ही चीज़ थी जो स्रोत कोड से ऑब्जेक्ट कोड में अनुवादित की गई थी, बीच में कुछ भी दिखाई नहीं दे रहा था।
इसके बजाय, जावा ने जावा डेवलपमेंट किट में फ्रंट-एंड और जावा वर्चुअल मशीन में बैक-एंड वितरित किया। प्रत्येक जावा उपयोगकर्ता के पास एक संकलक बैक-एंड था, जो भी सिस्टम का उपयोग कर रहा था, उसे लक्षित करने के लिए। जावा डेवलपर्स ने मध्यवर्ती प्रारूप में कोड वितरित किया, इसलिए जब एक उपयोगकर्ता ने इसे लोड किया, तो जेवीएम ने इसे विशेष मशीन पर निष्पादित करने के लिए जो भी आवश्यक था, किया।
उदाहरण
ध्यान दें कि यह वितरण मॉडल पूरी तरह से नया भी नहीं था। उदाहरण के लिए, यूसीएसडी पी-सिस्टम ने समान रूप से काम किया: कंपाइलर फ्रंट एंड ने पी-कोड का उत्पादन किया, और पी-सिस्टम की प्रत्येक कॉपी में एक वर्चुअल मशीन शामिल थी जो उस विशेष लक्ष्य 1 पर पी-कोड को निष्पादित करने के लिए आवश्यक थी ।
जावा बाइट-कोड
जावा बाइट कोड पी-कोड से काफी मिलता-जुलता है। यह मूल रूप से काफी सरल मशीन के लिए निर्देश है । उस मशीन को मौजूदा मशीनों के अमूर्त होने का इरादा है, इसलिए लगभग किसी भी विशिष्ट लक्ष्य के लिए जल्दी से अनुवाद करना काफी आसान है। अनुवाद में आसानी जल्दी थी क्योंकि मूल इरादा बाइट कोड की व्याख्या करना था, जैसे कि पी-सिस्टम ने किया था (और, हां, यह ठीक है कि शुरुआती कार्यान्वयन कैसे काम किया गया)।
ताकत
एक कंपाइलर फ्रंट-एंड के लिए जावा बाइट कोड आसान है। यदि (उदाहरण के लिए) आपके पास एक बहुत ही विशिष्ट पेड़ है जो एक अभिव्यक्ति का प्रतिनिधित्व करता है तो यह आम तौर पर पेड़ को पार करने के लिए बहुत आसान होता है, और प्रत्येक नोड पर आपको जो भी मिलता है उससे सीधे कोड उत्पन्न करता है।
जावा बाइट कोड काफी कॉम्पैक्ट होते हैं - ज्यादातर मामलों में, ज्यादातर विशिष्ट प्रोसेसर के लिए स्रोत कोड या मशीन कोड की तुलना में बहुत अधिक कॉम्पैक्ट (और, विशेष रूप से अधिकांश आरआईएससी प्रोसेसर के लिए, जैसे कि SPARC जब सूर्य ने जावा को डिजाइन किया था)। यह उस समय विशेष रूप से महत्वपूर्ण था, क्योंकि जावा का एक प्रमुख उद्देश्य एप्लेट्स का समर्थन करना था - कोड वेब पृष्ठों में एम्बेडेड था जो निष्पादन से पहले डाउनलोड किया जाएगा - एक ऐसे समय में जब ज्यादातर लोगों ने हमें फोन लाइनों पर मोडेम के माध्यम से लगभग 28.8 पर पहुँचा दिया किलोबाइट प्रति सेकंड (हालांकि, निश्चित रूप से, पुराने, धीमे मोडेम का उपयोग करने वाले कुछ लोग अभी भी थे)।
कमजोरियों
जावा बाइट कोड की प्रमुख कमजोरी यह है कि वे विशेष रूप से अभिव्यंजक नहीं हैं। यद्यपि वे जावा में मौजूद अवधारणाओं को बहुत अच्छी तरह से व्यक्त कर सकते हैं, वे उन अवधारणाओं को व्यक्त करने के लिए लगभग इतनी अच्छी तरह से काम नहीं करते हैं जो जावा का हिस्सा नहीं हैं। इसी तरह, जबकि अधिकांश मशीनों पर बाइट कोड निष्पादित करना आसान है, यह उस तरह से बहुत कठिन है जो किसी विशेष मशीन का पूरा लाभ उठाता है।
उदाहरण के लिए, यह बहुत नियमित है कि यदि आप वास्तव में जावा बाइट कोड का अनुकूलन करना चाहते हैं, तो आप मूल रूप से प्रतिनिधित्व की तरह मशीन-कोड से उन्हें पीछे की ओर ट्रांसलेट करने के लिए कुछ रिवर्स इंजीनियरिंग करते हैं, और उन्हें एसएसए निर्देशों (या कुछ इसी तरह) 2 में बदल देते हैं । फिर आप अपने अनुकूलन को करने के लिए SSA के निर्देशों में फेरबदल करते हैं, फिर वहाँ से किसी ऐसी चीज़ का अनुवाद करते हैं जो उस वास्तुकला को लक्षित करती है जिसकी आप वास्तव में परवाह करते हैं। यहां तक कि इस जटिल प्रक्रिया के साथ, हालांकि, कुछ अवधारणाएं जो जावा के लिए विदेशी हैं, यह व्यक्त करना पर्याप्त रूप से कठिन है कि कुछ स्रोत भाषाओं से मशीन कोड में अनुवाद करना मुश्किल है, जो कि (यहां तक कि लगभग) सबसे विशिष्ट मशीनों पर भी चलता है।
सारांश
यदि आप सामान्य रूप से मध्यवर्ती अभ्यावेदन का उपयोग करने के बारे में पूछ रहे हैं, तो दो प्रमुख कारक हैं:
- एक O (N + M) समस्या को O (N * M) समस्या को कम करें, और
- समस्या को अधिक प्रबंधनीय टुकड़ों में तोड़ दें।
यदि आप जावा बाइट कोड की बारीकियों के बारे में पूछ रहे हैं, और उन्होंने किसी अन्य के बजाय इस विशेष प्रतिनिधित्व को क्यों चुना है, तो मैं कहूंगा कि उत्तर मूल रूप से उनके मूल इरादे और उस समय वेब की सीमाओं पर वापस आता है। , निम्नलिखित प्राथमिकताओं के लिए अग्रणी:
- कॉम्पैक्ट प्रतिनिधित्व।
- त्वरित और डिकोड और निष्पादित करने में आसान।
- सबसे आम मशीनों पर लागू करने के लिए त्वरित और आसान।
कई भाषाओं का प्रतिनिधित्व करने में सक्षम होने या व्यापक रूप से विभिन्न प्रकार के लक्ष्यों पर अमल करने की प्राथमिकताएँ बहुत कम थीं (यदि उन्हें प्राथमिकताएँ माना जाता था)।
- तो पी-सिस्टम को ज्यादातर क्यों भुला दिया जाता है? ज्यादातर एक मूल्य निर्धारण की स्थिति। पी-सिस्टम ने Apple II, Commodore SuperPets, आदि पर काफी शालीनता से बिक्री की, जब IBM PC बाहर आया, P- सिस्टम एक समर्थित OS था, लेकिन MS-DOS की लागत कम थी (ज्यादातर लोगों के दृष्टिकोण से, अनिवार्य रूप से मुफ्त में फेंक दिया गया था) जल्दी से अधिक कार्यक्रम उपलब्ध थे, क्योंकि यह माइक्रोसॉफ्ट और आईबीएम (दूसरों के बीच) के लिए क्या लिखा था।
- उदाहरण के लिए, यह कैसे है कालिख काम करता है।