2015-05-14 4 views
7

एक answer to a question about JVM byte code offsets लेखन करते हुए मैं javac के व्यवहार और जिसके परिणामस्वरूप वर्ग फ़ाइलों में कुछ है कि मैं व्याख्या नहीं कर सकते देखा:एक JVM कूद निर्देश के लिए ऑफसेट 32768 कैसे हो सकता है?

जब यह

class FarJump 
{ 
    public static void main(String args[]) 
    { 
     call(0, 1); 
    } 

    public static void call(int x, int y) 
    { 
     if (x < y) 
     { 
      y++; 
      y++; 

      // ... (10921 times - too much code to post here!) 

      y++; 
      y++; 
     } 
     System.out.println(y); 
    } 

} 

की तरह एक वर्ग संकलन फिर परिणामी बाइट कोड में शामिल होंगे निम्नलिखित if_icmpge अनुदेश:

public static void call(int, int); 
    Code: 
     0: iload_0 
     1: iload_1 
     2: if_icmpge  32768 
     5: iinc   1, 1 
     8: iinc   1, 1 
     ... 

कूद निर्देश के प्रलेखन के अनुसार, ऑफसेट (जो इस मामले में 32768 है) में की जाती है इस प्रकार है:

तुलना सफल होती है, अहस्ताक्षरित branchbyte1 और branchbyte2 के निर्माण के लिए एक हस्ताक्षरित 16-बिट, ऑफसेट उपयोग किया जाता है जहां ऑफसेट होने की गणना की जाती है (branchbyte1 < < 8) | branchbyte2

तो ऑफ़सेट को पर हस्ताक्षर किया गया 16 बिट मान पर हस्ताक्षर किए गए। हालांकि, पर हस्ताक्षर किए गए अधिकतम मूल्य 16 बिट मान हो सकते हैं 32767, और 32768 नहीं।

परिणामस्वरूप क्लास फ़ाइल अभी भी वैध मानी जाती है, और इसे सामान्य रूप से निष्पादित किया जा सकता है।

मैं bytecode checking in the OpenJDK पर एक नज़र था, और यह (मेरे लिए) लगता है कि इस कोष्ठक गलत होने के कारण ही मान्य है:

int jump = (((signed char)(code[offset+1])) << 8) + code[offset+2]; 

यह signed char करने के लिए पहली बाइट डाली जाएगी। फिर यह शिफ्ट लागू करेगा, और दूसरा बाइट जोड़ देगा। मैं यह अपेक्षा की होगी

int jump = (((signed char)(code[offset+1]) << 8)) + code[offset+2]; 

या शायद

int jump = (signed char)((code[offset+1]) << 8) + code[offset+2]); 

होने के लिए, लेकिन मैं प्रकार प्रोन्नति और हस्ताक्षर किए और अहस्ताक्षरित प्रकार स्थानांतरण के संभावित संकलक विशेष चेतावनियां से परिचित नहीं हूँ, इसलिए मैं मुझे यकीन नहीं है कि इस कास्ट के पीछे गहरा अर्थ है ...

तो क्या 32768 की एक कूद ऑफ़सेट विनिर्देश का पालन करती है? और क्या ओपनजेडीके में कूद गणना कोड इस संबंध में कोई समझ में आता है?

उत्तर

3

if_icmpge पर तर्क ऑफसेट है, लेकिन जावप कूद लक्ष्य को पूर्ण स्थिति के रूप में दिखाता है। यही है, जावप को getstatic32768: पर और 32770: (यानी, 2 + 32768) पर नहीं दिखाना चाहिए।

+0

ठीक है, यह आसान था। दरअसल, हेक्स संपादक के साथ कक्षा फ़ाइल को देखते समय, कोई ऑफसेट 32766 (7 एफएफई) हो सकता है। मैं इसे "स्वीकृत" के रूप में चिह्नित करूंगा, लेकिन ... OpenJDK के 'check_code.c' में कलाकारों के बारे में कोई विचार? यही है: क्या यह कलाकार किसी भी तरह का अर्थ बनाता है? मुझे लगता है कि इस कास्ट पर ध्यान दिए बिना पूर्णांक पदोन्नति होनी चाहिए, और परिणामस्वरूप मूल्य का संभावित * डोमेन * इस कलाकार द्वारा प्रभावित नहीं होता है ... – Marco13

+0

मैं सी प्रकार पदोन्नति नियमों पर एक विशेषज्ञ नहीं हूं (इसलिए मैंने पढ़ा http://icecube.wisc.edu/~dglo/c_class/promo_conv.html), लेकिन मेरा मानना ​​है कि उन सभी अभिव्यक्ति समान हैं। आंतरिक अभिव्यक्ति से शुरू होने पर, मेरा मानना ​​है कि '8' टाइप int है, जो '<<' के बाएं तर्क को int में परिवर्तित करने का कारण बनता है। एक हस्ताक्षरित डेटा प्रकार के लिए कलाकार को किसी बिंदु पर (पीछे की तरफ कूदने की अनुमति देने) की आवश्यकता होती है, इससे वास्तव में कोई फर्क नहीं पड़ता। –

0

मैंने आगे खोदने के लिए कोड उत्पन्न करने के लिए एक सरल स्कैला कोड लिखा था। कूद के सभी प्रकार के निर्देशों के लिए, ऑफ़सेट को पिछड़ा समर्थन करने के लिए हस्ताक्षर किया गया है, और आगे बढ़ें।

अगर ऑफ़सेट 0x7FFF के बराबर है, तो मुझे गेटो निर्देश दिखाई देता है, और अगर 0x7FFF से अधिक ऑफसेट होता है, तो मुझे goto_w निर्देश दिखाई देता है।

तो, जावा में एक विधि 65535 बाइट तक सीमित है, क्योंकि LineNumberTable, LocalVariableTable, upgrade_table ... और 65535 बाइट तक सीमित है। JVM आवश्यकतानुसार 16/32 ऑफसेट पर हस्ताक्षर करने के लिए goto/goto_w निर्देशों का उपयोग करता है।

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