diff --git a/.gitignore b/.gitignore index 19474da5..59200b96 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ bin obj .vs -/packages \ No newline at end of file +/packages +.DS_Store +.idea +TestResult.xml diff --git a/Backend/Analyses/TypeInferenceAnalysis.cs b/Backend/Analyses/TypeInferenceAnalysis.cs index b25cde66..9ec8ef12 100644 --- a/Backend/Analyses/TypeInferenceAnalysis.cs +++ b/Backend/Analyses/TypeInferenceAnalysis.cs @@ -10,6 +10,7 @@ using Backend.Model; using Model.ThreeAddressCode.Values; using Backend.Utils; +using Model; namespace Backend.Analyses { @@ -56,6 +57,27 @@ public override void Visit(MethodCallInstruction instruction) if (instruction.HasResult) { instruction.Result.Type = instruction.Method.ReturnType; + + // if returnType is a genericParameter that is instantiated, then use its instantiated type + if (instruction.Method.ReturnType is IGenericParameterReference genericParameterReference) + { + IList genericArguments; + switch (genericParameterReference.Kind) + { + case GenericParameterKind.Type: + genericArguments = ((IBasicType) genericParameterReference.GenericContainer).GenericArguments; + break; + case GenericParameterKind.Method: + genericArguments = ((IMethodReference) genericParameterReference.GenericContainer).GenericArguments; + break; + default: + throw genericParameterReference.Kind.ToUnknownValueException(); + } + if (genericArguments.Count > 0) + { + instruction.Result.Type = genericArguments[genericParameterReference.Index]; + } + } } // Skip implicit "this" parameter. @@ -325,6 +347,10 @@ instruction.RightOperand is Constant && } } } + public override void Visit(FilterInstruction instruction) + { + instruction.Result.Type = instruction.ExceptionType; + } } #endregion diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj index 4cf55d5c..8fadd328 100644 --- a/Backend/Backend.csproj +++ b/Backend/Backend.csproj @@ -62,6 +62,8 @@ + + diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs new file mode 100644 index 00000000..08077523 --- /dev/null +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -0,0 +1,553 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Backend.Utils; +using Model; +using Model.ThreeAddressCode.Instructions; +using Model.ThreeAddressCode.Values; +using Model.ThreeAddressCode.Visitor; +using Model.Types; +using ConvertInstruction = Model.ThreeAddressCode.Instructions.ConvertInstruction; +using CreateArrayInstruction = Model.ThreeAddressCode.Instructions.CreateArrayInstruction; +using CreateObjectInstruction = Model.ThreeAddressCode.Instructions.CreateObjectInstruction; +using IndirectMethodCallInstruction = Model.ThreeAddressCode.Instructions.IndirectMethodCallInstruction; +using LoadInstruction = Model.ThreeAddressCode.Instructions.LoadInstruction; +using LoadTokenInstruction = Model.ThreeAddressCode.Instructions.LoadTokenInstruction; +using MethodCallInstruction = Model.ThreeAddressCode.Instructions.MethodCallInstruction; +using SizeofInstruction = Model.ThreeAddressCode.Instructions.SizeofInstruction; +using StoreInstruction = Model.ThreeAddressCode.Instructions.StoreInstruction; +using SwitchInstruction = Model.ThreeAddressCode.Instructions.SwitchInstruction; +using Bytecode = Model.Bytecode; +using ConstrainedInstruction = Model.ThreeAddressCode.Instructions.ConstrainedInstruction; +using Instruction = Model.ThreeAddressCode.Instructions.Instruction; + +namespace Backend.Transformations.Assembly +{ + public class Assembler : IInstructionVisitor + { + private readonly MethodDefinition method; + + private readonly IList translatedInstructions; + private readonly ExceptionInformationBuilder exceptionInformationBuilder; + private readonly ISet ignoredInstructions; + private int Index { get; set; } + + public Assembler(MethodDefinition method) + { + if (!method.Body.Kind.Equals(MethodBodyKind.ThreeAddressCode)) + { + throw new Exception("MethodBody must be in Three Address Code"); + } + + this.method = method; + translatedInstructions = new List(); + exceptionInformationBuilder = new ExceptionInformationBuilder(); + ignoredInstructions = new HashSet(); + } + + public MethodBody Execute() + { + var body = new MethodBody(MethodBodyKind.Bytecode); + body.Parameters.AddRange(method.Body.Parameters); + + for (Index = 0; Index < method.Body.Instructions.Count; Index++) + { + var instruction = (Instruction) method.Body.Instructions[Index]; + if (!ignoredInstructions.Contains(Index)) + { + instruction.Accept(this); + } + } + + body.ExceptionInformation.AddRange(exceptionInformationBuilder.Build()); + body.Instructions.AddRange(translatedInstructions); + body.UpdateVariables(); + + return body; + } + + // abstract + public void Visit(IInstructionContainer container) + { + } + + public void Visit(Instruction instruction) + { + } + + public void Visit(DefinitionInstruction instruction) + { + } + + public void Visit(BranchInstruction instruction) + { + } + + public void Visit(ExceptionalBranchInstruction instruction) + { + } + // + + public void Visit(BinaryInstruction instruction) + { + if (instruction.Operation == BinaryOperation.Neq) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Eq) + { + Label = instruction.Label, + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands + }; + translatedInstructions.Add(basicInstruction); + + basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Neg) + { + Label = instruction.Label + "º", // ensure unique label + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands + }; + translatedInstructions.Add(basicInstruction); + } + else + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, OperationHelper.ToBasicOperation(instruction.Operation)) + { + Label = instruction.Label, + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands + }; + translatedInstructions.Add(basicInstruction); + } + } + + public void Visit(UnaryInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, OperationHelper.ToBasicOperation(instruction.Operation)) + { + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } + + public void Visit(LoadInstruction instruction) + { + Bytecode.Instruction bytecodeInstruction; + if (instruction.Result is TemporalVariable) + { + switch (instruction.Operand) + { + case TemporalVariable _: + bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Dup); + break; + case Constant constant: + bytecodeInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant); + break; + case LocalVariable localVariable: + bytecodeInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Content, localVariable); + break; + case Dereference dereference: + bytecodeInstruction = new Bytecode.LoadIndirectInstruction(instruction.Offset, dereference.Type); + break; + case Reference reference: + switch (reference.Value) + { + case ArrayElementAccess arrayElementAccess: + bytecodeInstruction = new Bytecode.LoadArrayElementInstruction( + instruction.Offset, + Bytecode.LoadArrayElementOperation.Address, + (ArrayType) arrayElementAccess.Array.Type) {Method = arrayElementAccess.Method}; + break; + + case LocalVariable localVariable: + bytecodeInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Address, localVariable); + break; + case InstanceFieldAccess instanceFieldAccess: + bytecodeInstruction = new Bytecode.LoadFieldInstruction( + instruction.Offset, + Bytecode.LoadFieldOperation.Address, + instanceFieldAccess.Field); + break; + default: + throw new CaseNotHandledException(); + } + + break; + case ArrayLengthAccess _: + bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LoadArrayLength); + break; + case VirtualMethodReference virtualMethodReference: + bytecodeInstruction = new Bytecode.LoadMethodAddressInstruction( + instruction.Offset, + Bytecode.LoadMethodAddressOperation.Virtual, + virtualMethodReference.Method); + break; + case StaticMethodReference staticMethodReference: + bytecodeInstruction = new Bytecode.LoadMethodAddressInstruction( + instruction.Offset, + Bytecode.LoadMethodAddressOperation.Static, + staticMethodReference.Method); + break; + case InstanceFieldAccess instanceFieldAccess: + bytecodeInstruction = new Bytecode.LoadFieldInstruction( + instruction.Offset, + Bytecode.LoadFieldOperation.Content, + instanceFieldAccess.Field); + break; + case StaticFieldAccess staticFieldAccess: + bytecodeInstruction = new Bytecode.LoadFieldInstruction( + instruction.Offset, + Bytecode.LoadFieldOperation.Content, + staticFieldAccess.Field); + break; + case ArrayElementAccess arrayElementAccess: + bytecodeInstruction = new Bytecode.LoadArrayElementInstruction( + instruction.Offset, + Bytecode.LoadArrayElementOperation.Content, + (ArrayType) arrayElementAccess.Array.Type) {Method = arrayElementAccess.Method}; + + break; + default: + throw new CaseNotHandledException(); + } + } + else + { + bytecodeInstruction = new Bytecode.StoreInstruction(instruction.Offset, (LocalVariable) instruction.Result); + } + + bytecodeInstruction.Label = instruction.Label; + translatedInstructions.Add(bytecodeInstruction); + } + + public void Visit(StoreInstruction instruction) + { + Bytecode.Instruction storeInstruction; + switch (instruction.Result) + { + case ArrayElementAccess arrayElementAccess: + storeInstruction = new Bytecode.StoreArrayElementInstruction(instruction.Offset, (ArrayType) arrayElementAccess.Array.Type) + { + Method = arrayElementAccess.Method + }; + break; + case Dereference dereference: + storeInstruction = new Bytecode.StoreIndirectInstruction(instruction.Offset, dereference.Type); + break; + case InstanceFieldAccess instanceFieldAccess: + storeInstruction = new Bytecode.StoreFieldInstruction(instruction.Offset, instanceFieldAccess.Field); + break; + case StaticFieldAccess staticFieldAccess: + storeInstruction = new Bytecode.StoreFieldInstruction(instruction.Offset, staticFieldAccess.Field); + break; + default: + throw new CaseNotHandledException(); + } + + storeInstruction.Label = instruction.Label; + translatedInstructions.Add(storeInstruction); + } + + public void Visit(NopInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop) + { + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } + + public void Visit(BreakpointInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Breakpoint) + { + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } + + public void Visit(TryInstruction instruction) + { + // try with multiple handlers is modelled as multiple consecutive try instructions with different handlers. + var previousInstructionIsTry = Index > 0 && method.Body.Instructions[Index - 1] is TryInstruction; + if (previousInstructionIsTry) + { + exceptionInformationBuilder.IncrementCurrentProtectedBlockExpectedHandlers(); + } + else + { + // try starts at the instruction following the try instruction. + var label = ""; + for (var i = Index + 1; i < method.Body.Instructions.Count; i++) + { + var currentInstruction = method.Body.Instructions[i]; + if (!(currentInstruction is TryInstruction)) + { + label = currentInstruction.Label; + break; + } + } + + exceptionInformationBuilder.BeginProtectedBlockAt(label); + } + } + + public void Visit(FaultInstruction instruction) + { + var label = method.Body.Instructions[Index + 1].Label; + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(label, ExceptionHandlerBlockKind.Fault); + } + + public void Visit(FinallyInstruction instruction) + { + var label = method.Body.Instructions[Index + 1].Label; + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(label, ExceptionHandlerBlockKind.Finally); + } + + + public void Visit(FilterInstruction instruction) + { + var label = method.Body.Instructions[Index + 1].Label; + exceptionInformationBuilder.AddFilterHandlerToCurrentProtectedBlock(label, instruction.kind, instruction.ExceptionType); + } + + public void Visit(CatchInstruction instruction) + { + var label = method.Body.Instructions[Index + 1].Label; + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(label, ExceptionHandlerBlockKind.Catch, instruction.ExceptionType); + } + + public void Visit(ThrowInstruction instruction) + { + var basicInstruction = instruction.HasOperand + ? new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Throw) + : new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Rethrow); + basicInstruction.Label = instruction.Label; + translatedInstructions.Add(basicInstruction); + if (Index < method.Body.Instructions.Count - 1) //not last instruction. Throw can be the last instruction and not inside a protected block + { + var label = method.Body.Instructions[Index + 1].Label; + exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(label); // block ends after instruction + } + } + + public void Visit(UnconditionalBranchInstruction instruction) + { + Bytecode.Instruction bytecodeInstruction; + switch (instruction.Operation) + { + case UnconditionalBranchOperation.Leave: + { + bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Leave, instruction.Target); + var label = method.Body.Instructions[Index + 1].Label; + exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(label); // block ends after instruction + + break; + } + case UnconditionalBranchOperation.Branch: + bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Branch, instruction.Target); + break; + case UnconditionalBranchOperation.EndFinally: + { + bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFinally); + // no more handlers after finally + var label = method.Body.Instructions[Index + 1].Label; + exceptionInformationBuilder.EndCurrentProtectedBlockAt(label); // block ends after instruction + break; + } + case UnconditionalBranchOperation.EndFilter: + // nothing is done with exceptionInformation since filter area is the gap between try end and handler start + bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFilter); + break; + default: + throw instruction.Operation.ToUnknownValueException(); + } + + bytecodeInstruction.Label = instruction.Label; + translatedInstructions.Add(bytecodeInstruction); + } + + public void Visit(ConvertInstruction instruction) + { + var convertInstruction = new Bytecode.ConvertInstruction( + instruction.Offset, + OperationHelper.ToConvertOperation(instruction.Operation), + instruction.ConversionType) + { + Label = instruction.Label, + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands + }; + translatedInstructions.Add(convertInstruction); + } + + public void Visit(ReturnInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Return) + { + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } + + public void Visit(ConditionalBranchInstruction instruction) + { + var branchOperation = OperationHelper.ToBranchOperation(instruction.Operation); + if (instruction.RightOperand is Constant constant) + { + var loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant) + { + Label = instruction.Label + "º" // ensure unique label + }; + translatedInstructions.Add(loadInstruction); + } + var branchInstruction = new Bytecode.BranchInstruction(instruction.Offset, branchOperation, instruction.Target) + { + Label = instruction.Label + }; + translatedInstructions.Add(branchInstruction); + } + + public void Visit(SwitchInstruction instruction) + { + var switchInstruction = new Bytecode.SwitchInstruction(instruction.Offset, instruction.Targets) + { + Label = instruction.Label + }; + translatedInstructions.Add(switchInstruction); + } + + public void Visit(SizeofInstruction instruction) + { + var sizeofInstruction = new Bytecode.SizeofInstruction(instruction.Offset, instruction.MeasuredType) + { + Label = instruction.Label + }; + translatedInstructions.Add(sizeofInstruction); + } + + public void Visit(LoadTokenInstruction instruction) + { + var loadTokenInstruction = new Bytecode.LoadTokenInstruction(instruction.Offset, instruction.Token) + { + Label = instruction.Label + }; + translatedInstructions.Add(loadTokenInstruction); + } + + public void Visit(MethodCallInstruction instruction) + { + var methodCallInstruction = new Bytecode.MethodCallInstruction( + instruction.Offset, + OperationHelper.ToMethodCallOperation(instruction.Operation), + instruction.Method + ) + { + Label = instruction.Label + }; + translatedInstructions.Add(methodCallInstruction); + } + + public void Visit(IndirectMethodCallInstruction instruction) + { + var indirectMethodCallInstruction = new Bytecode.IndirectMethodCallInstruction(instruction.Offset, instruction.Function) + { + Label = instruction.Label + }; + translatedInstructions.Add(indirectMethodCallInstruction); + } + + public void Visit(CreateObjectInstruction instruction) + { + var methodCallInstruction = (MethodCallInstruction) method.Body.Instructions[Index + 1]; + + // do not translate following method call and load instruction + ignoredInstructions.Add(Index + 1); // method call + ignoredInstructions.Add(Index + 2); // load + + var createObjectInstruction = new Bytecode.CreateObjectInstruction(instruction.Offset, methodCallInstruction.Method) + { + Label = instruction.Label + }; + translatedInstructions.Add(createObjectInstruction); + } + + public void Visit(CopyMemoryInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyBlock) + { + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } + + public void Visit(LocalAllocationInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LocalAllocation) + { + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } + + public void Visit(InitializeMemoryInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.InitBlock) + { + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } + + public void Visit(InitializeObjectInstruction instruction) + { + var type = ((PointerType) instruction.TargetAddress.Type).TargetType; + var initObjInstruction = new Bytecode.InitObjInstruction(instruction.Offset, type) + { + Label = instruction.Label + }; + translatedInstructions.Add(initObjInstruction); + } + + public void Visit(CopyObjectInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyObject) + { + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } + + public void Visit(CreateArrayInstruction instruction) + { + var arrayType = new ArrayType(instruction.ElementType, instruction.Rank); + var createArrayInstruction = new Bytecode.CreateArrayInstruction(instruction.Offset, arrayType) + { + Label = instruction.Label, + WithLowerBound = instruction.LowerBounds.Any(), + Constructor = instruction.Constructor + }; + translatedInstructions.Add(createArrayInstruction); + } + + public void Visit(PhiInstruction instruction) => throw new CaseNotHandledException(); + + public void Visit(ConstrainedInstruction instruction) + { + var constrainedInstruction = new Bytecode.ConstrainedInstruction(instruction.Offset, instruction.ThisType) + { + Label = instruction.Label + }; + translatedInstructions.Add(constrainedInstruction); + } + + public void Visit(PopInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Pop); + translatedInstructions.Add(basicInstruction); + } + + private class CaseNotHandledException : Exception + { + } + } +} \ No newline at end of file diff --git a/Backend/Transformations/Assembly/ExceptionInformationBuilder.cs b/Backend/Transformations/Assembly/ExceptionInformationBuilder.cs new file mode 100644 index 00000000..91098767 --- /dev/null +++ b/Backend/Transformations/Assembly/ExceptionInformationBuilder.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Model; +using Model.ThreeAddressCode.Instructions; +using Model.Types; + +namespace Backend.Transformations.Assembly +{ + // Helps with the translation of exception handling instructions from TAC to SIL. In SIL, exception information is stored + // separately from the method body instructions while in TAC there are instructions that represent the exception handling + // information (try, catch, etc). + // + // Since TAC => SIL translation is achieved by processing its instructions in sequential order, this builder keeps track of the + // the exception handling instructions and internally builds this information in the format that SIL manages. + // + // Each protected region is composed of a try clause and one or more handlers. Each region is created initially with the try clause + // and handlers are added as they appear in the TAC instructions. + // + // stores ongoing protected regions, that is those which all handlers were not added yet. Once completed, they are + // removed from this structure and stored in + // + // Protected regions can be nested (try inside another try) and each one exits onto the containing one, so a stack is used to locate + // easily which region is completed and must be placed in + // + internal class ExceptionInformationBuilder + { + private readonly Stack protectedBlocks = new Stack(); + private readonly IList result = new List(); + + public IList Build() + { + if (protectedBlocks.Count > 0) throw new Exception("Protected Blocks not generated correctly"); + return result; + } + + public void BeginProtectedBlockAt(string label) + { + var protectedBlockBuilder = new ProtectedBlockBuilder {TryStart = label, HandlerCount = 1}; + protectedBlocks.Push(protectedBlockBuilder); + } + + public void IncrementCurrentProtectedBlockExpectedHandlers() => protectedBlocks.Peek().HandlerCount++; + + public void AddHandlerToCurrentProtectedBlock(string label, ExceptionHandlerBlockKind handlerBlockKind, IType exceptionType) => + protectedBlocks + .Peek() + .EndPreviousRegionAt(label) + .Handlers.Add(new ProtectedBlockHandlerBuilder + { + HandlerStart = label, + HandlerBlockKind = handlerBlockKind, + ExceptionType = exceptionType + }); + + public void AddHandlerToCurrentProtectedBlock(string label, ExceptionHandlerBlockKind handlerBlockKind) => + AddHandlerToCurrentProtectedBlock(label, handlerBlockKind, null); + + // filter is a special case since it has a two regions (filter and handler). A filter in this TAC is modeled as two FilterInstruction + // with different kinds, one for each region. If the previous region is a Filter, it must be ended only if it is in it's handler region. + public void AddFilterHandlerToCurrentProtectedBlock(string label, FilterInstructionKind kind, IType exceptionType) + { + var protectedBlockBuilder = protectedBlocks.Peek(); + + bool EndPreviousHandlerCondition() => + protectedBlockBuilder.Handlers.Last().HandlerBlockKind != ExceptionHandlerBlockKind.Filter || + kind == FilterInstructionKind.FilterSection; + + protectedBlockBuilder.EndPreviousRegionAt(label, EndPreviousHandlerCondition); + + switch (kind) + { + case FilterInstructionKind.FilterSection: + protectedBlockBuilder.Handlers.Add(new ProtectedBlockHandlerBuilder + { + FilterStart = label, + HandlerBlockKind = ExceptionHandlerBlockKind.Filter + }); + break; + case FilterInstructionKind.FilterHandler: + var handler = protectedBlockBuilder.Handlers.Last(); + handler.HandlerStart = label; + handler.ExceptionType = exceptionType; + break; + default: throw kind.ToUnknownValueException(); + } + } + + public void EndCurrentProtectedBlockIfAppliesAt(string label) + { + if (protectedBlocks.Count > 0 && protectedBlocks.Peek().AllHandlersAdded()) + { + EndCurrentProtectedBlockAt(label); + } + } + + public void EndCurrentProtectedBlockAt(string label) + { + var exceptionBlockBuilder = protectedBlocks.Pop(); + exceptionBlockBuilder + .Handlers + .Last() + .HandlerEnd = label; + result.AddRange(exceptionBlockBuilder.Build()); + } + + private class ProtectedBlockBuilder + { + private string tryStart; + + public string TryStart + { + get => tryStart ?? throw new Exception("TryStart was not set"); + set + { + if (tryStart != null) throw new Exception("TryStart was already set"); + tryStart = value; + } + } + + private string tryEnd; + + private string TryEnd + { + get => tryEnd ?? throw new Exception("TryEnd was not set"); + set + { + if (tryEnd != null) throw new Exception("TryEnd was already set"); + tryEnd = value; + } + } + + public uint HandlerCount { get; set; } + + public bool AllHandlersAdded() => HandlerCount == Handlers.Count; + + public readonly IList Handlers = new List(); + + public ProtectedBlockBuilder EndPreviousRegionAt(string label) => EndPreviousRegionAt(label, () => true); + + public ProtectedBlockBuilder EndPreviousRegionAt(string label, Func multipleHandlerCondition) + { + if (Handlers.Count == 0) // first handler, ends try region + { + TryEnd = label; + } + else if (multipleHandlerCondition()) // multiple handlers. End previous handler conditionally + { + Handlers.Last().HandlerEnd = label; + } + + return this; + } + + // try with multiple handlers is modelled as multiple try instructions with the same label but different handlers. + public IList Build() => + Handlers + .Select(handlerBuilder => handlerBuilder.Build()) + .Select(handler => new ProtectedBlock(TryStart, TryEnd) {Handler = handler}) + .ToList(); + } + + private class ProtectedBlockHandlerBuilder + { + private string filterStart; + + public string FilterStart + { + get => filterStart ?? throw new Exception("FilterStart was not set"); + set + { + if (filterStart != null) throw new Exception("FilterStart was already set"); + filterStart = value; + } + } + + private string handlerStart; + + public string HandlerStart + { + get => handlerStart ?? throw new Exception("HandlerStart was not set"); + set + { + if (handlerStart != null) throw new Exception("HandlerStart was already set"); + handlerStart = value; + } + } + + private string handlerEnd; + + public string HandlerEnd + { + get => handlerEnd ?? throw new Exception("HandlerEnd was not set"); + set + { + if (handlerEnd != null) throw new Exception("HandlerEnd was already set"); + handlerEnd = value; + } + } + + private ExceptionHandlerBlockKind? handlerBlockKind; + + public ExceptionHandlerBlockKind HandlerBlockKind + { + get => handlerBlockKind ?? throw new Exception("HandlerBlockKind was not set"); + set + { + if (handlerBlockKind != null) throw new Exception("HandlerBlockKind was already set"); + handlerBlockKind = value; + } + } + + private IType exceptionType; + + public IType ExceptionType + { + get => exceptionType ?? throw new Exception("ExceptionType was not set"); + set + { + if (exceptionType != null) throw new Exception("ExceptionType was already set"); + exceptionType = value; + } + } + + public IExceptionHandler Build() + { + switch (HandlerBlockKind) + { + case ExceptionHandlerBlockKind.Filter: + return new FilterExceptionHandler(FilterStart, HandlerStart, HandlerEnd, ExceptionType); + case ExceptionHandlerBlockKind.Catch: + return new CatchExceptionHandler(HandlerStart, HandlerEnd, ExceptionType); + case ExceptionHandlerBlockKind.Fault: + return new FaultExceptionHandler(HandlerStart, HandlerEnd); + case ExceptionHandlerBlockKind.Finally: + return new FinallyExceptionHandler(HandlerStart, HandlerEnd); + default: throw new UnknownValueException(HandlerBlockKind); + } + } + } + } +} \ No newline at end of file diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index f8e0b8c9..3b26b1ae 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -3,8 +3,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using Model.ThreeAddressCode; using Backend.Utils; using Model.ThreeAddressCode.Values; using Tac = Model.ThreeAddressCode.Instructions; @@ -100,6 +98,8 @@ public TemporalVariable Top() private class InstructionTranslator : InstructionVisitor { + public const string NextInstructionLabelPlaceHolder = "{nextInstructionLabelPlaceHolder}"; + private MethodBody body; private OperandStack stack; private IType returnType; @@ -110,8 +110,7 @@ public InstructionTranslator(OperandStack stack, MethodBody body, IType returnTy this.body = body; this.returnType = returnType; } - - public override void Visit(Bytecode.BasicInstruction op) + public override void Visit(Bytecode.BasicInstruction op) { switch (op.Operation) { @@ -172,10 +171,6 @@ public override void Visit(Bytecode.BasicInstruction op) ProcessInitializeMemory(op); break; - case Bytecode.BasicOperation.InitObject: - ProcessInitializeObject(op); - break; - case Bytecode.BasicOperation.CopyObject: ProcessCopyObject(op); break; @@ -188,26 +183,6 @@ public override void Visit(Bytecode.BasicInstruction op) ProcessLoadArrayLength(op); break; - case Bytecode.BasicOperation.IndirectLoad: - ProcessIndirectLoad(op); - break; - - case Bytecode.BasicOperation.LoadArrayElement: - ProcessLoadArrayElement(op); - break; - - case Bytecode.BasicOperation.LoadArrayElementAddress: - ProcessLoadArrayElementAddress(op); - break; - - case Bytecode.BasicOperation.IndirectStore: - ProcessIndirectStore(op); - break; - - case Bytecode.BasicOperation.StoreArrayElement: - ProcessStoreArrayElement(op); - break; - case Bytecode.BasicOperation.Breakpoint: ProcessBreakpointOperation(op); break; @@ -267,6 +242,8 @@ private void ProcessEmptyOperation(Bytecode.BasicInstruction op) private void ProcessPop(Bytecode.BasicInstruction op) { stack.Pop(); + var instruction = new Tac.PopInstruction(op.Offset); + body.Instructions.Add(instruction); } private void ProcessDup(Bytecode.BasicInstruction op) @@ -281,7 +258,13 @@ private void ProcessEndFinally(Bytecode.BasicInstruction op) { stack.Clear(); - ProcessEmptyOperation(op); + // jump target is always next instruction. However the next instruction label is not known so a placeholder is set + // instead and then correctly replaced withe label of the next instruction + var instruction = new Tac.UnconditionalBranchInstruction( + op.Offset, + NextInstructionLabelPlaceHolder, + Tac.UnconditionalBranchOperation.EndFinally); + body.Instructions.Add(instruction); //// TODO: Maybe we don't need to add this branch instruction //// since it is jumping to the next one, @@ -306,7 +289,13 @@ private void ProcessEndFilter(Bytecode.BasicInstruction op) { stack.Clear(); - ProcessEmptyOperation(op); + // jump target is always next instruction. However the next instruction label is not known so a placeholder is set + // instead and then correctly replaced withe label of the next instruction + var instruction = new Tac.UnconditionalBranchInstruction( + op.Offset, + NextInstructionLabelPlaceHolder, + Tac.UnconditionalBranchOperation.EndFilter); + body.Instructions.Add(instruction); } private void ProcessLocalAllocation(Bytecode.BasicInstruction op) @@ -328,7 +317,7 @@ private void ProcessInitializeMemory(Bytecode.BasicInstruction op) body.Instructions.Add(instruction); } - private void ProcessInitializeObject(Bytecode.BasicInstruction op) + public override void Visit(Bytecode.InitObjInstruction op) { var targetAddress = stack.Pop(); var instruction = new Tac.InitializeObjectInstruction(op.Offset, targetAddress); @@ -363,55 +352,6 @@ private void ProcessLoadArrayLength(Bytecode.BasicInstruction op) body.Instructions.Add(instruction); } - private void ProcessIndirectLoad(Bytecode.BasicInstruction op) - { - var address = stack.Pop(); - var dest = stack.Push(); - var source = new Dereference(address); - var instruction = new Tac.LoadInstruction(op.Offset, dest, source); - body.Instructions.Add(instruction); - } - - private void ProcessLoadArrayElement(Bytecode.BasicInstruction op) - { - var index = stack.Pop(); - var array = stack.Pop(); - var dest = stack.Push(); - var source = new ArrayElementAccess(array, index); - var instruction = new Tac.LoadInstruction(op.Offset, dest, source); - body.Instructions.Add(instruction); - } - - private void ProcessLoadArrayElementAddress(Bytecode.BasicInstruction op) - { - var index = stack.Pop(); - var array = stack.Pop(); - var dest = stack.Push(); - var access = new ArrayElementAccess(array, index); - var source = new Reference(access); - var instruction = new Tac.LoadInstruction(op.Offset, dest, source); - body.Instructions.Add(instruction); - } - - private void ProcessIndirectStore(Bytecode.BasicInstruction op) - { - var source = stack.Pop(); - var address = stack.Pop(); - var dest = new Dereference(address); - var instruction = new Tac.StoreInstruction(op.Offset, dest, source); - body.Instructions.Add(instruction); - } - - private void ProcessStoreArrayElement(Bytecode.BasicInstruction op) - { - var source = stack.Pop(); - var index = stack.Pop(); - var array = stack.Pop(); - var dest = new ArrayElementAccess(array, index); - var instruction = new Tac.StoreInstruction(op.Offset, dest, source); - body.Instructions.Add(instruction); - } - private void ProcessBreakpointOperation(Bytecode.BasicInstruction op) { var instruction = new Tac.BreakpointInstruction(op.Offset); @@ -538,7 +478,7 @@ private void ProcessLeave(Bytecode.BranchInstruction op) if (!isTryFinallyEnd) { - var instruction = new Tac.UnconditionalBranchInstruction(op.Offset, op.Target); + var instruction = new Tac.UnconditionalBranchInstruction(op.Offset, op.Target, Tac.UnconditionalBranchOperation.Leave); body.Instructions.Add(instruction); } } @@ -579,7 +519,10 @@ public override void Visit(Bytecode.CreateArrayInstruction op) sizes.Reverse(); var result = stack.Push(); - var instruction = new Tac.CreateArrayInstruction(op.Offset, result, op.Type.ElementsType, op.Type.Rank, lowerBounds, sizes); + var instruction = new Tac.CreateArrayInstruction(op.Offset, result, op.Type.ElementsType, op.Type.Rank, lowerBounds, sizes) + { + Constructor = op.Constructor + }; body.Instructions.Add(instruction); } @@ -614,7 +557,7 @@ private void ProcessLoadArrayElement(Bytecode.LoadArrayElementInstruction op) indices.Reverse(); var dest = stack.Push(); - var source = new ArrayElementAccess(array, indices); + var source = new ArrayElementAccess(array, indices) { Method = op.Method}; var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -634,7 +577,8 @@ private void ProcessLoadArrayElementAddress(Bytecode.LoadArrayElementInstruction indices.Reverse(); var dest = stack.Push(); - var access = new ArrayElementAccess(array, indices); + + var access = new ArrayElementAccess(array, indices) { Method = op.Method};; var source = new Reference(access); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); @@ -655,7 +599,7 @@ public override void Visit(Bytecode.StoreArrayElementInstruction op) indices.Reverse(); - var dest = new ArrayElementAccess(array, indices); + var dest = new ArrayElementAccess(array, indices) { Method = op.Method}; var instruction = new Tac.StoreInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -689,11 +633,13 @@ public override void Visit(Bytecode.CreateObjectInstruction op) body.Instructions.Add(instruction); instruction = new Tac.MethodCallInstruction(op.Offset, null, Tac.MethodCallOperation.Static, op.Constructor, arguments); + instruction.Label += "º"; // ensure unique label body.Instructions.Add(instruction); var result = stack.Push(); instruction = new Tac.LoadInstruction(op.Offset, result, allocationResult); + instruction.Label += "ºº"; // ensure unique label body.Instructions.Add(instruction); stack.DecrementCapacity(); @@ -804,8 +750,15 @@ private void ProcessLoadInstanceFieldAddress(Bytecode.LoadFieldInstruction op) var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } - - public override void Visit(Bytecode.LoadInstruction op) + public override void Visit(Bytecode.LoadIndirectInstruction op) + { + var address = stack.Pop(); + var dest = stack.Push(); + var source = new Dereference(address); + var instruction = new Tac.LoadInstruction(op.Offset, dest, source); + body.Instructions.Add(instruction); + } + public override void Visit(Bytecode.LoadInstruction op) { switch (op.Operation) { @@ -960,7 +913,16 @@ private void ProcessStoreInstanceField(Bytecode.StoreFieldInstruction op) body.Instructions.Add(instruction); } - public override void Visit(Bytecode.StoreInstruction op) + public override void Visit(Bytecode.StoreIndirectInstruction op) + { + var source = stack.Pop(); + var address = stack.Pop(); + var dest = new Dereference(address); + var instruction = new Tac.StoreInstruction(op.Offset, dest, source); + body.Instructions.Add(instruction); + } + + public override void Visit(Bytecode.StoreInstruction op) { var source = stack.Pop(); var instruction = new Tac.LoadInstruction(op.Offset, op.Target, source); @@ -973,6 +935,12 @@ public override void Visit(Bytecode.SwitchInstruction op) var instruction = new Tac.SwitchInstruction(op.Offset, operand, op.Targets); body.Instructions.Add(instruction); } + + public override void Visit(Bytecode.ConstrainedInstruction op) + { + var instruction = new Tac.ConstrainedInstruction(op.Offset, op.ThisType); + body.Instructions.Add(instruction); + } } #endregion @@ -997,7 +965,6 @@ public MethodBody Execute() body.MaxStack = method.Body.MaxStack; body.Parameters.AddRange(method.Body.Parameters); body.LocalVariables.AddRange(method.Body.LocalVariables); - body.ExceptionInformation.AddRange(method.Body.ExceptionInformation); if (method.Body.Instructions.Count > 0) { @@ -1036,12 +1003,12 @@ public MethodBody Execute() stackSize = stackSizeAtEntry[successor.Id]; - if (!stackSize.HasValue) + if (!stackSize.HasValue || successorIsHandlerHeader) { //Console.WriteLine("{0} -> {1} = {2}", node.Id, successor.Id, stack.Size); stackSizeAtEntry[successor.Id] = stack.Size; } - else if (stackSize.Value != stack.Size && !successorIsHandlerHeader) + else if (stackSize.Value != stack.Size) { // Check that the already saved stack size is the same as the current stack size throw new Exception("Basic block with different stack size at entry!"); @@ -1052,6 +1019,17 @@ public MethodBody Execute() var instructions = body.Instructions.OrderBy(op => op.Offset).ToList(); body.Instructions.Clear(); body.Instructions.AddRange(instructions); + + // replace target placeholders + for (var i = 0; i < instructions.Count; i++) + { + var instruction = instructions[i]; + if (instruction is Tac.BranchInstruction branchInstruction && + branchInstruction.Target.Equals(InstructionTranslator.NextInstructionLabelPlaceHolder)) + { + branchInstruction.Target = instructions[i + 1].Label; + } + } //body.LocalVariables.AddRange(stack.Variables); body.UpdateVariables(); @@ -1065,6 +1043,10 @@ private void FillExceptionHandlersStart() foreach (var protectedBlock in method.Body.ExceptionInformation) { exceptionHandlersStart.Add(protectedBlock.Start, protectedBlock); + if (protectedBlock.Handler is FilterExceptionHandler filterExceptionHandler) + { + exceptionHandlersStart.Add(filterExceptionHandler.FilterStart, protectedBlock.Handler); + } exceptionHandlersStart.Add(protectedBlock.Handler.Start, protectedBlock.Handler); //exceptionHandlersEnd.Add(protectedBlock.End, protectedBlock); //exceptionHandlersEnd.Add(protectedBlock.Handler.End, protectedBlock.Handler); @@ -1086,7 +1068,7 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) if (exceptionHandlersStart.ContainsKey(operation.Label)) { var handlerBlocks = exceptionHandlersStart[operation.Label]; - + var labelSuffix = "º"; // ensure unique label foreach (var block in handlerBlocks) { Tac.Instruction instruction; @@ -1100,8 +1082,11 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) case ExceptionHandlerBlockKind.Filter: // Push the exception into the stack var filterException = stack.Push(); - var filterBlock = block as FilterExceptionHandler; - instruction = new Tac.FilterInstruction(operation.Offset, filterException, filterBlock.ExceptionType); + var filterBlock = (FilterExceptionHandler) block; + var kind = operation.Label.Equals(filterBlock.FilterStart) + ? Tac.FilterInstructionKind.FilterSection + : Tac.FilterInstructionKind.FilterHandler; + instruction = new Tac.FilterInstruction(operation.Offset, filterException, filterBlock.ExceptionType, kind); break; case ExceptionHandlerBlockKind.Catch: @@ -1123,7 +1108,9 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) throw new Exception("Unknown ExceptionHandlerBlockKind."); } + instruction.Label = operation.Label + labelSuffix; body.Instructions.Add(instruction); + labelSuffix += "º"; } } } diff --git a/Backend/Utils/Helper.cs b/Backend/Utils/Helper.cs index 3c0f2047..43d53039 100644 --- a/Backend/Utils/Helper.cs +++ b/Backend/Utils/Helper.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Model; namespace Backend.Utils { diff --git a/Backend/Utils/OperationHelper.cs b/Backend/Utils/OperationHelper.cs index bdd4cb89..dacd86ca 100644 --- a/Backend/Utils/OperationHelper.cs +++ b/Backend/Utils/OperationHelper.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using Model; +using Model.ThreeAddressCode.Values; using Bytecode = Model.Bytecode; using Tac = Model.ThreeAddressCode.Instructions; @@ -33,7 +34,7 @@ public static Tac.ConvertOperation ToConvertOperation(Bytecode.ConvertOperation case Bytecode.ConvertOperation.Conv: return Tac.ConvertOperation.Conv; case Bytecode.ConvertOperation.Unbox: return Tac.ConvertOperation.Unbox; case Bytecode.ConvertOperation.UnboxPtr: return Tac.ConvertOperation.UnboxPtr; - + case Bytecode.ConvertOperation.IsInst: return Tac.ConvertOperation.IsInst; default: throw operation.ToUnknownValueException(); } } @@ -137,5 +138,75 @@ public static bool IsBranch(Bytecode.Instruction instruction) return result; } + + public static Bytecode.BranchOperation ToBranchOperation(Tac.BranchOperation operation) + { + switch (operation) + { + case Tac.BranchOperation.Eq: return Bytecode.BranchOperation.Eq; + case Tac.BranchOperation.Neq: return Bytecode.BranchOperation.Neq; + case Tac.BranchOperation.Lt: return Bytecode.BranchOperation.Lt; + case Tac.BranchOperation.Le: return Bytecode.BranchOperation.Le; + case Tac.BranchOperation.Gt: return Bytecode.BranchOperation.Gt; + case Tac.BranchOperation.Ge: return Bytecode.BranchOperation.Ge; + default: throw operation.ToUnknownValueException(); + } + } + + public static Bytecode.ConvertOperation ToConvertOperation(Tac.ConvertOperation operation) + { + switch (operation) + { + case Tac.ConvertOperation.Conv: return Bytecode.ConvertOperation.Conv; + case Tac.ConvertOperation.Cast: return Bytecode.ConvertOperation.Cast; + case Tac.ConvertOperation.Box: return Bytecode.ConvertOperation.Box; + case Tac.ConvertOperation.Unbox: return Bytecode.ConvertOperation.Unbox; + case Tac.ConvertOperation.UnboxPtr: return Bytecode.ConvertOperation.UnboxPtr; + case Tac.ConvertOperation.IsInst: return Bytecode.ConvertOperation.IsInst; + default: throw operation.ToUnknownValueException(); + } + } + + public static Bytecode.BasicOperation ToBasicOperation(Tac.UnaryOperation operation) + { + switch (operation) + { + case Tac.UnaryOperation.Not: return Bytecode.BasicOperation.Not; + case Tac.UnaryOperation.Neg: return Bytecode.BasicOperation.Neg; + default: throw operation.ToUnknownValueException(); + } + } + + public static Bytecode.BasicOperation ToBasicOperation(Tac.BinaryOperation operation) + { + switch (operation) + { + case Tac.BinaryOperation.Add: return Bytecode.BasicOperation.Add; + case Tac.BinaryOperation.Sub: return Bytecode.BasicOperation.Sub; + case Tac.BinaryOperation.Mul: return Bytecode.BasicOperation.Mul; + case Tac.BinaryOperation.Div: return Bytecode.BasicOperation.Div; + case Tac.BinaryOperation.Rem: return Bytecode.BasicOperation.Rem; + case Tac.BinaryOperation.And: return Bytecode.BasicOperation.And; + case Tac.BinaryOperation.Or: return Bytecode.BasicOperation.Or; + case Tac.BinaryOperation.Xor: return Bytecode.BasicOperation.Xor; + case Tac.BinaryOperation.Shl: return Bytecode.BasicOperation.Shl; + case Tac.BinaryOperation.Shr: return Bytecode.BasicOperation.Shr; + case Tac.BinaryOperation.Eq: return Bytecode.BasicOperation.Eq; + case Tac.BinaryOperation.Lt: return Bytecode.BasicOperation.Lt; + case Tac.BinaryOperation.Gt: return Bytecode.BasicOperation.Gt; + default: throw operation.ToUnknownValueException(); + } + } + + public static Bytecode.MethodCallOperation ToMethodCallOperation(Tac.MethodCallOperation operation) + { + switch (operation) + { + case Tac.MethodCallOperation.Static: return Bytecode.MethodCallOperation.Static; + case Tac.MethodCallOperation.Virtual: return Bytecode.MethodCallOperation.Virtual; + case Tac.MethodCallOperation.Jump: return Bytecode.MethodCallOperation.Jump; + default: throw operation.ToUnknownValueException(); + } + } } } diff --git a/CCI Backend.sln b/CCI Backend.sln index 0ffa6e87..8016a733 100644 --- a/CCI Backend.sln +++ b/CCI Backend.sln @@ -18,6 +18,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CCIProvider", "CCIProvider\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MetadataProvider", "MetadataProvider\MetadataProvider.csproj", "{7D94DAAC-E703-430D-BCEB-D10E4C565FF8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MetadataGenerator", "MetadataGenerator\MetadataGenerator.csproj", "{D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Examples", "Examples\Examples.csproj", "{73254DAD-0794-4BFA-A894-A24B79A006D0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExamplesEXE", "ExamplesEXE\ExamplesEXE.csproj", "{3630D8DA-4DAF-4983-9C02-EF5337B1050A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -92,6 +98,42 @@ Global {7D94DAAC-E703-430D-BCEB-D10E4C565FF8}.Release|Mixed Platforms.Build.0 = Release|Any CPU {7D94DAAC-E703-430D-BCEB-D10E4C565FF8}.Release|x86.ActiveCfg = Release|Any CPU {7D94DAAC-E703-430D-BCEB-D10E4C565FF8}.Release|x86.Build.0 = Release|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Debug|x86.ActiveCfg = Debug|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Debug|x86.Build.0 = Debug|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Release|Any CPU.Build.0 = Release|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Release|x86.ActiveCfg = Release|Any CPU + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3}.Release|x86.Build.0 = Release|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Debug|x86.ActiveCfg = Debug|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Debug|x86.Build.0 = Debug|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Release|Any CPU.Build.0 = Release|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Release|x86.ActiveCfg = Release|Any CPU + {73254DAD-0794-4BFA-A894-A24B79A006D0}.Release|x86.Build.0 = Release|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Debug|x86.ActiveCfg = Debug|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Debug|x86.Build.0 = Debug|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Release|Any CPU.Build.0 = Release|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Release|x86.ActiveCfg = Release|Any CPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/CCIProvider/AssemblyTraverser.cs b/CCIProvider/AssemblyTraverser.cs index 65a4af0b..e9730d28 100644 --- a/CCIProvider/AssemblyTraverser.cs +++ b/CCIProvider/AssemblyTraverser.cs @@ -34,10 +34,21 @@ public AssemblyTraverser(Host host, Cci.IMetadataHost cciHost, Cci.PdbReader pdb this.TraverseIntoMethodBodies = false; this.typeExtractor = new TypeExtractor(host); } + + private AssemblyKind AssemblyKindFrom(Cci.IAssembly cciAssembly) + { + switch (cciAssembly.Kind) + { + case Cci.ModuleKind.ConsoleApplication: + case Cci.ModuleKind.WindowsApplication: return AssemblyKind.Exe; + case Cci.ModuleKind.DynamicallyLinkedLibrary: return AssemblyKind.Dll; + default: throw new Exception($"Assembly kind {cciAssembly.Kind} not supported"); + } + } public override void TraverseChildren(Cci.IAssembly cciAssembly) { - var ourAssembly = new Assembly(cciAssembly.Name.Value); + var ourAssembly = new Assembly(cciAssembly.Name.Value, AssemblyKindFrom(cciAssembly)); foreach (var cciReference in cciAssembly.AssemblyReferences) { diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index ffdcfffa..b3d1abdf 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -128,68 +128,69 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) { IInstruction instruction = null; - switch (operation.OperationCode) - { - case Cci.OperationCode.Add: - case Cci.OperationCode.Add_Ovf: - case Cci.OperationCode.Add_Ovf_Un: - case Cci.OperationCode.And: - case Cci.OperationCode.Ceq: - case Cci.OperationCode.Cgt: - case Cci.OperationCode.Cgt_Un: - case Cci.OperationCode.Clt: - case Cci.OperationCode.Clt_Un: - case Cci.OperationCode.Div: - case Cci.OperationCode.Div_Un: - case Cci.OperationCode.Mul: - case Cci.OperationCode.Mul_Ovf: - case Cci.OperationCode.Mul_Ovf_Un: - case Cci.OperationCode.Or: - case Cci.OperationCode.Rem: - case Cci.OperationCode.Rem_Un: - case Cci.OperationCode.Shl: - case Cci.OperationCode.Shr: - case Cci.OperationCode.Shr_Un: - case Cci.OperationCode.Sub: - case Cci.OperationCode.Sub_Ovf: - case Cci.OperationCode.Sub_Ovf_Un: - case Cci.OperationCode.Xor: - instruction = ProcessBasic(operation); - break; + switch (operation.OperationCode) + { + case Cci.OperationCode.Add: + case Cci.OperationCode.Add_Ovf: + case Cci.OperationCode.Add_Ovf_Un: + case Cci.OperationCode.And: + case Cci.OperationCode.Ceq: + case Cci.OperationCode.Cgt: + case Cci.OperationCode.Cgt_Un: + case Cci.OperationCode.Clt: + case Cci.OperationCode.Clt_Un: + case Cci.OperationCode.Div: + case Cci.OperationCode.Div_Un: + case Cci.OperationCode.Mul: + case Cci.OperationCode.Mul_Ovf: + case Cci.OperationCode.Mul_Ovf_Un: + case Cci.OperationCode.Or: + case Cci.OperationCode.Rem: + case Cci.OperationCode.Rem_Un: + case Cci.OperationCode.Shl: + case Cci.OperationCode.Shr: + case Cci.OperationCode.Shr_Un: + case Cci.OperationCode.Sub: + case Cci.OperationCode.Sub_Ovf: + case Cci.OperationCode.Sub_Ovf_Un: + case Cci.OperationCode.Xor: + instruction = ProcessBasic(operation); + break; - //case Cci.OperationCode.Arglist: - // //expression = new RuntimeArgumentHandleExpression(); - // break; + //case Cci.OperationCode.Arglist: + // //expression = new RuntimeArgumentHandleExpression(); + // break; - case Cci.OperationCode.Array_Create_WithLowerBound: - case Cci.OperationCode.Array_Create: - case Cci.OperationCode.Newarr: - instruction = ProcessCreateArray(operation); - break; + case Cci.OperationCode.Array_Create_WithLowerBound: + case Cci.OperationCode.Array_Create: + case Cci.OperationCode.Newarr: + instruction = ProcessCreateArray(operation); + break; - case Cci.OperationCode.Array_Get: - case Cci.OperationCode.Array_Addr: - instruction = ProcessLoadArrayElement(operation); + case Cci.OperationCode.Array_Get: + instruction = ProcessLoadArrayElement(operation, LoadArrayElementOperation.Content); + break; + case Cci.OperationCode.Array_Addr: + instruction = ProcessLoadArrayElement(operation, LoadArrayElementOperation.Address); break; - case Cci.OperationCode.Ldelem: - case Cci.OperationCode.Ldelem_I: - case Cci.OperationCode.Ldelem_I1: - case Cci.OperationCode.Ldelem_I2: - case Cci.OperationCode.Ldelem_I4: - case Cci.OperationCode.Ldelem_I8: - case Cci.OperationCode.Ldelem_R4: - case Cci.OperationCode.Ldelem_R8: - case Cci.OperationCode.Ldelem_U1: - case Cci.OperationCode.Ldelem_U2: - case Cci.OperationCode.Ldelem_U4: - case Cci.OperationCode.Ldelem_Ref: - instruction = ProcessBasic(operation); + case Cci.OperationCode.Ldelem: + case Cci.OperationCode.Ldelem_I: + case Cci.OperationCode.Ldelem_I1: + case Cci.OperationCode.Ldelem_I2: + case Cci.OperationCode.Ldelem_I4: + case Cci.OperationCode.Ldelem_I8: + case Cci.OperationCode.Ldelem_R4: + case Cci.OperationCode.Ldelem_R8: + case Cci.OperationCode.Ldelem_U1: + case Cci.OperationCode.Ldelem_U2: + case Cci.OperationCode.Ldelem_U4: + case Cci.OperationCode.Ldelem_Ref: + instruction = ProcessLoadArrayElement(operation, LoadArrayElementOperation.Content); break; - case Cci.OperationCode.Ldelema: - instruction = ProcessBasic(operation); - break; + instruction = ProcessLoadArrayElement(operation, LoadArrayElementOperation.Address); + break; case Cci.OperationCode.Beq: case Cci.OperationCode.Beq_S: @@ -303,9 +304,9 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) // expression = new MethodCall() { Arguments = new List(1) { operand }, IsStaticCall = true, Type = operand.Type, MethodToCall = chkfinite }; // break; - //case Cci.OperationCode.Constrained_: - // // This prefix is redundant and is not represented in the code model. - // break; + case Cci.OperationCode.Constrained_: + instruction = ProcessConstrained(operation); + break; case Cci.OperationCode.Cpblk: instruction = ProcessBasic(operation); @@ -329,7 +330,7 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) break; case Cci.OperationCode.Initobj: - instruction = ProcessBasic(operation); + instruction = ProcessInitObj(operation); break; case Cci.OperationCode.Ldarg: @@ -461,19 +462,16 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) break; case Cci.OperationCode.Array_Set: - instruction = ProcessStoreArrayElement(operation); - break; - - case Cci.OperationCode.Stelem: - case Cci.OperationCode.Stelem_I: - case Cci.OperationCode.Stelem_I1: - case Cci.OperationCode.Stelem_I2: - case Cci.OperationCode.Stelem_I4: - case Cci.OperationCode.Stelem_I8: - case Cci.OperationCode.Stelem_R4: - case Cci.OperationCode.Stelem_R8: - case Cci.OperationCode.Stelem_Ref: - instruction = ProcessBasic(operation); + case Cci.OperationCode.Stelem: + case Cci.OperationCode.Stelem_I: + case Cci.OperationCode.Stelem_I1: + case Cci.OperationCode.Stelem_I2: + case Cci.OperationCode.Stelem_I4: + case Cci.OperationCode.Stelem_I8: + case Cci.OperationCode.Stelem_R4: + case Cci.OperationCode.Stelem_R8: + case Cci.OperationCode.Stelem_Ref: + instruction = ProcessStoreArrayElement(operation); break; case Cci.OperationCode.Stfld: @@ -490,7 +488,7 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) case Cci.OperationCode.Stind_R8: case Cci.OperationCode.Stind_Ref: case Cci.OperationCode.Stobj: - instruction = ProcessBasic(operation); + instruction = ProcessStoreIndirect(operation); break; case Cci.OperationCode.Stloc: @@ -538,9 +536,70 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) } return instruction; - } + } - private IInstruction ProcessSwitch(Cci.IOperation op) + private IInstruction ProcessConstrained(Cci.IOperation op) + { + var thisType = typeExtractor.ExtractType(op.Value as Cci.ITypeReference); + var ins = new ConstrainedInstruction(op.Offset, thisType); + return ins; + } + + private IInstruction ProcessStoreArrayElement(Cci.IOperation op) + { + ArrayType arrayType = null; + + switch (op.OperationCode) + { + case Cci.OperationCode.Array_Set: + arrayType = typeExtractor.ExtractType(op.Value as Cci.ITypeReference) as ArrayType; + break; + case Cci.OperationCode.Stelem: + var extractedType = typeExtractor.ExtractType(op.Value as Cci.ITypeReference); + arrayType = new ArrayType(extractedType); + break; + default: + arrayType = new ArrayType(OperationHelper.GetOperationType(op.OperationCode)); + break; + } + + if (arrayType == null) + throw new NotImplementedException(); + + var instruction = new StoreArrayElementInstruction(op.Offset, arrayType); + return instruction; + } + + private IInstruction ProcessLoadArrayElement(Cci.IOperation op, LoadArrayElementOperation operation) + { + ArrayType arrayType = null; + + switch (op.OperationCode) + { + case Cci.OperationCode.Array_Addr: + case Cci.OperationCode.Array_Create: + case Cci.OperationCode.Array_Create_WithLowerBound: + case Cci.OperationCode.Array_Get: + case Cci.OperationCode.Array_Set: + arrayType = typeExtractor.ExtractType(op.Value as Cci.ITypeReference) as ArrayType; + break; + case Cci.OperationCode.Ldelem: + case Cci.OperationCode.Ldelema: + arrayType = new ArrayType(typeExtractor.ExtractType(op.Value as Cci.ITypeReference)); + break; + default: + arrayType = new ArrayType(OperationHelper.GetOperationType(op.OperationCode)); + break; + } + + if (arrayType == null) + throw new NotImplementedException(); + + var instruction = new LoadArrayElementInstruction(op.Offset, operation, arrayType); + return instruction; + } + + private IInstruction ProcessSwitch(Cci.IOperation op) { var targets = op.Value as uint[]; @@ -559,26 +618,7 @@ private IInstruction ProcessCreateArray(Cci.IOperation op) return instruction; } - private IInstruction ProcessLoadArrayElement(Cci.IOperation op) - { - var operation = OperationHelper.ToLoadArrayElementOperation(op.OperationCode); - var cciArrayType = op.Value as Cci.IArrayTypeReference; - var ourArrayType = typeExtractor.ExtractType(cciArrayType); - - var instruction = new LoadArrayElementInstruction(op.Offset, operation, ourArrayType); - return instruction; - } - - private IInstruction ProcessStoreArrayElement(Cci.IOperation op) - { - var cciArrayType = op.Value as Cci.IArrayTypeReference; - var ourArrayType = typeExtractor.ExtractType(cciArrayType); - - var instruction = new StoreArrayElementInstruction(op.Offset, ourArrayType); - return instruction; - } - - private IInstruction ProcessCreateObject(Cci.IOperation op) + private IInstruction ProcessCreateObject(Cci.IOperation op) { var cciMethod = op.Value as Cci.IMethodReference; var ourMethod = typeExtractor.ExtractReference(cciMethod); @@ -687,7 +727,10 @@ private IInstruction ProcessLoadLocal(Cci.IOperation op) private IInstruction ProcessLoadIndirect(Cci.IOperation op) { - var instruction = new BasicInstruction(op.Offset, BasicOperation.IndirectLoad); + var type = OperationHelper.GetOperationType(op.OperationCode); + if (op.OperationCode == Cci.OperationCode.Ldobj) + type = typeExtractor.ExtractStruct(op.Value as Cci.INamedTypeDefinition, sourceLocationProvider); + var instruction = new LoadIndirectInstruction(op.Offset, type); return instruction; } @@ -743,7 +786,16 @@ private IInstruction ProcessStoreLocal(Cci.IOperation op) return instruction; } - private IInstruction ProcessStoreField(Cci.IOperation op) + private IInstruction ProcessStoreIndirect(Cci.IOperation op) + { + var type = OperationHelper.GetOperationType(op.OperationCode); + if (op.OperationCode == Cci.OperationCode.Stobj) + type = typeExtractor.ExtractStruct(op.Value as Cci.INamedTypeDefinition, sourceLocationProvider); + var instruction = new StoreIndirectInstruction(op.Offset, type); + return instruction; + } + + private IInstruction ProcessStoreField(Cci.IOperation op) { var cciField = op.Value as Cci.IFieldReference; var ourField = typeExtractor.ExtractReference(cciField); @@ -751,7 +803,12 @@ private IInstruction ProcessStoreField(Cci.IOperation op) var instruction = new StoreFieldInstruction(op.Offset, ourField); return instruction; } - + private IInstruction ProcessInitObj(Cci.IOperation op) + { + var type = typeExtractor.ExtractType(op.Value as Cci.ITypeReference); + var instruction = new InitObjInstruction(op.Offset, type); + return instruction; + } private IInstruction ProcessBasic(Cci.IOperation op) { var operation = OperationHelper.ToBasicOperation(op.OperationCode); diff --git a/CCIProvider/OperationHelper.cs b/CCIProvider/OperationHelper.cs index 22dfb724..81ae5521 100644 --- a/CCIProvider/OperationHelper.cs +++ b/CCIProvider/OperationHelper.cs @@ -52,54 +52,10 @@ public static BasicOperation ToBasicOperation(Cci.OperationCode opcode) case Cci.OperationCode.Dup: return BasicOperation.Dup; case Cci.OperationCode.Localloc: return BasicOperation.LocalAllocation; case Cci.OperationCode.Initblk: return BasicOperation.InitBlock; - case Cci.OperationCode.Initobj: return BasicOperation.InitObject; case Cci.OperationCode.Cpblk: return BasicOperation.CopyBlock; case Cci.OperationCode.Cpobj: return BasicOperation.CopyObject; case Cci.OperationCode.Ret: return BasicOperation.Return; case Cci.OperationCode.Ldlen: return BasicOperation.LoadArrayLength; - case Cci.OperationCode.Ldind_I: - case Cci.OperationCode.Ldind_I1: - case Cci.OperationCode.Ldind_I2: - case Cci.OperationCode.Ldind_I4: - case Cci.OperationCode.Ldind_I8: - case Cci.OperationCode.Ldind_R4: - case Cci.OperationCode.Ldind_R8: - case Cci.OperationCode.Ldind_Ref: - case Cci.OperationCode.Ldind_U1: - case Cci.OperationCode.Ldind_U2: - case Cci.OperationCode.Ldind_U4: - case Cci.OperationCode.Ldobj: return BasicOperation.IndirectLoad; - case Cci.OperationCode.Ldelem: - case Cci.OperationCode.Ldelem_I: - case Cci.OperationCode.Ldelem_I1: - case Cci.OperationCode.Ldelem_I2: - case Cci.OperationCode.Ldelem_I4: - case Cci.OperationCode.Ldelem_I8: - case Cci.OperationCode.Ldelem_R4: - case Cci.OperationCode.Ldelem_R8: - case Cci.OperationCode.Ldelem_U1: - case Cci.OperationCode.Ldelem_U2: - case Cci.OperationCode.Ldelem_U4: - case Cci.OperationCode.Ldelem_Ref: return BasicOperation.LoadArrayElement; - case Cci.OperationCode.Ldelema: return BasicOperation.LoadArrayElementAddress; - case Cci.OperationCode.Stind_I: - case Cci.OperationCode.Stind_I1: - case Cci.OperationCode.Stind_I2: - case Cci.OperationCode.Stind_I4: - case Cci.OperationCode.Stind_I8: - case Cci.OperationCode.Stind_R4: - case Cci.OperationCode.Stind_R8: - case Cci.OperationCode.Stind_Ref: - case Cci.OperationCode.Stobj: return BasicOperation.IndirectStore; - case Cci.OperationCode.Stelem: - case Cci.OperationCode.Stelem_I: - case Cci.OperationCode.Stelem_I1: - case Cci.OperationCode.Stelem_I2: - case Cci.OperationCode.Stelem_I4: - case Cci.OperationCode.Stelem_I8: - case Cci.OperationCode.Stelem_R4: - case Cci.OperationCode.Stelem_R8: - case Cci.OperationCode.Stelem_Ref: return BasicOperation.StoreArrayElement; case Cci.OperationCode.Break: return BasicOperation.Breakpoint; default: throw opcode.ToUnknownValueException(); @@ -109,9 +65,9 @@ public static BasicOperation ToBasicOperation(Cci.OperationCode opcode) public static ConvertOperation ToConvertOperation(Cci.OperationCode opcode) { switch (opcode) - { - case Cci.OperationCode.Castclass: - case Cci.OperationCode.Isinst: return ConvertOperation.Cast; + { + case Cci.OperationCode.Isinst: return ConvertOperation.IsInst; + case Cci.OperationCode.Castclass: return ConvertOperation.Cast; case Cci.OperationCode.Box: return ConvertOperation.Box; case Cci.OperationCode.Unbox: return ConvertOperation.UnboxPtr; case Cci.OperationCode.Unbox_Any: return ConvertOperation.Unbox; @@ -304,28 +260,32 @@ public static object GetOperationConstant(Cci.IOperation op) } public static IType GetOperationType(Cci.OperationCode opcode) - { + { switch (opcode) { - case Cci.OperationCode.Ldind_I: + case Cci.OperationCode.Ldelem_I: + case Cci.OperationCode.Ldind_I: case Cci.OperationCode.Stind_I: case Cci.OperationCode.Stelem_I: case Cci.OperationCode.Conv_I: case Cci.OperationCode.Conv_Ovf_I: case Cci.OperationCode.Conv_Ovf_I_Un: return PlatformTypes.IntPtr; - case Cci.OperationCode.Ldind_I1: + case Cci.OperationCode.Ldelem_I1: + case Cci.OperationCode.Ldind_I1: case Cci.OperationCode.Stind_I1: case Cci.OperationCode.Stelem_I1: case Cci.OperationCode.Conv_I1: case Cci.OperationCode.Conv_Ovf_I1: case Cci.OperationCode.Conv_Ovf_I1_Un: return PlatformTypes.Int8; - case Cci.OperationCode.Ldind_I2: + case Cci.OperationCode.Ldelem_I2: + case Cci.OperationCode.Ldind_I2: case Cci.OperationCode.Stind_I2: case Cci.OperationCode.Stelem_I2: case Cci.OperationCode.Conv_I2: case Cci.OperationCode.Conv_Ovf_I2: case Cci.OperationCode.Conv_Ovf_I2_Un: return PlatformTypes.Int16; - case Cci.OperationCode.Ldc_I4: + case Cci.OperationCode.Ldelem_I4: + case Cci.OperationCode.Ldc_I4: case Cci.OperationCode.Ldc_I4_0: case Cci.OperationCode.Ldc_I4_1: case Cci.OperationCode.Ldc_I4_2: @@ -343,7 +303,8 @@ public static IType GetOperationType(Cci.OperationCode opcode) case Cci.OperationCode.Conv_I4: case Cci.OperationCode.Conv_Ovf_I4: case Cci.OperationCode.Conv_Ovf_I4_Un: return PlatformTypes.Int32; - case Cci.OperationCode.Ldc_I8: + case Cci.OperationCode.Ldelem_I8: + case Cci.OperationCode.Ldc_I8: case Cci.OperationCode.Ldind_I8: case Cci.OperationCode.Stind_I8: case Cci.OperationCode.Stelem_I8: @@ -354,15 +315,18 @@ public static IType GetOperationType(Cci.OperationCode opcode) case Cci.OperationCode.Conv_Ovf_U: case Cci.OperationCode.Conv_Ovf_U_Un: case Cci.OperationCode.Ldlen: return PlatformTypes.UIntPtr; - case Cci.OperationCode.Ldind_U1: + case Cci.OperationCode.Ldelem_U1: + case Cci.OperationCode.Ldind_U1: case Cci.OperationCode.Conv_U1: case Cci.OperationCode.Conv_Ovf_U1: case Cci.OperationCode.Conv_Ovf_U1_Un: return PlatformTypes.UInt8; - case Cci.OperationCode.Ldind_U2: + case Cci.OperationCode.Ldelem_U2: + case Cci.OperationCode.Ldind_U2: case Cci.OperationCode.Conv_U2: case Cci.OperationCode.Conv_Ovf_U2: case Cci.OperationCode.Conv_Ovf_U2_Un: return PlatformTypes.UInt16; - case Cci.OperationCode.Ldind_U4: + case Cci.OperationCode.Ldelem_U4: + case Cci.OperationCode.Ldind_U4: case Cci.OperationCode.Conv_U4: case Cci.OperationCode.Conv_Ovf_U4: case Cci.OperationCode.Conv_Ovf_U4_Un: @@ -370,18 +334,23 @@ public static IType GetOperationType(Cci.OperationCode opcode) case Cci.OperationCode.Conv_U8: case Cci.OperationCode.Conv_Ovf_U8: case Cci.OperationCode.Conv_Ovf_U8_Un: return PlatformTypes.UInt64; - case Cci.OperationCode.Ldc_R4: + case Cci.OperationCode.Ldelem_R4: + case Cci.OperationCode.Ldc_R4: case Cci.OperationCode.Ldind_R4: case Cci.OperationCode.Stind_R4: case Cci.OperationCode.Stelem_R4: case Cci.OperationCode.Conv_R4: return PlatformTypes.Float32; - case Cci.OperationCode.Ldc_R8: + case Cci.OperationCode.Ldelem_R8: + case Cci.OperationCode.Ldc_R8: case Cci.OperationCode.Ldind_R8: case Cci.OperationCode.Stind_R8: case Cci.OperationCode.Stelem_R8: case Cci.OperationCode.Conv_R8: case Cci.OperationCode.Conv_R_Un: return PlatformTypes.Float64; - case Cci.OperationCode.Ldnull: return PlatformTypes.Object; + case Cci.OperationCode.Ldelem_Ref: + case Cci.OperationCode.Stind_Ref: + case Cci.OperationCode.Ldind_Ref: + case Cci.OperationCode.Ldnull: return PlatformTypes.Object; case Cci.OperationCode.Ldstr: return PlatformTypes.String; default: return null; diff --git a/CCIProvider/TypeExtractor.cs b/CCIProvider/TypeExtractor.cs index 19e64dda..b6a4869f 100644 --- a/CCIProvider/TypeExtractor.cs +++ b/CCIProvider/TypeExtractor.cs @@ -810,7 +810,22 @@ private void ExtractGenericTypeParameters(IGenericDefinition definingType, Cci.I var index = (ushort)i; var name = parameterdef.Name.Value; var typeKind = GetGenericParameterTypeKind(parameterdef); - var parameter = new GenericParameter(GenericParameterKind.Type, index, name, typeKind); + var variance = GenericParameterVariance.NONE; + switch (parameterdef.Variance) + { + case Cci.TypeParameterVariance.Contravariant: + variance = GenericParameterVariance.CONTRAVARIANT; + break; + case Cci.TypeParameterVariance.Covariant: + variance = GenericParameterVariance.COVARIANT; + break; + } + + var parameter = new GenericParameter(GenericParameterKind.Type, index, name, typeKind) + { + Variance = variance, + DefaultConstructorConstraint = parameterdef.MustHaveDefaultConstructor + }; ExtractAttributes(parameter.Attributes, parameterdef.Attributes); @@ -818,7 +833,8 @@ private void ExtractGenericTypeParameters(IGenericDefinition definingType, Cci.I definingType.GenericParameters.Add(parameter); defGenericContext.TypeParameters.Add(parameter); - } + parameter.Constraints.AddRange(parameterdef.Constraints.Select(cciTypeRef => ExtractType(cciTypeRef))); + } } private static IList GetAllGenericTypeParameters(Cci.ITypeDefinition typedef) @@ -972,7 +988,7 @@ private void ExtractParameters(IList dest, IEnumerable Debug - x86 + AnyCPU 8.0.30703 2.0 {C836D6AD-2A48-4FFF-A958-023C48A65478} @@ -65,6 +65,10 @@ {f08216ad-e55c-44b1-a253-ab8b024b7597} Model + + {D5B2B96D-DB11-4618-B820-F0FCD82F9FD3} + MetadataGenerator +