Search code examples
c#dynamicil

Dynamic Method, store return value in local


I am encountering some issues with a dynamic method. The (pseudo-)IL-Code for this method looks like this

var localB = dynMethodGen.DeclareLocal(typeof(Runtime.IntegerObject));
dynMethodGen.Emit(Ldc_I8, 2);
dynMethodGen.Emit(Newobj, Runtime.IntegerObject.Constructor);
dynMethodGen.Emit(ldstr, "a");
dynMethodGen.Emit(call, GlobalDeclaratorManager.SetMethod);
dynMethodGen.Emit(ldstr, "a");
dynMethodGen.Emit(call, GlobalDeclaratorManager.GetMethod);
dynMethodGen.Emit(Stloc, localB);

With this code i have the following problem: The final Stloc causes an exception: System.Security.VerificationException: Dieser Vorgang kann die Laufzeit destabilisieren. (In english it means the runtime could be destabilized).

I had this before when the stack was not correct but in this case the stack is correct. Replacing the Stloc in the end by a simple Pop everything works fine, except that the value is not stored in the locale.

The Get and Set methods look like that:

        public static GenericObject getGlobal(string name)
        {
            return mDeclarators[name];
        }

        public static void setGlobal(GenericObject value, string name)
        {
            mDeclarators[name] = value;
        }

What also works is replacing the Stloc with another call to SetMethod, the values are correctly passed along.

Am I missing some sort of restriction? Cant i store the return value of a function in a locale?


Solution

  • What you're trying to do is

    setGlobal(new IntegerObject(2), "a");
    
    IntegerObject localB = getGlobal("a");
    

    where getGlobal is declared to return a GenericObject instance.

    You can't store the reference to a GenericObject instance in an IntegerObject variable unless the GenericObject class extends the IntegerObject class. The C# compiler would give you the following error message:

    Cannot implicitly convert type 'GenericObject' to 'IntegerObject'

    Assuming IntegerObject extends GenericObject, the solution is to add a cast like

    IntegerObject localB = (IntegerObject)getGlobal("a");
    

    or

    IntegerObject localB = getGlobal("a") as IntegerObject;