Ejemplo n.º 1
0
        private void ProcessIlEmitMethodCall(Instruction emitCallInstruction, out Instruction?nextInstruction)
        {
            var emittedInstruction = CreateInstructionToEmit();

            _il.Replace(emitCallInstruction, emittedInstruction);

            if (emittedInstruction.OpCode.OpCodeType == OpCodeType.Prefix)
            {
                _il.RemoveNopsAfter(emittedInstruction);
            }

            var sequencePoint = _sequencePoints.MapSequencePoint(emitCallInstruction, emittedInstruction);

            if (emittedInstruction.Previous?.OpCode.OpCodeType == OpCodeType.Prefix)
            {
                _sequencePoints.MergeWithPreviousSequencePoint(sequencePoint);
            }

            nextInstruction = emittedInstruction.NextSkipNops();

            switch (emittedInstruction.OpCode.Code)
            {
            case Code.Ret:
            case Code.Endfinally:
            case Code.Endfilter:
            {
                if (nextInstruction?.OpCode == emittedInstruction.OpCode)
                {
                    _il.Remove(emittedInstruction);
                    _log.Debug($"Removed duplicate {emittedInstruction.OpCode}");
                }

                break;
            }

            case Code.Leave:
            case Code.Leave_S:
            case Code.Throw:
            case Code.Rethrow:
            {
                if (nextInstruction?.OpCode == OpCodes.Leave || nextInstruction?.OpCode == OpCodes.Leave_S)
                {
                    _il.RemoveNopsAfter(emittedInstruction);
                    _il.Remove(emittedInstruction);
                    _il.Replace(nextInstruction, emittedInstruction);
                    _log.Debug($"Replaced {nextInstruction.OpCode} with emitted {emittedInstruction.OpCode}");
                    nextInstruction = emittedInstruction.NextSkipNops();
                }

                break;
            }
            }

            Instruction CreateInstructionToEmit()
            {
                var method = (MethodReference)emitCallInstruction.Operand;
                var opCode = OpCodeMap.FromCecilFieldName(method.Name);
                var args   = _il.GetArgumentPushInstructionsInSameBasicBlock(emitCallInstruction);

                switch (opCode.OperandType)
                {
                case OperandType.InlineNone:
                    if (args.Length != 0)
                    {
                        throw new InstructionWeavingException(emitCallInstruction, "Unexpected operand argument");
                    }

                    return(_il.Create(opCode));

                case OperandType.InlineI:
                case OperandType.ShortInlineI:
                case OperandType.InlineI8:
                case OperandType.InlineR:
                case OperandType.ShortInlineR:
                    return(_il.CreateConst(opCode, _consumer.ConsumeArgConst(args.Single())));

                case OperandType.InlineString:
                    return(_il.CreateConst(opCode, _consumer.ConsumeArgString(args.Single())));

                case OperandType.InlineType:
                {
                    if (method.IsGenericInstance)
                    {
                        return(_il.Create(opCode, ((GenericInstanceMethod)method).GenericArguments[0]));
                    }

                    return(_il.Create(opCode, _consumer.ConsumeArgTypeRef(args.Single())));
                }

                case OperandType.InlineMethod:
                    return(_il.Create(opCode, _consumer.ConsumeArgMethodRef(args.Single())));

                case OperandType.InlineField:
                    return(_il.Create(opCode, _consumer.ConsumeArgFieldRef(args.Single())));

                case OperandType.InlineTok:
                {
                    if (method.IsGenericInstance)
                    {
                        return(_il.Create(opCode, ((GenericInstanceMethod)method).GenericArguments[0]));
                    }

                    return(method.Parameters[0].ParameterType.FullName switch
                        {
                            KnownNames.Full.TypeRefType => _il.Create(opCode, _consumer.ConsumeArgTypeRef(args.Single())),
                            KnownNames.Full.MethodRefType => _il.Create(opCode, _consumer.ConsumeArgMethodRef(args.Single())),
                            KnownNames.Full.FieldRefType => _il.Create(opCode, _consumer.ConsumeArgFieldRef(args.Single())),
                            _ => throw new InstructionWeavingException(emitCallInstruction, $"Unexpected argument type: {method.Parameters[0].ParameterType.FullName}")
                        });
                }
Ejemplo n.º 2
0
        private TypeRefBuilder ConsumeArgTypeRefBuilder(Instruction instruction)
        {
            if (instruction.OpCode.FlowControl != FlowControl.Call || !(instruction.Operand is MethodReference method))
            {
                throw UnexpectedInstruction(instruction, "a method call");
            }

            switch (method.FullName)
            {
            case "System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)":
            {
                var ldToken = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction).Single();
                if (ldToken.OpCode != OpCodes.Ldtoken)
                {
                    throw UnexpectedInstruction(ldToken, OpCodes.Ldtoken);
                }

                var builder = new TypeRefBuilder(Module, (TypeReference)ldToken.Operand);

                _il.Remove(ldToken);
                _il.Remove(instruction);
                return(builder);
            }

            case "InlineIL.TypeRef InlineIL.TypeRef::op_Implicit(System.Type)":
            case "System.Void InlineIL.TypeRef::.ctor(System.Type)":
            {
                var builder = ConsumeArgTypeRefBuilder(_il.GetArgumentPushInstructionsInSameBasicBlock(instruction).Single());

                _il.Remove(instruction);
                return(builder);
            }

            case "System.Void InlineIL.TypeRef::.ctor(System.String,System.String)":
            {
                var args         = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction);
                var assemblyName = ConsumeArgString(args[0]);
                var typeName     = ConsumeArgString(args[1]);
                var builder      = new TypeRefBuilder(Module, assemblyName, typeName);

                _il.Remove(instruction);
                return(builder);
            }

            case "InlineIL.TypeRef InlineIL.GenericParameters::get_Item(System.Int32)":
            {
                var args = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction);
                var genericParameterType  = ConsumeArgGenericParameterType(args[0]);
                var genericParameterIndex = ConsumeArgInt32(args[1]);
                var builder = new TypeRefBuilder(Module, genericParameterType, genericParameterIndex);

                _il.Remove(instruction);
                return(builder);
            }

            case "System.Type System.Type::MakeGenericMethodParameter(System.Int32)":
            {
                var args = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction);
                var genericParameterIndex = ConsumeArgInt32(args[0]);
                var builder = new TypeRefBuilder(Module, GenericParameterType.Method, genericParameterIndex);

                _il.Remove(instruction);
                return(builder);
            }

            case "InlineIL.TypeRef InlineIL.TypeRef::MakePointerType()":
            case "System.Type System.Type::MakePointerType()":
            {
                var builder = ConsumeArgTypeRefBuilder(_il.GetArgumentPushInstructionsInSameBasicBlock(instruction).Single());
                builder.MakePointerType();

                _il.Remove(instruction);
                return(builder);
            }

            case "InlineIL.TypeRef InlineIL.TypeRef::MakeByRefType()":
            case "System.Type System.Type::MakeByRefType()":
            {
                var builder = ConsumeArgTypeRefBuilder(_il.GetArgumentPushInstructionsInSameBasicBlock(instruction).Single());
                builder.MakeByRefType();

                _il.Remove(instruction);
                return(builder);
            }

            case "InlineIL.TypeRef InlineIL.TypeRef::MakeArrayType()":
            case "System.Type System.Type::MakeArrayType()":
            {
                var builder = ConsumeArgTypeRefBuilder(_il.GetArgumentPushInstructionsInSameBasicBlock(instruction).Single());
                builder.MakeArrayType(1);

                _il.Remove(instruction);
                return(builder);
            }

            case "InlineIL.TypeRef InlineIL.TypeRef::MakeArrayType(System.Int32)":
            case "System.Type System.Type::MakeArrayType(System.Int32)":
            {
                var args    = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction);
                var builder = ConsumeArgTypeRefBuilder(args[0]);
                var rank    = ConsumeArgInt32(args[1]);
                builder.MakeArrayType(rank);

                _il.Remove(instruction);
                return(builder);
            }

            case "InlineIL.TypeRef InlineIL.TypeRef::MakeGenericType(InlineIL.TypeRef[])":
            case "System.Type System.Type::MakeGenericType(System.Type[])":
            {
                var args        = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction);
                var builder     = ConsumeArgTypeRefBuilder(args[0]);
                var genericArgs = ConsumeArgArray(args[1], ConsumeArgTypeRefBuilder);
                builder.MakeGenericType(genericArgs);

                _il.Remove(instruction);
                return(builder);
            }

            case "InlineIL.TypeRef InlineIL.TypeRef::WithOptionalModifier(InlineIL.TypeRef)":
            {
                var args         = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction);
                var builder      = ConsumeArgTypeRefBuilder(args[0]);
                var modifierType = ConsumeArgTypeRef(args[1]);
                builder.AddOptionalModifier(modifierType);

                _il.Remove(instruction);
                return(builder);
            }

            case "InlineIL.TypeRef InlineIL.TypeRef::WithRequiredModifier(InlineIL.TypeRef)":
            {
                var args         = _il.GetArgumentPushInstructionsInSameBasicBlock(instruction);
                var builder      = ConsumeArgTypeRefBuilder(args[0]);
                var modifierType = ConsumeArgTypeRef(args[1]);
                builder.AddRequiredModifier(modifierType);

                _il.Remove(instruction);
                return(builder);
            }

            default:
                throw UnexpectedInstruction(instruction, "a type reference");
            }
        }