2012-10-14 10 views
7

मान लें कि आप जावा (या सबसेट-ऑफ-जावा) कंपाइलर लिख रहे हैं और आप एक यूनरी नहीं अभिव्यक्ति के लिए बाइटकोड उत्पन्न करना चाहते हैं, !E। आप पिछले प्रकार की जांच कर रहे हैं ताकि आपको पता चल सके कि E में boolean टाइप है, यानी यह ऑपरेटिंग स्टैक पर 1 या 0 दबाएगा।एक यूनरी नहीं अभिव्यक्ति के लिए जेवीएम बाइटकोड उत्पन्न करना

एक तरह से यह करने के लिए (जैस्मिन वाक्य रचना में) की तरह कुछ है:

E 
ifeq truelabel 
iconst_0 
goto stoplabel 
truelabel: 
iconst_1 
stoplabel: 

यानी अगर वहाँ ढेर धक्का 1, और धक्का 0. यह करने के लिए एक और तरीका है पर एक 0 है, का लाभ लेने तथ्य यह है कि एक boolean है बस मूल्य 1 या 0 के साथ एक int, !E = (E + 1) % 2 कहना और उत्पन्न

E 
iconst_1 
iadd 
iconst_2 
irem 

वहाँ एक दूसरे के ऊपर का उपयोग करने का लाभ है के लिए है? या पूरी तरह से कुछ और?

उत्तर

4

मैं बाइटकोड स्तर पर सत्य रखने के लिए निम्न परिभाषा पर भरोसा नहीं करता।

true == 1 

द्विआधारी स्तर पर (और इसके लगभग भाषा स्वतंत्र), एक बूलियन आमतौर पर javac संकलक जाहिरा तौर पर भी इस परिभाषा (javac बाईटकोड में सभी चेक मैं सिर्फ देखा है इस प्रकार है

false == 0 
true != 0 

के रूप में परिभाषित किया गया है हमेशा शून्य की जांच करता है, कभी भी एक के खिलाफ नहीं)।

और यह केवल परिभाषा को 1 के रूप में इलाज करने के लिए इस परिभाषा का उपयोग करने के लिए समझ में आता है, सी भी इसे इस तरह परिभाषित करता है (सच है बस! = 0, केवल 1 नहीं) और असेंबली कोड में इस सम्मेलन का भी आमतौर पर उपयोग किया जाता है। तो जावा इस परिभाषा का उपयोग करके जावा बूलियन को किसी भी विशेष रूपांतरण के बिना अन्य कोड में ले जाना/पास करना संभव बनाता है।

मुझे संदेह है कि आपका पहला कोड उदाहरण (ifeq के साथ) बूलियन के लिए ऑपरेटर को सही ढंग से कार्यान्वित करने का एकमात्र तरीका है।^1-विधि (xor with 1) विफल हो जाएगा यदि बूलियन मान को स्ट्रेटली रूप से 0/1 के रूप में प्रदर्शित नहीं किया जाता है। कोई अन्य int मान अभिव्यक्ति को गलत तरीके से काम करने का कारण बनता है।

+0

जेवीएम स्पेक कहता है: "जावा आभासी मशीन 1 का उपयोग करके बूलियन सरणी घटकों को एन्कोड करता है और झूठी प्रतिनिधित्व करने के लिए 0 का प्रतिनिधित्व करता है। जहां जावा प्रोग्रामिंग भाषा बूलियन मानों को जावा वर्चुअल मशीन प्रकार int के मानों के लिए कंपाइलर्स द्वारा मैप किया जाता है, तो कंपाइलर्स का उपयोग करना चाहिए एक ही एन्कोडिंग। " http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.3.4 –

+0

@isbadawi यह वर्णन करता है कि कैसे JVM एन्कोड * बूलियन के सरणी * और जावा कंपाइलर्स को कैसे जरूरी है स्याही के रूप में एन्कोड बूलियन * कब और यदि वे ऐसा करते हैं। * यह प्रश्न के तुरंत बाद प्रासंगिक नहीं है। – EJP

+0

@EJP यह मेरे लिए संदिग्ध लगता है। पहला वाक्य बूलियन सरणी के बारे में है, लेकिन दूसरा बुलियन मूल्यों के बारे में है। हालांकि मैं शायद गलत हूँ। –

5

मैंने एक बार जावा डिकंपेलर लिखने की कोशिश की, इसलिए मुझे पता था कि कोड जेवाक किस प्रकार उत्पन्न हुआ था। जैसा कि मुझे याद है, javac 1.0.x !E = E ? false : true का उपयोग किया गया जबकि javac 1.1 !E = E^1 (bitwise XOR) का उपयोग किया गया।

+0

मैंने '^ 1' के बारे में सोचा नहीं था; यह निश्चित रूप से दूसरे की तुलना में बेहतर है। क्या आप पूर्व से बाद वाले में स्विच करने के पीछे तर्क को जानते हैं, या क्यों पहली जगह '^ 1' का उपयोग नहीं किया गया था? –

+0

असल में मैंने अभी 'javac 1.6.0_26' के साथ प्रयास किया है और यह पहली बार उत्पन्न हुआ है ('ifeq' के बजाय' ifne' को छोड़कर), तो मुझे लगता है कि वे वापस स्विच कर चुके हैं। मुझे लगता है कि मैं अभी भी एक बनाम दूसरे के लाभों के बारे में सोच रहा हूं। –

+1

यह सिर्फ एक जंगली अनुमान है, लेकिन शायद वे इस तरह के माइक्रो-ऑप्टिमाइज़ेशन को जेआईटी में ले जाया गया, जो शायद वे कहां से संबंधित हैं। – Neil

0

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

इसके साथ, मुझे संदेह होगा कि नील का E^1 सबसे तेज़ है, लेकिन यह सिर्फ एक झटका है। आपको बस एक तर्क सर्किट के माध्यम से नंबर पास करना है, और आप कर चुके हैं! एक मुट्ठी भर के बजाय बस एक ऑपरेशन।

+0

^1 निश्चित रूप से * * * div/rem से कम computationally गहन और सशर्त शाखाएं कुछ हद तक महंगा हैं (क्योंकि वे अधिकांश मौजूदा CPU आर्किटेक्चर के साथ शाखा गलत भविष्यवाणी दंड का कारण बन सकते हैं)। बड़ा सवाल यह है कि यदि यह बूलियन को लागू करने के लिए int सेवारत करने के लिए मान्य है तो 0/1 मानों के लिए कड़ाई से संकुचित है। – Durandal

+0

मैं जावा में विश्वास करता हूं, यह है। किसी भी मामले में, यदि आप नहीं जानते थे तो आप केवल '(ई और 1)^1' कर सकते हैं। –

+0

(& 1)^1 0x2 से 0x1 परिवर्तित करता है (उदाहरण के लिए)। सच ==! सच वास्तव में कोई उम्मीद नहीं है। मुझे तार्किक या एक बिट के सभी 32 बिट्स को एक ही बिट में पतन करने के लिए किसी भी सरल अभिव्यक्ति के बारे में पता नहीं है। या तो बूलियन * कड़ाई से * बाधित हैं, या^-method का उपयोग नहीं किया जा सकता है। – Durandal

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