I'm looking for all assignments to a specific fields and replace them by a 
call to a generated method passing the field by ref. The problem is that 
existing short form instructions can be invalidated because now distance 
between the instruction and its target can be too long for short form. It's 
just an example, I believe any modification that makes byte code bigger can 
lead to this problem. 

The solution is to change short-form to long-form. It's not so simple is 
easier to resolve this problem in generic way. So I modified Cecil code 
writing. Please check it and point to any problems. Please fill free to 
incorporate it in Cecil (with any modification) if you think it's useful.

Two new methods of CodeWriter are:

bool CorrectInstructions()
{
    var instructions = body.Instructions;
    var items = instructions.items;
    var size = instructions.size;

    var anythingChanged = false;
    for (int i = 0; i < size; i++)
    {
        var instruction = items[i];
        anythingChanged |= CorrectInstructionShortForm(instruction);
    }

    return anythingChanged;
}

bool CorrectInstructionShortForm(Instruction instruction)
{
    var opcode = instruction.OpCode;
    var operand = instruction.operand;
    switch (opcode.OperandType)
    {
        case OperandType.ShortInlineBrTarget:
            var target = (Instruction)instruction.operand;
            var offset = target.Offset - (instruction.Offset + opcode.Size + 
1);
            if (offset > sbyte.MaxValue)
            {
                if (opcode != OpCodes.Leave_S)
                {
                    const int diff = Code.Br - Code.Br_S;
                    instruction.OpCode = new OpCode(opcode.Op1 << 0 | (
opcode.Op2 + diff) << 8 | ((byte)opcode.Code + diff) << 16 | (byte)opcode.
FlowControl << 24,
                        (byte)OpCodeType.Macro << 0 | (byte)OperandType.
InlineBrTarget << 8 | (byte)opcode.StackBehaviourPop << 16 | (byte)opcode.
StackBehaviourPush << 24);
                }
                else
                {
                    instruction.OpCode = new OpCode(opcode.Op1 << 0 | (
opcode.Op2 - 1) << 8 | ((byte)opcode.Code - 1) << 16 | (byte)opcode.
FlowControl << 24,
                        (byte)OpCodeType.Primitive << 0 | (byte)OperandType.
InlineBrTarget << 8 | (byte)opcode.StackBehaviourPop << 16 | (byte)opcode.
StackBehaviourPush << 24);
                }
            }
            return true;
        case OperandType.ShortInlineVar:
            if (GetVariableIndex((VariableDefinition)operand) > byte.
MaxValue)
            {
                var op2Diff = OpCodes.Ldloc.Op2 - OpCodes.Ldloc_S.Op2;
                const int codeDiff = Code.Ldloc - Code.Ldloc_S;
                instruction.OpCode = new OpCode(0xfe << 0 | (opcode.Op2 + 
op2Diff) << 8 | ((byte)opcode.Code + codeDiff) << 16 | (byte)opcode.
FlowControl << 24,
                    (byte)OpCodeType.Primitive << 0 | (byte)OperandType.
InlineVar << 8 | (byte)opcode.StackBehaviourPop << 16 | (byte)opcode.
StackBehaviourPush << 24);
            }
            return true;
        case OperandType.ShortInlineArg:
            if (GetParameterIndex((ParameterDefinition)operand) > byte.
MaxValue)
            {
                var op2Diff = OpCodes.Ldloc.Op2 - OpCodes.Ldloc_S.Op2;
                const int codeDiff = Code.Ldloc - Code.Ldloc_S;
                instruction.OpCode = new OpCode(0xfe << 0 | (opcode.Op2 + 
op2Diff) << 8 | ((byte)opcode.Code + codeDiff) << 16 | (byte)opcode.
FlowControl << 24,
                    (byte)OpCodeType.Primitive << 0 | (byte)OperandType.
InlineArg << 8 | (byte)opcode.StackBehaviourPop << 16 | (byte)opcode.
StackBehaviourPush << 24);
            }
            return true;
        default:
            return false;
    }
}


and the usage is:

void WriteResolvedMethodBody (MethodDefinition method)
{
    body = method.Body;
    ComputeHeader ();
    if (CorrectInstructions ())
        ComputeHeader ();
    if (RequiresFatHeader ())
        WriteFatHeader ();
    else
        WriteByte ((byte) (0x2 | (body.CodeSize << 2))); // tiny

    WriteInstructions ();

    if (body.HasExceptionHandlers)
        WriteExceptionHandlers ();

    var symbol_writer = metadata.symbol_writer;
    if (symbol_writer != null)
        symbol_writer.Write (body);
}



Cheers,
Andriy

-- 
-- 
--
mono-cecil
--- 
You received this message because you are subscribed to the Google Groups 
"mono-cecil" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to