2011-02-17 14 views
22

मैंने सी में वर्चुअल मशीन लिखी है जिसमें गैर-जेआईटी वीएम के लिए अच्छा प्रदर्शन है, लेकिन मैं कुछ नया सीखना चाहता हूं, और प्रदर्शन में सुधार करना चाहता हूं। मेरा वर्तमान कार्यान्वयन केवल वीएम बाइटकोड से निर्देशों के लिए अनुवाद करने के लिए एक स्विच का उपयोग करता है, जो एक कूद तालिका में संकलित किया जाता है। जैसे मैंने कहा, यह क्या है इसके लिए सभ्य प्रदर्शन, लेकिन मैंने एक बाधा डाली है जिसे केवल एक जेआईटी कंपाइलर से दूर किया जा सकता है।असेंबली में एक जेआईटी कंपाइलर लिखना

मैंने पहले ही एक ही प्रश्न पूछा है जो स्वयं को संशोधित कोड के बारे में नहीं था, लेकिन मुझे एहसास हुआ कि मैं सही सवाल नहीं पूछ रहा था।

तो मेरा लक्ष्य इस सी वर्चुअल मशीन के लिए एक जेआईटी कंपाइलर लिखना है, और मैं इसे x86 असेंबली में करना चाहता हूं। (मैं अपने असेंबलर के रूप में NASM का उपयोग कर रहा हूं) मुझे पूरा यकीन नहीं है कि यह करने के बारे में कैसे जाना है। मैं असेंबली के साथ सहज हूं, और मैंने कुछ स्व-संशोधित कोड उदाहरणों को देखा है, लेकिन मुझे यह पता लगाने के लिए नहीं आया है कि अभी तक कोड जनरेशन कैसे करें।

मेरा मुख्य ब्लॉक अब तक मेमोरी के निष्पादन योग्य टुकड़े, के साथ निर्देशों की प्रतिलिपि बना रहा है। मुझे पता है कि मैं NASM में एक निश्चित पंक्ति को लेबल कर सकता हूं, और उस पते से संपूर्ण तर्क को स्थिर तर्कों के साथ प्रतिलिपि बना सकता हूं, लेकिन यह बहुत गतिशील नहीं है, और यह एक जेआईटी कंपाइलर के लिए काम नहीं करता है। मुझे बाइटकोड से निर्देश की व्याख्या करने में सक्षम होना चाहिए, इसे निष्पादन योग्य स्मृति में कॉपी करें, पहले तर्क की व्याख्या करें, इसे स्मृति में कॉपी करें, फिर दूसरे तर्क की व्याख्या करें, और इसे स्मृति में कॉपी करें।

मुझे कई पुस्तकालयों के बारे में सूचित किया गया है जो इस कार्य को आसान बना देंगे, जैसे जीएनयू बिजली, और यहां तक ​​कि एलएलवीएम। हालांकि, बाहरी संसाधनों का उपयोग करने से पहले, मैं इसे पहले हाथ से लिखना चाहता हूं, यह समझने के लिए कि यह कैसे काम करता है।

क्या इस समुदाय को शुरू करने में मेरी सहायता करने के लिए कोई समुदाय या उदाहरण उपलब्ध हैं? निष्पादन योग्य कोड उत्पन्न करने के लिए "एड" और "mov" जैसे दो या तीन निर्देशों का उपयोग करने वाला एक सरल उदाहरण, गतिशील रूप से, स्मृति में, चमत्कार में, चमत्कार करेगा।

+10

सिर्फ इसलिए कि एक जिटर जेनरेट करता है मशीन कोड * नहीं * का मतलब है कि इसे स्वयं असेंबली में लिखा जाना चाहिए। ऐसा करने का कोई मतलब नहीं है। –

+0

जीसीसी के गणना वाले गोटो एक्सटेंशन ('शून्य * ऑप्टेबल [] = {&& op_add, && op_subtract, ...}' का उपयोग करके थ्रेड किए गए प्रेषण का प्रयास करने के लिए एक मध्यवर्ती चरण है और प्रत्येक ऑपरेंड 'op_add: ... goto * optable [* ip ++] है ; ')। मैंने आपके जैसे वर्णन किए गए स्विच किए गए दुभाषियों में बड़े लाभ देखा है। –

उत्तर

18

