17

एफ # भाषा के रूप में भाषा दुभाषियों या कंपाइलर्स लिखने के लिए बहुत अच्छा है, हालांकि, एक चीज हमें मारती रहती है जहां हम इसे नहीं चाहते हैं: StackOverflowException।भाषा दुभाषियों में स्टैक ओवरव्लो को रोकना

यह अच्छी तरह से ज्ञात है कि एक एसओ-अपवाद पकड़ा नहीं जा सकता है और इसे पुनर्प्राप्त नहीं किया जा सकता है। इस तरह के अपवाद को रोकने के लिए एक स्पष्ट तकनीक है जब आप साथ जाते हैं तो ढेर की गहराई को गिनना। ओवरहेड, हाँ, लेकिन काम करने योग्य और शायद हर समारोह में आवश्यक नहीं है।

एफ # के साथ, यह तकनीक हालांकि अधिक लाभ नहीं लाती है। हम दुभाषिया के ऑन-द-फ्लाई जेनरेटेड एक्सप्रेशन में पूंछ-कॉल अनुकूलन तकनीकों का बहुत अधिक उपयोग करते हैं। एसओ-अपवादों के साथ हमें जिन समस्याओं का सामना करना पड़ता है वे हैं:

  • हम वर्तमान उपयोगकर्ता को क्रैश करने के बजाय, उनके उपयोगकर्ता को कैसे सूचित कर सकते हैं?
  • यदि हम स्टैक-गहराई की गिनती के लिए जाते हैं, तो हम कैसे जानते हैं कि कोई कार्य TCO'ed है या रेखांकित है, इसलिए हमें गिनने की आवश्यकता नहीं है?
  • यदि हम किसी अन्य दृष्टिकोण के लिए जाते हैं (जैसे गहराई से अंतराल पर ढेर का निरीक्षण करना), क्या प्रदर्शन करने में गंभीरता से बिना किसी ज्ञात तरीके से ऐसा करने का कोई तरीका है?

बस स्टैक-साइज को बढ़ाने में काफी मदद नहीं मिल रही है, हम उपयोगकर्ता को लॉगिंग योग्य त्रुटि देना चाहते हैं, जो कॉलिंग एप्लिकेशन द्वारा अधिमानतः आकर्षक है। इसके लिए हमें अपवाद को हाथ से फेंकने में सक्षम होना चाहिए, जो इसे पकड़ने योग्य बनाता है। लेकिन हम सही पल कैसे निर्धारित करते हैं?

