سؤال

يمكن للشخص أن يفسر هذه الأسطر القليلة من MSIL?لماذا لا تتحرك قيمة من التقييم المكدس إلى متغير محلي فقط إلى التحرك فورا والعودة ؟

التالية البرمجية MSIL الأحمال حجة واحدة (سلسلة), المكالمات الأسلوب ، والتي ترجع منطقي ، ثم يعود أن قيمة منطقي.ما لا أفهمه هو لماذا تسميه stloc.0 لتخزين الأسلوب بإرجاع قيمة في متغير محلي ، ثم ينفذ صريح غير المشروط التحكم في نقل القادم المسمى خط (يبدو لا لزوم لها) ، إلا أن التحرك قيمة الحق مرة أخرى على التقييم المكدس قبل إعادته.

.maxstack 1
.locals init ([0] bool CS$1$0000)
L_0000: nop
L_0001: ldarg.0
L_0002: call bool FuncNameNotImporant::MethodNameNotImporant(string)
L_0007: stloc.0 
L_0008: br.s L_000a
L_000a: ldloc.0 
L_000b: ret 

أفضل تخمين لماذا يفعل هذا هو أداء بعض نوع من نوع الاختيار لضمان القيمة على التقييم المكدس هو في الواقع قيمة منطقية قبل إعادته.ولكن أنا جاهل عن صريح الانتقال إلى السطر التالي;أعني لن نذهب إلى هناك على أي حال ؟ C# كود المصدر لهذا الأسلوب هو سطر واحد فقط ، والتي ترجع نتيجة الأسلوب.

هل كانت مفيدة؟

المحلول

إذا قمت بفتح هذه الوظيفة في المصحح ، مع رمز جمعت في وضع التصحيح:

bool foo(string arg)
{
    return bar(arg);
}

هناك 3 نقاط لكسر يمكنك تعيين:

  1. في افتتاح هدفين من وظيفة.
  2. على "عودة" الخط.
  3. في ختام هدفين من وظيفة.

تعيين نقطة فاصل على افتتاح هدفين يعني "كسر عند هذه الوظيفة الحصول على ما يسمى".لهذا السبب هناك عدم المرجع التعليمات في بداية الطريقة.عند تعيين نقطة توقف في افتتاح هدفين المصحح في الواقع مجموعات على أي المرجع.

تعيين نقطة فاصل على قوس الإغلاق يعني "كسر عندما يخرج هذه الوظيفة".من أجل أن يحصل على وظيفة يحتاج إلى العودة التعليمات في IL, حيث كسر نقطة يمكن تعيين.المترجم يمكن ذلك باستخدام متغير مؤقت لتخزين قيمة الإرجاع, وتحويل

return retVal;

في

$retTmp = retVal;
goto exit;

ثم حقن التعليمات البرمجية التالية في الجزء السفلي من طريقة:

exit:
return $ret;

أيضا, عندما تكون في وضع التصحيح ، المجمعين أغبياء حول رمز أنهم جيل.أنها في الأساس لا شيء من هذا القبيل:

GenerateProlog();
foreach (var statement in statements)
{
    Generate(statement);
}
GenerateEpilog();

في حال كنت ترى:

return foo(arg);

التي ترجمت إلى:

; //this is a no-op
bool retTemp = false;
retTemp = foo(arg);
goto exit;
exit:
return retTemp;

إذا كان المترجم كان يفعل "انزلاق نافذة الأمثل" قد تكون قادرة على إلقاء نظرة على هذا الرمز و أدرك أن هناك بعض redundency.ومع ذلك ، المجمعين عموما لا تفعل ذلك في وضع التصحيح.مترجم تحسينات يمكن أن تفعل أشياء مثل القضاء على المتغيرات ، وإعادة ترتيب التعليمات ، مما يجعل من الصعب تصحيح الأخطاء.لأن الغرض من بناء التصحيح هو تمكين التصحيح ، فإنه لن يكون من الجيد أن تتحول على التحسينات.

في بيان بناء رمز لا تبدو مثل هذا.ذلك لأن المترجم لا إدخال رمز خاص لتمكين نقاط على فتح و إغلاق الأقواس ، مما يترك التالية التي سيتم تجميعها:

return bar(arg);

أن ينتهي يبحث بسيطة جدا.

شيء واحد أن نلاحظ ذلك هو أنني لا أعتقد C# compiler يقوم الكثير من انزلاق نافذة التحسينات ، حتى في التجزئة يبني.هذا لأن معظم هذه التحسينات تعتمد على المعالج الأساسي العمارة حتى تتم بواسطة برنامج التحويل البرمجي JIT.القيام التحسينات ، حتى تلك التي هي المعالج الملحد في C# compiler يمكن أن تعوق جيت على تحسين رمز (انها تبحث عن الأنماط التي يتم إنشاؤها من قبل غير رمز الأمثل الجيل ، إذا كان يرى الأمثل بشكل كبير IL أنه يمكن الحصول على الخلط).لذلك عادة أشبال رمز المجمعين لا تفعل لهم.يفعل بعض "أشياء باهظة الثمن" (التي JIT لا تريد أن تفعل في وقت التشغيل) مثل رمز ميت الكشف والعيش متغير تحليل لكنها لا تعالج المشاكل تحل عن طريق تحريك نافذة الأمثل.

نصائح أخرى

هل تجميع في التصحيح أو الإفراج الوضع؟ في وضع إطلاق أحصل على:

.method private hidebysig static bool Test1(string arg) cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: call bool FuncNameNotImportant::MethodNameNotImportant(string)
    L_0006: ret 
}

ووالمتفرعة ترونه على الأرجح للحصول على الدعم المصحح.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top