एथेरियम वर्चुअल मशीन अधिकांश अन्य वर्चुअल मशीनों की तुलना में अलग तरह की है। मेरे में पिछला पद मैंने पहले ही समझाया है कि इसका उपयोग कैसे किया जाता है और इसकी कुछ विशेषताओं का वर्णन किया है।
एथेरियम वर्चुअल मशीन (ईवीएम) एक सरल लेकिन शक्तिशाली, ट्यूरिंग पूर्ण 256 बिट वर्चुअल मशीन है जो किसी को भी मनमाने ढंग से निष्पादित करने की अनुमति देती है ईवीएम बाइट कोड.
गो-एथेरियम परियोजना में ईवीएम के दो कार्यान्वयन शामिल हैं। एक सरल और सीधा बाइट-कोड वीएम और एक अधिक परिष्कृत जेआईटी-वीएम. इस पोस्ट में मैं दो कार्यान्वयनों के बीच कुछ अंतरों की व्याख्या करने जा रहा हूं और जेआईटी ईवीएम की कुछ विशेषताओं का वर्णन करने जा रहा हूं और यह बाइट-कोड ईवीएम से इतना तेज क्यों हो सकता है।
गो-एथेरियम की बाइट कोड वर्चुअल मशीन
ईवीएम के आंतरिक भाग काफी सरल हैं; इसमें एक सिंगल रन लूप है जो वर्तमान में निर्देश को निष्पादित करने का प्रयास करेगा कार्यक्रम काउंटर (पीसी संक्षेप में)। इस लूप के भीतर गैस प्रत्येक निर्देश के लिए गणना की जाती है, यदि आवश्यक हो तो स्मृति का विस्तार किया जाता है और प्रस्तावना सफल होने पर निर्देश निष्पादित करता है। यह तब तक जारी रहेगा जब तक कि वीएम या तो शालीनता से समाप्त नहीं हो जाता या अपवाद फेंककर त्रुटि के साथ वापस आ जाता है (उदाहरण के लिए गैस खत्म हुई).
for op = contract[pc] {
if !sufficientGas(op) {
return error("insufficient gas for op:", or)
}
switch op {
case ...:
/* execute */
case RETURN:
return memory[stack[-1], stack[-2]]
}
pc++
}
निष्पादन पाश के अंत में प्रोग्राम-काउंटर को अगले निर्देश को चलाने के लिए वेतन वृद्धि मिलती है और जब तक यह समाप्त नहीं हो जाता तब तक ऐसा करना जारी रखता है।
ईवीएम का दूसरा तरीका है परिवर्तन प्रोग्राम-काउंटर के माध्यम से कुछ कहा जाता है कूदना-निर्देश (कूदना और जम्पी). प्रोग्राम-काउंटर इंक्रीमेंट (पीसी++) देने के बजाय ईवीएम अनुबंध कोड में मनमाने पदों पर भी जा सकता है। ईवीएम दो जंप निर्देशों को जानती है, एक सामान्य जंप जिसे “के रूप में पढ़ा जाता है”स्थिति X पर कूदें“और एक सशर्त छलांग जो” के रूप में पढ़ती हैस्थिति X पर कूदें यदि स्थिति Y सत्य है”। जब ऐसी कोई छलांग लगती है तो उसे हमेशा a पर उतरना चाहिए कूद गंतव्य. यदि प्रोग्राम जंप डेस्टिनेशन के अलावा किसी अन्य निर्देश पर लैंड करता है, तो प्रोग्राम विफल हो जाता है – दूसरे शब्दों में, जंप के वैध होने के लिए, यदि स्थिति सही होती है तो जंप-डेस्टिनेशन इंस्ट्रक्शन का हमेशा पालन किया जाना चाहिए।
किसी भी एथेरियम प्रोग्राम को चलाने से पहले ईवीएम कोड पर पुनरावृति करता है और सभी संभावित जंप-गंतव्यों को ढूंढता है, फिर उन्हें एक मानचित्र में रखता है जिसे प्रोग्राम-काउंटर द्वारा उन्हें खोजने के लिए संदर्भित किया जा सकता है। हर बार जब ईवीएम जंप-निर्देशों का सामना करता है तो जंप की वैधता की जांच की जाती है।
जैसा कि आप देख सकते हैं कि निष्पादन कोड अपेक्षाकृत आसान है और बाइट-कोड वीएम द्वारा आसानी से व्याख्या की जाती है, हम यह भी निष्कर्ष निकाल सकते हैं कि इसकी सरलता के माध्यम से यह वास्तव में बहुत गूंगा है।
आपका स्वागत है जेआईटी वीएम
जेआईटी-ईवीएम ईवीएम बाइट-कोड चलाने के लिए एक अलग दृष्टिकोण अपनाता है और परिभाषा के अनुसार है शुरू में बाइट-कोड वीएम से धीमा। इससे पहले कि VM किसी भी कोड को चला सके, उसे पहले होना चाहिए संकलन जेआईटी वीएम द्वारा समझे जा सकने वाले घटकों में बाइट-कोड।
आरंभीकरण- और निष्पादन प्रक्रिया 3-चरणों में की जाती है:
- हम जाँचते हैं कि कोड के हैश का उपयोग करके कोई JIT प्रोग्राम चलाने के लिए तैयार है या नहीं —एच (सी) कार्यक्रम की पहचान करने के लिए पहचानकर्ता के रूप में प्रयोग किया जाता है;
- यदि कोई प्रोग्राम पाया गया तो हम प्रोग्राम चलाते हैं और परिणाम लौटाते हैं;
- अगर कोई प्रोग्राम नहीं मिला तो हम बाइट-कोड चलाते हैं और हम पृष्ठभूमि में एक JIT प्रोग्राम संकलित करते हैं।
शुरू में मैंने यह जांचने की कोशिश की कि क्या JIT प्रोग्राम ने संकलन पूरा कर लिया है और निष्पादन को JIT में स्थानांतरित कर दिया है – यह सब गो के उपयोग से एक ही लूप में रनटाइम के दौरान हुआ परमाणु पैकेज – दुर्भाग्य से यह बाइट-कोड वीएम को चलने देने की तुलना में धीमा निकला और कार्यक्रम के संकलन समाप्त होने के बाद प्रत्येक अनुक्रमिक कॉल के लिए जेआईटी कार्यक्रम का उपयोग किया।
बाइट-कोड को तार्किक टुकड़ों में संकलित करके JIT में कोड का अधिक सटीक विश्लेषण करने और जहां और जब भी आवश्यक हो, अनुकूलन करने की क्षमता होती है।
उदाहरण के लिए एक अविश्वसनीय सरल अनुकूलन जो मैंने किया वह कई संकलित कर रहा था धक्का देना एक निर्देश में संचालन। आइए लेते हैं बुलाना निर्देश; कॉल को 7 पुश निर्देशों की आवश्यकता होती है – यानी गैस, पता, मूल्य, इनपुट ऑफ़सेट, इनपुट आकार, रिटर्न ऑफ़सेट और रिटर्न आकार – इसे निष्पादित करने से पहले, और मैंने इन 7 निर्देशों के माध्यम से लूप करने के बजाय क्या किया, उन्हें एक-एक करके निष्पादित किया one, मैंने 7 निर्देशों को लेकर और 7 मानों को एक स्लाइस में जोड़कर इसे अनुकूलित किया है। अब, जब भी शुरु 7 पुश निर्देशों में से एक को निष्पादित किया जाता है, इसके बजाय यह VM स्टैक में स्थिर स्लाइस को तुरंत जोड़कर एक अनुकूलित निर्देश को निष्पादित करता है। अब बेशक यह केवल स्थिर मूल्यों के लिए काम करता है (यानी पुश 0x10), लेकिन ये कोड में काफी मौजूद हैं।
मैंने भी अनुकूलित किया है स्थिर कूद निर्देश। स्टैटिक जंप वे जंप होते हैं जो हमेशा एक ही स्थिति में कूदते हैं (यानी धक्का 0x1, कूदो) और किसी भी परिस्थिति में कभी न बदलें। यह निर्धारित करके कि कौन सी छलांग स्थिर है, हम पूर्व-जाँच कर सकते हैं कि क्या छलांग वैध है और अनुबंध की सीमा के भीतर है और यदि ऐसा है तो हम एक नया निर्देश बनाते हैं जो दोनों को बदल देता है धक्का देना और कूदनानिर्देश और के रूप में चिह्नित किया गया है वैध. यह वीएम को दो निर्देश करने से रोकता है और यह यह जांचने से रोकता है कि कूद वैध है या नहीं और वैध कूद स्थिति के लिए महंगा हैश-मैप लुकअप कर रहा है।
अगले कदम
पूर्ण स्टैक और मेमोरी विश्लेषण भी इस मॉडल में अच्छी तरह से फिट होंगे जहां कोड के बड़े हिस्से एकल निर्देशों में फिट हो सकते हैं। आगे मैं जोड़ना चाहूंगा प्रतीकात्मक-निष्पादन और JIT को उचित JIT-VM में बदलें। मुझे लगता है कि एक बार कार्यक्रम इन अनुकूलनों का लाभ उठाने के लिए पर्याप्त रूप से बड़ा हो जाए तो यह एक तार्किक अगला कदम होगा।
निष्कर्ष
हेआपका जेआईटी-वीएम बाइट-कोड वीएम की तुलना में बहुत अधिक स्मार्ट है, लेकिन पूरी तरह से (यदि कभी) किया जा रहा है तो यह बहुत दूर है। इस संरचना के साथ हम और भी कई चतुर तरकीबें जोड़ सकते हैं, लेकिन फिलहाल वे यथार्थवादी नहीं हैं। रनटाइम “उचित” तेज़ होने की सीमा के भीतर है। वीएम को और अधिक अनुकूलित करने की आवश्यकता हो सकती है, हमारे पास ऐसा करने के लिए उपकरण हैं।
आगे कोड पढ़ना
क्रॉस पोस्टिंग – https://medium.com/@jeff.ethereum/go-ethereums-jit-evm-27ef88277520#.1ed9lj7dz