डगलस का जवाब JIT के डेड कोड को अनुकूलित करने के बारे में सही है ( दोनों x86 और x64 कंपाइलर ऐसा करेंगे)। हालांकि, अगर JIT कंपाइलर मृत कोड का अनुकूलन कर रहा था, तो यह तुरंत स्पष्ट हो xजाएगा क्योंकि स्थानीय विंडो में भी नहीं दिखाई देगा। इसके अलावा, घड़ी और तत्काल विंडो आपको इसे एक्सेस करने का प्रयास करते समय एक त्रुटि देगा: "वर्तमान संदर्भ में 'x' नाम मौजूद नहीं है"। यह वही नहीं है जो आपने वर्णित किया है।
आप जो देख रहे हैं, वह वास्तव में Visual Studio 2010 में एक बग है।
सबसे पहले, मैंने अपने मुख्य मशीन पर इस मुद्दे को पुन: पेश करने की कोशिश की: Win7x64 और VS2012। .NET 4.0 टारगेट के लिए, x3.0D के बराबर होता है जब यह क्लोजिंग कर्ली ब्रेस पर टूटता है। मैंने .NET 3.5 लक्ष्य के रूप में अच्छी तरह से कोशिश करने का फैसला किया, और इसके साथ ही, x3.0D पर सेट किया गया, शून्य नहीं।
चूंकि मैं .NET 4.0 के शीर्ष पर स्थापित .NET 4.5 के बाद से मैं इस मुद्दे का एक पूर्ण प्रजनन नहीं कर सकता, इसलिए मैंने एक वर्चुअल मशीन को स्थापित किया और उस पर VS2010 स्थापित किया।
यहाँ, मैं इस मुद्दे को पुन: पेश करने में सक्षम था। Mainविधि के समापन घुंघराले ब्रैकेट पर एक विराम बिंदु के साथ , घड़ी की खिड़की और स्थानीय खिड़की दोनों में, मैंने देखा कि वह xथा null। यह वह जगह है जहाँ यह दिलचस्प होने लगता है। मैंने इसके बजाय v2.0 रनटाइम को लक्षित किया और पाया कि यह वहां भी अशक्त था। निश्चित रूप से ऐसा नहीं हो सकता है क्योंकि मेरे पास अपने दूसरे कंप्यूटर पर .NET 2.0 रनटाइम का समान संस्करण है जो सफलतापूर्वक xएक मान के साथ दिखाया गया है 3.0D।
तो, फिर क्या हो रहा है? विंडबग में कुछ खुदाई के बाद, मुझे यह मुद्दा मिला:
VS2010 आपको एक्स का मूल्य दिखा रहा है इससे पहले कि यह वास्तव में सौंपा गया है ।
मुझे पता है कि यह ऐसा नहीं है जैसा कि निर्देश सूचक x = y + zलाइन से अतीत है । आप विधि की कुछ पंक्तियों को जोड़कर स्वयं इसका परीक्षण कर सकते हैं:
double? y = 1D;
double? z = 2D;
double? x;
x = y + z;
Console.WriteLine();
अंतिम घुंघराले ब्रेस पर एक ब्रेकपॉइंट के साथ, स्थानीय और घड़ी खिड़की के शो xके बराबर है 3.0D। हालाँकि, यदि आप कोड के माध्यम से कदम बढ़ाते हैं, तो आप देखेंगे कि VS2010 आपके द्वारा दिए गए कदम के बादx असाइन किए जाने तक प्रदर्शित नहीं होता है ।Console.WriteLine()
मुझे नहीं पता कि क्या यह बग कभी Microsoft कनेक्ट को सूचित किया गया था, लेकिन आप उदाहरण के रूप में इस कोड के साथ ऐसा करना चाह सकते हैं। यह स्पष्ट रूप से VS2012 में तय किया गया है, लेकिन मुझे यकीन नहीं है कि इसे ठीक करने के लिए कोई अपडेट होगा या नहीं।
यहाँ वास्तव में JIT और VS2010 में क्या हो रहा है
मूल कोड के साथ, हम देख सकते हैं कि वीएस क्या कर रहा है और क्यों गलत है। हम यह भी देख सकते हैं कि xचर को अनुकूलित नहीं किया जा रहा है (जब तक कि आपने असेंबली को चिह्नित नहीं किया है कि वह अनुकूलन योग्य के साथ संकलित हो)।
आइए, आइएल की स्थानीय परिवर्तनशील परिभाषाओं को देखें:
.locals init (
[0] valuetype [mscorlib]System.Nullable`1<float64> y,
[1] valuetype [mscorlib]System.Nullable`1<float64> z,
[2] valuetype [mscorlib]System.Nullable`1<float64> x,
[3] valuetype [mscorlib]System.Nullable`1<float64> CS$0$0000,
[4] valuetype [mscorlib]System.Nullable`1<float64> CS$0$0001,
[5] valuetype [mscorlib]System.Nullable`1<float64> CS$0$0002)
यह डिबग मोड में सामान्य आउटपुट है। विजुअल स्टूडियो डुप्लिकेट लोकल वैरिएबल को परिभाषित करता है जो असाइनमेंट के दौरान उपयोग करता है, और फिर इसे CS * वैरिएबल से कॉपी करने के लिए अतिरिक्त आईएल कमांड जोड़ता है। यहाँ संगत आईएल कोड है जो यह दर्शाता है:
L_0045: ldloca.s CS$0$0000
L_0047: call instance !0 [mscorlib]System.Nullable`1<float64>::GetValueOrDefault()
L_004c: conv.r8
L_004d: ldloca.s CS$0$0001
L_004f: call instance !0 [mscorlib]System.Nullable`1<float64>::GetValueOrDefault()
L_0054: conv.r8
L_0055: add
L_0056: newobj instance void [mscorlib]System.Nullable`1<float64>::.ctor(!0)
L_005b: nop
L_005c: stloc.2
L_005d: ret
आइए WinDbg के साथ कुछ गहरी डीबगिंग करते हैं:
यदि आप VS2010 में एप्लिकेशन को डीबग करते हैं और विधि के अंत में एक ब्रेकपॉइंट छोड़ते हैं, तो हम नॉन-इनवेसिव मोड में विनडबग को आसानी से संलग्न कर सकते हैं।
यहाँ Mainकॉल स्टैक में विधि के लिए फ्रेम है । हम आईपी (इंस्ट्रक्शन पॉइंटर) की परवाह करते हैं।
0: 009>!
ओएस थ्रेड आईडी: 0x135c (9)
बाल एसपी आईपी कॉल साइट
000000001c48dc00 000007ff0017338d ConsoleApplication1.Program.Main (System.String [])
[और इसी तरह...]
यदि हम Mainविधि के लिए मूल मशीन कोड देखते हैं, तो हम देख सकते हैं कि वीएस द्वारा निष्पादन को तोड़ने के समय क्या निर्देश चलाए गए हैं:
000007ff`00173388 e813fe25f2 कॉल mscorlib_ni + 0xd431a0
(000007fe`f23d31a0) (System.Nullable`1 [[System.Double, mscorlib]] .. ctor (डबल), mdToken: 0000000006001ef2)
**** 000007ff`0017338d cc int 3 ****
000007ff`0017338e 8d8c2490000000 ईएक्स एक्सएक्सएक्स, [आरएसपी + 90 एच]
000007ff`00173395 488b01 mov rax, qword ptr [rcx]
000007ff`00173398 4889842480000000 mov qword ptr [rsp + 80h], rax
000007ff`001733a0 488b4108 mov rax, qword ptr [rcx + 8]
000007ff`001733a4 4889842488000000 mov qword ptr [rsp + 88h], rax
000007ff`001733ac 488d8c2480000000 लीक आरसीएक्स, [आरएसपी + 80 h]
000007ff`001733b4 488b01 mov rax, qword ptr [rcx]
000007ff`001733b7 4889442440 mov qword ptr [rsp + 40h], rax
000007ff`001733bc 488b4108 mov rax, qword ptr [rcx + 8]
000007ff`001733c0 4889442448 mov qword ptr [rsp + 48h], rax
000007ff`001733c5 eb00 jmp 000007ff`001733c7
000007ff`001733c7 0f28b424c0000000 xmm6, xmmword ptr [rsp + 0C0h] चलता है
000007ff`001733cf 4881c4d8000000 rsp, 0D8h जोड़ें
000007ff`001733d6 c3 रिट
हमारे द्वारा प्राप्त वर्तमान आईपी का उपयोग करते !clrstackहुए Main, हम देखते हैं कि इंस्ट्रक्शन को कॉल करने के बाद सीधे इंस्ट्रक्शन पर निलंबित कर दिया गया था System.Nullable<double>। ( int 3निष्पादन को रोकने के लिए डिबगर्स द्वारा उपयोग की जाने वाली रुकावट है) मैंने उस लाइन को * के साथ घेर लिया है, और आप L_0056IL में लाइन को मेल भी कर सकते हैं ।
X64 असेंबली जो वास्तव में इसे स्थानीय चर को असाइन करती है x। हमारे निर्देश सूचक ने उस कोड को अभी तक निष्पादित नहीं किया है, इसलिए समय से पहले ही वीआर2010 xदेशी कोड द्वारा चर को सौंपा गया है।
EDIT: x64 में, int 3निर्देश असाइनमेंट कोड से पहले रखा गया है, जैसा कि आप ऊपर देख सकते हैं। X86 में, उस निर्देश को असाइनमेंट कोड के बाद रखा गया है। यह बताता है कि वीएस केवल एक्स 64 में जल्दी क्यों टूट रहा है। यह कहना मुश्किल है कि यह विजुअल स्टूडियो या JIT कंपाइलर की गलती है। मैं अनिश्चित हूं कि कौन सा एप्लिकेशन विराम बिंदु हुक सम्मिलित करता है।