public void VisitInstructionExpression(CilInstructionExpression expression) { if (expression.Instructions.Count == 1 && IsArrayMemberAccess(expression.Instructions[0], out var method)) { var arrayExpr = expression.Arguments[0]; if (arrayExpr.ExpressionType is SzArrayTypeSignature arrayType) { if (IsArrayGetLength(method)) { ReplaceWithLdlen(expression, arrayType); } else if (IsArrayGetValue(method)) { ReplaceWithLdelem(expression, arrayType); } else if (IsArraySetValue(method)) { ReplaceWithStelem(expression, arrayType); } else if (IsArrayAddress(method)) { ReplaceWithLdelema(expression, arrayType); } } } foreach (var argument in expression.Arguments.ToArray()) { argument.AcceptVisitor(this); } }
public CilExpression Translate(RecompilerContext context, ILVCallExpression expression) { var annotation = (LdftnAnnotation)expression.Annotation; ICallableMemberReference method; if (!annotation.IsIntraLinked) { method = annotation.Method; } else { method = context.ExportResolver.ResolveMethod(annotation.Function.EntrypointAddress); if (method == null) { throw new RecompilerException( $"Could not resolve function_{annotation.Function.EntrypointAddress:X4} to a physical method."); } } var result = new CilInstructionExpression(CilOpCodes.Ldftn, method) { ExpressionType = context.TargetImage.TypeSystem.IntPtr }; return(result); }
public CilExpression Translate(RecompilerContext context, ILVCallExpression expression) { var annotation = (LdftnAnnotation)expression.Annotation; IMethodDescriptor method; if (!annotation.IsIntraLinked) { method = annotation.Method; } else { method = context.ExportResolver.ResolveMethod(annotation.Function.EntrypointAddress); if (method == null) { throw new RecompilerException( $"Could not resolve function_{annotation.Function.EntrypointAddress:X4} to a physical method."); } } var result = new CilInstructionExpression(CilOpCodes.Ldftn, method) { ExpressionType = context.TargetModule.CorLibTypeFactory.IntPtr }; if (annotation.IsVirtual) { var callingObject = (CilExpression)expression.Arguments[expression.Arguments.Count - 1] .AcceptVisitor(context.Recompiler); result.Instructions[0].OpCode = CilOpCodes.Ldvirtftn; result.Arguments.Add(callingObject); } return(result); }
public virtual bool VisitInstructionExpression(CilInstructionExpression expression) { bool changed = false; foreach (var argument in expression.Arguments.ToArray()) { changed |= argument.AcceptVisitor(this); } return(changed); }
public CilExpression Translate(RecompilerContext context, ILVCallExpression expression) { var metadata = (FieldAnnotation)expression.Annotation; // Enter generic context for member. context.EnterMember(metadata.Field); var fieldDef = metadata.Field.Resolve(); bool hasThis = !fieldDef?.IsStatic ?? metadata.Field.Signature.HasThis; // Select opcode and expression type. var expressionType = metadata.Field.Signature.FieldType; CilOpCode opCode; if (metadata.IsAddress) { expressionType = new ByReferenceTypeSignature(expressionType); opCode = hasThis ? CilOpCodes.Ldflda : CilOpCodes.Ldsflda; } else { opCode = hasThis ? CilOpCodes.Ldfld : CilOpCodes.Ldsfld; } // Construct CIL expression. var result = new CilInstructionExpression(opCode, metadata.Field) { ExpressionType = expressionType.InstantiateGenericTypes(context.GenericContext) }; if (hasThis) { // Recompile object expression if field is an instance field. var objectExpression = (CilExpression)expression.Arguments[expression.Arguments.Count - 1] .AcceptVisitor(context.Recompiler); var objectType = metadata.Field.DeclaringType .ToTypeSignature() .InstantiateGenericTypes(context.GenericContext); if (metadata.IsAddress) { objectType = new ByReferenceTypeSignature(objectType); } objectExpression.ExpectedType = objectType; result.Arguments.Add(objectExpression); } // Leave generic context. context.ExitMember(); return(result); }
public CilExpression Translate(RecompilerContext context, ILVCallExpression expression) { var annotation = (ThrowAnnotation)expression.Annotation; var argument = (CilExpression)expression.Arguments[2].AcceptVisitor(context.Recompiler); argument.ExpectedType = context.ReferenceImporter.ImportType(typeof(Exception)); var result = new CilInstructionExpression(annotation.IsRethrow ? CilOpCodes.Rethrow : CilOpCodes.Throw, null, argument); return(result); }
private void ReplaceWithLdlen(CilInstructionExpression expression, SzArrayTypeSignature arrayType) { var arrayExpr = expression.Arguments[0]; arrayExpr.ExpectedType = arrayType; var arrayLengthExpr = new CilInstructionExpression(CilOpCodes.Ldlen, null, (CilExpression)arrayExpr.Remove()) { ExpressionType = _context.TargetModule.CorLibTypeFactory.Int32 }; expression.ReplaceWith(arrayLengthExpr); }
public override bool VisitInstructionExpression(CilInstructionExpression expression) { if (expression.Instructions.Count == 1 && expression.Instructions[0].OpCode.Code == CilCode.Unbox_Any && IsBoxExpression(expression.Arguments[0], out var argument, out var boxedType) && expression.Instructions[0].Operand is ITypeDefOrRef type && type.FullName == boxedType.FullName) { argument.ExpectedType = expression.ExpectedType; expression.ReplaceWith(argument.Remove()); } return(base.VisitInstructionExpression(expression)); }
private void ReplaceWithLdlen(CilInstructionExpression expression, SzArrayTypeSignature arrayType) { var arrayExpr = expression.Arguments[0]; arrayExpr.ExpectedType = arrayType; var arrayLoadExpr = new CilInstructionExpression(CilOpCodes.Ldlen, null, (CilExpression)arrayExpr.Remove()) { ExpressionType = arrayType.BaseType }; expression.ReplaceWith(arrayLoadExpr); }
public virtual CilExpression Translate(RecompilerContext context, ILInstructionExpression expression) { if (!SupportedOpCodes.Contains(expression.OpCode.Code)) { throw new NotSupportedException(); } var result = new CilInstructionExpression(); // Copy instructions foreach (var instruction in NewInstructions) { result.Instructions.Add(new CilInstruction(0, instruction.OpCode, instruction.Operand)); } // Create arguments for (var i = 0; i < expression.Arguments.Count; i++) { // Convert argument. var argument = expression.Arguments[i]; var cilArgument = (CilExpression)argument.AcceptVisitor(context.Recompiler); // Check type. cilArgument.ExpectedType = expression.OpCode.StackBehaviourPop .GetArgumentType(i) .ToMetadataType(context.TargetImage); // Convert if necessary, and add to argument list. result.Arguments.Add(cilArgument); } // Determine expression type from opcode. if (expression.OpCode.StackBehaviourPush != ILStackBehaviour.None) { result.ExpressionType = expression.OpCode.StackBehaviourPush .GetResultType() .ToMetadataType(context.TargetImage); } result.ShouldEmitFlagsUpdate = expression.IsFlagDataSource; if (expression.IsFlagDataSource) { result.AffectedFlags = expression.OpCode.AffectedFlags; result.InvertedFlagsUpdate = InvertedFlagsUpdate; } return(result); }
public CilExpression Translate(RecompilerContext context, ILVCallExpression expression) { var metadata = (FieldAnnotation)expression.Annotation; var fieldType = metadata.Field.Signature.FieldType; // Enter generic context. context.EnterMember(metadata.Field); var fieldDef = metadata.Field.Resolve(); bool hasThis = !fieldDef?.IsStatic ?? metadata.Field.Signature.HasThis; // Construct CIL expression. var result = new CilInstructionExpression(hasThis ? CilOpCodes.Stfld : CilOpCodes.Stsfld, metadata.Field); if (hasThis) { // Recompile object expression if field is an instance field. var objectExpression = (CilExpression)expression.Arguments[expression.Arguments.Count - 2] .AcceptVisitor(context.Recompiler); var objectType = metadata.Field.DeclaringType .ToTypeSignature() .InstantiateGenericTypes(context.GenericContext); // Struct members can only be accessed when the object is passed on by reference. if (metadata.Field.DeclaringType.IsValueType) { objectType = new ByReferenceTypeSignature(objectType); } objectExpression.ExpectedType = objectType; result.Arguments.Add(objectExpression); } // Recompile value. var valueExpression = (CilExpression)expression.Arguments[expression.Arguments.Count - 1] .AcceptVisitor(context.Recompiler); valueExpression.ExpectedType = fieldType.InstantiateGenericTypes(context.GenericContext); result.Arguments.Add(valueExpression); // Exit generic context. context.ExitMember(); return(result); }
public IList <CilInstruction> VisitInstructionExpression(CilInstructionExpression expression) { var result = new List <CilInstruction>(); // Sanity check for expression validity. ValidateExpression(expression); // Decide whether to emit FL updates or not. if (expression.ShouldEmitFlagsUpdate) { var first = expression.Arguments[0]; switch (expression.Arguments.Count) { case 1: result.AddRange(_context.BuildFlagAffectingExpression32( first.AcceptVisitor(this), expression.Instructions, _context.Constants.GetFlagMask(expression.AffectedFlags), expression.ExpressionType != null)); break; case 2: var second = expression.Arguments[1]; result.AddRange(_context.BuildFlagAffectingExpression32( first.AcceptVisitor(this), second.AcceptVisitor(this), expression.Instructions, _context.Constants.GetFlagMask(expression.AffectedFlags), expression.InvertedFlagsUpdate, expression.ExpressionType != null)); break; } } else { foreach (var argument in expression.Arguments) { result.AddRange(argument.AcceptVisitor(this)); } result.AddRange(expression.Instructions); } return(result); }
public CilExpression Translate(RecompilerContext context, ILVCallExpression expression) { var annotation = (TypeAnnotation)expression.Annotation; var argument = (CilExpression)expression.Arguments[expression.Arguments.Count - 1] .AcceptVisitor(context.Recompiler); argument.ExpectedType = new ByReferenceTypeSignature( context.ReferenceImporter.ImportTypeSignature(annotation.Type.ToTypeSignature())); var result = new CilInstructionExpression(CilOpCodes.Initobj, annotation.Type, argument) { ExpressionType = null }; return(result); }
public CilExpression Translate(RecompilerContext context, ILInstructionExpression expression) { var callMetadata = (CallAnnotation)expression.Annotation; // Convert entrypoint address to physical method def. var method = context.ExportResolver.ResolveMethod(callMetadata.Function.EntrypointAddress); var methodSig = ((MethodSignature)method.Signature); // Create call instruction. CilExpression result = new CilInstructionExpression(CilOpCodes.Call, method, context.RecompileCallArguments(method, expression.Arguments.Skip(1).ToArray(), VMECallOpCode.CALL)) { ExpressionType = methodSig.ReturnType }; // Make sure the resulting object is converted to an unsigned integer if necessary. return(result); }
private void ReplaceWithLdelema(CilInstructionExpression expression, SzArrayTypeSignature arrayType) { var arrayExpr = expression.Arguments[0]; var indexExpr = expression.Arguments[1]; arrayExpr.ExpectedType = arrayType; var elementTypeRef = _context.ReferenceImporter .ImportType(arrayType.BaseType.ToTypeDefOrRef()); var arrayLoadExpr = new CilInstructionExpression(CilOpCodes.Ldelema, elementTypeRef, (CilExpression)arrayExpr.Remove(), (CilExpression)indexExpr.Remove()) { ExpressionType = new ByReferenceTypeSignature(arrayType.BaseType) }; expression.ReplaceWith(arrayLoadExpr); }
private void ValidateExpression(CilInstructionExpression expression) { int stackSize = expression.Arguments.Count; foreach (var instruction in expression.Instructions) { stackSize += instruction.GetStackPopCount(_context.MethodBody); if (stackSize < 0) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Insufficient arguments are pushed onto the stack'{expression.AcceptVisitor(_formatter)}'.")); } stackSize += instruction.GetStackPushCount(_context.MethodBody); ValidateInstruction(expression, instruction); } }
private static unsafe bool TryOptimizeLdcI(CilInstructionExpression expression) { if (expression.Instructions.Count != 1 || expression.ExpectedType == null) { return(false); } var instruction = expression.Instructions[0]; if (instruction.IsLdcI4()) { int i4Value = instruction.GetLdcI4Constant(); if (!expression.ExpectedType.IsValueType) { if (i4Value == 0) { // If ldc.i4.0 and expected type is a ref type, the ldc.i4.0 pushes null. We can therefore // optimize to ldnull. ReplaceWithSingleInstruction(expression, new CilInstruction(CilOpCodes.Ldnull)); return(true); } } else if (expression.ExpectedType.IsTypeOf("System", "Single")) { // KoiVM pushes floats using the pushi_dword instruction. Convert to ldc.r4 if a float is expected // but an ldc.i4 instruction is pushing the value. float actualValue = *(float *)&i4Value; ReplaceWithSingleInstruction(expression, new CilInstruction(CilOpCodes.Ldc_R4, actualValue)); return(true); } } else if (instruction.OpCode.Code == CilCode.Ldc_I8 && expression.ExpectedType.IsTypeOf("System", "Double")) { // KoiVM pushes doubles using the pushi_qword instruction. Convert to ldc.r8 if a double is expected // but an ldc.i8 instruction is pushing the value. long i8Value = (long)instruction.Operand; double actualValue = *(double *)&i8Value; ReplaceWithSingleInstruction(expression, new CilInstruction(CilOpCodes.Ldc_R8, actualValue)); return(true); } return(false); }
public override bool VisitInstructionExpression(CilInstructionExpression expression) { // KoiVM emits pushi_dword or pushi_qwords not only for pushing integers, but also for pushing null or // floating point numbers as well. if (TryOptimizeLdcI(expression)) { return(true); } // Insert conversions in all arguments. bool changed = base.VisitInstructionExpression(expression); // Ensure type safety for all processed arguments. foreach (var argument in expression.Arguments.ToArray()) { changed = EnsureTypeSafety(argument); } return(changed); }
public override bool VisitInstructionExpression(CilInstructionExpression expression) { if (expression.Instructions.Count == 1 && expression.Instructions[0].IsLdcI4 && expression.Instructions[0].GetLdcValue() == 0 && expression.ExpectedType != null && !expression.ExpectedType.IsValueType) { expression.Instructions.Clear(); expression.Instructions.Add(CilInstruction.Create(CilOpCodes.Ldnull)); expression.ExpressionType = expression.ExpectedType; return(true); } bool changed = base.VisitInstructionExpression(expression); foreach (var argument in expression.Arguments.ToArray()) { changed = EnsureTypeSafety(argument); } return(changed); }
private void ReplaceWithLdelem(CilInstructionExpression expression, SzArrayTypeSignature arrayType) { var arrayExpr = expression.Arguments[0]; var indexExpr = expression.Arguments[1]; arrayExpr.ExpectedType = arrayType; var elementTypeRef = _context.ReferenceImporter .ImportType(arrayType.BaseType.ToTypeDefOrRef()); // Select appropriate opcode. CilOpCode opCode; object operand = null; switch (arrayType.BaseType.ElementType) { case ElementType.I1: opCode = CilOpCodes.Ldelem_I1; break; case ElementType.U1: opCode = CilOpCodes.Ldelem_U1; break; case ElementType.I2: opCode = CilOpCodes.Ldelem_I2; break; case ElementType.Char: case ElementType.U2: opCode = CilOpCodes.Ldelem_U2; break; case ElementType.Boolean: case ElementType.I4: opCode = CilOpCodes.Ldelem_I4; break; case ElementType.U4: opCode = CilOpCodes.Ldelem_U4; break; case ElementType.I8: case ElementType.U8: opCode = CilOpCodes.Ldelem_I8; break; case ElementType.R4: opCode = CilOpCodes.Ldelem_R4; break; case ElementType.R8: opCode = CilOpCodes.Ldelem_R8; break; case ElementType.I: case ElementType.U: opCode = CilOpCodes.Ldelem_I; break; case ElementType.ValueType: opCode = CilOpCodes.Ldelem; operand = elementTypeRef; break; default: opCode = CilOpCodes.Ldelem_Ref; break; } // Create the ldelem expression var arrayLoadExpr = new CilInstructionExpression(opCode, operand, (CilExpression)arrayExpr.Remove(), (CilExpression)indexExpr.Remove()) { ExpressionType = arrayType.BaseType }; if (arrayType.BaseType.IsValueType) { // Array.GetValue boxes value typed values. arrayLoadExpr = new CilInstructionExpression(CilOpCodes.Box, elementTypeRef, arrayLoadExpr) { ExpectedType = expression.ExpectedType, ExpressionType = expression.ExpressionType }; } expression.ReplaceWith(arrayLoadExpr); }
private void ValidateInstruction(CilInstructionExpression expression, CilInstruction instruction) { switch (instruction.OpCode.OperandType) { case CilOperandType.ShortInlineBrTarget: case CilOperandType.InlineBrTarget: if (!(instruction.Operand is CilInstruction)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected a branch target operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.InlineMethod: case CilOperandType.InlineField: case CilOperandType.InlineType: case CilOperandType.InlineTok: if (!(instruction.Operand is IMemberReference)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected a member reference operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.InlineSig: if (!(instruction.Operand is StandAloneSignature)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected a signature operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.InlineI: if (!(instruction.Operand is int)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected an int32 operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.InlineI8: if (!(instruction.Operand is long)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected an int64 operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.InlineNone: if (instruction.Operand != null) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Unexpected operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.InlineR: if (!(instruction.Operand is double)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected a float64 operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.ShortInlineI: if (!(instruction.Operand is sbyte)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected an int8 operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.ShortInlineR: if (!(instruction.Operand is float)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected a float32 operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.InlineString: if (!(instruction.Operand is string)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected a string operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.InlineSwitch: if (!(instruction.Operand is IList <CilInstruction>)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected a switch table operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.ShortInlineVar: case CilOperandType.InlineVar: if (!(instruction.Operand is VariableSignature)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected a variable operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; case CilOperandType.InlineArgument: case CilOperandType.ShortInlineArgument: if (!(instruction.Operand is ParameterSignature)) { throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Expected a parameter operand in '{expression.AcceptVisitor(_formatter)}'.")); } break; default: throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException( $"Unexpected opcode in '{expression.AcceptVisitor(_formatter)}'.")); } }
private void ReplaceWithStelem(CilInstructionExpression expression, SzArrayTypeSignature arrayType) { var arrayExpr = expression.Arguments[0]; var valueExpr = expression.Arguments[1]; var indexExpr = expression.Arguments[2]; arrayExpr.ExpectedType = arrayType; // Select appropriate opcode. CilOpCode opCode; object operand = null; switch (arrayType.BaseType.ElementType) { case ElementType.I1: case ElementType.U1: opCode = CilOpCodes.Stelem_I1; break; case ElementType.Char: case ElementType.I2: case ElementType.U2: opCode = CilOpCodes.Stelem_I2; break; case ElementType.Boolean: case ElementType.I4: case ElementType.U4: opCode = CilOpCodes.Stelem_I4; break; case ElementType.I8: case ElementType.U8: opCode = CilOpCodes.Stelem_I8; break; case ElementType.R4: opCode = CilOpCodes.Stelem_R4; break; case ElementType.R8: opCode = CilOpCodes.Stelem_R8; break; case ElementType.I: case ElementType.U: opCode = CilOpCodes.Stelem_I; break; case ElementType.ValueType: opCode = CilOpCodes.Stelem; operand = _context.ReferenceImporter .ImportType(arrayType.BaseType.ToTypeDefOrRef()); break; default: opCode = CilOpCodes.Stelem_Ref; break; } valueExpr.ExpectedType = arrayType.BaseType; var arrayStoreExpr = new CilInstructionExpression(opCode, operand, (CilExpression)arrayExpr.Remove(), (CilExpression)indexExpr.Remove(), (CilExpression)valueExpr.Remove()); expression.ReplaceWith(arrayStoreExpr); }
private static CilExpression CompileRegisterPush(RecompilerContext context, ILInstructionExpression expression) { var cilExpression = (CilExpression)expression.Arguments[0].AcceptVisitor(context.Recompiler); var resultType = expression.OpCode.StackBehaviourPush.GetResultType(); if (cilExpression is CilUnboxToVmExpression) { // HACK: Unbox expressions unbox the value from the stack, but also convert it to their unsigned // variant and box it again into an object. We need to unpack it again, however, we do not // know the actual type of the value inside the box, as this is determined at runtime. // // For now, we just make use of the Convert class provided by .NET, which works but would rather // see a true "native" CIL conversion instead. MethodBase convertMethod; switch (resultType) { case VMType.Byte: convertMethod = typeof(Convert).GetMethod("ToByte", new[] { typeof(object) }); break; case VMType.Word: convertMethod = typeof(Convert).GetMethod("ToUInt16", new[] { typeof(object) }); break; case VMType.Dword: convertMethod = typeof(Convert).GetMethod("ToUInt32", new[] { typeof(object) }); break; case VMType.Qword: convertMethod = typeof(Convert).GetMethod("ToUInt64", new[] { typeof(object) }); break; default: throw new ArgumentOutOfRangeException(); } cilExpression.ExpectedType = context.TargetImage.TypeSystem.Object; cilExpression = new CilInstructionExpression( CilOpCodes.Call, context.ReferenceImporter.ImportMethod(convertMethod), cilExpression); } if (resultType == VMType.Object) { if (cilExpression.ExpressionType.IsValueType) { if (cilExpression is CilInstructionExpression instructionExpression && instructionExpression.Instructions.Count == 1 && instructionExpression.Instructions[0].IsLdcI4 && instructionExpression.Instructions[0].GetLdcValue() == 0) { cilExpression = new CilInstructionExpression(CilOpCodes.Ldnull); } else { // If expression returns a value type, we have to box it to an object. cilExpression = new CilInstructionExpression(CilOpCodes.Box, context.ReferenceImporter.ImportType(cilExpression.ExpressionType.ToTypeDefOrRef()), cilExpression); } } else { // Use the reference type of the expression instead of System.Object. cilExpression.ExpressionType = cilExpression.ExpressionType; } }
public CilExpression Translate(RecompilerContext context, ILVCallExpression expression) { var ecall = (ECallAnnotation)expression.Annotation; var methodSig = ecall.Method.Signature; // Select calling instruction, return type and call prefix. CilInstruction prefix = null; TypeSignature resultType; CilOpCode opcode; object operand = ecall.Method; switch (ecall.OpCode) { case VMECallOpCode.CALL: opcode = CilOpCodes.Call; resultType = methodSig.ReturnType; break; case VMECallOpCode.CALLVIRT: opcode = CilOpCodes.Callvirt; resultType = methodSig.ReturnType; break; case VMECallOpCode.NEWOBJ: opcode = CilOpCodes.Newobj; resultType = ecall.Method.DeclaringType.ToTypeSignature(); // KoiVM translates "newarr ElementType" instructions to "newobj ElementType[]::.ctor(int32)". // Revert this operation if necessary: if (resultType is SzArrayTypeSignature arrayType) { opcode = CilOpCodes.Newarr; operand = context.ReferenceImporter.ImportType(arrayType.BaseType.ToTypeDefOrRef()); } break; case VMECallOpCode.CALLVIRT_CONSTRAINED: prefix = new CilInstruction(CilOpCodes.Constrained, ecall.ConstrainedType); opcode = CilOpCodes.Callvirt; resultType = methodSig.ReturnType; break; default: throw new ArgumentOutOfRangeException(); } // Enter generic context of method. context.EnterMember(ecall.Method); // Collect arguments. var arguments = expression.Arguments .Skip(ecall.IsConstrained ? 3 : 2) .ToArray(); // Build call expression. var result = new CilInstructionExpression(opcode, operand, context.RecompileCallArguments(ecall.Method, arguments, ecall.OpCode, ecall.ConstrainedType)) { ExpressionType = resultType.InstantiateGenericTypes(context.GenericContext) }; // Add prefix when necessary. if (prefix != null) { result.Instructions.Insert(0, prefix); } // Leave generic context. context.ExitMember(); return(result); }
public string VisitInstructionExpression(CilInstructionExpression expression) { return(string.Join(" - ", expression.Instructions.Select(i => i.Operand == null ? _formatter.FormatOpCode(i.OpCode) : $"{_formatter.FormatOpCode(i.OpCode)} {_formatter.FormatOperand(i.OpCode.OperandType, i.Operand)}"))); }
public CilExpression Translate(RecompilerContext context, ILVCallExpression expression) { var ecall = (ECallAnnotation)expression.Annotation; var methodSig = (MethodSignature)ecall.Method.Signature; // Select calling instruction, return type and call prefix. CilInstruction prefix = null; TypeSignature resultType; CilOpCode opcode; switch (ecall.OpCode) { case VMECallOpCode.CALL: opcode = CilOpCodes.Call; resultType = methodSig.ReturnType; break; case VMECallOpCode.CALLVIRT: opcode = CilOpCodes.Callvirt; resultType = methodSig.ReturnType; break; case VMECallOpCode.NEWOBJ: opcode = CilOpCodes.Newobj; resultType = ecall.Method.DeclaringType.ToTypeSignature(); break; case VMECallOpCode.CALLVIRT_CONSTRAINED: prefix = CilInstruction.Create(CilOpCodes.Constrained, ecall.ConstrainedType); opcode = CilOpCodes.Callvirt; resultType = methodSig.ReturnType; break; default: throw new ArgumentOutOfRangeException(); } // Enter generic context of method. context.EnterMember(ecall.Method); // Collect arguments. var arguments = expression.Arguments .Skip(ecall.IsConstrained ? 3 : 2) .ToArray(); // Build call expression. var result = new CilInstructionExpression(opcode, ecall.Method, context.RecompileCallArguments(ecall.Method, arguments, ecall.OpCode == VMECallOpCode.NEWOBJ)) { ExpressionType = resultType.InstantiateGenericTypes(context.GenericContext) }; // Add prefix when necessary. if (prefix != null) { result.Arguments[0].ExpectedType = ecall.ConstrainedType; result.Instructions.Insert(0, prefix); } // Leave generic context. context.ExitMember(); return(result); }
public CilExpression Translate(RecompilerContext context, ILInstructionExpression expression) { var arguments = expression.Arguments .Select(a => (CilExpression)a.AcceptVisitor(context.Recompiler)) .ToArray(); CilOpCode opCode; switch (expression.OpCode.Code) { case ILCode.__EQUALS_OBJECT: opCode = CilOpCodes.Ceq; break; case ILCode.__EQUALS_R32: case ILCode.__EQUALS_R64: case ILCode.__EQUALS_DWORD: case ILCode.__EQUALS_QWORD: opCode = CilOpCodes.Ceq; break; case ILCode.__GT_R32: case ILCode.__GT_R64: opCode = CilOpCodes.Cgt; break; case ILCode.__GT_DWORD: case ILCode.__GT_QWORD: opCode = CilOpCodes.Cgt_Un; break; case ILCode.__LT_R32: case ILCode.__LT_R64: opCode = CilOpCodes.Clt; break; case ILCode.__LT_DWORD: case ILCode.__LT_QWORD: opCode = CilOpCodes.Clt_Un; break; default: throw new ArgumentOutOfRangeException(nameof(expression)); } var argumentType = expression.OpCode.StackBehaviourPop.GetArgumentType(0) .ToMetadataType(context.TargetModule) .ToTypeSignature(); var result = new CilInstructionExpression(opCode) { ExpressionType = context.TargetModule.CorLibTypeFactory.Boolean }; foreach (var argument in arguments) { argument.ExpectedType = argumentType; result.Arguments.Add(argument); } return(result); }
private static void ReplaceWithSingleInstruction(CilInstructionExpression expression, CilInstruction newInstruction) { expression.Instructions.Clear(); expression.Instructions.Add(newInstruction); expression.ExpressionType = expression.ExpectedType; }