मैं असेंबली में एक जेआईटी लिखने की सिफारिश नहीं करता। विधानसभा में दुभाषिया की सबसे अधिक बार निष्पादित बिट्स लिखने के लिए अच्छे तर्क हैं। उदाहरण के लिए यह कैसे दिखता है यह comment from Mike Pall, लुआजिट के लेखक को देखता है।

  1. बस दुभाषिया के कोड को कॉपी करके एक बुनियादी ब्लॉक (गैर शाखाओं में निर्देशों का एक अनुक्रम) संकलित करें: JIT का सवाल है

    , वहाँ अलग जटिलता के साथ कई अलग अलग स्तर हैं। उदाहरण के लिए, कुछ (रजिस्टर आधारित) बाईटकोड निर्देश के कार्यान्वयन इस प्रकार दिखाई देंगे:

    ; ebp points to virtual register 0 on the stack 
    instr_ADD: 
        <decode instruction> 
        mov eax, [ebp + ecx * 4] ; load first operand from stack 
        add eax, [ebp + edx * 4] ; add second operand from stack 
        mov [ebp + ebx * 4], eax ; write back result 
        <dispatch next instruction> 
    instr_SUB: 
        ... ; similar 
    

    तो, दिए गए अनुदेश अनुक्रम ADD R3, R1, R2, SUB R3, R3, R4 एक सरल JIT एक में दुभाषिए कार्यान्वयन के प्रासंगिक भागों नकल कर सकता है नई मशीन कोड हिस्सा:

    mov ecx, 1 
        mov edx, 2 
        mov ebx, 3 
        mov eax, [ebp + ecx * 4] ; load first operand from stack 
        add eax, [ebp + edx * 4] ; add second operand from stack 
        mov [ebp + ebx * 4], eax ; write back result 
        mov ecx, 3 
        mov edx, 4 
        mov ebx, 3 
        mov eax, [ebp + ecx * 4] ; load first operand from stack 
        sub eax, [ebp + edx * 4] ; add second operand from stack 
        mov [ebp + ebx * 4], eax ; write back result 
    

    यह केवल प्रतियां प्रासंगिक कोड है, तो हम उसके अनुसार इस्तेमाल किया रजिस्टरों आरंभ करने की जरूरत है। एक बेहतर समाधान यह सीधे मशीन निर्देश mov eax, [ebp + 4] में अनुवाद करना होगा, लेकिन अब आपको पहले से ही अनुरोधित निर्देशों को मैन्युअल रूप से एन्कोड करना होगा।

    यह तकनीक व्याख्या के ऊपरी भाग को हटा देती है, लेकिन अन्यथा दक्षता में सुधार नहीं होता है।यदि कोड केवल एक या दो बार निष्पादित किया जाता है, तो इसे पहले इसे कोड कोड में अनुवाद करने के लायक नहीं हो सकता है (जिसके लिए I-cache के कम से कम हिस्सों को फ़्लश करना आवश्यक है)।

  2. जबकि कुछ जेआईटी एक दुभाषिया के बजाय उपरोक्त तकनीक का उपयोग करते हैं, फिर वे अक्सर निष्पादित कोड के लिए एक और अधिक जटिल अनुकूलन तंत्र को नियोजित करते हैं। इसमें निष्पादित बाइटकोड को एक मध्यवर्ती प्रतिनिधित्व (आईआर) में अनुवाद करना शामिल है जिस पर अतिरिक्त अनुकूलन किए जाते हैं।

    स्रोत भाषा और जेआईटी के प्रकार के आधार पर, यह बहुत जटिल हो सकता है (यही कारण है कि कई जेआईटी इस कार्य को एलएलवीएम को सौंपते हैं)। एक विधि-आधारित जेआईटी को नियंत्रण-प्रवाह ग्राफ में शामिल होने की आवश्यकता होती है, इसलिए वे एसएसए फॉर्म का उपयोग करते हैं और उस पर विभिन्न विश्लेषण चलाते हैं (उदा।, हॉटस्पॉट)।

    एक ट्रेसिंग जेआईटी (जैसे लुआजिट 2) केवल सीधी रेखा कोड को संकलित करता है जो कई चीजों को कार्यान्वित करने में आसान बनाता है, लेकिन आपको बहुत सावधान रहना होगा कि आप निशान कैसे चुनते हैं और आप कुशलतापूर्वक एक साथ कई निशान कैसे जोड़ते हैं। गैल और फ्रांज this paper (PDF) में एक विधि का वर्णन करते हैं। एक और विधि के लिए LuaJIT स्रोत कोड देखें। दोनों जेआईटी सी (या शायद सी ++) में लिखे गए हैं।

+0

ब्रांचिंग का उपयोग करने वाले कोड के ब्लॉक के बारे में क्या? – jakogut

+1

सही, प्रत्येक मूल ब्लॉक के अंत में आपको एक दिनचर्या में वापस आना चाहिए जो कि कहां से शाखा का फैसला करता है। इसके बाद एक नया बाइटकोड पता होता है जिसे संबंधित मशीन कोड के पते पर मैप किया जाना चाहिए। [संदर्भ थ्रेडिंग (पीडीएफ)] (http://www.cs.toronto.edu/syslab/pubs/zaleski_shapes2005.pdf) नामक एक तकनीक है जो दुभाषिया और जेआईटी के अधिक चिकनी एकीकरण की अनुमति देती है। मुख्य विचार शाखाओं को वास्तविक मशीन निर्देशों में अनुवाद करना है ताकि शाखा भविष्यवाणियों उन्हें देख सकें। – nominolo

7

मेरा सुझाव है कि आप प्रोजेक्ट http://code.google.com/p/asmjit/ देखें। यह प्रदान करता है कि ढांचे का उपयोग करके, आप बहुत सारी ऊर्जा बचा सकते हैं। यदि आप सभी चीज़ों को हाथ से लिखना चाहते हैं, तो बस स्रोत पढ़ें और इसे स्वयं लिखें, मुझे लगता है कि यह बहुत कठिन नहीं है।

संबंधित मुद्दे