अद्यतन:
हंस पासेंट सही ढंग से भविष्यवाणी का सुझाव देता है। हालांकि, इस डीएसएल का उपयोग करने वाले प्रोग्रामर उम्मीद करते हैं कि (निश्चित) कॉल टीसीओ प्राप्त करें, इसलिए वे एक मजबूत स्टैक-सीमा नहीं चाहते हैं। वे जानते हैं वे क्या कर रहे हैं। फिर भी, उनके कार्यक्रमों को कम से कम विस्तार करने की आवश्यकता है, कम से कम विस्तार करने के लिए कि किसी भी कॉलिंग एप्लिकेशन (यानी, हमारे पुस्तकालयों का उपयोग कर एक सी # प्रोग्राम) को नुकसान नहीं पहुंचाया जाता है।

+0

@ हंसपैसेंट, कूदने के लिए धन्यवाद। यह इस तरह से हल करने के लिए हमारे दिमाग को पार कर गया है, लेकिन यह एक स्लेज हथौड़ा के साथ एक छोटी सी समस्या को हल करने की तरह लगता है कि हमने अभी तक इसका प्रयास नहीं किया है। इसके अलावा, हमारे कंपाइलर को एक मेजबान भाषा के भीतर से लाइब्रेरी के रूप में कॉल करने योग्य होना चाहिए और प्रत्येक बार जब एक छोटे स्निपेट को संकलित किया जाता है, तो प्रक्रिया बहुत अधिक हो जाती है। – Abel

+0

ओह, आपने अपनी टिप्पणी अपडेट की है। यहां समस्या भविष्यवाणी है। डीएसएल में कई कार्य हो सकते हैं जो टीसीओ प्राप्त करेंगे, एक कठोर सीमा निर्धारित करते हैं (जो वर्तमान में हमारे पास है) बहुत कठोर प्रतीत होता है, क्योंकि हम किसी भी कल्पनाशील तरीके से उस सीमा की गणना नहीं कर सकते हैं। – Abel

+0

@ हंसपैसेंट: हमारा प्रोग्राम संकलित अभिव्यक्तियों में एक और भाषा का अनुवाद करता है और फिर परिवर्तनीय इनपुट के विरुद्ध चलता है। जटिल चीजों को आगे बढ़ाने के लिए, भाषा परिभाषा में एक मूल्यांकन-कार्य होता है। बढ़ते ढेर आकार केवल एक निश्चित स्तर पर काम करते हैं, मुझे नहीं पता क्यों, लेकिन एक निश्चित सीमा के बाद यह कार्यक्रम को घोंघा-गति में लाता है। एक के लिए, हमारे कार्यक्रम को आईडीई (हमारे नहीं) से बुलाया जाएगा, जिससे आईडीई नीचे आ जाएगा क्योंकि हमारे पास एसओएस विनाशकारी होगा। AppDomains के साथ एक रास्ता था, लेकिन मुझे विश्वास है कि अब और संभव नहीं है। – Abel

उत्तर

5

मैं एफ # से परिचित नहीं हूं लेकिन मैंने सी # में एक ईसीएमएस्क्रिप्ट -262 वी.5 दुभाषिया लिखा है, इसलिए मैं आपके कुछ मुद्दों से संबंधित हूं। जैसा कि आप जानते हैं, stackOverFlowException v2.0 के बाद .NET ऐप्स में नहीं पकड़ा जा सकता है। यद्यपि यह काफी विश्वसनीय कामकाज है और यह तेज़ है।

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

यहां मेरे दुभाषिया से कुछ अंश दिए गए हैं जो इस मुद्दे को संबोधित करते हैं।

सी #:

ये स्थैतिक चर रहे हैं मुख्य दुभाषिया वर्ग में घोषित कर दिया।

private static int TopOfStack; 
private const int STACK_SIZE = 1000000; 

यह मुख्य इंटरप्रेटर वर्ग का स्थिर निर्माता है।

static Interpreter() { 
    InitializeGlobalEnvironment(); 

    //--------------------------------------------------- 
    // Get the address of a new variable allocated on the stack 
    // to represent the amount of memory available. Record 
    // the address. 
    //--------------------------------------------------- 
    int stackVariable; 
    TopOfStack = (int)&stackVariable; 
} 

यह कोड ईसीएमएस्क्रिप्ट फ़ंक्शन का अर्थ लेने से पहले कहा जाता है। यदि एक नए स्टैक आवंटित चर का पता छोटा से कम है। मैक्स, मैं पकड़ने योग्य अपवाद फेंक देता हूं। कॉल स्टैक को खोलने के लिए आपको कुछ जगह छोड़नी होगी।

internal static ExecutionContext EnterFunctionContext(IValue thisArg, LIST args, FUNCTION function) { 
... 
    LexicalEnvironment localEnv = ECMA.NewDeclarativeEnvironment(function.Scope); 

    ExecutionContext context = new ExecutionContext() { 
     Strict = function.IsStrict, 
     VariableEnvironment = localEnv, 
     LexicalEnvironment = localEnv 
    }; 

    int remainingStackSpace; 

    if (STACK_SIZE - (TopOfStack - (int)&remainingStackSpace) < short.MaxValue) 
      throw new ECMARuntimeException("stack overflow", RuntimeErrorType.RangeError); 


    CallStack.Push(context); 
    LexicalEnvironment env = CurrentContext.VariableEnvironment; 
... 
} 

जब निम्नलिखित कोड व्याख्या की है, अपवाद यात्रा के आसपास फेंक दिया जाता है 1200.

अद्यतन: विज्ञप्ति में निर्माण के चारों ओर 4100 पुनरावृत्तियों है।

ECMAScript:

RecursiveCall(0); 

function RecursiveCall(counter){ 
    return RecursiveCall(++counter); 
} 

आउटपुट: RangeError: stack overflow

आप Thread(ParameterizedThreadStart, Int32) निर्माता का उपयोग कर थ्रेड में ढेर आकार में वृद्धि कर सकता है। मुझे बस जरूरत महसूस नहीं हुई।

आपकी परियोजना के साथ शुभकामनाएँ। आशा है कि ये आपकी मदद करेगा।

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