From 46a669db4a47570b24645b22357ddacecbf3161b Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 8 Jun 2019 16:08:26 -0300 Subject: [PATCH 001/256] draft --- .gitignore | 3 +- Backend/Backend.csproj | 1 + Backend/Transformations/Assembler.cs | 17 + CCI Backend.sln | 28 + Console/Console.csproj | 6 +- Console/Program.cs | 761 +++++++++++---------- Examples/ExampleClass.cs | 36 + Examples/Examples.csproj | 37 + Examples/Properties/AssemblyInfo.cs | 26 + MetadataGenerator/Generator.cs | 227 ++++++ MetadataGenerator/MetadataGenerator.csproj | 46 ++ MetadataGenerator/packages.config | 5 + MetadataProvider/MetadataProvider.csproj | 2 +- Model/IGenerator.cs | 7 + Model/Model.csproj | 1 + 15 files changed, 831 insertions(+), 372 deletions(-) create mode 100644 Backend/Transformations/Assembler.cs create mode 100644 Examples/ExampleClass.cs create mode 100644 Examples/Examples.csproj create mode 100644 Examples/Properties/AssemblyInfo.cs create mode 100644 MetadataGenerator/Generator.cs create mode 100644 MetadataGenerator/MetadataGenerator.csproj create mode 100644 MetadataGenerator/packages.config create mode 100644 Model/IGenerator.cs diff --git a/.gitignore b/.gitignore index 19474da5..b6bf094e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ bin obj .vs -/packages \ No newline at end of file +/packages +.DS_Store diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj index 4cf55d5c..a96e42d4 100644 --- a/Backend/Backend.csproj +++ b/Backend/Backend.csproj @@ -79,6 +79,7 @@ + diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs new file mode 100644 index 00000000..29c9e9c7 --- /dev/null +++ b/Backend/Transformations/Assembler.cs @@ -0,0 +1,17 @@ +using System; +using Model.Types; +namespace Backend.Transformations +{ + // Responsible for converting three address code to simplified bytecode + public class Assembler + { + public Assembler() + { + } + // TODO extract interface for assembler and disassembler?? SSA? + public MethodBody Execute() + { + throw new NotImplementedException(); + } + } +} diff --git a/CCI Backend.sln b/CCI Backend.sln index 0ffa6e87..b9e06e23 100644 --- a/CCI Backend.sln +++ b/CCI Backend.sln @@ -18,6 +18,10 @@ 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 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -92,6 +96,30 @@ 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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Console/Console.csproj b/Console/Console.csproj index 526b84c2..5c97e82e 100644 --- a/Console/Console.csproj +++ b/Console/Console.csproj @@ -2,7 +2,7 @@ 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 + Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos + + + /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. + /// If no type defines any fields in the module, (1). + + + methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); + //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos + + /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. + /// If no type defines any methods in the module, (1). + + + } } var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); @@ -165,6 +164,88 @@ public void Generate(Assembly assembly) } + private static TypeAttributes EnumTypeAttributesFor(Model.Types.TypeDefinition typeDefinition) + { + return TypeAttributes.Class | + (Model.Types.VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic) | + TypeAttributes.Sealed; + } + + private static TypeAttributes ClassTypeAttributesFor(Model.Types.TypeDefinition typeDefinition) + { + return TypeAttributes.Class | + TypeAttributes.BeforeFieldInit | + (Model.Types.VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); + } + + private MethodDefinitionHandle generateMethod(MetadataBuilder metadata, ref MethodBodyStreamEncoder methodBodyStream, Model.Types.MethodDefinition method) + { + var methodSignature = new BlobBuilder(); + new BlobEncoder(methodSignature). + MethodSignature(). + Parameters( + method.Parameters.Count, + returnType => + { + if (method.ReturnType.Equals(Model.Types.PlatformTypes.Void)) + { + returnType.Void(); + } + else + { + EncodeType(method.ReturnType, returnType.Type()); + } + + }, + parameters => + { + foreach (var parameter in method.Parameters) + { + EncodeType(parameter.Type, parameters.AddParameter().Type()); + } + + }); + + var instructions = new InstructionEncoder(new BlobBuilder()); + + instructions.OpCode(ILOpCode.Nop); + instructions.OpCode(ILOpCode.Ret); + + var methodAttributes = + (method.IsAbstract ? MethodAttributes.Abstract : 0) | + (method.IsStatic ? MethodAttributes.Static : 0) | + (method.IsVirtual ? MethodAttributes.Virtual : 0) | + // (method.IsExternal ? MethodAttributes.) | // FIXME + (method.IsConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | + MethodAttributes.HideBySig; + + switch (method.Visibility) + { + case Model.Types.VisibilityKind.Public: + methodAttributes |= MethodAttributes.Public; + break; + case Model.Types.VisibilityKind.Private: + methodAttributes |= MethodAttributes.Private; + break; + case Model.Types.VisibilityKind.Protected: + methodAttributes |= MethodAttributes.Family; + break; + case Model.Types.VisibilityKind.Internal: + methodAttributes |= MethodAttributes.Assembly; + break; + default: + throw method.Visibility.ToUnknownValueException(); + } + + return metadata.AddMethodDefinition( + attributes: methodAttributes, + implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME + name: metadata.GetOrAddString(method.Name), + signature: metadata.GetOrAddBlob(methodSignature), + bodyOffset: methodBodyStream.AddMethodBody(instructions), + parameterList: default(ParameterHandle)); //FIXME + } + //FIXME: names, type of parameters private void EncodeType(Model.Types.IType returnType, SignatureTypeEncoder signatureTypeEncoder) { @@ -183,6 +264,7 @@ private void EncodeType(Model.Types.IType returnType, SignatureTypeEncoder signa //} //FIXME incomplete + if (returnType.Equals(Model.Types.PlatformTypes.Boolean)) { signatureTypeEncoder.Boolean(); @@ -216,9 +298,13 @@ private void EncodeType(Model.Types.IType returnType, SignatureTypeEncoder signa { signatureTypeEncoder.String(); } + else if (returnType.Equals(Model.Types.PlatformTypes.Single)) + { + signatureTypeEncoder.Single(); + } else { - throw signatureTypeEncoder.ToUnknownValueException(); + throw new Exception("Unknown value:" + returnType.ToString()); } } From 9d1376e16103c203e7a7c22d0079b70f7ee757b7 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 15 Jun 2019 18:02:54 -0300 Subject: [PATCH 003/256] Better enum generation --- Examples/Examples.cs | 4 +- MetadataGenerator/Generator.cs | 75 ++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index dc0d0679..c8bd19e0 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -3,8 +3,8 @@ public enum AtTheBeginingEnum { - CONSTANT1, - CONSTANT2 + CONSTANT1 = 10, + CONSTANT2 = 12 } public class EmptyClass diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 90509d18..5130abba 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -55,7 +55,7 @@ public void Generate(Assembly assembly) var systemEnumTypeRef = metadata.AddTypeReference( resolutionScope: mscorlibAssemblyRef, @namespace: metadata.GetOrAddString("System"), - name: metadata.GetOrAddString("enum")); //FIXME ->> es "Enum" pero rompe + name: metadata.GetOrAddString("Enum")); var ilBuilder = new BlobBuilder(); var methodBodyStream = new MethodBodyStreamEncoder(ilBuilder); @@ -65,10 +65,8 @@ public void Generate(Assembly assembly) { foreach (var typeDefinition in namezpace.Types) { - TypeAttributes typeAttributes; MethodDefinitionHandle? firstMethodHandle = null; FieldDefinitionHandle? firstFieldHandle = null; - EntityHandle baseType; if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Class)) { @@ -83,14 +81,24 @@ public void Generate(Assembly assembly) } metadataTokensMethodsOffset += typeDefinition.Methods.Count; - typeAttributes = ClassTypeAttributesFor(typeDefinition); - baseType = systemObjectTypeRef; + + metadata.AddTypeDefinition( + attributes: ClassTypeAttributesFor(typeDefinition), + @namespace: metadata.GetOrAddString(namezpace.Name), + name: metadata.GetOrAddString(typeDefinition.Name), + baseType: systemObjectTypeRef, //FIXME podria ser una subclase de otra cosa + fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), + //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos + /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. + /// If no type defines any fields in the module, (1). + methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); + //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos + /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. + /// If no type defines any methods in the module, (1). + } else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Enum)) { - typeAttributes = EnumTypeAttributesFor(typeDefinition); - baseType = systemEnumTypeRef; - var fieldSignatureBlobBuilder = new BlobBuilder(); new BlobEncoder(fieldSignatureBlobBuilder) .FieldSignature() @@ -100,23 +108,39 @@ public void Generate(Assembly assembly) firstFieldHandle = metadata.AddFieldDefinition( attributes: FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName, - name: metadata.GetOrAddString("value_"), + name: metadata.GetOrAddString("value__"), signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); + var selfTypeDefinitionHandle = metadata.AddTypeDefinition( + attributes: EnumTypeAttributesFor(typeDefinition), + @namespace: metadata.GetOrAddString(namezpace.Name), + name: metadata.GetOrAddString(typeDefinition.Name), + baseType: systemEnumTypeRef, + fieldList: firstFieldHandle.Value, + //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos + /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. + /// If no type defines any fields in the module, (1). + methodList: MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); + //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos + /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. + /// If no type defines any methods in the module, (1). + typeDefinition.Fields - .Where(field => !field.Name.Equals("value_")) + .Where(field => !field.Name.Equals("value__")) .ToList() .ForEach(field => { fieldSignatureBlobBuilder.Clear(); new BlobEncoder(fieldSignatureBlobBuilder) .FieldSignature() - .Int32(); //FIXME hay que sacarlo del field.type + .Type(selfTypeDefinitionHandle, true); - var fieldDefinitionHandle = metadata.AddFieldDefinition( - attributes: FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal, - name: metadata.GetOrAddString(field.Name), - signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); + metadata.AddConstant( + metadata.AddFieldDefinition( + attributes: FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal, + name: metadata.GetOrAddString(field.Name), + signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)), + field.Value.Value); metadataTokensFieldsOffset++; }); @@ -126,27 +150,6 @@ public void Generate(Assembly assembly) throw new Exception(); } - metadata.AddTypeDefinition( - attributes: typeAttributes, - @namespace: metadata.GetOrAddString(namezpace.Name), - name: metadata.GetOrAddString(typeDefinition.Name), - baseType: baseType, - fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), - //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos - - - /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. - /// If no type defines any fields in the module, (1). - - - methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); - //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos - - /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. - /// If no type defines any methods in the module, (1). - - - } } var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); From 3e7c34fd0c856f09c03d0caab1c315c92e11f398 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 16 Jun 2019 11:33:19 -0300 Subject: [PATCH 004/256] Support for enum of different types --- Examples/Examples.cs | 22 ++++++++-------- MetadataGenerator/Generator.cs | 47 ++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index c8bd19e0..06919324 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -3,18 +3,18 @@ public enum AtTheBeginingEnum { - CONSTANT1 = 10, - CONSTANT2 = 12 + CONSTANT1, + CONSTANT2 } public class EmptyClass { } - public enum AtTheMiddleEnum + public enum AtTheMiddleEnumOfBytes : byte { - CONSTANT1, - CONSTANT2 + CONSTANT1 = 10, + CONSTANT2 = 20 } public class ClassWithMethods @@ -43,10 +43,10 @@ float ReturnAFloat(float arg) } - public enum AtTheEndEnum + public enum AtTheEndEnumOfUShorts : ushort { - CONSTANT1, - CONSTANT2 + CONSTANT1 = 1, + CONSTANT2 = 2 } @@ -54,10 +54,10 @@ public enum AtTheEndEnum namespace SecondNamespace { - public enum AnotheEnum + public enum EnumOfLongValues : long { - CONSTANT1, - CONSTANT2 + CONSTANT = 2L, + CONSTANT2 = 50L } public class AnotherClassWithMethods diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 5130abba..888f0d05 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -100,9 +100,10 @@ public void Generate(Assembly assembly) else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Enum)) { var fieldSignatureBlobBuilder = new BlobBuilder(); - new BlobEncoder(fieldSignatureBlobBuilder) - .FieldSignature() - .Int32(); //FIXME hay que sacarlo del field.type + EncodeType( + typeDefinition.Fields.First().Type, + new BlobEncoder(fieldSignatureBlobBuilder) + .FieldSignature()); metadataTokensFieldsOffset++; @@ -250,7 +251,7 @@ private MethodDefinitionHandle generateMethod(MetadataBuilder metadata, ref Meth } //FIXME: names, type of parameters - private void EncodeType(Model.Types.IType returnType, SignatureTypeEncoder signatureTypeEncoder) + private void EncodeType(Model.Types.IType type, SignatureTypeEncoder signatureTypeEncoder) { // reflection? FIXME @@ -267,47 +268,61 @@ private void EncodeType(Model.Types.IType returnType, SignatureTypeEncoder signa //} //FIXME incomplete - - if (returnType.Equals(Model.Types.PlatformTypes.Boolean)) + if (type.Equals(Model.Types.PlatformTypes.Boolean)) { signatureTypeEncoder.Boolean(); } - else if (returnType.Equals(Model.Types.PlatformTypes.Byte)) + else if (type.Equals(Model.Types.PlatformTypes.Byte)) { signatureTypeEncoder.Byte(); } - else if (returnType.Equals(Model.Types.PlatformTypes.Char)) + else if (type.Equals(Model.Types.PlatformTypes.SByte)) + { + signatureTypeEncoder.SByte(); + } + else if (type.Equals(Model.Types.PlatformTypes.Char)) { signatureTypeEncoder.Char(); } - else if (returnType.Equals(Model.Types.PlatformTypes.Double)) + else if (type.Equals(Model.Types.PlatformTypes.Double)) { signatureTypeEncoder.Double(); } - else if (returnType.Equals(Model.Types.PlatformTypes.Int16)) + else if (type.Equals(Model.Types.PlatformTypes.Int16)) { signatureTypeEncoder.Int16(); } - else if (returnType.Equals(Model.Types.PlatformTypes.Int32)) + else if (type.Equals(Model.Types.PlatformTypes.UInt16)) + { + signatureTypeEncoder.UInt16(); + } + else if (type.Equals(Model.Types.PlatformTypes.Int32)) { signatureTypeEncoder.Int32(); } - else if (returnType.Equals(Model.Types.PlatformTypes.Int64)) + else if (type.Equals(Model.Types.PlatformTypes.UInt32)) + { + signatureTypeEncoder.UInt32(); + } + else if (type.Equals(Model.Types.PlatformTypes.Int64)) { signatureTypeEncoder.Int64(); } - - else if (returnType.Equals(Model.Types.PlatformTypes.String)) + else if (type.Equals(Model.Types.PlatformTypes.UInt64)) + { + signatureTypeEncoder.UInt64(); + } + else if (type.Equals(Model.Types.PlatformTypes.String)) { signatureTypeEncoder.String(); } - else if (returnType.Equals(Model.Types.PlatformTypes.Single)) + else if (type.Equals(Model.Types.PlatformTypes.Single)) { signatureTypeEncoder.Single(); } else { - throw new Exception("Unknown value:" + returnType.ToString()); + throw new Exception("Unknown value:" + type.ToString()); } } From 131e3e83ee61001c5eb14c806890e4b81dc96512 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 16 Jun 2019 19:43:30 -0300 Subject: [PATCH 005/256] Partial support for interfaces --- Examples/Examples.cs | 30 +++++++++++++++++++++--- MetadataGenerator/Generator.cs | 42 ++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 06919324..85e48283 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -60,14 +60,38 @@ public enum EnumOfLongValues : long CONSTANT2 = 50L } - public class AnotherClassWithMethods + public class ClassImplementingInterface : ISampleInterface { + public int Prop + { + get + { + return Prop; + } + set + { + this.Prop = value; + } + } - public string Hello() + public void DoSomething() { - return "Hello"; } } + public interface ISampleInterface + { + + void DoSomething(); + + int Prop + { + get; + set; + } + + + } + } \ No newline at end of file diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 888f0d05..52164b1e 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -72,7 +72,7 @@ public void Generate(Assembly assembly) foreach (var method in typeDefinition.Methods) { - var methodHandle = generateMethod(metadata, ref methodBodyStream, method); + var methodHandle = GenerateMethod(metadata, ref methodBodyStream, method); if (!firstMethodHandle.HasValue) { firstMethodHandle = methodHandle; @@ -146,9 +146,35 @@ public void Generate(Assembly assembly) metadataTokensFieldsOffset++; }); } - else + else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Interface)) { - throw new Exception(); + + + foreach (var method in typeDefinition.Methods) + { + var methodHandle = GenerateMethod(metadata, ref methodBodyStream, method); + if (!firstMethodHandle.HasValue) + { + firstMethodHandle = methodHandle; + } + } + + metadataTokensMethodsOffset += typeDefinition.Methods.Count; + + metadata.AddTypeDefinition( + attributes: InterfaceTypeAttributesFor(typeDefinition), + @namespace: metadata.GetOrAddString(namezpace.Name), + name: metadata.GetOrAddString(typeDefinition.Name), + baseType: default(EntityHandle), + fieldList: default(FieldDefinitionHandle), //FIXME props + //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos + /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. + /// If no type defines any fields in the module, (1). + methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); + //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos + /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. + /// If no type defines any methods in the module, (1). + } } @@ -182,7 +208,12 @@ private static TypeAttributes ClassTypeAttributesFor(Model.Types.TypeDefinition (Model.Types.VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); } - private MethodDefinitionHandle generateMethod(MetadataBuilder metadata, ref MethodBodyStreamEncoder methodBodyStream, Model.Types.MethodDefinition method) + private static TypeAttributes InterfaceTypeAttributesFor(Model.Types.TypeDefinition typeDefinition) + { + return TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; + } + + private MethodDefinitionHandle GenerateMethod(MetadataBuilder metadata, ref MethodBodyStreamEncoder methodBodyStream, Model.Types.MethodDefinition method) { var methodSignature = new BlobBuilder(); new BlobEncoder(methodSignature). @@ -219,8 +250,9 @@ private MethodDefinitionHandle generateMethod(MetadataBuilder metadata, ref Meth (method.IsAbstract ? MethodAttributes.Abstract : 0) | (method.IsStatic ? MethodAttributes.Static : 0) | (method.IsVirtual ? MethodAttributes.Virtual : 0) | - // (method.IsExternal ? MethodAttributes.) | // FIXME + // MethodAttributes.NewSlot | FIXME how to know? needed for interface method at least (method.IsConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | + (method.Name.Equals("get_Prop") || method.Name.Equals("set_Prop") ? MethodAttributes.SpecialName : 0) | //FIXME MethodAttributes.HideBySig; switch (method.Visibility) From 61dbca5437dcc561cd45868b1c3f62b3e1ca070d Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 17 Jun 2019 16:55:17 -0300 Subject: [PATCH 006/256] instance methods --- MetadataGenerator/Generator.cs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 52164b1e..29260942 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -101,7 +101,7 @@ public void Generate(Assembly assembly) { var fieldSignatureBlobBuilder = new BlobBuilder(); EncodeType( - typeDefinition.Fields.First().Type, + typeDefinition.Fields.First().Type, //FIXME first if empty new BlobEncoder(fieldSignatureBlobBuilder) .FieldSignature()); @@ -155,12 +155,32 @@ public void Generate(Assembly assembly) var methodHandle = GenerateMethod(metadata, ref methodBodyStream, method); if (!firstMethodHandle.HasValue) { + firstMethodHandle = methodHandle; } } metadataTokensMethodsOffset += typeDefinition.Methods.Count; + /* //FIXME properties + var propertySignatureBlogBuilder = new BlobBuilder(); + new BlobEncoder(propertySignatureBlogBuilder) + .PropertySignature(isInstanceProperty: true) //FIXME when false? + .Parameters( + 0, + returnType => + { + returnType.Type().Int32(); + }, + parameters => + { + }); + + metadata.AddProperty( + attributes: PropertyAttributes.None, + name: metadata.GetOrAddString("get_Prop"), + signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); + */ metadata.AddTypeDefinition( attributes: InterfaceTypeAttributesFor(typeDefinition), @namespace: metadata.GetOrAddString(namezpace.Name), @@ -174,7 +194,6 @@ public void Generate(Assembly assembly) //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. /// If no type defines any methods in the module, (1). - } } @@ -216,9 +235,9 @@ private static TypeAttributes InterfaceTypeAttributesFor(Model.Types.TypeDefinit private MethodDefinitionHandle GenerateMethod(MetadataBuilder metadata, ref MethodBodyStreamEncoder methodBodyStream, Model.Types.MethodDefinition method) { var methodSignature = new BlobBuilder(); - new BlobEncoder(methodSignature). - MethodSignature(). - Parameters( + new BlobEncoder(methodSignature) + .MethodSignature(isInstanceMethod: true) //FIXME when false? + .Parameters( method.Parameters.Count, returnType => { From 55a7fb840cc0f5baae9e86ccab4a5505ab10dd99 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 17 Jun 2019 20:02:21 -0300 Subject: [PATCH 007/256] basic field generation for classes --- Examples/Examples.cs | 19 ++++++++------ MetadataGenerator/Generator.cs | 46 +++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 85e48283..67b4850b 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -13,12 +13,17 @@ public class EmptyClass public enum AtTheMiddleEnumOfBytes : byte { - CONSTANT1 = 10, - CONSTANT2 = 20 + Byte10 = 10, + Byte20 = 20 } - public class ClassWithMethods + public class ComplexClass { + + static readonly double staticDouble = 5.27; + private readonly int readOnlyIntField = 212; + public string unassignedString; + public void DoNothing() { } private int Sum(int arg1, int arg2) @@ -45,8 +50,8 @@ float ReturnAFloat(float arg) public enum AtTheEndEnumOfUShorts : ushort { - CONSTANT1 = 1, - CONSTANT2 = 2 + USHORT1 = 1, + USHORT2 = 2 } @@ -56,8 +61,8 @@ namespace SecondNamespace { public enum EnumOfLongValues : long { - CONSTANT = 2L, - CONSTANT2 = 50L + LONG2 = 2L, + LONG50 = 50L } public class ClassImplementingInterface : ISampleInterface diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 29260942..ed53f394 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -82,6 +82,51 @@ public void Generate(Assembly assembly) metadataTokensMethodsOffset += typeDefinition.Methods.Count; + // Field initial values are assigned either on ctor or cctor (if static) + typeDefinition.Fields //TODO extract method? duplicated code for enum + .ToList() + .ForEach(field => + { + var fieldSignatureBlobBuilder = new BlobBuilder(); + EncodeType( + field.Type, + new BlobEncoder(fieldSignatureBlobBuilder) + .FieldSignature()); + + var fieldAttributes = + (field.IsStatic ? FieldAttributes.Static : 0); + // (field is readonly ? FieldAttributes.InitOnly : 0); //FIXME how to know if readonly? + switch (field.Visibility) //TODO extract, duplicated + { + + case Model.Types.VisibilityKind.Public: + fieldAttributes |= FieldAttributes.Public; + break; + case Model.Types.VisibilityKind.Private: + fieldAttributes |= FieldAttributes.Private; + break; + case Model.Types.VisibilityKind.Protected: + fieldAttributes |= FieldAttributes.Family; + break; + case Model.Types.VisibilityKind.Internal: + fieldAttributes |= FieldAttributes.Assembly; + break; + default: + throw field.Visibility.ToUnknownValueException(); + } + var fieldDefinitionHandle = metadata.AddFieldDefinition( + attributes: fieldAttributes, + name: metadata.GetOrAddString(field.Name), + signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); + + if (!firstFieldHandle.HasValue) + { + firstFieldHandle = fieldDefinitionHandle; + } + + metadataTokensFieldsOffset++; + }); + metadata.AddTypeDefinition( attributes: ClassTypeAttributesFor(typeDefinition), @namespace: metadata.GetOrAddString(namezpace.Name), @@ -377,6 +422,5 @@ private void EncodeType(Model.Types.IType type, SignatureTypeEncoder signatureTy } } - } } \ No newline at end of file From 5846cb32539b1283e70b065c330b83a4c14f316e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 29 Jun 2019 16:22:19 -0300 Subject: [PATCH 008/256] property handling (commented) --- Examples/Examples.cs | 42 ++++++++++++++---------- MetadataGenerator/Generator.cs | 60 +++++++++++++++++++--------------- 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 67b4850b..726b5f97 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -7,6 +7,19 @@ public enum AtTheBeginingEnum CONSTANT2 } + public class ClassWithProperties + { + public double AutoImplementedProperty { get; set; } + public char AnotherAutoImplementedProperty { get; } + + public int PropertyWithBackingField { get => backingField; set => backingField = value; } + private int backingField; + + public string AnotherPropertyWithBackingField { get => otherBackingField; } + private string otherBackingField; + + } + public class EmptyClass { } @@ -28,6 +41,7 @@ public void DoNothing() { } private int Sum(int arg1, int arg2) { + return arg1 + arg2; } @@ -46,6 +60,16 @@ float ReturnAFloat(float arg) return arg; } + static void StaticMethod() { } + + } + + public abstract class AbstractClass + { + + public virtual void VirtualMethod() { } + + public abstract void AbstractMethod(); } public enum AtTheEndEnumOfUShorts : ushort @@ -67,18 +91,6 @@ public enum EnumOfLongValues : long public class ClassImplementingInterface : ISampleInterface { - public int Prop - { - get - { - return Prop; - } - set - { - this.Prop = value; - } - } - public void DoSomething() { } @@ -90,11 +102,7 @@ public interface ISampleInterface void DoSomething(); - int Prop - { - get; - set; - } + // todo properties } diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index ed53f394..5fb83d26 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -69,10 +69,37 @@ public void Generate(Assembly assembly) FieldDefinitionHandle? firstFieldHandle = null; if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Class)) { + //TODO metadata.AddInterfaceImplementation() if applies + //TODO metadata.AddNestedType() if applies + + /* TODO Properties: works but model is missing Property concept + var propertySignatureBlogBuilder = new BlobBuilder(); + new BlobEncoder(propertySignatureBlogBuilder) + .PropertySignature(isInstanceProperty: true) //FIXME when false + .Parameters( + 0, + returnType => returnType.Type().Int32(), //FIXME backingField type + parameters => { }); + + + var propertyDefinitionHandle = metadata.AddProperty( + attributes: PropertyAttributes.None, //FIXME + name: metadata.GetOrAddString(""), //FIXME property name + signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); + + // asociate methods (get, set) to property + metadata.AddMethodSemantics( + propertyDefinitionHandle, + method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, + methodHandle); //getter/setter + metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); + + */ foreach (var method in typeDefinition.Methods) { var methodHandle = GenerateMethod(metadata, ref methodBodyStream, method); + if (!firstMethodHandle.HasValue) { firstMethodHandle = methodHandle; @@ -127,7 +154,7 @@ public void Generate(Assembly assembly) metadataTokensFieldsOffset++; }); - metadata.AddTypeDefinition( + var typeDefinitionHandle = metadata.AddTypeDefinition( attributes: ClassTypeAttributesFor(typeDefinition), @namespace: metadata.GetOrAddString(namezpace.Name), name: metadata.GetOrAddString(typeDefinition.Name), @@ -139,7 +166,7 @@ public void Generate(Assembly assembly) methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. - /// If no type defines any methods in the module, (1). + /// If no type defines any methods in the module, (1) } else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Enum)) @@ -193,6 +220,7 @@ public void Generate(Assembly assembly) } else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Interface)) { + //TODO properties foreach (var method in typeDefinition.Methods) @@ -207,25 +235,6 @@ public void Generate(Assembly assembly) metadataTokensMethodsOffset += typeDefinition.Methods.Count; - /* //FIXME properties - var propertySignatureBlogBuilder = new BlobBuilder(); - new BlobEncoder(propertySignatureBlogBuilder) - .PropertySignature(isInstanceProperty: true) //FIXME when false? - .Parameters( - 0, - returnType => - { - returnType.Type().Int32(); - }, - parameters => - { - }); - - metadata.AddProperty( - attributes: PropertyAttributes.None, - name: metadata.GetOrAddString("get_Prop"), - signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); - */ metadata.AddTypeDefinition( attributes: InterfaceTypeAttributesFor(typeDefinition), @namespace: metadata.GetOrAddString(namezpace.Name), @@ -238,7 +247,7 @@ public void Generate(Assembly assembly) methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. - /// If no type defines any methods in the module, (1). + /// If no type defines any methods in the module, (1) } } @@ -281,7 +290,7 @@ private MethodDefinitionHandle GenerateMethod(MetadataBuilder metadata, ref Meth { var methodSignature = new BlobBuilder(); new BlobEncoder(methodSignature) - .MethodSignature(isInstanceMethod: true) //FIXME when false? + .MethodSignature(isInstanceMethod: !method.IsStatic) //FIXME ? .Parameters( method.Parameters.Count, returnType => @@ -302,7 +311,6 @@ private MethodDefinitionHandle GenerateMethod(MetadataBuilder metadata, ref Meth { EncodeType(parameter.Type, parameters.AddParameter().Type()); } - }); var instructions = new InstructionEncoder(new BlobBuilder()); @@ -314,9 +322,9 @@ private MethodDefinitionHandle GenerateMethod(MetadataBuilder metadata, ref Meth (method.IsAbstract ? MethodAttributes.Abstract : 0) | (method.IsStatic ? MethodAttributes.Static : 0) | (method.IsVirtual ? MethodAttributes.Virtual : 0) | - // MethodAttributes.NewSlot | FIXME how to know? needed for interface method at least + (method.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Interface) ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct (method.IsConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | - (method.Name.Equals("get_Prop") || method.Name.Equals("set_Prop") ? MethodAttributes.SpecialName : 0) | //FIXME + (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0) | //FIXME MethodAttributes.HideBySig; switch (method.Visibility) From 49d4ac210000921a82516947b2fa6ace8012b28c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 29 Jun 2019 18:31:58 -0300 Subject: [PATCH 009/256] add interface implementation --- Examples/Examples.cs | 2 +- MetadataGenerator/Generator.cs | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 726b5f97..a65c28f3 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -102,7 +102,7 @@ public interface ISampleInterface void DoSomething(); - // todo properties + // todo interface can have properties } diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 5fb83d26..ba7162c5 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -69,7 +69,6 @@ public void Generate(Assembly assembly) FieldDefinitionHandle? firstFieldHandle = null; if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Class)) { - //TODO metadata.AddInterfaceImplementation() if applies //TODO metadata.AddNestedType() if applies /* TODO Properties: works but model is missing Property concept @@ -81,7 +80,6 @@ public void Generate(Assembly assembly) returnType => returnType.Type().Int32(), //FIXME backingField type parameters => { }); - var propertyDefinitionHandle = metadata.AddProperty( attributes: PropertyAttributes.None, //FIXME name: metadata.GetOrAddString(""), //FIXME property name @@ -168,6 +166,19 @@ public void Generate(Assembly assembly) /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. /// If no type defines any methods in the module, (1) + + foreach (var interfaze in typeDefinition.Interfaces) + { + metadata.AddInterfaceImplementation( + type: typeDefinitionHandle, + implementedInterface: metadata.AddTypeReference( //FIXME multiple classes could implement same interface + //FIXME so should addTypeReference only once. check MetadataTokens for reference? + resolutionScope: default(TypeReferenceHandle), + @namespace: metadata.GetOrAddString(interfaze.ContainingNamespace), + name: metadata.GetOrAddString(interfaze.Name))); + } + + } else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Enum)) { @@ -240,10 +251,10 @@ public void Generate(Assembly assembly) @namespace: metadata.GetOrAddString(namezpace.Name), name: metadata.GetOrAddString(typeDefinition.Name), baseType: default(EntityHandle), - fieldList: default(FieldDefinitionHandle), //FIXME props - //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos - /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. - /// If no type defines any fields in the module, (1). + fieldList: default(FieldDefinitionHandle), + //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos + /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. + /// If no type defines any fields in the module, (1). methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. From effbcb702c9549433d2c2a7e51bfe2f7c9bee7bc Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 7 Jul 2019 19:02:20 -0300 Subject: [PATCH 010/256] some fixes + basic inheritance generation --- Examples/Examples.cs | 40 ++++++++++++++++++++++-- Examples/Examples.csproj | 1 + MetadataGenerator/Generator.cs | 56 ++++++++++++++++++++-------------- 3 files changed, 71 insertions(+), 26 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index a65c28f3..294dafaa 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1,4 +1,6 @@ -namespace FirstNamespace +using System; + +namespace FirstNamespace { public enum AtTheBeginingEnum @@ -24,6 +26,17 @@ public class EmptyClass { } + public static class StaticClass + { + static readonly double StaticDouble; + + static StaticClass() + { + StaticDouble = 0.5; + } + + } + public enum AtTheMiddleEnumOfBytes : byte { Byte10 = 10, @@ -32,8 +45,6 @@ public enum AtTheMiddleEnumOfBytes : byte public class ComplexClass { - - static readonly double staticDouble = 5.27; private readonly int readOnlyIntField = 212; public string unassignedString; @@ -104,7 +115,30 @@ public interface ISampleInterface // todo interface can have properties + } + +} + +namespace ThirdNamespace +{ + public class BaseClass + { + } + + public class DerivedClass : BaseClass + { + + } + + + public class ClassDerivedFromSystemClass : Exception + { + + } + + public class ClassDerivedFromAccessibilityClass : Accessibility.CAccPropServicesClass + { } } \ No newline at end of file diff --git a/Examples/Examples.csproj b/Examples/Examples.csproj index dfa7ee5f..c452715f 100644 --- a/Examples/Examples.csproj +++ b/Examples/Examples.csproj @@ -28,6 +28,7 @@ + diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index ba7162c5..65bb670e 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; @@ -16,6 +17,7 @@ public class Generator : IGenerator private static readonly Guid s_guid = new Guid("97F4DBD4-F6D1-4FAD-91B3-1001F92068E5"); //FIXME: ?? private static readonly BlobContentId s_contentId = new BlobContentId(s_guid, 0x04030201); //FIXME: ?? + private IDictionary assemblyReferences = new Dictionary(); public void Generate(Assembly assembly) { @@ -32,6 +34,20 @@ public void Generate(Assembly assembly) flags: AssemblyFlags.PublicKey, // FIXME ?? hashAlgorithm: AssemblyHashAlgorithm.Sha1); // FIXME ?? + //FIXME see references in IlSpy generated vs original + //FIXME: assemblyName => assemblyRef could result in false positive? + foreach (var assemblyReference in assembly.References) + { + assemblyReferences.Add(assemblyReference.Name, metadata.AddAssemblyReference( + name: metadata.GetOrAddString(assemblyReference.Name), + version: new Version(4, 0, 0, 0), //FIXME ?? + culture: metadata.GetOrAddString("neutral"), //FIXME ?? + publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)),//FIXME ?? + flags: default(AssemblyFlags), //FIXME ?? + hashValue: default(BlobHandle))//FIXME ?? + ); + } + metadata.AddModule( generation: 0, // FIXME ?? moduleName: metadata.GetOrAddString($"{assembly.Name}.dll"), @@ -39,24 +55,6 @@ public void Generate(Assembly assembly) encId: default(GuidHandle), // FIXME ?? encBaseId: default(GuidHandle)); // FIXME ?? - var mscorlibAssemblyRef = metadata.AddAssemblyReference( - name: metadata.GetOrAddString("mscorlib"), - version: new Version(4, 0, 0, 0), //FIXME ?? - culture: default(StringHandle), //FIXME ?? - publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)),//FIXME ?? - flags: default(AssemblyFlags), //FIXME ?? - hashValue: default(BlobHandle));//FIXME ?? - - var systemObjectTypeRef = metadata.AddTypeReference( - resolutionScope: mscorlibAssemblyRef, - @namespace: metadata.GetOrAddString("System"), - name: metadata.GetOrAddString("Object")); - - var systemEnumTypeRef = metadata.AddTypeReference( - resolutionScope: mscorlibAssemblyRef, - @namespace: metadata.GetOrAddString("System"), - name: metadata.GetOrAddString("Enum")); - var ilBuilder = new BlobBuilder(); var methodBodyStream = new MethodBodyStreamEncoder(ilBuilder); var metadataTokensMethodsOffset = 1; @@ -156,7 +154,7 @@ public void Generate(Assembly assembly) attributes: ClassTypeAttributesFor(typeDefinition), @namespace: metadata.GetOrAddString(namezpace.Name), name: metadata.GetOrAddString(typeDefinition.Name), - baseType: systemObjectTypeRef, //FIXME podria ser una subclase de otra cosa + baseType: BaseType(assembly, metadata, typeDefinition), fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. @@ -199,7 +197,7 @@ public void Generate(Assembly assembly) attributes: EnumTypeAttributesFor(typeDefinition), @namespace: metadata.GetOrAddString(namezpace.Name), name: metadata.GetOrAddString(typeDefinition.Name), - baseType: systemEnumTypeRef, + baseType: BaseType(assembly, metadata, typeDefinition), fieldList: firstFieldHandle.Value, //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. @@ -278,6 +276,17 @@ public void Generate(Assembly assembly) } + //FIXME name + //FIXME: comparing to the name of the current assembly could result in a false positive? + //FIXME: this posibly adds the type reference more than once + private TypeReferenceHandle BaseType(Assembly assembly, MetadataBuilder metadata, Model.Types.TypeDefinition typeDefinition) + { + return metadata.AddTypeReference( + resolutionScope: typeDefinition.Base.ContainingAssembly.Name.Equals(assembly.Name) ? default(AssemblyReferenceHandle) : assemblyReferences[typeDefinition.Base.ContainingAssembly.Name], + @namespace: metadata.GetOrAddString(typeDefinition.Base.ContainingNamespace), + name: metadata.GetOrAddString(typeDefinition.Base.Name)); + } + private static TypeAttributes EnumTypeAttributesFor(Model.Types.TypeDefinition typeDefinition) { return TypeAttributes.Class | @@ -288,7 +297,8 @@ private static TypeAttributes EnumTypeAttributesFor(Model.Types.TypeDefinition t private static TypeAttributes ClassTypeAttributesFor(Model.Types.TypeDefinition typeDefinition) { return TypeAttributes.Class | - TypeAttributes.BeforeFieldInit | + //TODO: static => abstract & sealed and no BeforeFieldInitBeforeFieldInit + TypeAttributes.BeforeFieldInit | //FIXME: when? (Model.Types.VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); } @@ -334,9 +344,9 @@ private MethodDefinitionHandle GenerateMethod(MetadataBuilder metadata, ref Meth (method.IsStatic ? MethodAttributes.Static : 0) | (method.IsVirtual ? MethodAttributes.Virtual : 0) | (method.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Interface) ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct - (method.IsConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | + (method.IsConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | //FIXME should do the same for class constructor (cctor) (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0) | //FIXME - MethodAttributes.HideBySig; + MethodAttributes.HideBySig; //FIXME when? switch (method.Visibility) { From f5a00fb2713222e44fe16f7cbfec17822d6d02c0 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 8 Jul 2019 15:06:32 -0300 Subject: [PATCH 011/256] refactor --- Examples/Examples.cs | 1 + MetadataGenerator/AttributesProvider.cs | 67 +++++ MetadataGenerator/Generator.cs | 289 +++------------------ MetadataGenerator/MetadataGenerator.csproj | 3 + MetadataGenerator/MethodGenerator.cs | 89 +++++++ MetadataGenerator/TypeEncoder.cs | 86 ++++++ 6 files changed, 284 insertions(+), 251 deletions(-) create mode 100644 MetadataGenerator/AttributesProvider.cs create mode 100644 MetadataGenerator/MethodGenerator.cs create mode 100644 MetadataGenerator/TypeEncoder.cs diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 294dafaa..9315ef3e 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -47,6 +47,7 @@ public class ComplexClass { private readonly int readOnlyIntField = 212; public string unassignedString; + public const string CONST_STRING = "const"; public void DoNothing() { } diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs new file mode 100644 index 00000000..226f7a26 --- /dev/null +++ b/MetadataGenerator/AttributesProvider.cs @@ -0,0 +1,67 @@ +using System; +using System.Reflection; +using Model; + +namespace MetadataGenerator +{ + //FIXME class and file name + public static class AttributesProvider + { + public static TypeAttributes GetAttributesFor(Model.Types.TypeDefinition typedefinition) + { + switch (typedefinition.Kind) + { + case Model.Types.TypeDefinitionKind.Class: return ClassTypeAttributes(typedefinition); + case Model.Types.TypeDefinitionKind.Enum: return EnumTypeAttributes(typedefinition); + case Model.Types.TypeDefinitionKind.Interface: return InterfaceTypeAttributes(typedefinition); + default: throw new Exception(); // FIXME + }; + } + + private static TypeAttributes EnumTypeAttributes(Model.Types.TypeDefinition self) + { + return TypeAttributes.Class | + (Model.Types.VisibilityKind.Public.Equals(self.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic) | + TypeAttributes.Sealed; + } + + private static TypeAttributes ClassTypeAttributes(Model.Types.TypeDefinition self) + { + return TypeAttributes.Class | + //TODO: static => abstract & sealed and no BeforeFieldInitBeforeFieldInit + TypeAttributes.BeforeFieldInit | //FIXME: when? + (Model.Types.VisibilityKind.Public.Equals(self.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); + } + + private static TypeAttributes InterfaceTypeAttributes(Model.Types.TypeDefinition self) + { + return TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; + } + + public static FieldAttributes GetAttributesFor(Model.Types.FieldDefinition field) { + var fieldAttributes = + (field.IsStatic ? FieldAttributes.Static : 0) | + (field.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Enum) ? FieldAttributes.Literal : 0); //FIXME also applies for const fields. + // (field is readonly ? FieldAttributes.InitOnly : 0); //FIXME + switch (field.Visibility) //TODO extract, duplicated + { + + case Model.Types.VisibilityKind.Public: + fieldAttributes |= FieldAttributes.Public; + break; + case Model.Types.VisibilityKind.Private: + fieldAttributes |= FieldAttributes.Private; + break; + case Model.Types.VisibilityKind.Protected: + fieldAttributes |= FieldAttributes.Family; + break; + case Model.Types.VisibilityKind.Internal: + fieldAttributes |= FieldAttributes.Assembly; + break; + default: + throw field.Visibility.ToUnknownValueException(); + } + return fieldAttributes; + } + } +} diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 65bb670e..3889e033 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -17,7 +17,7 @@ public class Generator : IGenerator private static readonly Guid s_guid = new Guid("97F4DBD4-F6D1-4FAD-91B3-1001F92068E5"); //FIXME: ?? private static readonly BlobContentId s_contentId = new BlobContentId(s_guid, 0x04030201); //FIXME: ?? - private IDictionary assemblyReferences = new Dictionary(); + private readonly IDictionary assemblyReferences = new Dictionary(); public void Generate(Assembly assembly) { @@ -59,17 +59,30 @@ public void Generate(Assembly assembly) var methodBodyStream = new MethodBodyStreamEncoder(ilBuilder); var metadataTokensMethodsOffset = 1; var metadataTokensFieldsOffset = 1; + var methodGenerator = new MethodGenerator(metadata, ref methodBodyStream); + foreach (var namezpace in assembly.RootNamespace.Namespaces) { foreach (var typeDefinition in namezpace.Types) { MethodDefinitionHandle? firstMethodHandle = null; FieldDefinitionHandle? firstFieldHandle = null; - if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Class)) + + var typeAttributes = AttributesProvider.GetAttributesFor(typeDefinition); + + foreach (var method in typeDefinition.Methods) { - //TODO metadata.AddNestedType() if applies + var methodHandle = methodGenerator.Generate(method); + + if (!firstMethodHandle.HasValue) + { + firstMethodHandle = methodHandle; + } + metadataTokensMethodsOffset++; + } - /* TODO Properties: works but model is missing Property concept + /* TODO Properties: works but model is missing Property concept + var propertySignatureBlogBuilder = new BlobBuilder(); new BlobEncoder(propertySignatureBlogBuilder) .PropertySignature(isInstanceProperty: true) //FIXME when false @@ -77,7 +90,7 @@ public void Generate(Assembly assembly) 0, returnType => returnType.Type().Int32(), //FIXME backingField type parameters => { }); - + var propertyDefinitionHandle = metadata.AddProperty( attributes: PropertyAttributes.None, //FIXME name: metadata.GetOrAddString(""), //FIXME property name @@ -89,21 +102,13 @@ public void Generate(Assembly assembly) method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, methodHandle); //getter/setter metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); - - */ - foreach (var method in typeDefinition.Methods) - { - var methodHandle = GenerateMethod(metadata, ref methodBodyStream, method); + */ - if (!firstMethodHandle.HasValue) - { - firstMethodHandle = methodHandle; - } - - } + if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Class)) + { + //TODO metadata.AddNestedType() if applies - metadataTokensMethodsOffset += typeDefinition.Methods.Count; // Field initial values are assigned either on ctor or cctor (if static) typeDefinition.Fields //TODO extract method? duplicated code for enum @@ -111,34 +116,13 @@ public void Generate(Assembly assembly) .ForEach(field => { var fieldSignatureBlobBuilder = new BlobBuilder(); - EncodeType( - field.Type, - new BlobEncoder(fieldSignatureBlobBuilder) - .FieldSignature()); - - var fieldAttributes = - (field.IsStatic ? FieldAttributes.Static : 0); - // (field is readonly ? FieldAttributes.InitOnly : 0); //FIXME how to know if readonly? - switch (field.Visibility) //TODO extract, duplicated - { + TypeEncoder.Encode( + field.Type, + new BlobEncoder(fieldSignatureBlobBuilder) + .FieldSignature()); - case Model.Types.VisibilityKind.Public: - fieldAttributes |= FieldAttributes.Public; - break; - case Model.Types.VisibilityKind.Private: - fieldAttributes |= FieldAttributes.Private; - break; - case Model.Types.VisibilityKind.Protected: - fieldAttributes |= FieldAttributes.Family; - break; - case Model.Types.VisibilityKind.Internal: - fieldAttributes |= FieldAttributes.Assembly; - break; - default: - throw field.Visibility.ToUnknownValueException(); - } var fieldDefinitionHandle = metadata.AddFieldDefinition( - attributes: fieldAttributes, + attributes: AttributesProvider.GetAttributesFor(field), name: metadata.GetOrAddString(field.Name), signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); @@ -151,19 +135,12 @@ public void Generate(Assembly assembly) }); var typeDefinitionHandle = metadata.AddTypeDefinition( - attributes: ClassTypeAttributesFor(typeDefinition), + attributes: typeAttributes, @namespace: metadata.GetOrAddString(namezpace.Name), name: metadata.GetOrAddString(typeDefinition.Name), - baseType: BaseType(assembly, metadata, typeDefinition), + baseType: typeDefinition.Base == null ? default(EntityHandle) : BaseType(assembly, metadata, typeDefinition), fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), - //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos - /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. - /// If no type defines any fields in the module, (1). methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); - //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos - /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. - /// If no type defines any methods in the module, (1) - foreach (var interfaze in typeDefinition.Interfaces) { @@ -181,7 +158,7 @@ public void Generate(Assembly assembly) else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Enum)) { var fieldSignatureBlobBuilder = new BlobBuilder(); - EncodeType( + TypeEncoder.Encode( typeDefinition.Fields.First().Type, //FIXME first if empty new BlobEncoder(fieldSignatureBlobBuilder) .FieldSignature()); @@ -194,18 +171,12 @@ public void Generate(Assembly assembly) signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); var selfTypeDefinitionHandle = metadata.AddTypeDefinition( - attributes: EnumTypeAttributesFor(typeDefinition), + attributes: typeAttributes, @namespace: metadata.GetOrAddString(namezpace.Name), name: metadata.GetOrAddString(typeDefinition.Name), - baseType: BaseType(assembly, metadata, typeDefinition), - fieldList: firstFieldHandle.Value, - //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos - /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. - /// If no type defines any fields in the module, (1). - methodList: MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); - //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos - /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. - /// If no type defines any methods in the module, (1). + baseType: typeDefinition.Base == null ? default(EntityHandle) : BaseType(assembly, metadata, typeDefinition), + fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), + methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); typeDefinition.Fields .Where(field => !field.Name.Equals("value__")) @@ -219,7 +190,7 @@ public void Generate(Assembly assembly) metadata.AddConstant( metadata.AddFieldDefinition( - attributes: FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal, + attributes: AttributesProvider.GetAttributesFor(field), name: metadata.GetOrAddString(field.Name), signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)), field.Value.Value); @@ -229,34 +200,13 @@ public void Generate(Assembly assembly) } else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Interface)) { - //TODO properties - - - foreach (var method in typeDefinition.Methods) - { - var methodHandle = GenerateMethod(metadata, ref methodBodyStream, method); - if (!firstMethodHandle.HasValue) - { - - firstMethodHandle = methodHandle; - } - } - - metadataTokensMethodsOffset += typeDefinition.Methods.Count; - metadata.AddTypeDefinition( - attributes: InterfaceTypeAttributesFor(typeDefinition), + attributes: typeAttributes, @namespace: metadata.GetOrAddString(namezpace.Name), name: metadata.GetOrAddString(typeDefinition.Name), - baseType: default(EntityHandle), - fieldList: default(FieldDefinitionHandle), - //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los fields incorrectos - /// If the type declares fields the handle of the first one, otherwise the handle of the first field declared by the next type definition. - /// If no type defines any fields in the module, (1). + baseType: typeDefinition.Base == null ? default(EntityHandle) : BaseType(assembly, metadata, typeDefinition), + fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); - //FIXME ---> Por ahora funca pero MetadataTokens parece ser global. Si proceso mas de un assembly seguro accedo a los metodos incorrectos - /// If the type declares methods the handle of the first one, otherwise the handle of the first method declared by the next type definition. - /// If no type defines any methods in the module, (1) } } @@ -287,169 +237,6 @@ private TypeReferenceHandle BaseType(Assembly assembly, MetadataBuilder metadata name: metadata.GetOrAddString(typeDefinition.Base.Name)); } - private static TypeAttributes EnumTypeAttributesFor(Model.Types.TypeDefinition typeDefinition) - { - return TypeAttributes.Class | - (Model.Types.VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic) | - TypeAttributes.Sealed; - } - - private static TypeAttributes ClassTypeAttributesFor(Model.Types.TypeDefinition typeDefinition) - { - return TypeAttributes.Class | - //TODO: static => abstract & sealed and no BeforeFieldInitBeforeFieldInit - TypeAttributes.BeforeFieldInit | //FIXME: when? - (Model.Types.VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); - } - - private static TypeAttributes InterfaceTypeAttributesFor(Model.Types.TypeDefinition typeDefinition) - { - return TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; - } - - private MethodDefinitionHandle GenerateMethod(MetadataBuilder metadata, ref MethodBodyStreamEncoder methodBodyStream, Model.Types.MethodDefinition method) - { - var methodSignature = new BlobBuilder(); - new BlobEncoder(methodSignature) - .MethodSignature(isInstanceMethod: !method.IsStatic) //FIXME ? - .Parameters( - method.Parameters.Count, - returnType => - { - if (method.ReturnType.Equals(Model.Types.PlatformTypes.Void)) - { - returnType.Void(); - } - else - { - EncodeType(method.ReturnType, returnType.Type()); - } - - }, - parameters => - { - foreach (var parameter in method.Parameters) - { - EncodeType(parameter.Type, parameters.AddParameter().Type()); - } - }); - - var instructions = new InstructionEncoder(new BlobBuilder()); - - instructions.OpCode(ILOpCode.Nop); - instructions.OpCode(ILOpCode.Ret); - - var methodAttributes = - (method.IsAbstract ? MethodAttributes.Abstract : 0) | - (method.IsStatic ? MethodAttributes.Static : 0) | - (method.IsVirtual ? MethodAttributes.Virtual : 0) | - (method.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Interface) ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct - (method.IsConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | //FIXME should do the same for class constructor (cctor) - (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0) | //FIXME - MethodAttributes.HideBySig; //FIXME when? - - switch (method.Visibility) - { - case Model.Types.VisibilityKind.Public: - methodAttributes |= MethodAttributes.Public; - break; - case Model.Types.VisibilityKind.Private: - methodAttributes |= MethodAttributes.Private; - break; - case Model.Types.VisibilityKind.Protected: - methodAttributes |= MethodAttributes.Family; - break; - case Model.Types.VisibilityKind.Internal: - methodAttributes |= MethodAttributes.Assembly; - break; - default: - throw method.Visibility.ToUnknownValueException(); - } - - return metadata.AddMethodDefinition( - attributes: methodAttributes, - implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME - name: metadata.GetOrAddString(method.Name), - signature: metadata.GetOrAddBlob(methodSignature), - bodyOffset: methodBodyStream.AddMethodBody(instructions), - parameterList: default(ParameterHandle)); //FIXME - } - - //FIXME: names, type of parameters - private void EncodeType(Model.Types.IType type, SignatureTypeEncoder signatureTypeEncoder) - { - // reflection? FIXME - //var type = Model.Types.PlatformTypes.Values().FirstOrDefault(t => method.ReturnType.Equals(t)); - //if (type == null) - //{ - // throw new Exception("Unknow return type"); - - //} - //else - //{ - // var returnTypeMethod = returnType.GetType().GetMethod(type.ToString()); - // returnTypeMethod.Invoke(returnType, new Object[] { }); - //} - - //FIXME incomplete - if (type.Equals(Model.Types.PlatformTypes.Boolean)) - { - signatureTypeEncoder.Boolean(); - } - else if (type.Equals(Model.Types.PlatformTypes.Byte)) - { - signatureTypeEncoder.Byte(); - } - else if (type.Equals(Model.Types.PlatformTypes.SByte)) - { - signatureTypeEncoder.SByte(); - } - else if (type.Equals(Model.Types.PlatformTypes.Char)) - { - signatureTypeEncoder.Char(); - } - else if (type.Equals(Model.Types.PlatformTypes.Double)) - { - signatureTypeEncoder.Double(); - } - else if (type.Equals(Model.Types.PlatformTypes.Int16)) - { - signatureTypeEncoder.Int16(); - } - else if (type.Equals(Model.Types.PlatformTypes.UInt16)) - { - signatureTypeEncoder.UInt16(); - } - else if (type.Equals(Model.Types.PlatformTypes.Int32)) - { - signatureTypeEncoder.Int32(); - } - else if (type.Equals(Model.Types.PlatformTypes.UInt32)) - { - signatureTypeEncoder.UInt32(); - } - else if (type.Equals(Model.Types.PlatformTypes.Int64)) - { - signatureTypeEncoder.Int64(); - } - else if (type.Equals(Model.Types.PlatformTypes.UInt64)) - { - signatureTypeEncoder.UInt64(); - } - else if (type.Equals(Model.Types.PlatformTypes.String)) - { - signatureTypeEncoder.String(); - } - else if (type.Equals(Model.Types.PlatformTypes.Single)) - { - signatureTypeEncoder.Single(); - } - else - { - throw new Exception("Unknown value:" + type.ToString()); - } - - } } } \ No newline at end of file diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 7a75ca69..87e8e4da 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -27,6 +27,9 @@ + + + diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs new file mode 100644 index 00000000..a427e343 --- /dev/null +++ b/MetadataGenerator/MethodGenerator.cs @@ -0,0 +1,89 @@ +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using Model; + +namespace MetadataGenerator +{ + public class MethodGenerator + { + private readonly MetadataBuilder metadata; + private readonly MethodBodyStreamEncoder methodBodyStream; + + public MethodGenerator(MetadataBuilder metadata, ref MethodBodyStreamEncoder methodBodyStream) + { + this.metadata = metadata; + this.methodBodyStream = methodBodyStream; + } + + public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) + { + var methodSignature = new BlobBuilder(); + new BlobEncoder(methodSignature) + .MethodSignature(isInstanceMethod: !method.IsStatic) //FIXME ? + .Parameters( + method.Parameters.Count, + returnType => + { + if (method.ReturnType.Equals(Model.Types.PlatformTypes.Void)) + { + returnType.Void(); + } + else + { + TypeEncoder.Encode(method.ReturnType, returnType.Type()); + } + + }, + parameters => + { + foreach (var parameter in method.Parameters) + { + TypeEncoder.Encode(parameter.Type, parameters.AddParameter().Type()); + } + }); + + var instructions = new InstructionEncoder(new BlobBuilder()); + + instructions.OpCode(ILOpCode.Nop); + instructions.OpCode(ILOpCode.Ret); + + var methodAttributes = + (method.IsAbstract ? MethodAttributes.Abstract : 0) | + (method.IsStatic ? MethodAttributes.Static : 0) | + (method.IsVirtual ? MethodAttributes.Virtual : 0) | + (method.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Interface) ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct + (method.IsConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | //FIXME should do the same for class constructor (cctor) + (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0) | //FIXME + MethodAttributes.HideBySig; //FIXME when? + + switch (method.Visibility) + { + case Model.Types.VisibilityKind.Public: + methodAttributes |= MethodAttributes.Public; + break; + case Model.Types.VisibilityKind.Private: + methodAttributes |= MethodAttributes.Private; + break; + case Model.Types.VisibilityKind.Protected: + methodAttributes |= MethodAttributes.Family; + break; + case Model.Types.VisibilityKind.Internal: + methodAttributes |= MethodAttributes.Assembly; + break; + default: + throw method.Visibility.ToUnknownValueException(); + } + + return metadata.AddMethodDefinition( + attributes: methodAttributes, + implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME + name: metadata.GetOrAddString(method.Name), + signature: metadata.GetOrAddBlob(methodSignature), + bodyOffset: methodBodyStream.AddMethodBody(instructions), + parameterList: default(ParameterHandle)); //FIXME + } + + + } +} diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs new file mode 100644 index 00000000..9b71d9dd --- /dev/null +++ b/MetadataGenerator/TypeEncoder.cs @@ -0,0 +1,86 @@ +using System; +using System.Reflection.Metadata.Ecma335; + +namespace MetadataGenerator +{ + public static class TypeEncoder + { + //FIXME: names, type of parameters + public static void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEncoder) + { + + // reflection? FIXME + //var type = Model.Types.PlatformTypes.Values().FirstOrDefault(t => method.ReturnType.Equals(t)); + //if (type == null) + //{ + // throw new Exception("Unknow return type"); + + //} + //else + //{ + // var returnTypeMethod = returnType.GetType().GetMethod(type.ToString()); + // returnTypeMethod.Invoke(returnType, new Object[] { }); + //} + + //FIXME incomplete + if (type.Equals(Model.Types.PlatformTypes.Boolean)) + { + signatureTypeEncoder.Boolean(); + } + else if (type.Equals(Model.Types.PlatformTypes.Byte)) + { + signatureTypeEncoder.Byte(); + } + else if (type.Equals(Model.Types.PlatformTypes.SByte)) + { + signatureTypeEncoder.SByte(); + } + else if (type.Equals(Model.Types.PlatformTypes.Char)) + { + signatureTypeEncoder.Char(); + } + else if (type.Equals(Model.Types.PlatformTypes.Double)) + { + signatureTypeEncoder.Double(); + } + else if (type.Equals(Model.Types.PlatformTypes.Int16)) + { + signatureTypeEncoder.Int16(); + } + else if (type.Equals(Model.Types.PlatformTypes.UInt16)) + { + signatureTypeEncoder.UInt16(); + } + else if (type.Equals(Model.Types.PlatformTypes.Int32)) + { + signatureTypeEncoder.Int32(); + } + else if (type.Equals(Model.Types.PlatformTypes.UInt32)) + { + signatureTypeEncoder.UInt32(); + } + else if (type.Equals(Model.Types.PlatformTypes.Int64)) + { + signatureTypeEncoder.Int64(); + } + else if (type.Equals(Model.Types.PlatformTypes.UInt64)) + { + signatureTypeEncoder.UInt64(); + } + else if (type.Equals(Model.Types.PlatformTypes.String)) + { + signatureTypeEncoder.String(); + } + else if (type.Equals(Model.Types.PlatformTypes.Single)) + { + signatureTypeEncoder.Single(); + } + else + { + throw new Exception("Unknown value:" + type.ToString()); + } + + } + + } +} From 23b4638a693458c5532956851b1184e0c7f9e15c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 8 Jul 2019 15:33:34 -0300 Subject: [PATCH 012/256] structs generation --- Examples/Examples.cs | 59 +++++++++++++++++++++++++ MetadataGenerator/AttributesProvider.cs | 26 ++++++++--- MetadataGenerator/Generator.cs | 54 +++++++++++++++++++++- 3 files changed, 131 insertions(+), 8 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 9315ef3e..30c6e9a6 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -142,4 +142,63 @@ public class ClassDerivedFromAccessibilityClass : Accessibility.CAccPropServices { } +} + +namespace FourthNamespace +{ + public struct EmptyStruct + { + } + public struct ComplexStruct : SecondNamespace.ISampleInterface + { + private readonly int x; + + public void DoNothing() + { + } + + public void DoSomething() + { + } + + // todo structs can have properties + + } + +} + +namespace FifthNamespace +{ + + public class ClassContainingNestedTypes + { + public class NestedClass + { + } + + public enum NestedEnum + { + CONSTANT1 = 1 + } + + public struct NestedStruct + { + } + } + + public struct StructContainingNestedTypes + { + + public struct NestedStruct { } + + public enum NestedEnum + { + CONSTANT1 = 1 + } + + public class NestedClass + { + } + } + } \ No newline at end of file diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs index 226f7a26..4b527fbe 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -1,6 +1,7 @@ using System; using System.Reflection; using Model; +using Model.Types; namespace MetadataGenerator { @@ -14,32 +15,43 @@ public static TypeAttributes GetAttributesFor(Model.Types.TypeDefinition typedef case Model.Types.TypeDefinitionKind.Class: return ClassTypeAttributes(typedefinition); case Model.Types.TypeDefinitionKind.Enum: return EnumTypeAttributes(typedefinition); case Model.Types.TypeDefinitionKind.Interface: return InterfaceTypeAttributes(typedefinition); + case Model.Types.TypeDefinitionKind.Struct: return StructTypeAttributes(typedefinition); default: throw new Exception(); // FIXME }; } - private static TypeAttributes EnumTypeAttributes(Model.Types.TypeDefinition self) + private static TypeAttributes StructTypeAttributes(TypeDefinition typedefinition) { return TypeAttributes.Class | - (Model.Types.VisibilityKind.Public.Equals(self.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic) | + (Model.Types.VisibilityKind.Public.Equals(typedefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic) | + TypeAttributes.SequentialLayout | + TypeAttributes.Sealed | + TypeAttributes.BeforeFieldInit; //FIXME: when? + } + + private static TypeAttributes EnumTypeAttributes(Model.Types.TypeDefinition typedefinition) + { + return TypeAttributes.Class | + (Model.Types.VisibilityKind.Public.Equals(typedefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic) | TypeAttributes.Sealed; } - private static TypeAttributes ClassTypeAttributes(Model.Types.TypeDefinition self) + private static TypeAttributes ClassTypeAttributes(Model.Types.TypeDefinition typedefinition) { return TypeAttributes.Class | //TODO: static => abstract & sealed and no BeforeFieldInitBeforeFieldInit TypeAttributes.BeforeFieldInit | //FIXME: when? - (Model.Types.VisibilityKind.Public.Equals(self.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); + (Model.Types.VisibilityKind.Public.Equals(typedefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); } - private static TypeAttributes InterfaceTypeAttributes(Model.Types.TypeDefinition self) + private static TypeAttributes InterfaceTypeAttributes(Model.Types.TypeDefinition typedefinition) { return TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; } - public static FieldAttributes GetAttributesFor(Model.Types.FieldDefinition field) { - var fieldAttributes = + public static FieldAttributes GetAttributesFor(Model.Types.FieldDefinition field) + { + var fieldAttributes = (field.IsStatic ? FieldAttributes.Static : 0) | (field.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Enum) ? FieldAttributes.Literal : 0); //FIXME also applies for const fields. // (field is readonly ? FieldAttributes.InitOnly : 0); //FIXME diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 3889e033..0edaad93 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -148,7 +148,7 @@ public void Generate(Assembly assembly) type: typeDefinitionHandle, implementedInterface: metadata.AddTypeReference( //FIXME multiple classes could implement same interface //FIXME so should addTypeReference only once. check MetadataTokens for reference? - resolutionScope: default(TypeReferenceHandle), + resolutionScope: default(TypeReferenceHandle), //FIXME interface could be in another assembly @namespace: metadata.GetOrAddString(interfaze.ContainingNamespace), name: metadata.GetOrAddString(interfaze.Name))); } @@ -208,6 +208,58 @@ public void Generate(Assembly assembly) fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); } + else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Struct)) + { + + //FIXME: Exact same code that when handling class and similar to enum + + + //TODO metadata.AddNestedType() if applies + + // Field initial values are assigned either on ctor or cctor (if static) + typeDefinition.Fields + .ToList() + .ForEach(field => + { + var fieldSignatureBlobBuilder = new BlobBuilder(); + TypeEncoder.Encode( + field.Type, + new BlobEncoder(fieldSignatureBlobBuilder) + .FieldSignature()); + + var fieldDefinitionHandle = metadata.AddFieldDefinition( + attributes: AttributesProvider.GetAttributesFor(field), + name: metadata.GetOrAddString(field.Name), + signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); + + if (!firstFieldHandle.HasValue) + { + firstFieldHandle = fieldDefinitionHandle; + } + + metadataTokensFieldsOffset++; + }); + + var typeDefinitionHandle = metadata.AddTypeDefinition( + attributes: typeAttributes, + @namespace: metadata.GetOrAddString(namezpace.Name), + name: metadata.GetOrAddString(typeDefinition.Name), + baseType: typeDefinition.Base == null ? default(EntityHandle) : BaseType(assembly, metadata, typeDefinition), + fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), + methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); + + foreach (var interfaze in typeDefinition.Interfaces) + { + metadata.AddInterfaceImplementation( + type: typeDefinitionHandle, + implementedInterface: metadata.AddTypeReference( //FIXME multiple classes could implement same interface + //FIXME so should addTypeReference only once. check MetadataTokens for reference? + resolutionScope: default(TypeReferenceHandle), //FIXME interface could be in another assembly + @namespace: metadata.GetOrAddString(interfaze.ContainingNamespace), + name: metadata.GetOrAddString(interfaze.Name))); + } + + } } } From c1b421814789de0c14011cc45d9ef0a2183be091 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 9 Jul 2019 16:17:01 -0300 Subject: [PATCH 013/256] refactor: same logic for all types --- Examples/Examples.cs | 4 +- MetadataGenerator/Generator.cs | 208 +++++++++------------------------ 2 files changed, 58 insertions(+), 154 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 30c6e9a6..4c328698 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -201,4 +201,6 @@ public class NestedClass } } -} \ No newline at end of file +} + +//TODO class with fields or methods that return other clases, structs, etc \ No newline at end of file diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 0edaad93..63a480b8 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.IO; -using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -96,7 +95,7 @@ public void Generate(Assembly assembly) name: metadata.GetOrAddString(""), //FIXME property name signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); - // asociate methods (get, set) to property + // asociate methods (get, set) to property metadata.AddMethodSemantics( propertyDefinitionHandle, method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, @@ -105,160 +104,75 @@ public void Generate(Assembly assembly) */ - if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Class)) + foreach (var field in typeDefinition.Fields) { - //TODO metadata.AddNestedType() if applies - - - // Field initial values are assigned either on ctor or cctor (if static) - typeDefinition.Fields //TODO extract method? duplicated code for enum - .ToList() - .ForEach(field => - { - var fieldSignatureBlobBuilder = new BlobBuilder(); - TypeEncoder.Encode( - field.Type, - new BlobEncoder(fieldSignatureBlobBuilder) - .FieldSignature()); - - var fieldDefinitionHandle = metadata.AddFieldDefinition( - attributes: AttributesProvider.GetAttributesFor(field), - name: metadata.GetOrAddString(field.Name), - signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); - - if (!firstFieldHandle.HasValue) - { - firstFieldHandle = fieldDefinitionHandle; - } + var fieldSignatureBlobBuilder = new BlobBuilder(); + var fieldSignature = new BlobEncoder(fieldSignatureBlobBuilder).FieldSignature(); - metadataTokensFieldsOffset++; - }); + //FIXME: should be: if it is a custom type (not primitive nor primitive wrapper) + //FIXME: in the examples for the only one that needs this is the enum values + //FIXME: and the field value__ that is generated for the enum it is always a primitive so it needs to go to the else branch + if (field.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Enum) && !field.Name.Equals("value__")) + { + fieldSignature.Type( + metadata.AddTypeReference( //FIXME: this should be done only once per type. + default(AssemblyReferenceHandle), + metadata.GetOrAddString(namezpace.Name), + metadata.GetOrAddString(typeDefinition.Name)), + true); + } + else + { + TypeEncoder.Encode(field.Type, fieldSignature); + } - var typeDefinitionHandle = metadata.AddTypeDefinition( - attributes: typeAttributes, - @namespace: metadata.GetOrAddString(namezpace.Name), - name: metadata.GetOrAddString(typeDefinition.Name), - baseType: typeDefinition.Base == null ? default(EntityHandle) : BaseType(assembly, metadata, typeDefinition), - fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), - methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); + var fieldDefinitionHandle = metadata.AddFieldDefinition( + attributes: AttributesProvider.GetAttributesFor(field), + name: metadata.GetOrAddString(field.Name), + signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); - foreach (var interfaze in typeDefinition.Interfaces) + if (!firstFieldHandle.HasValue) { - metadata.AddInterfaceImplementation( - type: typeDefinitionHandle, - implementedInterface: metadata.AddTypeReference( //FIXME multiple classes could implement same interface - //FIXME so should addTypeReference only once. check MetadataTokens for reference? - resolutionScope: default(TypeReferenceHandle), //FIXME interface could be in another assembly - @namespace: metadata.GetOrAddString(interfaze.ContainingNamespace), - name: metadata.GetOrAddString(interfaze.Name))); + firstFieldHandle = fieldDefinitionHandle; } - - } - else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Enum)) - { - var fieldSignatureBlobBuilder = new BlobBuilder(); - TypeEncoder.Encode( - typeDefinition.Fields.First().Type, //FIXME first if empty - new BlobEncoder(fieldSignatureBlobBuilder) - .FieldSignature()); + if (field.Value != null) + { + metadata.AddConstant(fieldDefinitionHandle, field.Value.Value); + } metadataTokensFieldsOffset++; - - firstFieldHandle = metadata.AddFieldDefinition( - attributes: FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName, - name: metadata.GetOrAddString("value__"), - signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); - - var selfTypeDefinitionHandle = metadata.AddTypeDefinition( - attributes: typeAttributes, - @namespace: metadata.GetOrAddString(namezpace.Name), - name: metadata.GetOrAddString(typeDefinition.Name), - baseType: typeDefinition.Base == null ? default(EntityHandle) : BaseType(assembly, metadata, typeDefinition), - fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), - methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); - - typeDefinition.Fields - .Where(field => !field.Name.Equals("value__")) - .ToList() - .ForEach(field => - { - fieldSignatureBlobBuilder.Clear(); - new BlobEncoder(fieldSignatureBlobBuilder) - .FieldSignature() - .Type(selfTypeDefinitionHandle, true); - - metadata.AddConstant( - metadata.AddFieldDefinition( - attributes: AttributesProvider.GetAttributesFor(field), - name: metadata.GetOrAddString(field.Name), - signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)), - field.Value.Value); - - metadataTokensFieldsOffset++; - }); } - else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Interface)) - { - metadata.AddTypeDefinition( - attributes: typeAttributes, - @namespace: metadata.GetOrAddString(namezpace.Name), - name: metadata.GetOrAddString(typeDefinition.Name), - baseType: typeDefinition.Base == null ? default(EntityHandle) : BaseType(assembly, metadata, typeDefinition), - fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), - methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); - } - else if (typeDefinition.Kind.Equals(Model.Types.TypeDefinitionKind.Struct)) - { - - //FIXME: Exact same code that when handling class and similar to enum - - - //TODO metadata.AddNestedType() if applies - - // Field initial values are assigned either on ctor or cctor (if static) - typeDefinition.Fields - .ToList() - .ForEach(field => - { - var fieldSignatureBlobBuilder = new BlobBuilder(); - TypeEncoder.Encode( - field.Type, - new BlobEncoder(fieldSignatureBlobBuilder) - .FieldSignature()); - var fieldDefinitionHandle = metadata.AddFieldDefinition( - attributes: AttributesProvider.GetAttributesFor(field), - name: metadata.GetOrAddString(field.Name), - signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); + //TODO metadata.AddNestedType() if applies - if (!firstFieldHandle.HasValue) - { - firstFieldHandle = fieldDefinitionHandle; - } - metadataTokensFieldsOffset++; - }); + //FIXME: comparing to the name of the current assembly could result in a false positive? + //FIXME: this posibly adds the type reference more than once + var baseType = typeDefinition.Base == null + ? default(EntityHandle) + : metadata.AddTypeReference( + resolutionScope: typeDefinition.Base.ContainingAssembly.Name.Equals(assembly.Name) ? default(AssemblyReferenceHandle) : assemblyReferences[typeDefinition.Base.ContainingAssembly.Name], + @namespace: metadata.GetOrAddString(typeDefinition.Base.ContainingNamespace), + name: metadata.GetOrAddString(typeDefinition.Base.Name)); - var typeDefinitionHandle = metadata.AddTypeDefinition( - attributes: typeAttributes, - @namespace: metadata.GetOrAddString(namezpace.Name), - name: metadata.GetOrAddString(typeDefinition.Name), - baseType: typeDefinition.Base == null ? default(EntityHandle) : BaseType(assembly, metadata, typeDefinition), - fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), - methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); - - foreach (var interfaze in typeDefinition.Interfaces) - { - metadata.AddInterfaceImplementation( - type: typeDefinitionHandle, - implementedInterface: metadata.AddTypeReference( //FIXME multiple classes could implement same interface - //FIXME so should addTypeReference only once. check MetadataTokens for reference? - resolutionScope: default(TypeReferenceHandle), //FIXME interface could be in another assembly - @namespace: metadata.GetOrAddString(interfaze.ContainingNamespace), - name: metadata.GetOrAddString(interfaze.Name))); - } + var typeDefinitionHandle = metadata.AddTypeDefinition( + attributes: typeAttributes, + @namespace: metadata.GetOrAddString(namezpace.Name), + name: metadata.GetOrAddString(typeDefinition.Name), + baseType: baseType, + fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), + methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); + foreach (var interfaze in typeDefinition.Interfaces) + { + metadata.AddInterfaceImplementation( + type: typeDefinitionHandle, + implementedInterface: metadata.AddTypeReference( //FIXME multiple classes could implement same interface + //FIXME so should addTypeReference only once. check MetadataTokens for reference? + resolutionScope: default(TypeReferenceHandle), //FIXME interface could be in another assembly + @namespace: metadata.GetOrAddString(interfaze.ContainingNamespace), + name: metadata.GetOrAddString(interfaze.Name))); } } @@ -278,17 +192,5 @@ public void Generate(Assembly assembly) } - //FIXME name - //FIXME: comparing to the name of the current assembly could result in a false positive? - //FIXME: this posibly adds the type reference more than once - private TypeReferenceHandle BaseType(Assembly assembly, MetadataBuilder metadata, Model.Types.TypeDefinition typeDefinition) - { - return metadata.AddTypeReference( - resolutionScope: typeDefinition.Base.ContainingAssembly.Name.Equals(assembly.Name) ? default(AssemblyReferenceHandle) : assemblyReferences[typeDefinition.Base.ContainingAssembly.Name], - @namespace: metadata.GetOrAddString(typeDefinition.Base.ContainingNamespace), - name: metadata.GetOrAddString(typeDefinition.Base.Name)); - } - - } } \ No newline at end of file From 32d53236bd5013a0acb5ba8917bd0e9b795013d7 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 9 Jul 2019 16:31:29 -0300 Subject: [PATCH 014/256] whitespace --- MetadataGenerator/Generator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 63a480b8..a1cec483 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -174,7 +174,6 @@ public void Generate(Assembly assembly) @namespace: metadata.GetOrAddString(interfaze.ContainingNamespace), name: metadata.GetOrAddString(interfaze.Name))); } - } } var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); From 2e40b9a749cf1a8f8a8f809d397e0ccf60fa5322 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 9 Jul 2019 22:05:25 -0300 Subject: [PATCH 015/256] more refactors --- MetadataGenerator/FieldGenerator.cs | 60 ++++++++++++++++++++ MetadataGenerator/Generator.cs | 65 ++++++---------------- MetadataGenerator/MetadataGenerator.csproj | 1 + MetadataGenerator/MethodGenerator.cs | 18 +++++- 4 files changed, 92 insertions(+), 52 deletions(-) create mode 100644 MetadataGenerator/FieldGenerator.cs diff --git a/MetadataGenerator/FieldGenerator.cs b/MetadataGenerator/FieldGenerator.cs new file mode 100644 index 00000000..85a21f51 --- /dev/null +++ b/MetadataGenerator/FieldGenerator.cs @@ -0,0 +1,60 @@ +using System; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +namespace MetadataGenerator +{ + public class FieldGenerator + { + private MetadataBuilder metadata; + private int nextOffset; + + public FieldGenerator(MetadataBuilder metadata) + { + this.metadata = metadata; + this.nextOffset = 1; + } + + public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) { + var fieldSignatureBlobBuilder = new BlobBuilder(); + var fieldSignature = new BlobEncoder(fieldSignatureBlobBuilder).FieldSignature(); + + //FIXME: should be: if it is a custom type (not primitive nor primitive wrapper) + //FIXME: in the examples for the only one that needs this is the enum values + //FIXME: and the field value__ that is generated for the enum it is always a primitive so it needs to go to the else branch + if (field.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Enum) && !field.Name.Equals("value__")) + { + fieldSignature.Type( + metadata.AddTypeReference( //FIXME: this should be done only once per type. + default(AssemblyReferenceHandle), + metadata.GetOrAddString(field.ContainingType.ContainingNamespace.Name), + metadata.GetOrAddString(field.ContainingType.Name)), + true); + } + else + { + TypeEncoder.Encode(field.Type, fieldSignature); + } + + var fieldDefinitionHandle = metadata.AddFieldDefinition( + attributes: AttributesProvider.GetAttributesFor(field), + name: metadata.GetOrAddString(field.Name), + signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); + + + if (field.Value != null) + { + metadata.AddConstant(fieldDefinitionHandle, field.Value.Value); + } + + nextOffset++; + + return fieldDefinitionHandle; + + } + + public FieldDefinitionHandle NextFieldHandle() { + return MetadataTokens.FieldDefinitionHandle(nextOffset); + } + } +} diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index a1cec483..96cfaec8 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -54,11 +54,8 @@ public void Generate(Assembly assembly) encId: default(GuidHandle), // FIXME ?? encBaseId: default(GuidHandle)); // FIXME ?? - var ilBuilder = new BlobBuilder(); - var methodBodyStream = new MethodBodyStreamEncoder(ilBuilder); - var metadataTokensMethodsOffset = 1; - var metadataTokensFieldsOffset = 1; - var methodGenerator = new MethodGenerator(metadata, ref methodBodyStream); + var methodGenerator = new MethodGenerator(metadata); + var fieldGenerator = new FieldGenerator(metadata); foreach (var namezpace in assembly.RootNamespace.Namespaces) { @@ -77,7 +74,17 @@ public void Generate(Assembly assembly) { firstMethodHandle = methodHandle; } - metadataTokensMethodsOffset++; + } + + foreach (var field in typeDefinition.Fields) + { + var fieldDefinitionHandle = fieldGenerator.Generate(field); + + + if (!firstFieldHandle.HasValue) + { + firstFieldHandle = fieldDefinitionHandle; + } } /* TODO Properties: works but model is missing Property concept @@ -101,48 +108,8 @@ public void Generate(Assembly assembly) method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, methodHandle); //getter/setter metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); - */ - foreach (var field in typeDefinition.Fields) - { - var fieldSignatureBlobBuilder = new BlobBuilder(); - var fieldSignature = new BlobEncoder(fieldSignatureBlobBuilder).FieldSignature(); - - //FIXME: should be: if it is a custom type (not primitive nor primitive wrapper) - //FIXME: in the examples for the only one that needs this is the enum values - //FIXME: and the field value__ that is generated for the enum it is always a primitive so it needs to go to the else branch - if (field.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Enum) && !field.Name.Equals("value__")) - { - fieldSignature.Type( - metadata.AddTypeReference( //FIXME: this should be done only once per type. - default(AssemblyReferenceHandle), - metadata.GetOrAddString(namezpace.Name), - metadata.GetOrAddString(typeDefinition.Name)), - true); - } - else - { - TypeEncoder.Encode(field.Type, fieldSignature); - } - - var fieldDefinitionHandle = metadata.AddFieldDefinition( - attributes: AttributesProvider.GetAttributesFor(field), - name: metadata.GetOrAddString(field.Name), - signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); - - if (!firstFieldHandle.HasValue) - { - firstFieldHandle = fieldDefinitionHandle; - } - - if (field.Value != null) - { - metadata.AddConstant(fieldDefinitionHandle, field.Value.Value); - } - - metadataTokensFieldsOffset++; - } //TODO metadata.AddNestedType() if applies @@ -161,8 +128,8 @@ public void Generate(Assembly assembly) @namespace: metadata.GetOrAddString(namezpace.Name), name: metadata.GetOrAddString(typeDefinition.Name), baseType: baseType, - fieldList: firstFieldHandle ?? MetadataTokens.FieldDefinitionHandle(metadataTokensFieldsOffset), - methodList: firstMethodHandle ?? MetadataTokens.MethodDefinitionHandle(metadataTokensMethodsOffset)); + fieldList: firstFieldHandle ?? fieldGenerator.NextFieldHandle(), + methodList: firstMethodHandle ?? methodGenerator.NextMethodHandle()); foreach (var interfaze in typeDefinition.Interfaces) { @@ -180,7 +147,7 @@ public void Generate(Assembly assembly) var peBuilder = new ManagedPEBuilder( header: peHeaderBuilder, metadataRootBuilder: new MetadataRootBuilder(metadata), - ilStream: ilBuilder, + ilStream: methodGenerator.IlStream(), entryPoint: default(MethodDefinitionHandle), flags: CorFlags.ILOnly | CorFlags.StrongNameSigned, deterministicIdProvider: content => s_contentId); diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 87e8e4da..887fd1e6 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -30,6 +30,7 @@ + diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index a427e343..7fa32d1e 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -9,11 +9,13 @@ public class MethodGenerator { private readonly MetadataBuilder metadata; private readonly MethodBodyStreamEncoder methodBodyStream; + private int nextOffset; - public MethodGenerator(MetadataBuilder metadata, ref MethodBodyStreamEncoder methodBodyStream) + public MethodGenerator(MetadataBuilder metadata) { this.metadata = metadata; - this.methodBodyStream = methodBodyStream; + this.methodBodyStream = new MethodBodyStreamEncoder(new BlobBuilder()); + this.nextOffset = 1; } public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) @@ -74,7 +76,7 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) default: throw method.Visibility.ToUnknownValueException(); } - + nextOffset++; return metadata.AddMethodDefinition( attributes: methodAttributes, implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME @@ -84,6 +86,16 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) parameterList: default(ParameterHandle)); //FIXME } + public BlobBuilder IlStream() + { + return methodBodyStream.Builder; + } + + public MethodDefinitionHandle NextMethodHandle() + { + return MetadataTokens.MethodDefinitionHandle(nextOffset); + } + } } From 421d5ea46b59d70d5b302973a56402ee1874d9c0 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 10 Jul 2019 23:00:25 -0300 Subject: [PATCH 016/256] generate nested types --- Examples/Examples.cs | 108 ++++++++++++-------- MetadataGenerator/Generator.cs | 165 ++++++++++++++++--------------- MetadataGenerator/TypeEncoder.cs | 14 --- 3 files changed, 152 insertions(+), 135 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 4c328698..e8d6083b 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1,14 +1,37 @@ using System; -namespace FirstNamespace +namespace Enums { - public enum AtTheBeginingEnum + public enum DefaultEnum { CONSTANT1, CONSTANT2 } + public enum EnumOfLongValues : long + { + LONG2 = 2L, + LONG50 = 50L + } + + public enum EnumOfBytes : byte + { + Byte10 = 10, + Byte20 = 20 + + } + + public enum EnumOfUShorts : ushort + { + USHORT1 = 1, + USHORT2 = 2 + } +} + +namespace Classes +{ + public class ClassWithProperties { public double AutoImplementedProperty { get; set; } @@ -34,14 +57,8 @@ static StaticClass() { StaticDouble = 0.5; } - } - public enum AtTheMiddleEnumOfBytes : byte - { - Byte10 = 10, - Byte20 = 20 - } public class ComplexClass { @@ -84,23 +101,41 @@ public virtual void VirtualMethod() { } public abstract void AbstractMethod(); } - public enum AtTheEndEnumOfUShorts : ushort +} + +namespace Structs +{ + public struct EmptyStruct { - USHORT1 = 1, - USHORT2 = 2 } + public struct ComplexStruct + { -} + private const string helloMessage = "hello"; -namespace SecondNamespace -{ - public enum EnumOfLongValues : long - { - LONG2 = 2L, - LONG50 = 50L + public void DoNothing() { } + + private string Greet() + { + + return helloMessage; + } + + private int Sum(int arg1, int arg2) + { + + return arg1 + arg2; + } } + //TODO struct with properties + +} + + +namespace Interfaces +{ public class ClassImplementingInterface : ISampleInterface { public void DoSomething() @@ -118,9 +153,17 @@ public interface ISampleInterface } + + public struct ComplexStruct : ISampleInterface + { + public void DoSomething() + { + } + } + } -namespace ThirdNamespace +namespace Hierarchy { public class BaseClass @@ -144,30 +187,7 @@ public class ClassDerivedFromAccessibilityClass : Accessibility.CAccPropServices } -namespace FourthNamespace -{ - public struct EmptyStruct - { - } - public struct ComplexStruct : SecondNamespace.ISampleInterface - { - private readonly int x; - - public void DoNothing() - { - } - - public void DoSomething() - { - } - - // todo structs can have properties - - } - -} - -namespace FifthNamespace +namespace Nested { public class ClassContainingNestedTypes @@ -203,4 +223,6 @@ public class NestedClass } +//TODO namespace with all things combined + //TODO class with fields or methods that return other clases, structs, etc \ No newline at end of file diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 96cfaec8..b9d62356 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -61,85 +61,12 @@ public void Generate(Assembly assembly) { foreach (var typeDefinition in namezpace.Types) { - MethodDefinitionHandle? firstMethodHandle = null; - FieldDefinitionHandle? firstFieldHandle = null; - - var typeAttributes = AttributesProvider.GetAttributesFor(typeDefinition); - - foreach (var method in typeDefinition.Methods) - { - var methodHandle = methodGenerator.Generate(method); - - if (!firstMethodHandle.HasValue) - { - firstMethodHandle = methodHandle; - } - } - - foreach (var field in typeDefinition.Fields) - { - var fieldDefinitionHandle = fieldGenerator.Generate(field); - - - if (!firstFieldHandle.HasValue) - { - firstFieldHandle = fieldDefinitionHandle; - } - } - - /* TODO Properties: works but model is missing Property concept - - var propertySignatureBlogBuilder = new BlobBuilder(); - new BlobEncoder(propertySignatureBlogBuilder) - .PropertySignature(isInstanceProperty: true) //FIXME when false - .Parameters( - 0, - returnType => returnType.Type().Int32(), //FIXME backingField type - parameters => { }); - - var propertyDefinitionHandle = metadata.AddProperty( - attributes: PropertyAttributes.None, //FIXME - name: metadata.GetOrAddString(""), //FIXME property name - signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); - - // asociate methods (get, set) to property - metadata.AddMethodSemantics( - propertyDefinitionHandle, - method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, - methodHandle); //getter/setter - metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); - */ - - - //TODO metadata.AddNestedType() if applies - - - //FIXME: comparing to the name of the current assembly could result in a false positive? - //FIXME: this posibly adds the type reference more than once - var baseType = typeDefinition.Base == null - ? default(EntityHandle) - : metadata.AddTypeReference( - resolutionScope: typeDefinition.Base.ContainingAssembly.Name.Equals(assembly.Name) ? default(AssemblyReferenceHandle) : assemblyReferences[typeDefinition.Base.ContainingAssembly.Name], - @namespace: metadata.GetOrAddString(typeDefinition.Base.ContainingNamespace), - name: metadata.GetOrAddString(typeDefinition.Base.Name)); - - var typeDefinitionHandle = metadata.AddTypeDefinition( - attributes: typeAttributes, - @namespace: metadata.GetOrAddString(namezpace.Name), - name: metadata.GetOrAddString(typeDefinition.Name), - baseType: baseType, - fieldList: firstFieldHandle ?? fieldGenerator.NextFieldHandle(), - methodList: firstMethodHandle ?? methodGenerator.NextMethodHandle()); - - foreach (var interfaze in typeDefinition.Interfaces) + var typeDefinitionHandle = GenerateType(assembly, metadata, methodGenerator, fieldGenerator, typeDefinition); + foreach (var nestedType in typeDefinition.Types) { - metadata.AddInterfaceImplementation( - type: typeDefinitionHandle, - implementedInterface: metadata.AddTypeReference( //FIXME multiple classes could implement same interface - //FIXME so should addTypeReference only once. check MetadataTokens for reference? - resolutionScope: default(TypeReferenceHandle), //FIXME interface could be in another assembly - @namespace: metadata.GetOrAddString(interfaze.ContainingNamespace), - name: metadata.GetOrAddString(interfaze.Name))); + metadata.AddNestedType( + GenerateType(assembly, metadata, methodGenerator, fieldGenerator, nestedType), + typeDefinitionHandle); } } } @@ -158,5 +85,87 @@ public void Generate(Assembly assembly) } + private TypeDefinitionHandle GenerateType(Assembly assembly, MetadataBuilder metadata, MethodGenerator methodGenerator, FieldGenerator fieldGenerator, Model.Types.TypeDefinition typeDefinition) + { + MethodDefinitionHandle? firstMethodHandle = null; + FieldDefinitionHandle? firstFieldHandle = null; + + var typeAttributes = AttributesProvider.GetAttributesFor(typeDefinition); + + foreach (var method in typeDefinition.Methods) + { + var methodHandle = methodGenerator.Generate(method); + + if (!firstMethodHandle.HasValue) + { + firstMethodHandle = methodHandle; + } + } + + foreach (var field in typeDefinition.Fields) + { + var fieldDefinitionHandle = fieldGenerator.Generate(field); + + + if (!firstFieldHandle.HasValue) + { + firstFieldHandle = fieldDefinitionHandle; + } + } + + /* TODO Properties: works but model is missing Property concept + + var propertySignatureBlogBuilder = new BlobBuilder(); + new BlobEncoder(propertySignatureBlogBuilder) + .PropertySignature(isInstanceProperty: true) //FIXME when false + .Parameters( + 0, + returnType => returnType.Type().Int32(), //FIXME backingField type + parameters => { }); + + var propertyDefinitionHandle = metadata.AddProperty( + attributes: PropertyAttributes.None, //FIXME + name: metadata.GetOrAddString(""), //FIXME property name + signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); + + // asociate methods (get, set) to property + metadata.AddMethodSemantics( + propertyDefinitionHandle, + method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, + methodHandle); //getter/setter + metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); + */ + + + //FIXME: comparing to the name of the current assembly could result in a false positive? + //FIXME: this posibly adds the type reference more than once + var baseType = typeDefinition.Base == null + ? default(EntityHandle) + : metadata.AddTypeReference( + resolutionScope: typeDefinition.Base.ContainingAssembly.Name.Equals(assembly.Name) ? default(AssemblyReferenceHandle) : assemblyReferences[typeDefinition.Base.ContainingAssembly.Name], + @namespace: metadata.GetOrAddString(typeDefinition.Base.ContainingNamespace), + name: metadata.GetOrAddString(typeDefinition.Base.Name)); + + var typeDefinitionHandle = metadata.AddTypeDefinition( + attributes: typeAttributes, + @namespace: metadata.GetOrAddString(typeDefinition.ContainingNamespace.Name), + name: metadata.GetOrAddString(typeDefinition.Name), + baseType: baseType, + fieldList: firstFieldHandle ?? fieldGenerator.NextFieldHandle(), + methodList: firstMethodHandle ?? methodGenerator.NextMethodHandle()); + + foreach (var interfaze in typeDefinition.Interfaces) + { + metadata.AddInterfaceImplementation( + type: typeDefinitionHandle, + implementedInterface: metadata.AddTypeReference( //FIXME multiple classes could implement same interface + //FIXME so should addTypeReference only once. check MetadataTokens for reference? + resolutionScope: default(TypeReferenceHandle), //FIXME interface could be in another assembly + @namespace: metadata.GetOrAddString(interfaze.ContainingNamespace), + name: metadata.GetOrAddString(interfaze.Name))); + } + + return typeDefinitionHandle; + } } } \ No newline at end of file diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 9b71d9dd..1d4ae62a 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -8,20 +8,6 @@ public static class TypeEncoder //FIXME: names, type of parameters public static void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEncoder) { - - // reflection? FIXME - //var type = Model.Types.PlatformTypes.Values().FirstOrDefault(t => method.ReturnType.Equals(t)); - //if (type == null) - //{ - // throw new Exception("Unknow return type"); - - //} - //else - //{ - // var returnTypeMethod = returnType.GetType().GetMethod(type.ToString()); - // returnTypeMethod.Invoke(returnType, new Object[] { }); - //} - //FIXME incomplete if (type.Equals(Model.Types.PlatformTypes.Boolean)) { From 3f3009d7b6518e0095fc44aa31c9e0a85085da52 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 11 Jul 2019 20:54:05 -0300 Subject: [PATCH 017/256] better interface and hierarchy --- Examples/Examples.cs | 14 ++++++-- MetadataGenerator/Generator.cs | 57 ++++++++++++++++++++++---------- MetadataGenerator/TypeEncoder.cs | 4 +++ 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index e8d6083b..6a0aa028 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -136,8 +136,13 @@ private int Sum(int arg1, int arg2) namespace Interfaces { - public class ClassImplementingInterface : ISampleInterface + public class ClassImplementingInterface : ISampleInterface, IComparable { + public int CompareTo(object obj) + { + return 0; + } + public void DoSomething() { } @@ -154,11 +159,16 @@ public interface ISampleInterface } - public struct ComplexStruct : ISampleInterface + public struct ComplexStruct : ISampleInterface, IComparable { public void DoSomething() { } + + public int CompareTo(object obj) + { + return 0; + } } } diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index b9d62356..cb64aaba 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -13,10 +13,11 @@ namespace MetadataGenerator { public class Generator : IGenerator { - private static readonly Guid s_guid = new Guid("97F4DBD4-F6D1-4FAD-91B3-1001F92068E5"); //FIXME: ?? private static readonly BlobContentId s_contentId = new BlobContentId(s_guid, 0x04030201); //FIXME: ?? private readonly IDictionary assemblyReferences = new Dictionary(); + //FIXME better name. It's not all the type references but just the ones needed for Base type and interfaces + private readonly IDictionary typeReferences = new Dictionary(); public void Generate(Assembly assembly) { @@ -47,10 +48,11 @@ public void Generate(Assembly assembly) ); } + // FIXME parameters depend of assembly info that is not in the model? metadata.AddModule( generation: 0, // FIXME ?? moduleName: metadata.GetOrAddString($"{assembly.Name}.dll"), - mvid: metadata.GetOrAddGuid(s_guid), // FIXME ?? + mvid: metadata.GetOrAddGuid(s_guid), // FIXME ?? module identified id encId: default(GuidHandle), // FIXME ?? encBaseId: default(GuidHandle)); // FIXME ?? @@ -136,15 +138,11 @@ private TypeDefinitionHandle GenerateType(Assembly assembly, MetadataBuilder met metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); */ - - //FIXME: comparing to the name of the current assembly could result in a false positive? - //FIXME: this posibly adds the type reference more than once - var baseType = typeDefinition.Base == null - ? default(EntityHandle) - : metadata.AddTypeReference( - resolutionScope: typeDefinition.Base.ContainingAssembly.Name.Equals(assembly.Name) ? default(AssemblyReferenceHandle) : assemblyReferences[typeDefinition.Base.ContainingAssembly.Name], - @namespace: metadata.GetOrAddString(typeDefinition.Base.ContainingNamespace), - name: metadata.GetOrAddString(typeDefinition.Base.Name)); + var baseType = default(EntityHandle); + if (typeDefinition.Base != null) + { + baseType = GetOrAddTypeReference(assembly, metadata, typeDefinition.Base); + } var typeDefinitionHandle = metadata.AddTypeDefinition( attributes: typeAttributes, @@ -156,16 +154,39 @@ private TypeDefinitionHandle GenerateType(Assembly assembly, MetadataBuilder met foreach (var interfaze in typeDefinition.Interfaces) { - metadata.AddInterfaceImplementation( - type: typeDefinitionHandle, - implementedInterface: metadata.AddTypeReference( //FIXME multiple classes could implement same interface - //FIXME so should addTypeReference only once. check MetadataTokens for reference? - resolutionScope: default(TypeReferenceHandle), //FIXME interface could be in another assembly - @namespace: metadata.GetOrAddString(interfaze.ContainingNamespace), - name: metadata.GetOrAddString(interfaze.Name))); + metadata.AddInterfaceImplementation(type: typeDefinitionHandle, implementedInterface: GetOrAddTypeReference(assembly, metadata, interfaze)); } return typeDefinitionHandle; } + + + private EntityHandle GetOrAddTypeReference(Assembly currentAssembly, MetadataBuilder metadata, Model.Types.IBasicType type) + { + TypeReferenceHandle typeReference; + var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{type.Name}"; + if (typeReferences.TryGetValue(typeReferenceKey, out var value)) + { + typeReference = value; + } + else + { + var resolutionScope = type.ContainingAssembly.Name.Equals(currentAssembly.Name) + ? default(AssemblyReferenceHandle) + : assemblyReferences[type.ContainingAssembly.Name]; + + //FIXME: comparing to the name of the current assembly could result in a false positive? + typeReference = metadata.AddTypeReference( + resolutionScope: resolutionScope, + @namespace: metadata.GetOrAddString(type.ContainingNamespace), + name: metadata.GetOrAddString(type.Name)); + + typeReferences.Add(typeReferenceKey, typeReference); + + } + + return typeReference; + } + } } \ No newline at end of file diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 1d4ae62a..10ac1cb9 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -61,6 +61,10 @@ public static void Encode(Model.Types.IType type, SignatureTypeEncoder signature { signatureTypeEncoder.Single(); } + else if (type.Equals(Model.Types.PlatformTypes.Object)) + { + signatureTypeEncoder.Object(); + } else { throw new Exception("Unknown value:" + type.ToString()); From d3a8c01a2e152d9e0ca02f51005de2c743ac7ab1 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 14 Jul 2019 14:35:45 -0300 Subject: [PATCH 018/256] Fix nested namespaces and types generation --- Examples/Examples.cs | 58 ++++++++++++++++++++++++++++++++-- MetadataGenerator/Generator.cs | 43 ++++++++++++++++++------- 2 files changed, 87 insertions(+), 14 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 6a0aa028..d5a655fe 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -27,6 +27,7 @@ public enum EnumOfUShorts : ushort USHORT1 = 1, USHORT2 = 2 } + } namespace Classes @@ -60,7 +61,7 @@ static StaticClass() } - public class ComplexClass + public class NonEmptyClass { private readonly int readOnlyIntField = 212; public string unassignedString; @@ -109,7 +110,7 @@ public struct EmptyStruct { } - public struct ComplexStruct + public struct NonEmptyStruct { private const string helloMessage = "hello"; @@ -231,8 +232,59 @@ public class NestedClass } } + namespace NestedNamespace + { + + public class A { } + + namespace NestedNestedNamesace + { + public class B + { + public class NestedB + { + + public class NestedNestedB { } + } + } + } + } + } //TODO namespace with all things combined +//TODO class with fields or methods that return other clases, structs, etc +/*namespace Complex +{ + namespace NestedNamespace + { + + public class ClassWithMethodsWithNonBuiltInReturnTypes + { + + public Exception ReturnsException() + { + return new Exception(); + } + + public Classes.EmptyClass ReturnsClassFromOtherNamespaceButCurrentAssembly() + { + return new Classes.EmptyClass(); + } + } + + public class OuterClass + { + public void DoNothingWith(Exception e) + { + + } + + public void DoNothingWith(Classes.EmptyClass e) + { + + } + } + } +}*/ -//TODO class with fields or methods that return other clases, structs, etc \ No newline at end of file diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index cb64aaba..699f40b8 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -61,16 +61,7 @@ public void Generate(Assembly assembly) foreach (var namezpace in assembly.RootNamespace.Namespaces) { - foreach (var typeDefinition in namezpace.Types) - { - var typeDefinitionHandle = GenerateType(assembly, metadata, methodGenerator, fieldGenerator, typeDefinition); - foreach (var nestedType in typeDefinition.Types) - { - metadata.AddNestedType( - GenerateType(assembly, metadata, methodGenerator, fieldGenerator, nestedType), - typeDefinitionHandle); - } - } + GenerateNamespace(assembly, metadata, methodGenerator, fieldGenerator, namezpace); } var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); var peBuilder = new ManagedPEBuilder( @@ -87,6 +78,36 @@ public void Generate(Assembly assembly) } + private void GenerateNamespace(Assembly assembly, MetadataBuilder metadata, MethodGenerator methodGenerator, FieldGenerator fieldGenerator, Namespace namezpace) + { + foreach (var nestedNamespace in namezpace.Namespaces) + { + GenerateNamespace(assembly, metadata, methodGenerator, fieldGenerator, nestedNamespace); + } + + foreach (var typeDefinition in namezpace.Types) + { + GenerateTypes(assembly, metadata, methodGenerator, fieldGenerator, typeDefinition); + } + } + + private TypeDefinitionHandle GenerateTypes(Assembly assembly, MetadataBuilder metadata, MethodGenerator methodGenerator, FieldGenerator fieldGenerator, Model.Types.TypeDefinition typeDefinition) + { + var nestedTypes = new List(); + foreach (var nestedType in typeDefinition.Types) + { + nestedTypes.Add(GenerateTypes(assembly, metadata, methodGenerator, fieldGenerator, nestedType)); + } + + var typeDefinitionHandle = GenerateType(assembly, metadata, methodGenerator, fieldGenerator, typeDefinition); + foreach (var nestedType in nestedTypes) + { + metadata.AddNestedType(nestedType, typeDefinitionHandle); + } + + return typeDefinitionHandle; + } + private TypeDefinitionHandle GenerateType(Assembly assembly, MetadataBuilder metadata, MethodGenerator methodGenerator, FieldGenerator fieldGenerator, Model.Types.TypeDefinition typeDefinition) { MethodDefinitionHandle? firstMethodHandle = null; @@ -146,7 +167,7 @@ private TypeDefinitionHandle GenerateType(Assembly assembly, MetadataBuilder met var typeDefinitionHandle = metadata.AddTypeDefinition( attributes: typeAttributes, - @namespace: metadata.GetOrAddString(typeDefinition.ContainingNamespace.Name), + @namespace: metadata.GetOrAddString(typeDefinition.ContainingNamespace.FullName), name: metadata.GetOrAddString(typeDefinition.Name), baseType: baseType, fieldList: firstFieldHandle ?? fieldGenerator.NextFieldHandle(), From 8bd668b75c3c4257a2a1a3257d06586b26a00e2c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 14 Jul 2019 17:50:58 -0300 Subject: [PATCH 019/256] refactor + non built in type encoding (to be fixed) --- Examples/Examples.cs | 38 ++-- MetadataGenerator/AssemblyGenerator.cs | 183 +++++++++++++++++++ MetadataGenerator/FieldGenerator.cs | 15 +- MetadataGenerator/Generator.cs | 196 ++------------------- MetadataGenerator/MetadataGenerator.csproj | 2 + MetadataGenerator/MethodGenerator.cs | 8 +- MetadataGenerator/TypeEncoder.cs | 24 ++- MetadataGenerator/TypeReferences.cs | 66 +++++++ 8 files changed, 306 insertions(+), 226 deletions(-) create mode 100644 MetadataGenerator/AssemblyGenerator.cs create mode 100644 MetadataGenerator/TypeReferences.cs diff --git a/Examples/Examples.cs b/Examples/Examples.cs index d5a655fe..a1545782 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -252,39 +252,25 @@ public class NestedNestedB { } } -//TODO namespace with all things combined -//TODO class with fields or methods that return other clases, structs, etc -/*namespace Complex +namespace Complex { - namespace NestedNamespace - { - public class ClassWithMethodsWithNonBuiltInReturnTypes - { + public class ClassWithMethodsWithNonBuiltInTypes + { - public Exception ReturnsException() - { - return new Exception(); - } + private Nested.NestedNamespace.NestedNestedNamesace.B b; - public Classes.EmptyClass ReturnsClassFromOtherNamespaceButCurrentAssembly() - { - return new Classes.EmptyClass(); - } + public Hierarchy.DerivedClass DoSomethingWith(Hierarchy.DerivedClass d) + { + return d; } - public class OuterClass + public Exception DoSomethingWith(Exception e) { - public void DoNothingWith(Exception e) - { - - } - - public void DoNothingWith(Classes.EmptyClass e) - { - - } + return e; } + } -}*/ + +} diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs new file mode 100644 index 00000000..d7e97b46 --- /dev/null +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using Model; + +namespace MetadataGenerator +{ + public class AssemblyGenerator + { + private readonly Model.Assembly assembly; + private readonly MetadataBuilder metadata; + private readonly TypeReferences typeReferences; + private readonly MethodGenerator methodGenerator; + private readonly FieldGenerator fieldGenerator; + private MetadataBuilder resolvedMetadata = null; + + public MetadataBuilder ResolvedMetadata => resolvedMetadata ?? throw new Exception("Generate was not called"); + public BlobBuilder IlStream => resolvedMetadata != null ? methodGenerator.IlStream() : throw new Exception("Generate was not called"); + + private AssemblyGenerator(Model.Assembly assembly, MetadataBuilder metadata, TypeReferences typeReferences, MethodGenerator methodGenerator, FieldGenerator fieldGenerator) + { + this.metadata = metadata; + this.typeReferences = typeReferences; + this.methodGenerator = methodGenerator; + this.fieldGenerator = fieldGenerator; + this.assembly = assembly; + } + + public static AssemblyGenerator For(Model.Assembly assembly) + { + var metadata = new MetadataBuilder(); + var typeReferences = new TypeReferences(metadata, assembly); + var typeEncoder = new TypeEncoder(typeReferences); + var methodGenerator = new MethodGenerator(metadata, typeEncoder); + var fieldGenerator = new FieldGenerator(metadata, typeEncoder); + return new AssemblyGenerator( + assembly, + metadata, + typeReferences, + methodGenerator, + fieldGenerator); + } + + + public AssemblyGenerator Generate() + { + if (resolvedMetadata != null) + { + throw new Exception("Generate was already called for this generator"); + } + + metadata.AddAssembly( + name: metadata.GetOrAddString(assembly.Name), + version: new Version(1, 0, 0, 0), // FIXME ?? + culture: default(StringHandle), // FIXME ?? + publicKey: default(BlobHandle), // FIXME ?? + flags: AssemblyFlags.PublicKey, // FIXME ?? + hashAlgorithm: AssemblyHashAlgorithm.Sha1); // FIXME ?? + + // FIXME parameters depend of assembly info that is not in the model? + metadata.AddModule( + generation: 0, // FIXME ?? + moduleName: metadata.GetOrAddString($"{assembly.Name}.dll"), + mvid: default(GuidHandle), // FIXME ?? + encId: default(GuidHandle), // FIXME ?? + encBaseId: default(GuidHandle)); // FIXME ?? + + foreach (var namezpace in assembly.RootNamespace.Namespaces) + { + Generate(namezpace); + } + + resolvedMetadata = metadata; + + return this; + } + + private void Generate(Namespace namezpace) + { + foreach (var nestedNamespace in namezpace.Namespaces) + { + Generate(nestedNamespace); + } + + foreach (var type in namezpace.Types) + { + GenerateTypesOf(type); + } + } + + private TypeDefinitionHandle GenerateTypesOf(Model.Types.TypeDefinition type) + { + var nestedTypes = new List(); + foreach (var nestedType in type.Types) + { + nestedTypes.Add(GenerateTypesOf(nestedType)); + } + + var typeDefinitionHandle = Generate(type); + foreach (var nestedType in nestedTypes) + { + metadata.AddNestedType(nestedType, typeDefinitionHandle); + } + + return typeDefinitionHandle; + } + + private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) + { + MethodDefinitionHandle? firstMethodHandle = null; + FieldDefinitionHandle? firstFieldHandle = null; + + var typeAttributes = AttributesProvider.GetAttributesFor(type); + + foreach (var method in type.Methods) + { + var methodHandle = methodGenerator.Generate(method); + + if (!firstMethodHandle.HasValue) + { + firstMethodHandle = methodHandle; + } + } + + foreach (var field in type.Fields) + { + var fieldDefinitionHandle = fieldGenerator.Generate(field); + + + if (!firstFieldHandle.HasValue) + { + firstFieldHandle = fieldDefinitionHandle; + } + } + + /* TODO Properties: works but model is missing Property concept + + var propertySignatureBlogBuilder = new BlobBuilder(); + new BlobEncoder(propertySignatureBlogBuilder) + .PropertySignature(isInstanceProperty: true) //FIXME when false + .Parameters( + 0, + returnType => returnType.Type().Int32(), //FIXME backingField type + parameters => { }); + + var propertyDefinitionHandle = metadata.AddProperty( + attributes: PropertyAttributes.None, //FIXME + name: metadata.GetOrAddString(""), //FIXME property name + signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); + + // asociate methods (get, set) to property + metadata.AddMethodSemantics( + propertyDefinitionHandle, + method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, + methodHandle); //getter/setter + metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); + */ + + var baseType = default(EntityHandle); + if (type.Base != null) + { + baseType = typeReferences.TypeReferenceOf(type.Base); + } + + var typeDefinitionHandle = metadata.AddTypeDefinition( + attributes: typeAttributes, + @namespace: metadata.GetOrAddString(type.ContainingNamespace.FullName), + name: metadata.GetOrAddString(type.Name), + baseType: baseType, + fieldList: firstFieldHandle ?? fieldGenerator.NextFieldHandle(), + methodList: firstMethodHandle ?? methodGenerator.NextMethodHandle()); + + foreach (var interfaze in type.Interfaces) + { + metadata.AddInterfaceImplementation(type: typeDefinitionHandle, implementedInterface: typeReferences.TypeReferenceOf(interfaze)); + } + + return typeDefinitionHandle; + } + } +} diff --git a/MetadataGenerator/FieldGenerator.cs b/MetadataGenerator/FieldGenerator.cs index 85a21f51..7fd5d25a 100644 --- a/MetadataGenerator/FieldGenerator.cs +++ b/MetadataGenerator/FieldGenerator.cs @@ -1,5 +1,4 @@ -using System; -using System.Reflection.Metadata; +using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; namespace MetadataGenerator @@ -8,14 +7,17 @@ public class FieldGenerator { private MetadataBuilder metadata; private int nextOffset; + private readonly TypeEncoder typeEncoder; - public FieldGenerator(MetadataBuilder metadata) + public FieldGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) { this.metadata = metadata; this.nextOffset = 1; + this.typeEncoder = typeEncoder; } - public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) { + public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) + { var fieldSignatureBlobBuilder = new BlobBuilder(); var fieldSignature = new BlobEncoder(fieldSignatureBlobBuilder).FieldSignature(); @@ -33,7 +35,7 @@ public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) { } else { - TypeEncoder.Encode(field.Type, fieldSignature); + typeEncoder.Encode(field.Type, fieldSignature); } var fieldDefinitionHandle = metadata.AddFieldDefinition( @@ -53,7 +55,8 @@ public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) { } - public FieldDefinitionHandle NextFieldHandle() { + public FieldDefinitionHandle NextFieldHandle() + { return MetadataTokens.FieldDefinitionHandle(nextOffset); } } diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 699f40b8..1795314a 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.IO; -using System.Reflection; +using System.IO; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; @@ -13,201 +9,29 @@ namespace MetadataGenerator { public class Generator : IGenerator { - private static readonly Guid s_guid = new Guid("97F4DBD4-F6D1-4FAD-91B3-1001F92068E5"); //FIXME: ?? - private static readonly BlobContentId s_contentId = new BlobContentId(s_guid, 0x04030201); //FIXME: ?? - private readonly IDictionary assemblyReferences = new Dictionary(); - //FIXME better name. It's not all the type references but just the ones needed for Base type and interfaces - private readonly IDictionary typeReferences = new Dictionary(); public void Generate(Assembly assembly) { using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) { - var metadata = new MetadataBuilder(); - metadata.AddAssembly( - name: metadata.GetOrAddString(assembly.Name), - version: new Version(1, 0, 0, 0), // FIXME ?? - culture: default(StringHandle), // FIXME ?? - publicKey: default(BlobHandle), // FIXME ?? - flags: AssemblyFlags.PublicKey, // FIXME ?? - hashAlgorithm: AssemblyHashAlgorithm.Sha1); // FIXME ?? + var assemblyGenerator = AssemblyGenerator + .For(assembly) + .Generate(); - //FIXME see references in IlSpy generated vs original - //FIXME: assemblyName => assemblyRef could result in false positive? - foreach (var assemblyReference in assembly.References) - { - assemblyReferences.Add(assemblyReference.Name, metadata.AddAssemblyReference( - name: metadata.GetOrAddString(assemblyReference.Name), - version: new Version(4, 0, 0, 0), //FIXME ?? - culture: metadata.GetOrAddString("neutral"), //FIXME ?? - publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)),//FIXME ?? - flags: default(AssemblyFlags), //FIXME ?? - hashValue: default(BlobHandle))//FIXME ?? - ); - } - - // FIXME parameters depend of assembly info that is not in the model? - metadata.AddModule( - generation: 0, // FIXME ?? - moduleName: metadata.GetOrAddString($"{assembly.Name}.dll"), - mvid: metadata.GetOrAddGuid(s_guid), // FIXME ?? module identified id - encId: default(GuidHandle), // FIXME ?? - encBaseId: default(GuidHandle)); // FIXME ?? - - var methodGenerator = new MethodGenerator(metadata); - var fieldGenerator = new FieldGenerator(metadata); - - foreach (var namezpace in assembly.RootNamespace.Namespaces) - { - GenerateNamespace(assembly, metadata, methodGenerator, fieldGenerator, namezpace); - } - var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); + var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); //FIXME var peBuilder = new ManagedPEBuilder( header: peHeaderBuilder, - metadataRootBuilder: new MetadataRootBuilder(metadata), - ilStream: methodGenerator.IlStream(), - entryPoint: default(MethodDefinitionHandle), - flags: CorFlags.ILOnly | CorFlags.StrongNameSigned, - deterministicIdProvider: content => s_contentId); + metadataRootBuilder: new MetadataRootBuilder(assemblyGenerator.ResolvedMetadata), + ilStream: assemblyGenerator.IlStream, + entryPoint: default(MethodDefinitionHandle), //FIXME + flags: CorFlags.ILOnly | CorFlags.StrongNameSigned, //FIXME + deterministicIdProvider: content => default(BlobContentId)); //FIXME var peBlob = new BlobBuilder(); var contentId = peBuilder.Serialize(peBlob); peBlob.WriteContentTo(peStream); } - - } - - private void GenerateNamespace(Assembly assembly, MetadataBuilder metadata, MethodGenerator methodGenerator, FieldGenerator fieldGenerator, Namespace namezpace) - { - foreach (var nestedNamespace in namezpace.Namespaces) - { - GenerateNamespace(assembly, metadata, methodGenerator, fieldGenerator, nestedNamespace); - } - - foreach (var typeDefinition in namezpace.Types) - { - GenerateTypes(assembly, metadata, methodGenerator, fieldGenerator, typeDefinition); - } - } - - private TypeDefinitionHandle GenerateTypes(Assembly assembly, MetadataBuilder metadata, MethodGenerator methodGenerator, FieldGenerator fieldGenerator, Model.Types.TypeDefinition typeDefinition) - { - var nestedTypes = new List(); - foreach (var nestedType in typeDefinition.Types) - { - nestedTypes.Add(GenerateTypes(assembly, metadata, methodGenerator, fieldGenerator, nestedType)); - } - - var typeDefinitionHandle = GenerateType(assembly, metadata, methodGenerator, fieldGenerator, typeDefinition); - foreach (var nestedType in nestedTypes) - { - metadata.AddNestedType(nestedType, typeDefinitionHandle); - } - - return typeDefinitionHandle; } - - private TypeDefinitionHandle GenerateType(Assembly assembly, MetadataBuilder metadata, MethodGenerator methodGenerator, FieldGenerator fieldGenerator, Model.Types.TypeDefinition typeDefinition) - { - MethodDefinitionHandle? firstMethodHandle = null; - FieldDefinitionHandle? firstFieldHandle = null; - - var typeAttributes = AttributesProvider.GetAttributesFor(typeDefinition); - - foreach (var method in typeDefinition.Methods) - { - var methodHandle = methodGenerator.Generate(method); - - if (!firstMethodHandle.HasValue) - { - firstMethodHandle = methodHandle; - } - } - - foreach (var field in typeDefinition.Fields) - { - var fieldDefinitionHandle = fieldGenerator.Generate(field); - - - if (!firstFieldHandle.HasValue) - { - firstFieldHandle = fieldDefinitionHandle; - } - } - - /* TODO Properties: works but model is missing Property concept - - var propertySignatureBlogBuilder = new BlobBuilder(); - new BlobEncoder(propertySignatureBlogBuilder) - .PropertySignature(isInstanceProperty: true) //FIXME when false - .Parameters( - 0, - returnType => returnType.Type().Int32(), //FIXME backingField type - parameters => { }); - - var propertyDefinitionHandle = metadata.AddProperty( - attributes: PropertyAttributes.None, //FIXME - name: metadata.GetOrAddString(""), //FIXME property name - signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); - - // asociate methods (get, set) to property - metadata.AddMethodSemantics( - propertyDefinitionHandle, - method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, - methodHandle); //getter/setter - metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); - */ - - var baseType = default(EntityHandle); - if (typeDefinition.Base != null) - { - baseType = GetOrAddTypeReference(assembly, metadata, typeDefinition.Base); - } - - var typeDefinitionHandle = metadata.AddTypeDefinition( - attributes: typeAttributes, - @namespace: metadata.GetOrAddString(typeDefinition.ContainingNamespace.FullName), - name: metadata.GetOrAddString(typeDefinition.Name), - baseType: baseType, - fieldList: firstFieldHandle ?? fieldGenerator.NextFieldHandle(), - methodList: firstMethodHandle ?? methodGenerator.NextMethodHandle()); - - foreach (var interfaze in typeDefinition.Interfaces) - { - metadata.AddInterfaceImplementation(type: typeDefinitionHandle, implementedInterface: GetOrAddTypeReference(assembly, metadata, interfaze)); - } - - return typeDefinitionHandle; - } - - - private EntityHandle GetOrAddTypeReference(Assembly currentAssembly, MetadataBuilder metadata, Model.Types.IBasicType type) - { - TypeReferenceHandle typeReference; - var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{type.Name}"; - if (typeReferences.TryGetValue(typeReferenceKey, out var value)) - { - typeReference = value; - } - else - { - var resolutionScope = type.ContainingAssembly.Name.Equals(currentAssembly.Name) - ? default(AssemblyReferenceHandle) - : assemblyReferences[type.ContainingAssembly.Name]; - - //FIXME: comparing to the name of the current assembly could result in a false positive? - typeReference = metadata.AddTypeReference( - resolutionScope: resolutionScope, - @namespace: metadata.GetOrAddString(type.ContainingNamespace), - name: metadata.GetOrAddString(type.Name)); - - typeReferences.Add(typeReferenceKey, typeReference); - - } - - return typeReference; - } - } } \ No newline at end of file diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 887fd1e6..d4f9fd93 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -31,6 +31,8 @@ + + diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index 7fa32d1e..0f11eeba 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -10,12 +10,14 @@ public class MethodGenerator private readonly MetadataBuilder metadata; private readonly MethodBodyStreamEncoder methodBodyStream; private int nextOffset; + private readonly TypeEncoder typeEncoder; - public MethodGenerator(MetadataBuilder metadata) + public MethodGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) { this.metadata = metadata; this.methodBodyStream = new MethodBodyStreamEncoder(new BlobBuilder()); this.nextOffset = 1; + this.typeEncoder = typeEncoder; } public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) @@ -33,7 +35,7 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) } else { - TypeEncoder.Encode(method.ReturnType, returnType.Type()); + typeEncoder.Encode(method.ReturnType, returnType.Type()); } }, @@ -41,7 +43,7 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) { foreach (var parameter in method.Parameters) { - TypeEncoder.Encode(parameter.Type, parameters.AddParameter().Type()); + typeEncoder.Encode(parameter.Type, parameters.AddParameter().Type()); } }); diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 10ac1cb9..a8955266 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -1,14 +1,23 @@ -using System; +using System.Linq; using System.Reflection.Metadata.Ecma335; +using Model.Types; namespace MetadataGenerator { - public static class TypeEncoder + public class TypeEncoder { + + private readonly TypeReferences typeReferences; + + public TypeEncoder(TypeReferences typeReferences) + { + this.typeReferences = typeReferences; + } + //FIXME: names, type of parameters - public static void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEncoder) + public void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEncoder) { - //FIXME incomplete + //FIXME incomplete: missing some built in types if (type.Equals(Model.Types.PlatformTypes.Boolean)) { signatureTypeEncoder.Boolean(); @@ -67,7 +76,12 @@ public static void Encode(Model.Types.IType type, SignatureTypeEncoder signature } else { - throw new Exception("Unknown value:" + type.ToString()); + //FIXME: GetOrAddTypeReference needs IBasicType and type is IType. + //FIXME does this conversion always work? Equals works? breaks encapsulation + //FIXME: nonetheless it is a hack + // var convertedType = type as IBasicType; FIXME casting also breaks encapsulation and could fail + var convertedType = TypeHelper.GetClassHierarchy(type).First(t => t.Equals(type)); + signatureTypeEncoder.Type(typeReferences.TypeReferenceOf(convertedType), false); } } diff --git a/MetadataGenerator/TypeReferences.cs b/MetadataGenerator/TypeReferences.cs new file mode 100644 index 00000000..d3fe6d93 --- /dev/null +++ b/MetadataGenerator/TypeReferences.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +namespace MetadataGenerator +{ + //FIXME name, + public class TypeReferences + { + private readonly Model.Assembly assembly; + private readonly MetadataBuilder metadata; + private readonly IDictionary assemblyReferences = new Dictionary(); + //FIXME better name. It's not all the type references but just the ones needed for Base type and interfaces + private readonly IDictionary typeReferences = new Dictionary(); + + public TypeReferences(MetadataBuilder metadata, Model.Assembly assembly) + { + this.metadata = metadata; + this.assembly = assembly; + + //FIXME see references in IlSpy generated vs original + //FIXME: assemblyName => assemblyRef could result in false positive? + foreach (var assemblyReference in assembly.References) + { + assemblyReferences.Add(assemblyReference.Name, metadata.AddAssemblyReference( + name: metadata.GetOrAddString(assemblyReference.Name), + version: new Version(4, 0, 0, 0), //FIXME ?? + culture: metadata.GetOrAddString("neutral"), //FIXME ?? + publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)),//FIXME ?? + flags: default(AssemblyFlags), //FIXME ?? + hashValue: default(BlobHandle))//FIXME ?? + ); + } + } + + public EntityHandle TypeReferenceOf(Model.Types.IBasicType type) + { + TypeReferenceHandle typeReference; + var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{type.Name}"; + if (typeReferences.TryGetValue(typeReferenceKey, out var value)) + { + typeReference = value; + } + else + { + var resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) + ? default(AssemblyReferenceHandle) + : assemblyReferences[type.ContainingAssembly.Name]; + + //FIXME: comparing to the name of the current assembly could result in a false positive? + typeReference = metadata.AddTypeReference( + resolutionScope: resolutionScope, + @namespace: metadata.GetOrAddString(type.ContainingNamespace), + name: metadata.GetOrAddString(type.Name)); + + typeReferences.Add(typeReferenceKey, typeReference); + + } + + return typeReference; + } + } +} From 99088623bed051b5e5d19e89bf5311983b0f95b1 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 15 Jul 2019 23:18:50 -0300 Subject: [PATCH 020/256] minor refactor --- MetadataGenerator/AssemblyGenerator.cs | 1 + MetadataGenerator/AttributesProvider.cs | 35 ++++++++++++++++++++++++- MetadataGenerator/FieldGenerator.cs | 2 +- MetadataGenerator/Generator.cs | 8 ++---- MetadataGenerator/MethodGenerator.cs | 30 ++------------------- MetadataGenerator/TypeEncoder.cs | 1 - MetadataGenerator/TypeReferences.cs | 1 + 7 files changed, 41 insertions(+), 37 deletions(-) diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index d7e97b46..5a3ec2bf 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -51,6 +51,7 @@ public AssemblyGenerator Generate() throw new Exception("Generate was already called for this generator"); } + // FIXME parameters depend of assembly info that is not in the model? metadata.AddAssembly( name: metadata.GetOrAddString(assembly.Name), version: new Version(1, 0, 0, 0), // FIXME ?? diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs index 4b527fbe..3aeefd08 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -16,6 +16,7 @@ public static TypeAttributes GetAttributesFor(Model.Types.TypeDefinition typedef case Model.Types.TypeDefinitionKind.Enum: return EnumTypeAttributes(typedefinition); case Model.Types.TypeDefinitionKind.Interface: return InterfaceTypeAttributes(typedefinition); case Model.Types.TypeDefinitionKind.Struct: return StructTypeAttributes(typedefinition); + //TODO Delegate default: throw new Exception(); // FIXME }; } @@ -55,7 +56,7 @@ public static FieldAttributes GetAttributesFor(Model.Types.FieldDefinition field (field.IsStatic ? FieldAttributes.Static : 0) | (field.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Enum) ? FieldAttributes.Literal : 0); //FIXME also applies for const fields. // (field is readonly ? FieldAttributes.InitOnly : 0); //FIXME - switch (field.Visibility) //TODO extract, duplicated + switch (field.Visibility) { case Model.Types.VisibilityKind.Public: @@ -75,5 +76,37 @@ public static FieldAttributes GetAttributesFor(Model.Types.FieldDefinition field } return fieldAttributes; } + + public static MethodAttributes GetAttributesFor(Model.Types.MethodDefinition method) + { + var methodAttributes = + (method.IsAbstract ? MethodAttributes.Abstract : 0) | + (method.IsStatic ? MethodAttributes.Static : 0) | + (method.IsVirtual ? MethodAttributes.Virtual : 0) | + (method.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Interface) ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct + (method.IsConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | //FIXME should do the same for class constructor (cctor) + (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0) | //FIXME + MethodAttributes.HideBySig; //FIXME when? + switch (method.Visibility) + { + case Model.Types.VisibilityKind.Public: + methodAttributes |= MethodAttributes.Public; + break; + case Model.Types.VisibilityKind.Private: + methodAttributes |= MethodAttributes.Private; + break; + case Model.Types.VisibilityKind.Protected: + methodAttributes |= MethodAttributes.Family; + break; + case Model.Types.VisibilityKind.Internal: + methodAttributes |= MethodAttributes.Assembly; + break; + default: + throw method.Visibility.ToUnknownValueException(); + } + return methodAttributes; + + } + } } diff --git a/MetadataGenerator/FieldGenerator.cs b/MetadataGenerator/FieldGenerator.cs index 7fd5d25a..6556d670 100644 --- a/MetadataGenerator/FieldGenerator.cs +++ b/MetadataGenerator/FieldGenerator.cs @@ -5,7 +5,7 @@ namespace MetadataGenerator { public class FieldGenerator { - private MetadataBuilder metadata; + private readonly MetadataBuilder metadata; private int nextOffset; private readonly TypeEncoder typeEncoder; diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 1795314a..1dc43d56 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -9,23 +9,19 @@ namespace MetadataGenerator { public class Generator : IGenerator { - public void Generate(Assembly assembly) { - using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) { - var assemblyGenerator = AssemblyGenerator .For(assembly) .Generate(); - - var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); //FIXME + var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); var peBuilder = new ManagedPEBuilder( header: peHeaderBuilder, metadataRootBuilder: new MetadataRootBuilder(assemblyGenerator.ResolvedMetadata), ilStream: assemblyGenerator.IlStream, - entryPoint: default(MethodDefinitionHandle), //FIXME + entryPoint: default(MethodDefinitionHandle), flags: CorFlags.ILOnly | CorFlags.StrongNameSigned, //FIXME deterministicIdProvider: content => default(BlobContentId)); //FIXME var peBlob = new BlobBuilder(); diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index 0f11eeba..c62986c3 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -1,7 +1,6 @@ using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; -using Model; namespace MetadataGenerator { @@ -49,38 +48,13 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) var instructions = new InstructionEncoder(new BlobBuilder()); + //TODO: real body instructions.OpCode(ILOpCode.Nop); instructions.OpCode(ILOpCode.Ret); - var methodAttributes = - (method.IsAbstract ? MethodAttributes.Abstract : 0) | - (method.IsStatic ? MethodAttributes.Static : 0) | - (method.IsVirtual ? MethodAttributes.Virtual : 0) | - (method.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Interface) ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct - (method.IsConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | //FIXME should do the same for class constructor (cctor) - (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0) | //FIXME - MethodAttributes.HideBySig; //FIXME when? - - switch (method.Visibility) - { - case Model.Types.VisibilityKind.Public: - methodAttributes |= MethodAttributes.Public; - break; - case Model.Types.VisibilityKind.Private: - methodAttributes |= MethodAttributes.Private; - break; - case Model.Types.VisibilityKind.Protected: - methodAttributes |= MethodAttributes.Family; - break; - case Model.Types.VisibilityKind.Internal: - methodAttributes |= MethodAttributes.Assembly; - break; - default: - throw method.Visibility.ToUnknownValueException(); - } nextOffset++; return metadata.AddMethodDefinition( - attributes: methodAttributes, + attributes: AttributesProvider.GetAttributesFor(method), implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME name: metadata.GetOrAddString(method.Name), signature: metadata.GetOrAddBlob(methodSignature), diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index a8955266..32738aa6 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -14,7 +14,6 @@ public TypeEncoder(TypeReferences typeReferences) this.typeReferences = typeReferences; } - //FIXME: names, type of parameters public void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEncoder) { //FIXME incomplete: missing some built in types diff --git a/MetadataGenerator/TypeReferences.cs b/MetadataGenerator/TypeReferences.cs index d3fe6d93..a740c8cc 100644 --- a/MetadataGenerator/TypeReferences.cs +++ b/MetadataGenerator/TypeReferences.cs @@ -25,6 +25,7 @@ public TypeReferences(MetadataBuilder metadata, Model.Assembly assembly) //FIXME: assemblyName => assemblyRef could result in false positive? foreach (var assemblyReference in assembly.References) { + // FIXME parameters depend of assembly info that is not in the model? assemblyReferences.Add(assemblyReference.Name, metadata.AddAssemblyReference( name: metadata.GetOrAddString(assemblyReference.Name), version: new Version(4, 0, 0, 0), //FIXME ?? From b5abe26bc5777b7d9c6166175bb30be7383e2863 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 21 Jul 2019 16:45:17 -0300 Subject: [PATCH 021/256] fixes --- Examples/Examples.cs | 17 +++++++++++++++-- MetadataGenerator/FieldGenerator.cs | 21 +-------------------- MetadataGenerator/Generator.cs | 6 +++--- MetadataGenerator/MethodGenerator.cs | 5 +++-- MetadataGenerator/TypeEncoder.cs | 2 ++ 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index a1545782..2130e57a 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -137,7 +137,7 @@ private int Sum(int arg1, int arg2) namespace Interfaces { - public class ClassImplementingInterface : ISampleInterface, IComparable + public class ClassImplementingInterface : IExtendingSampleInterface, IComparable { public int CompareTo(object obj) { @@ -148,6 +148,14 @@ public void DoSomething() { } + public void DoSomethingExtended() + { + } + } + + public interface IExtendingSampleInterface : ISampleInterface + { + void DoSomethingExtended(); } public interface ISampleInterface @@ -252,7 +260,7 @@ public class NestedNestedB { } } -namespace Complex +namespace NonBuiltInTypes { public class ClassWithMethodsWithNonBuiltInTypes @@ -274,3 +282,8 @@ public Exception DoSomethingWith(Exception e) } +namespace Generics +{ + +} + diff --git a/MetadataGenerator/FieldGenerator.cs b/MetadataGenerator/FieldGenerator.cs index 6556d670..4a3aa15c 100644 --- a/MetadataGenerator/FieldGenerator.cs +++ b/MetadataGenerator/FieldGenerator.cs @@ -20,30 +20,12 @@ public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) { var fieldSignatureBlobBuilder = new BlobBuilder(); var fieldSignature = new BlobEncoder(fieldSignatureBlobBuilder).FieldSignature(); - - //FIXME: should be: if it is a custom type (not primitive nor primitive wrapper) - //FIXME: in the examples for the only one that needs this is the enum values - //FIXME: and the field value__ that is generated for the enum it is always a primitive so it needs to go to the else branch - if (field.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Enum) && !field.Name.Equals("value__")) - { - fieldSignature.Type( - metadata.AddTypeReference( //FIXME: this should be done only once per type. - default(AssemblyReferenceHandle), - metadata.GetOrAddString(field.ContainingType.ContainingNamespace.Name), - metadata.GetOrAddString(field.ContainingType.Name)), - true); - } - else - { - typeEncoder.Encode(field.Type, fieldSignature); - } - + typeEncoder.Encode(field.Type, fieldSignature); var fieldDefinitionHandle = metadata.AddFieldDefinition( attributes: AttributesProvider.GetAttributesFor(field), name: metadata.GetOrAddString(field.Name), signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); - if (field.Value != null) { metadata.AddConstant(fieldDefinitionHandle, field.Value.Value); @@ -52,7 +34,6 @@ public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) nextOffset++; return fieldDefinitionHandle; - } public FieldDefinitionHandle NextFieldHandle() diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 1dc43d56..051e0be5 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -21,9 +21,9 @@ public void Generate(Assembly assembly) header: peHeaderBuilder, metadataRootBuilder: new MetadataRootBuilder(assemblyGenerator.ResolvedMetadata), ilStream: assemblyGenerator.IlStream, - entryPoint: default(MethodDefinitionHandle), - flags: CorFlags.ILOnly | CorFlags.StrongNameSigned, //FIXME - deterministicIdProvider: content => default(BlobContentId)); //FIXME + entryPoint: default(MethodDefinitionHandle), // dlls have no entry point + flags: CorFlags.ILOnly //FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll + ); var peBlob = new BlobBuilder(); var contentId = peBuilder.Serialize(peBlob); peBlob.WriteContentTo(peStream); diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index c62986c3..1cfdd6f1 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -23,7 +23,7 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) { var methodSignature = new BlobBuilder(); new BlobEncoder(methodSignature) - .MethodSignature(isInstanceMethod: !method.IsStatic) //FIXME ? + .MethodSignature(isInstanceMethod: !method.IsStatic) .Parameters( method.Parameters.Count, returnType => @@ -53,13 +53,14 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) instructions.OpCode(ILOpCode.Ret); nextOffset++; + return metadata.AddMethodDefinition( attributes: AttributesProvider.GetAttributesFor(method), implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME name: metadata.GetOrAddString(method.Name), signature: metadata.GetOrAddBlob(methodSignature), bodyOffset: methodBodyStream.AddMethodBody(instructions), - parameterList: default(ParameterHandle)); //FIXME + parameterList: default(ParameterHandle)); } public BlobBuilder IlStream() diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 32738aa6..ad9b2f43 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -14,6 +14,8 @@ public TypeEncoder(TypeReferences typeReferences) this.typeReferences = typeReferences; } + + //FIXME esta bien usar equals? public void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEncoder) { //FIXME incomplete: missing some built in types From d22f7c35fae2ec7e87a0d4a786cae3d793f7ade0 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 21 Jul 2019 19:04:22 -0300 Subject: [PATCH 022/256] delegates --- Examples/Examples.cs | 21 +++++++++++ MetadataGenerator/AttributesProvider.cs | 50 +++++++++++++++++-------- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 2130e57a..f5210f40 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -182,6 +182,27 @@ public int CompareTo(object obj) } + +namespace Delegates +{ + public class SampleClass + { + public void DelegateMethod(int x) + { + } + } + + public class ClassThatUsesDelegate + { + + public delegate void Del(int x); + + //FIXME: code is generating Delegates.Del instead of Delegates.ClassThatUsesDelegate.Del. might be wrong for all nested types + public Del ReturnsADelegate() => new Del(new SampleClass().DelegateMethod); + + } +} + namespace Hierarchy { diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs index 3aeefd08..32035563 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -8,44 +8,51 @@ namespace MetadataGenerator //FIXME class and file name public static class AttributesProvider { - public static TypeAttributes GetAttributesFor(Model.Types.TypeDefinition typedefinition) + public static TypeAttributes GetAttributesFor(Model.Types.TypeDefinition typeDefinition) { - switch (typedefinition.Kind) + switch (typeDefinition.Kind) { - case Model.Types.TypeDefinitionKind.Class: return ClassTypeAttributes(typedefinition); - case Model.Types.TypeDefinitionKind.Enum: return EnumTypeAttributes(typedefinition); - case Model.Types.TypeDefinitionKind.Interface: return InterfaceTypeAttributes(typedefinition); - case Model.Types.TypeDefinitionKind.Struct: return StructTypeAttributes(typedefinition); - //TODO Delegate - default: throw new Exception(); // FIXME + case Model.Types.TypeDefinitionKind.Class: return ClassTypeAttributes(typeDefinition); + case Model.Types.TypeDefinitionKind.Enum: return EnumTypeAttributes(typeDefinition); + case Model.Types.TypeDefinitionKind.Interface: return InterfaceTypeAttributes(typeDefinition); + case Model.Types.TypeDefinitionKind.Struct: return StructTypeAttributes(typeDefinition); + case Model.Types.TypeDefinitionKind.Delegate: return DelegateTypeAttributes(typeDefinition); + default: throw new Exception(); }; } - private static TypeAttributes StructTypeAttributes(TypeDefinition typedefinition) + private static TypeAttributes DelegateTypeAttributes(TypeDefinition typeDefinition) + { + return TypeAttributes.Class + | TypeAttributes.Sealed + | VisibilityAttributesFor(typeDefinition); + } + + private static TypeAttributes StructTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Class | - (Model.Types.VisibilityKind.Public.Equals(typedefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic) | + VisibilityAttributesFor(typeDefinition) | TypeAttributes.SequentialLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit; //FIXME: when? } - private static TypeAttributes EnumTypeAttributes(Model.Types.TypeDefinition typedefinition) + private static TypeAttributes EnumTypeAttributes(Model.Types.TypeDefinition typeDefinition) { return TypeAttributes.Class | - (Model.Types.VisibilityKind.Public.Equals(typedefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic) | + VisibilityAttributesFor(typeDefinition) | TypeAttributes.Sealed; } - private static TypeAttributes ClassTypeAttributes(Model.Types.TypeDefinition typedefinition) + private static TypeAttributes ClassTypeAttributes(Model.Types.TypeDefinition typeDefinition) { return TypeAttributes.Class | //TODO: static => abstract & sealed and no BeforeFieldInitBeforeFieldInit TypeAttributes.BeforeFieldInit | //FIXME: when? - (Model.Types.VisibilityKind.Public.Equals(typedefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); + VisibilityAttributesFor(typeDefinition); } - private static TypeAttributes InterfaceTypeAttributes(Model.Types.TypeDefinition typedefinition) + private static TypeAttributes InterfaceTypeAttributes(Model.Types.TypeDefinition typeDefinition) { return TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; } @@ -108,5 +115,18 @@ public static MethodAttributes GetAttributesFor(Model.Types.MethodDefinition met } + //FIXME + private static TypeAttributes VisibilityAttributesFor(TypeDefinition typeDefinition) + { + if (typeDefinition.ContainingType != null) + { + return (Model.Types.VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.NestedPublic : TypeAttributes.NestedPrivate); + } + else + { + return (Model.Types.VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); + } + } + } } From a8915c53628917b4697e25750c38dbecf56e805b Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 28 Jul 2019 17:49:00 -0300 Subject: [PATCH 023/256] add some arrays and generic type support --- Examples/Examples.cs | 38 ++++++++++++++++++++- MetadataGenerator/MethodGenerator.cs | 1 - MetadataGenerator/TypeEncoder.cs | 50 ++++++++++++++++++++++------ 3 files changed, 77 insertions(+), 12 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index f5210f40..2f8a29a5 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace Enums { @@ -197,7 +198,7 @@ public class ClassThatUsesDelegate public delegate void Del(int x); - //FIXME: code is generating Delegates.Del instead of Delegates.ClassThatUsesDelegate.Del. might be wrong for all nested types + //FIXME: code is generating Delegates.Del instead of Delegates.ClassThatUsesDelegate.Del public Del ReturnsADelegate() => new Del(new SampleClass().DelegateMethod); } @@ -281,12 +282,16 @@ public class NestedNestedB { } } +//FIXME name namespace NonBuiltInTypes { public class ClassWithMethodsWithNonBuiltInTypes { + public string[] stringArrayField; + public Exception[] exceptionArrayField; + private Nested.NestedNamespace.NestedNestedNamesace.B b; public Hierarchy.DerivedClass DoSomethingWith(Hierarchy.DerivedClass d) @@ -299,12 +304,43 @@ public Exception DoSomethingWith(Exception e) return e; } + public string[] GetStringArray() + { + return new string[] { "hello", "world" }; + } + + public Exception[] GetExceptionArray() + { + return new Exception[] { }; + } + + //TODO pointers } } namespace Generics { + public class Generic + { + public Dictionary genericField; + + public IList GetExceptionsList(List _) + { + return new List(); + } + /* TODO + public T RecievesAndReturnsGeneric(T param) + { + return param; + } + + public IList RecievesAndReturnsGenericList(IList param) + { + return param; + } + */ + } } diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index 1cfdd6f1..6b1d06fc 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -45,7 +45,6 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) typeEncoder.Encode(parameter.Type, parameters.AddParameter().Type()); } }); - var instructions = new InstructionEncoder(new BlobBuilder()); //TODO: real body diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index ad9b2f43..8ec71d89 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Collections.Immutable; using System.Reflection.Metadata.Ecma335; using Model.Types; @@ -15,7 +16,7 @@ public TypeEncoder(TypeReferences typeReferences) } - //FIXME esta bien usar equals? + //FIXME signatureTypeEncoder should be by reference? or value? public void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEncoder) { //FIXME incomplete: missing some built in types @@ -77,15 +78,44 @@ public void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEnc } else { - //FIXME: GetOrAddTypeReference needs IBasicType and type is IType. - //FIXME does this conversion always work? Equals works? breaks encapsulation - //FIXME: nonetheless it is a hack - // var convertedType = type as IBasicType; FIXME casting also breaks encapsulation and could fail - var convertedType = TypeHelper.GetClassHierarchy(type).First(t => t.Equals(type)); - signatureTypeEncoder.Type(typeReferences.TypeReferenceOf(convertedType), false); + if (type is IBasicType) + { + var basicType = type as IBasicType; + if (basicType.GenericArguments.Count > 0) + { + var genericInstantiation = signatureTypeEncoder.GenericInstantiation( + typeReferences.TypeReferenceOf(basicType), + basicType.GenericArguments.Count, + type.TypeKind == TypeKind.ValueType + ); + foreach (var genericArg in basicType.GenericArguments) + { + Encode(genericArg, genericInstantiation.AddArgument()); + } + } + else + { + signatureTypeEncoder.Type(typeReferences.TypeReferenceOf(basicType), type.TypeKind == TypeKind.ValueType); + } + } + else if (type is ArrayType) + { + signatureTypeEncoder.Array(out var elementTypeEncoder, out var arrayShapeEncoder); + Encode((type as ArrayType).ElementsType, elementTypeEncoder); + arrayShapeEncoder.Shape( + (int)(type as ArrayType).Rank, + ImmutableArray.Create(1), //FIXME como se el size?? + ImmutableArray.Create(0)); + } + else if (type is PointerType) + { + throw new Exception("TODO"); //FIXME + } + else + { + throw new Exception("Type not supported"); + } } - } - } } From 1680f266be6ee3f2196b9f918632ec5995983054 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 31 Jul 2019 22:04:39 -0300 Subject: [PATCH 024/256] refactor examples + minor fixes --- Examples/Examples.cs | 110 +++++++++++++++--------- MetadataGenerator/AssemblyGenerator.cs | 10 +-- MetadataGenerator/AttributesProvider.cs | 64 ++++++++------ MetadataGenerator/Generator.cs | 2 +- 4 files changed, 113 insertions(+), 73 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 2f8a29a5..9bbf819a 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -31,7 +31,8 @@ public enum EnumOfUShorts : ushort } -namespace Classes + +namespace PropertiesGettersAndSetters { public class ClassWithProperties @@ -45,8 +46,16 @@ public class ClassWithProperties public string AnotherPropertyWithBackingField { get => otherBackingField; } private string otherBackingField; + public void get_ShouldNotHaveSpecialname() { } } + // TODO interface with properties + // TODO struct with properties + +} + +namespace Classes +{ public class EmptyClass { } @@ -62,7 +71,7 @@ static StaticClass() } - public class NonEmptyClass + public class SimpleClass { private readonly int readOnlyIntField = 212; public string unassignedString; @@ -103,6 +112,37 @@ public virtual void VirtualMethod() { } public abstract void AbstractMethod(); } + //FIXME generation not entirely correct + public class ClassWithMoreComplexFieldsAndParamtersOrReturnTypes + { + + public string[] stringArrayField; + public Exception[] exceptionArrayField; + private Nested.NestedNamespace.NestedNestedNamesace.B b; + + public Hierarchy.DerivedClass DoSomethingWith(Hierarchy.DerivedClass d) + { + return d; + } + + public Exception DoSomethingWith(Exception e) + { + return e; + } + + public string[] GetStringArray() + { + return new string[] { "hello", "world" }; + } + + public Exception[] GetExceptionArray() + { + return new Exception[] { }; + } + + //TODO pointers + } + } namespace Structs @@ -131,8 +171,6 @@ private int Sum(int arg1, int arg2) } } - //TODO struct with properties - } @@ -207,19 +245,44 @@ public class ClassThatUsesDelegate namespace Hierarchy { - public class BaseClass + public abstract class AbstractBaseClass { + public abstract void MustImplement(); + + public virtual void CanImplement() + { + } + + } + + public class BaseClass : AbstractBaseClass + { + public override void MustImplement() + { + throw new NotImplementedException(); + } + + protected void NotVisibileToDerivedClass() + { + } + + } public class DerivedClass : BaseClass { + public override void CanImplement() { } + + + } public class ClassDerivedFromSystemClass : Exception { + } public class ClassDerivedFromAccessibilityClass : Accessibility.CAccPropServicesClass @@ -282,43 +345,6 @@ public class NestedNestedB { } } -//FIXME name -namespace NonBuiltInTypes -{ - - public class ClassWithMethodsWithNonBuiltInTypes - { - - public string[] stringArrayField; - public Exception[] exceptionArrayField; - - private Nested.NestedNamespace.NestedNestedNamesace.B b; - - public Hierarchy.DerivedClass DoSomethingWith(Hierarchy.DerivedClass d) - { - return d; - } - - public Exception DoSomethingWith(Exception e) - { - return e; - } - - public string[] GetStringArray() - { - return new string[] { "hello", "world" }; - } - - public Exception[] GetExceptionArray() - { - return new Exception[] { }; - } - - //TODO pointers - } - -} - namespace Generics { public class Generic diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index 5a3ec2bf..cf14ab34 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -14,10 +14,10 @@ public class AssemblyGenerator private readonly TypeReferences typeReferences; private readonly MethodGenerator methodGenerator; private readonly FieldGenerator fieldGenerator; - private MetadataBuilder resolvedMetadata = null; + private MetadataBuilder generatedMetadata = null; - public MetadataBuilder ResolvedMetadata => resolvedMetadata ?? throw new Exception("Generate was not called"); - public BlobBuilder IlStream => resolvedMetadata != null ? methodGenerator.IlStream() : throw new Exception("Generate was not called"); + public MetadataBuilder GeneratedMetadata => generatedMetadata ?? throw new Exception("Generate was not called"); + public BlobBuilder IlStream => generatedMetadata != null ? methodGenerator.IlStream() : throw new Exception("Generate was not called"); private AssemblyGenerator(Model.Assembly assembly, MetadataBuilder metadata, TypeReferences typeReferences, MethodGenerator methodGenerator, FieldGenerator fieldGenerator) { @@ -46,7 +46,7 @@ public static AssemblyGenerator For(Model.Assembly assembly) public AssemblyGenerator Generate() { - if (resolvedMetadata != null) + if (generatedMetadata != null) { throw new Exception("Generate was already called for this generator"); } @@ -73,7 +73,7 @@ public AssemblyGenerator Generate() Generate(namezpace); } - resolvedMetadata = metadata; + generatedMetadata = metadata; return this; } diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs index 32035563..e9045b20 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -5,18 +5,30 @@ namespace MetadataGenerator { + + + /* + + getters and setters => specialname (rt?) + + see cases for events + + + + */ + //FIXME class and file name public static class AttributesProvider { - public static TypeAttributes GetAttributesFor(Model.Types.TypeDefinition typeDefinition) + public static TypeAttributes GetAttributesFor(TypeDefinition typeDefinition) { switch (typeDefinition.Kind) { - case Model.Types.TypeDefinitionKind.Class: return ClassTypeAttributes(typeDefinition); - case Model.Types.TypeDefinitionKind.Enum: return EnumTypeAttributes(typeDefinition); - case Model.Types.TypeDefinitionKind.Interface: return InterfaceTypeAttributes(typeDefinition); - case Model.Types.TypeDefinitionKind.Struct: return StructTypeAttributes(typeDefinition); - case Model.Types.TypeDefinitionKind.Delegate: return DelegateTypeAttributes(typeDefinition); + case TypeDefinitionKind.Class: return ClassTypeAttributes(typeDefinition); + case TypeDefinitionKind.Enum: return EnumTypeAttributes(typeDefinition); + case TypeDefinitionKind.Interface: return InterfaceTypeAttributes(typeDefinition); + case TypeDefinitionKind.Struct: return StructTypeAttributes(typeDefinition); + case TypeDefinitionKind.Delegate: return DelegateTypeAttributes(typeDefinition); default: throw new Exception(); }; } @@ -37,14 +49,14 @@ private static TypeAttributes StructTypeAttributes(TypeDefinition typeDefinition TypeAttributes.BeforeFieldInit; //FIXME: when? } - private static TypeAttributes EnumTypeAttributes(Model.Types.TypeDefinition typeDefinition) + private static TypeAttributes EnumTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Class | VisibilityAttributesFor(typeDefinition) | TypeAttributes.Sealed; } - private static TypeAttributes ClassTypeAttributes(Model.Types.TypeDefinition typeDefinition) + private static TypeAttributes ClassTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Class | //TODO: static => abstract & sealed and no BeforeFieldInitBeforeFieldInit @@ -52,30 +64,31 @@ private static TypeAttributes ClassTypeAttributes(Model.Types.TypeDefinition typ VisibilityAttributesFor(typeDefinition); } - private static TypeAttributes InterfaceTypeAttributes(Model.Types.TypeDefinition typeDefinition) + private static TypeAttributes InterfaceTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; } - public static FieldAttributes GetAttributesFor(Model.Types.FieldDefinition field) + public static FieldAttributes GetAttributesFor(FieldDefinition field) { var fieldAttributes = (field.IsStatic ? FieldAttributes.Static : 0) | - (field.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Enum) ? FieldAttributes.Literal : 0); //FIXME also applies for const fields. + (field.ContainingType.Kind.Equals(TypeDefinitionKind.Enum) && field.Type.Equals(field.ContainingType) ? FieldAttributes.Literal : 0) | // TODO also applies for const fields. + (field.ContainingType.Kind.Equals(TypeDefinitionKind.Enum) && field.Name.Equals("value__", StringComparison.InvariantCultureIgnoreCase) ? FieldAttributes.RTSpecialName | FieldAttributes.SpecialName : 0); // (field is readonly ? FieldAttributes.InitOnly : 0); //FIXME switch (field.Visibility) { - case Model.Types.VisibilityKind.Public: + case VisibilityKind.Public: fieldAttributes |= FieldAttributes.Public; break; - case Model.Types.VisibilityKind.Private: + case VisibilityKind.Private: fieldAttributes |= FieldAttributes.Private; break; - case Model.Types.VisibilityKind.Protected: + case VisibilityKind.Protected: fieldAttributes |= FieldAttributes.Family; break; - case Model.Types.VisibilityKind.Internal: + case VisibilityKind.Internal: fieldAttributes |= FieldAttributes.Assembly; break; default: @@ -84,28 +97,29 @@ public static FieldAttributes GetAttributesFor(Model.Types.FieldDefinition field return fieldAttributes; } - public static MethodAttributes GetAttributesFor(Model.Types.MethodDefinition method) + public static MethodAttributes GetAttributesFor(MethodDefinition method) { + var isConstructor = method.IsConstructor || method.Name.Equals(".cctor"); // FIXME maybe method can have a isClassConstructor or isTypeInitializer var methodAttributes = (method.IsAbstract ? MethodAttributes.Abstract : 0) | (method.IsStatic ? MethodAttributes.Static : 0) | (method.IsVirtual ? MethodAttributes.Virtual : 0) | - (method.ContainingType.Kind.Equals(Model.Types.TypeDefinitionKind.Interface) ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct - (method.IsConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | //FIXME should do the same for class constructor (cctor) - (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0) | //FIXME + (method.ContainingType.Kind.Equals(TypeDefinitionKind.Interface) ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct + (isConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | + (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0) | // FIXME fails if non getter/setter method starts with get__/set__ MethodAttributes.HideBySig; //FIXME when? switch (method.Visibility) { - case Model.Types.VisibilityKind.Public: + case VisibilityKind.Public: methodAttributes |= MethodAttributes.Public; break; - case Model.Types.VisibilityKind.Private: + case VisibilityKind.Private: methodAttributes |= MethodAttributes.Private; break; - case Model.Types.VisibilityKind.Protected: + case VisibilityKind.Protected: methodAttributes |= MethodAttributes.Family; break; - case Model.Types.VisibilityKind.Internal: + case VisibilityKind.Internal: methodAttributes |= MethodAttributes.Assembly; break; default: @@ -120,11 +134,11 @@ private static TypeAttributes VisibilityAttributesFor(TypeDefinition typeDefinit { if (typeDefinition.ContainingType != null) { - return (Model.Types.VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.NestedPublic : TypeAttributes.NestedPrivate); + return (VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.NestedPublic : TypeAttributes.NestedPrivate); } else { - return (Model.Types.VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); + return (VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); } } diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 051e0be5..2a415591 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -19,7 +19,7 @@ public void Generate(Assembly assembly) var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); var peBuilder = new ManagedPEBuilder( header: peHeaderBuilder, - metadataRootBuilder: new MetadataRootBuilder(assemblyGenerator.ResolvedMetadata), + metadataRootBuilder: new MetadataRootBuilder(assemblyGenerator.GeneratedMetadata), ilStream: assemblyGenerator.IlStream, entryPoint: default(MethodDefinitionHandle), // dlls have no entry point flags: CorFlags.ILOnly //FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll From 355c4708f72519ffb029180cb658c30011ffb92a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 8 Aug 2019 08:45:28 -0300 Subject: [PATCH 025/256] comments --- Examples/Examples.cs | 49 ++++++++++++------------- MetadataGenerator/AssemblyGenerator.cs | 23 ++++++------ MetadataGenerator/AttributesProvider.cs | 24 +++--------- MetadataGenerator/FieldGenerator.cs | 2 +- MetadataGenerator/Generator.cs | 16 ++++---- MetadataGenerator/MethodGenerator.cs | 4 +- MetadataGenerator/TypeEncoder.cs | 46 +++++++++++++---------- MetadataGenerator/TypeReferences.cs | 20 ++++------ 8 files changed, 84 insertions(+), 100 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 9bbf819a..c158a88d 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -31,7 +31,9 @@ public enum EnumOfUShorts : ushort } - +// TODO no yet supported in the framework model +// TODO interface with properties +// TODO struct with properties namespace PropertiesGettersAndSetters { @@ -48,10 +50,6 @@ public class ClassWithProperties public void get_ShouldNotHaveSpecialname() { } } - - // TODO interface with properties - // TODO struct with properties - } namespace Classes @@ -112,7 +110,7 @@ public virtual void VirtualMethod() { } public abstract void AbstractMethod(); } - //FIXME generation not entirely correct + //FIXME arrays not being generated correctly public class ClassWithMoreComplexFieldsAndParamtersOrReturnTypes { @@ -139,10 +137,7 @@ public Exception[] GetExceptionArray() { return new Exception[] { }; } - - //TODO pointers } - } namespace Structs @@ -173,7 +168,7 @@ private int Sum(int arg1, int arg2) } - +// TODO interface can have properties namespace Interfaces { public class ClassImplementingInterface : IExtendingSampleInterface, IComparable @@ -199,14 +194,9 @@ public interface IExtendingSampleInterface : ISampleInterface public interface ISampleInterface { - void DoSomething(); - - // todo interface can have properties - } - public struct ComplexStruct : ISampleInterface, IComparable { public void DoSomething() @@ -221,7 +211,6 @@ public int CompareTo(object obj) } - namespace Delegates { public class SampleClass @@ -265,30 +254,21 @@ public override void MustImplement() protected void NotVisibileToDerivedClass() { } - - } public class DerivedClass : BaseClass { - public override void CanImplement() { } - - } - public class ClassDerivedFromSystemClass : Exception { - - } public class ClassDerivedFromAccessibilityClass : Accessibility.CAccPropServicesClass { } - } namespace Nested @@ -345,17 +325,34 @@ public class NestedNestedB { } } +// TODO pointers +namespace PointersAndReferences +{ + + public class ClassWithMethodWithParametersWithKeywords + { + // FIXME ref and out are beign generated like type* instead of type&. Also the bytecodes needs to include the "out" keyword + public void MethodWithRefAndOutParameters(ref string refString, ref Exception refException, out int outInt, out Classes.SimpleClass outClass) + { + outInt = 2; + outClass = new Classes.SimpleClass(); + } + } +} + namespace Generics { public class Generic { public Dictionary genericField; + public IList> listOfListField; + public IList GetExceptionsList(List _) { return new List(); } - /* TODO + /* TODO public T RecievesAndReturnsGeneric(T param) { return param; diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index cf14ab34..2d4d4658 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -43,7 +43,6 @@ public static AssemblyGenerator For(Model.Assembly assembly) fieldGenerator); } - public AssemblyGenerator Generate() { if (generatedMetadata != null) @@ -54,19 +53,19 @@ public AssemblyGenerator Generate() // FIXME parameters depend of assembly info that is not in the model? metadata.AddAssembly( name: metadata.GetOrAddString(assembly.Name), - version: new Version(1, 0, 0, 0), // FIXME ?? - culture: default(StringHandle), // FIXME ?? - publicKey: default(BlobHandle), // FIXME ?? - flags: AssemblyFlags.PublicKey, // FIXME ?? - hashAlgorithm: AssemblyHashAlgorithm.Sha1); // FIXME ?? + version: new Version(1, 0, 0, 0), + culture: default(StringHandle), + publicKey: default(BlobHandle), + flags: AssemblyFlags.PublicKey, + hashAlgorithm: AssemblyHashAlgorithm.Sha1); // FIXME parameters depend of assembly info that is not in the model? metadata.AddModule( - generation: 0, // FIXME ?? + generation: 0, moduleName: metadata.GetOrAddString($"{assembly.Name}.dll"), - mvid: default(GuidHandle), // FIXME ?? - encId: default(GuidHandle), // FIXME ?? - encBaseId: default(GuidHandle)); // FIXME ?? + mvid: default(GuidHandle), + encId: default(GuidHandle), + encBaseId: default(GuidHandle)); foreach (var namezpace in assembly.RootNamespace.Namespaces) { @@ -113,7 +112,7 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) MethodDefinitionHandle? firstMethodHandle = null; FieldDefinitionHandle? firstFieldHandle = null; - var typeAttributes = AttributesProvider.GetAttributesFor(type); + var typeAttributes = AttributesProvider.GetTypeAttributesFor(type); foreach (var method in type.Methods) { @@ -136,7 +135,7 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) } } - /* TODO Properties: works but model is missing Property concept + /* TODO Properties: (works) but model is missing Property concept var propertySignatureBlogBuilder = new BlobBuilder(); new BlobEncoder(propertySignatureBlogBuilder) diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs index e9045b20..69c1892c 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -5,22 +5,9 @@ namespace MetadataGenerator { - - - /* - - getters and setters => specialname (rt?) - - see cases for events - - - - */ - - //FIXME class and file name public static class AttributesProvider { - public static TypeAttributes GetAttributesFor(TypeDefinition typeDefinition) + public static TypeAttributes GetTypeAttributesFor(TypeDefinition typeDefinition) { switch (typeDefinition.Kind) { @@ -69,13 +56,13 @@ private static TypeAttributes InterfaceTypeAttributes(TypeDefinition typeDefinit return TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; } - public static FieldAttributes GetAttributesFor(FieldDefinition field) + public static FieldAttributes GetTypeAttributesFor(FieldDefinition field) { var fieldAttributes = (field.IsStatic ? FieldAttributes.Static : 0) | (field.ContainingType.Kind.Equals(TypeDefinitionKind.Enum) && field.Type.Equals(field.ContainingType) ? FieldAttributes.Literal : 0) | // TODO also applies for const fields. (field.ContainingType.Kind.Equals(TypeDefinitionKind.Enum) && field.Name.Equals("value__", StringComparison.InvariantCultureIgnoreCase) ? FieldAttributes.RTSpecialName | FieldAttributes.SpecialName : 0); - // (field is readonly ? FieldAttributes.InitOnly : 0); //FIXME + // (field is readonly ? FieldAttributes.InitOnly : 0); //TODO switch (field.Visibility) { @@ -97,9 +84,9 @@ public static FieldAttributes GetAttributesFor(FieldDefinition field) return fieldAttributes; } - public static MethodAttributes GetAttributesFor(MethodDefinition method) + public static MethodAttributes GetTypeAttributesFor(MethodDefinition method) { - var isConstructor = method.IsConstructor || method.Name.Equals(".cctor"); // FIXME maybe method can have a isClassConstructor or isTypeInitializer + var isConstructor = method.IsConstructor || method.Name.Equals(".cctor"); // FIXME maybe MethodDefinition can have a isClassConstructor or isTypeInitializer var methodAttributes = (method.IsAbstract ? MethodAttributes.Abstract : 0) | (method.IsStatic ? MethodAttributes.Static : 0) | @@ -126,7 +113,6 @@ public static MethodAttributes GetAttributesFor(MethodDefinition method) throw method.Visibility.ToUnknownValueException(); } return methodAttributes; - } //FIXME diff --git a/MetadataGenerator/FieldGenerator.cs b/MetadataGenerator/FieldGenerator.cs index 4a3aa15c..597f95e9 100644 --- a/MetadataGenerator/FieldGenerator.cs +++ b/MetadataGenerator/FieldGenerator.cs @@ -22,7 +22,7 @@ public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) var fieldSignature = new BlobEncoder(fieldSignatureBlobBuilder).FieldSignature(); typeEncoder.Encode(field.Type, fieldSignature); var fieldDefinitionHandle = metadata.AddFieldDefinition( - attributes: AttributesProvider.GetAttributesFor(field), + attributes: AttributesProvider.GetTypeAttributesFor(field), name: metadata.GetOrAddString(field.Name), signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 2a415591..a0271d2a 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -13,17 +13,15 @@ public void Generate(Assembly assembly) { using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) { - var assemblyGenerator = AssemblyGenerator - .For(assembly) - .Generate(); + var assemblyGenerator = AssemblyGenerator.For(assembly).Generate(); var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); var peBuilder = new ManagedPEBuilder( - header: peHeaderBuilder, - metadataRootBuilder: new MetadataRootBuilder(assemblyGenerator.GeneratedMetadata), - ilStream: assemblyGenerator.IlStream, - entryPoint: default(MethodDefinitionHandle), // dlls have no entry point - flags: CorFlags.ILOnly //FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll - ); + header: peHeaderBuilder, + metadataRootBuilder: new MetadataRootBuilder(assemblyGenerator.GeneratedMetadata), + ilStream: assemblyGenerator.IlStream, + entryPoint: default(MethodDefinitionHandle), // dlls have no entry point + flags: CorFlags.ILOnly //FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll + ); var peBlob = new BlobBuilder(); var contentId = peBuilder.Serialize(peBlob); peBlob.WriteContentTo(peStream); diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index 6b1d06fc..a0183f11 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -47,14 +47,14 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) }); var instructions = new InstructionEncoder(new BlobBuilder()); - //TODO: real body + // TODO: real body instructions.OpCode(ILOpCode.Nop); instructions.OpCode(ILOpCode.Ret); nextOffset++; return metadata.AddMethodDefinition( - attributes: AttributesProvider.GetAttributesFor(method), + attributes: AttributesProvider.GetTypeAttributesFor(method), implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME name: metadata.GetOrAddString(method.Name), signature: metadata.GetOrAddBlob(methodSignature), diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 8ec71d89..11b305fe 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -15,64 +15,62 @@ public TypeEncoder(TypeReferences typeReferences) this.typeReferences = typeReferences; } - - //FIXME signatureTypeEncoder should be by reference? or value? - public void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEncoder) + // FIXME signatureTypeEncoder should be by reference? or value? + public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) { - //FIXME incomplete: missing some built in types if (type.Equals(Model.Types.PlatformTypes.Boolean)) { signatureTypeEncoder.Boolean(); } - else if (type.Equals(Model.Types.PlatformTypes.Byte)) + else if (type.Equals(PlatformTypes.Byte)) { signatureTypeEncoder.Byte(); } - else if (type.Equals(Model.Types.PlatformTypes.SByte)) + else if (type.Equals(PlatformTypes.SByte)) { signatureTypeEncoder.SByte(); } - else if (type.Equals(Model.Types.PlatformTypes.Char)) + else if (type.Equals(PlatformTypes.Char)) { signatureTypeEncoder.Char(); } - else if (type.Equals(Model.Types.PlatformTypes.Double)) + else if (type.Equals(PlatformTypes.Double)) { signatureTypeEncoder.Double(); } - else if (type.Equals(Model.Types.PlatformTypes.Int16)) + else if (type.Equals(PlatformTypes.Int16)) { signatureTypeEncoder.Int16(); } - else if (type.Equals(Model.Types.PlatformTypes.UInt16)) + else if (type.Equals(PlatformTypes.UInt16)) { signatureTypeEncoder.UInt16(); } - else if (type.Equals(Model.Types.PlatformTypes.Int32)) + else if (type.Equals(PlatformTypes.Int32)) { signatureTypeEncoder.Int32(); } - else if (type.Equals(Model.Types.PlatformTypes.UInt32)) + else if (type.Equals(PlatformTypes.UInt32)) { signatureTypeEncoder.UInt32(); } - else if (type.Equals(Model.Types.PlatformTypes.Int64)) + else if (type.Equals(PlatformTypes.Int64)) { signatureTypeEncoder.Int64(); } - else if (type.Equals(Model.Types.PlatformTypes.UInt64)) + else if (type.Equals(PlatformTypes.UInt64)) { signatureTypeEncoder.UInt64(); } - else if (type.Equals(Model.Types.PlatformTypes.String)) + else if (type.Equals(PlatformTypes.String)) { signatureTypeEncoder.String(); } - else if (type.Equals(Model.Types.PlatformTypes.Single)) + else if (type.Equals(PlatformTypes.Single)) { signatureTypeEncoder.Single(); } - else if (type.Equals(Model.Types.PlatformTypes.Object)) + else if (type.Equals(PlatformTypes.Object)) { signatureTypeEncoder.Object(); } @@ -87,7 +85,7 @@ public void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEnc typeReferences.TypeReferenceOf(basicType), basicType.GenericArguments.Count, type.TypeKind == TypeKind.ValueType - ); + ); foreach (var genericArg in basicType.GenericArguments) { Encode(genericArg, genericInstantiation.AddArgument()); @@ -109,7 +107,17 @@ public void Encode(Model.Types.IType type, SignatureTypeEncoder signatureTypeEnc } else if (type is PointerType) { - throw new Exception("TODO"); //FIXME + + // TODO there's also signatureTypeEncode.FunctionPointer()/IntPtr()/UIntPtr + var targetType = (type as PointerType).TargetType; + if (targetType.Equals(PlatformTypes.Void)) + { + signatureTypeEncoder.VoidPointer(); + } + else + { + Encode(targetType, signatureTypeEncoder.Pointer()); + } } else { diff --git a/MetadataGenerator/TypeReferences.cs b/MetadataGenerator/TypeReferences.cs index a740c8cc..4d04fe36 100644 --- a/MetadataGenerator/TypeReferences.cs +++ b/MetadataGenerator/TypeReferences.cs @@ -7,13 +7,12 @@ namespace MetadataGenerator { - //FIXME name, public class TypeReferences { private readonly Model.Assembly assembly; private readonly MetadataBuilder metadata; private readonly IDictionary assemblyReferences = new Dictionary(); - //FIXME better name. It's not all the type references but just the ones needed for Base type and interfaces + // FIXME better name. It's not all the type references but just the ones needed for Base type and interfaces private readonly IDictionary typeReferences = new Dictionary(); public TypeReferences(MetadataBuilder metadata, Model.Assembly assembly) @@ -25,14 +24,14 @@ public TypeReferences(MetadataBuilder metadata, Model.Assembly assembly) //FIXME: assemblyName => assemblyRef could result in false positive? foreach (var assemblyReference in assembly.References) { - // FIXME parameters depend of assembly info that is not in the model? + // FIXME parameters depend of assembly info that is not in the model assemblyReferences.Add(assemblyReference.Name, metadata.AddAssemblyReference( name: metadata.GetOrAddString(assemblyReference.Name), - version: new Version(4, 0, 0, 0), //FIXME ?? - culture: metadata.GetOrAddString("neutral"), //FIXME ?? - publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)),//FIXME ?? - flags: default(AssemblyFlags), //FIXME ?? - hashValue: default(BlobHandle))//FIXME ?? + version: new Version(4, 0, 0, 0), + culture: metadata.GetOrAddString("neutral"), + publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), + flags: default(AssemblyFlags), + hashValue: default(BlobHandle)) ); } } @@ -51,16 +50,13 @@ public EntityHandle TypeReferenceOf(Model.Types.IBasicType type) ? default(AssemblyReferenceHandle) : assemblyReferences[type.ContainingAssembly.Name]; - //FIXME: comparing to the name of the current assembly could result in a false positive? + // FIXME: comparing to the name of the current assembly could result in a false positive? typeReference = metadata.AddTypeReference( resolutionScope: resolutionScope, @namespace: metadata.GetOrAddString(type.ContainingNamespace), name: metadata.GetOrAddString(type.Name)); - typeReferences.Add(typeReferenceKey, typeReference); - } - return typeReference; } } From f81c1171e67f502d4958b0be30024d75cec16fc2 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 10 Aug 2019 20:45:49 -0300 Subject: [PATCH 026/256] handle method parameters --- Examples/Examples.cs | 18 ++++++++--- Examples/Examples.csproj | 2 ++ MetadataGenerator/AssemblyGenerator.cs | 2 -- MetadataGenerator/AttributesProvider.cs | 20 ++++++++++++ MetadataGenerator/MethodGenerator.cs | 43 +++++++++++++++++++++++-- MetadataGenerator/TypeEncoder.cs | 31 +++++++++++------- 6 files changed, 95 insertions(+), 21 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index c158a88d..04c8e908 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -110,11 +110,12 @@ public virtual void VirtualMethod() { } public abstract void AbstractMethod(); } - //FIXME arrays not being generated correctly public class ClassWithMoreComplexFieldsAndParamtersOrReturnTypes { public string[] stringArrayField; + public string[][] stringArrayArrayField; + public string[,,] stringJaggedArrayField; public Exception[] exceptionArrayField; private Nested.NestedNamespace.NestedNestedNamesace.B b; @@ -150,20 +151,24 @@ public struct NonEmptyStruct { private const string helloMessage = "hello"; + private int number; public void DoNothing() { } private string Greet() { - return helloMessage; } private int Sum(int arg1, int arg2) { - return arg1 + arg2; } + + public void ModifiesField(int value) + { + number = value; + } } } @@ -222,12 +227,10 @@ public void DelegateMethod(int x) public class ClassThatUsesDelegate { - public delegate void Del(int x); //FIXME: code is generating Delegates.Del instead of Delegates.ClassThatUsesDelegate.Del public Del ReturnsADelegate() => new Del(new SampleClass().DelegateMethod); - } } @@ -337,6 +340,11 @@ public void MethodWithRefAndOutParameters(ref string refString, ref Exception re outInt = 2; outClass = new Classes.SimpleClass(); } + + public unsafe void* UnsafeMethod(int* intPointer, Structs.EmptyStruct* structPointer) + { + return null; + } } } diff --git a/Examples/Examples.csproj b/Examples/Examples.csproj index c452715f..17c74d1c 100644 --- a/Examples/Examples.csproj +++ b/Examples/Examples.csproj @@ -18,6 +18,7 @@ prompt 4 true + true true @@ -25,6 +26,7 @@ prompt 4 true + true diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index 2d4d4658..b9cae2a6 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -128,7 +128,6 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) { var fieldDefinitionHandle = fieldGenerator.Generate(field); - if (!firstFieldHandle.HasValue) { firstFieldHandle = fieldDefinitionHandle; @@ -163,7 +162,6 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) { baseType = typeReferences.TypeReferenceOf(type.Base); } - var typeDefinitionHandle = metadata.AddTypeDefinition( attributes: typeAttributes, @namespace: metadata.GetOrAddString(type.ContainingNamespace.FullName), diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs index 69c1892c..1658e772 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -5,6 +5,7 @@ namespace MetadataGenerator { + // FIXME method names public static class AttributesProvider { public static TypeAttributes GetTypeAttributesFor(TypeDefinition typeDefinition) @@ -115,6 +116,25 @@ public static MethodAttributes GetTypeAttributesFor(MethodDefinition method) return methodAttributes; } + public static ParameterAttributes GetTypeAttributesFor(MethodParameter parameter) + { + var attributes = (parameter.HasDefaultValue ? ParameterAttributes.HasDefault : 0); + switch (parameter.Kind) + { + case MethodParameterKind.In: + // attributes |= ParameterAttributes.In; + //FIXME this seems to be always true... and illspy of original is not + break; + case MethodParameterKind.Out: + attributes |= ParameterAttributes.Out; + break; + case MethodParameterKind.Ref: + // FIXME + break; + } + return attributes; + } + //FIXME private static TypeAttributes VisibilityAttributesFor(TypeDefinition typeDefinition) { diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index a0183f11..d5501c76 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -10,6 +10,7 @@ public class MethodGenerator private readonly MethodBodyStreamEncoder methodBodyStream; private int nextOffset; private readonly TypeEncoder typeEncoder; + private readonly MethodParameterGenerator methodParameterGenerator; public MethodGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) { @@ -17,10 +18,12 @@ public MethodGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) this.methodBodyStream = new MethodBodyStreamEncoder(new BlobBuilder()); this.nextOffset = 1; this.typeEncoder = typeEncoder; + this.methodParameterGenerator = new MethodParameterGenerator(metadata); } public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) { + ParameterHandle? firstParameterHandle = null; var methodSignature = new BlobBuilder(); new BlobEncoder(methodSignature) .MethodSignature(isInstanceMethod: !method.IsStatic) @@ -43,6 +46,11 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) foreach (var parameter in method.Parameters) { typeEncoder.Encode(parameter.Type, parameters.AddParameter().Type()); + var parameterHandle = methodParameterGenerator.Generate(parameter); + if (!firstParameterHandle.HasValue) + { + firstParameterHandle = parameterHandle; + } } }); var instructions = new InstructionEncoder(new BlobBuilder()); @@ -50,7 +58,6 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) // TODO: real body instructions.OpCode(ILOpCode.Nop); instructions.OpCode(ILOpCode.Ret); - nextOffset++; return metadata.AddMethodDefinition( @@ -59,7 +66,7 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) name: metadata.GetOrAddString(method.Name), signature: metadata.GetOrAddBlob(methodSignature), bodyOffset: methodBodyStream.AddMethodBody(instructions), - parameterList: default(ParameterHandle)); + parameterList: firstParameterHandle ?? methodParameterGenerator.NextParameterHandle()); } public BlobBuilder IlStream() @@ -73,5 +80,37 @@ public MethodDefinitionHandle NextMethodHandle() } + private class MethodParameterGenerator + { + private readonly MetadataBuilder metadata; + private int nextOffset; + + public MethodParameterGenerator(MetadataBuilder metadata) + { + this.metadata = metadata; + this.nextOffset = 1; + } + + public ParameterHandle Generate(Model.Types.MethodParameter methodParameter) + { + nextOffset++; + + // TODO: metadata.AddGenericParameter() + examples + + return metadata.AddParameter( + AttributesProvider.GetTypeAttributesFor(methodParameter), + metadata.GetOrAddString(methodParameter.Name), + methodParameter.Index); + } + + public ParameterHandle NextParameterHandle() + { + return MetadataTokens.ParameterHandle(nextOffset); + } + + + } + } + } diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 11b305fe..8a301d30 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -18,7 +18,7 @@ public TypeEncoder(TypeReferences typeReferences) // FIXME signatureTypeEncoder should be by reference? or value? public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) { - if (type.Equals(Model.Types.PlatformTypes.Boolean)) + if (type.Equals(PlatformTypes.Boolean)) { signatureTypeEncoder.Boolean(); } @@ -76,9 +76,8 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) } else { - if (type is IBasicType) + if (type is IBasicType basicType) { - var basicType = type as IBasicType; if (basicType.GenericArguments.Count > 0) { var genericInstantiation = signatureTypeEncoder.GenericInstantiation( @@ -96,20 +95,28 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) signatureTypeEncoder.Type(typeReferences.TypeReferenceOf(basicType), type.TypeKind == TypeKind.ValueType); } } - else if (type is ArrayType) + else if (type is ArrayType arrayType) { - signatureTypeEncoder.Array(out var elementTypeEncoder, out var arrayShapeEncoder); - Encode((type as ArrayType).ElementsType, elementTypeEncoder); - arrayShapeEncoder.Shape( - (int)(type as ArrayType).Rank, - ImmutableArray.Create(1), //FIXME como se el size?? - ImmutableArray.Create(0)); + signatureTypeEncoder.Array( + elementTypeEncoder => + { + Encode(arrayType.ElementsType, elementTypeEncoder); + }, + arrayShapeEncoder => + { + // FIXME real values for sizes and lowerBounds + arrayShapeEncoder.Shape( + rank: (int)arrayType.Rank, + sizes: ImmutableArray.Empty, + lowerBounds: ImmutableArray.Empty); + }); + } - else if (type is PointerType) + else if (type is PointerType pointerType) { // TODO there's also signatureTypeEncode.FunctionPointer()/IntPtr()/UIntPtr - var targetType = (type as PointerType).TargetType; + var targetType = pointerType.TargetType; if (targetType.Equals(PlatformTypes.Void)) { signatureTypeEncoder.VoidPointer(); From 3488f62f69163ce7fb8b7f93630db76d6da0efc9 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 15 Aug 2019 23:18:45 -0300 Subject: [PATCH 027/256] support for executables --- CCI Backend.sln | 14 +++++++++ Console/Program.cs | 11 +++---- ExamplesEXE/ExamplesEXE.csproj | 43 ++++++++++++++++++++++++++ ExamplesEXE/Program.cs | 12 +++++++ ExamplesEXE/Properties/AssemblyInfo.cs | 26 ++++++++++++++++ MetadataGenerator/AssemblyGenerator.cs | 34 ++++++++++++-------- MetadataGenerator/Generator.cs | 9 ++++-- MetadataGenerator/MethodGenerator.cs | 3 +- MetadataGenerator/TypeEncoder.cs | 1 - 9 files changed, 129 insertions(+), 24 deletions(-) create mode 100644 ExamplesEXE/ExamplesEXE.csproj create mode 100644 ExamplesEXE/Program.cs create mode 100644 ExamplesEXE/Properties/AssemblyInfo.cs diff --git a/CCI Backend.sln b/CCI Backend.sln index b9e06e23..8016a733 100644 --- a/CCI Backend.sln +++ b/CCI Backend.sln @@ -22,6 +22,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MetadataGenerator", "Metada 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 @@ -120,6 +122,18 @@ Global {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/Console/Program.cs b/Console/Program.cs index c4d79bea..d4283981 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -364,10 +364,8 @@ private static void RunInterPointsToTests() } } - private static void DisassembleAndThenAssemble() + private static void DisassembleAndThenAssemble(string input) { - const string input = @"../../../Examples/bin/Debug/Examples.dll"; - var host = new Host(); PlatformTypes.Resolve(host); @@ -386,10 +384,11 @@ private static void DisassembleAndThenAssemble() } + static void Main(string[] args) - { - - DisassembleAndThenAssemble(); + { + DisassembleAndThenAssemble(@"../../../Examples/bin/Debug/Examples.dll"); + // DisassembleAndThenAssemble(@"../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"); //RunSomeTests(); //RunGenericsTests(); diff --git a/ExamplesEXE/ExamplesEXE.csproj b/ExamplesEXE/ExamplesEXE.csproj new file mode 100644 index 00000000..7a5d8886 --- /dev/null +++ b/ExamplesEXE/ExamplesEXE.csproj @@ -0,0 +1,43 @@ + + + + Debug + AnyCPU + {3630D8DA-4DAF-4983-9C02-EF5337B1050A} + Exe + ExamplesEXE + ExamplesEXE + v4.7 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + true + bin\Release + prompt + 4 + true + + + + + + + + + + + {73254DAD-0794-4BFA-A894-A24B79A006D0} + Examples + + + + \ No newline at end of file diff --git a/ExamplesEXE/Program.cs b/ExamplesEXE/Program.cs new file mode 100644 index 00000000..de46f74c --- /dev/null +++ b/ExamplesEXE/Program.cs @@ -0,0 +1,12 @@ +using Classes; + +namespace ExamplesEXE +{ + public class MainClass + { + public static void Main(string[] args) + { + _ = new SimpleClass(); + } + } +} diff --git a/ExamplesEXE/Properties/AssemblyInfo.cs b/ExamplesEXE/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..75a42525 --- /dev/null +++ b/ExamplesEXE/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("ExamplesEXE")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("${AuthorCopyright}")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index b9cae2a6..c7addda4 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -14,7 +14,11 @@ public class AssemblyGenerator private readonly TypeReferences typeReferences; private readonly MethodGenerator methodGenerator; private readonly FieldGenerator fieldGenerator; - private MetadataBuilder generatedMetadata = null; + private MetadataBuilder generatedMetadata; + + private MethodDefinitionHandle? mainMethodHandle; + public MethodDefinitionHandle? MainMethodHandle => generatedMetadata != null ? mainMethodHandle : throw new Exception("Generate was not called"); + public Boolean Executable => mainMethodHandle != null; public MetadataBuilder GeneratedMetadata => generatedMetadata ?? throw new Exception("Generate was not called"); public BlobBuilder IlStream => generatedMetadata != null ? methodGenerator.IlStream() : throw new Exception("Generate was not called"); @@ -50,7 +54,12 @@ public AssemblyGenerator Generate() throw new Exception("Generate was already called for this generator"); } - // FIXME parameters depend of assembly info that is not in the model? + foreach (var namezpace in assembly.RootNamespace.Namespaces) + { + Generate(namezpace); + } + + // FIXME args? metadata.AddAssembly( name: metadata.GetOrAddString(assembly.Name), version: new Version(1, 0, 0, 0), @@ -59,18 +68,12 @@ public AssemblyGenerator Generate() flags: AssemblyFlags.PublicKey, hashAlgorithm: AssemblyHashAlgorithm.Sha1); - // FIXME parameters depend of assembly info that is not in the model? metadata.AddModule( - generation: 0, - moduleName: metadata.GetOrAddString($"{assembly.Name}.dll"), - mvid: default(GuidHandle), - encId: default(GuidHandle), - encBaseId: default(GuidHandle)); - - foreach (var namezpace in assembly.RootNamespace.Namespaces) - { - Generate(namezpace); - } + generation: 0, + moduleName: metadata.GetOrAddString($"{assembly.Name}.{(Executable ? "exe" : "dll")}"), + mvid: metadata.GetOrAddGuid(Guid.NewGuid()), + encId: metadata.GetOrAddGuid(Guid.Empty), + encBaseId: metadata.GetOrAddGuid(Guid.Empty)); generatedMetadata = metadata; @@ -122,6 +125,11 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) { firstMethodHandle = methodHandle; } + + if (method.Name.Equals("Main")) // FIXME can a non entry point be called Main? + { + mainMethodHandle = methodHandle; + } } foreach (var field in type.Fields) diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index a0271d2a..8601c7b5 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -12,15 +12,18 @@ public class Generator : IGenerator public void Generate(Assembly assembly) { using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) + // using (var peStream = File.OpenWrite($"./{assembly.Name}.exe")) { var assemblyGenerator = AssemblyGenerator.For(assembly).Generate(); - var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: Characteristics.Dll); + var peHeaderBuilder = new PEHeaderBuilder( + imageCharacteristics: assemblyGenerator.Executable ? Characteristics.ExecutableImage : Characteristics.Dll + ); var peBuilder = new ManagedPEBuilder( header: peHeaderBuilder, metadataRootBuilder: new MetadataRootBuilder(assemblyGenerator.GeneratedMetadata), ilStream: assemblyGenerator.IlStream, - entryPoint: default(MethodDefinitionHandle), // dlls have no entry point - flags: CorFlags.ILOnly //FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll + entryPoint: assemblyGenerator.MainMethodHandle ?? default(MethodDefinitionHandle), + flags: CorFlags.ILOnly //FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll. Requires/prefers 32 bit? ); var peBlob = new BlobBuilder(); var contentId = peBuilder.Serialize(peBlob); diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index d5501c76..fedbae61 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -55,9 +55,10 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) }); var instructions = new InstructionEncoder(new BlobBuilder()); - // TODO: real body + // TODO real body instructions.OpCode(ILOpCode.Nop); instructions.OpCode(ILOpCode.Ret); + nextOffset++; return metadata.AddMethodDefinition( diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 8a301d30..50812dcc 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -7,7 +7,6 @@ namespace MetadataGenerator { public class TypeEncoder { - private readonly TypeReferences typeReferences; public TypeEncoder(TypeReferences typeReferences) From 46d34171de9fffb23c8aa501f0a64c714afe78df Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Fri, 23 Aug 2019 18:49:12 -0300 Subject: [PATCH 028/256] Indirect stores are a new bytecode instruction. --- Backend/Transformations/Disassembler.cs | 26 ++++++++----------- CCIProvider/CodeProvider.cs | 12 +++++++-- CCIProvider/OperationHelper.cs | 11 ++------ MetadataProvider/AssemblyExtractor.cs | 12 +++++++-- MetadataProvider/OperationHelper.cs | 15 +++-------- Model/Bytecode/Instructions.cs | 25 ++++++++++++++++-- Model/Bytecode/Visitor/IInstructionVisitor.cs | 3 ++- Model/Bytecode/Visitor/InstructionVisitor.cs | 1 + 8 files changed, 63 insertions(+), 42 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index f8e0b8c9..17d51a30 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -111,7 +111,7 @@ public InstructionTranslator(OperandStack stack, MethodBody body, IType returnTy this.returnType = returnType; } - public override void Visit(Bytecode.BasicInstruction op) + public override void Visit(Bytecode.BasicInstruction op) { switch (op.Operation) { @@ -200,10 +200,6 @@ public override void Visit(Bytecode.BasicInstruction op) ProcessLoadArrayElementAddress(op); break; - case Bytecode.BasicOperation.IndirectStore: - ProcessIndirectStore(op); - break; - case Bytecode.BasicOperation.StoreArrayElement: ProcessStoreArrayElement(op); break; @@ -393,15 +389,6 @@ private void ProcessLoadArrayElementAddress(Bytecode.BasicInstruction op) 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(); @@ -960,7 +947,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); diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index ffdcfffa..8e8a9d0a 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -490,7 +490,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: @@ -743,7 +743,15 @@ 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); + + 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); diff --git a/CCIProvider/OperationHelper.cs b/CCIProvider/OperationHelper.cs index 22dfb724..009c3172 100644 --- a/CCIProvider/OperationHelper.cs +++ b/CCIProvider/OperationHelper.cs @@ -82,15 +82,6 @@ public static BasicOperation ToBasicOperation(Cci.OperationCode opcode) 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: @@ -381,6 +372,8 @@ public static IType GetOperationType(Cci.OperationCode opcode) case Cci.OperationCode.Stelem_R8: case Cci.OperationCode.Conv_R8: case Cci.OperationCode.Conv_R_Un: return PlatformTypes.Float64; + case Cci.OperationCode.Stobj: return PlatformTypes.ValueType; + case Cci.OperationCode.Stind_Ref: case Cci.OperationCode.Ldnull: return PlatformTypes.Object; case Cci.OperationCode.Ldstr: return PlatformTypes.String; diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..33496933 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1095,7 +1095,7 @@ private IInstruction ExtractInstruction(ILInstruction operation) case SRM.ILOpCode.Stind_r8: case SRM.ILOpCode.Stind_ref: case SRM.ILOpCode.Stobj: - instruction = ProcessBasic(operation); + instruction = ProcessStoreIndirect(operation); break; case SRM.ILOpCode.Stloc: @@ -1608,7 +1608,15 @@ private IInstruction ProcessStoreLocal(ILInstruction op) return instruction; } - private IInstruction ProcessStoreField(ILInstruction op) + private IInstruction ProcessStoreIndirect(ILInstruction op) + { + var type = OperationHelper.GetOperationType(op.Opcode); + + var instruction = new StoreIndirectInstruction(op.Offset, type); + return instruction; + } + + private IInstruction ProcessStoreField(ILInstruction op) { var field = GetOperand(op); diff --git a/MetadataProvider/OperationHelper.cs b/MetadataProvider/OperationHelper.cs index c4999197..ed43d97c 100644 --- a/MetadataProvider/OperationHelper.cs +++ b/MetadataProvider/OperationHelper.cs @@ -82,15 +82,6 @@ public static BasicOperation ToBasicOperation(SRM.ILOpCode opcode) case SRM.ILOpCode.Ldelem_u4: case SRM.ILOpCode.Ldelem_ref: return BasicOperation.LoadArrayElement; case SRM.ILOpCode.Ldelema: return BasicOperation.LoadArrayElementAddress; - case SRM.ILOpCode.Stind_i: - case SRM.ILOpCode.Stind_i1: - case SRM.ILOpCode.Stind_i2: - case SRM.ILOpCode.Stind_i4: - case SRM.ILOpCode.Stind_i8: - case SRM.ILOpCode.Stind_r4: - case SRM.ILOpCode.Stind_r8: - case SRM.ILOpCode.Stind_ref: - case SRM.ILOpCode.Stobj: return BasicOperation.IndirectStore; case SRM.ILOpCode.Stelem: case SRM.ILOpCode.Stelem_i: case SRM.ILOpCode.Stelem_i1: @@ -365,8 +356,10 @@ public static IType GetOperationType(SRM.ILOpCode opcode) case SRM.ILOpCode.Stelem_r8: case SRM.ILOpCode.Conv_r8: case SRM.ILOpCode.Conv_r_un: return PlatformTypes.Float64; - case SRM.ILOpCode.Ldnull: return PlatformTypes.Object; - case SRM.ILOpCode.Ldstr: return PlatformTypes.String; + case SRM.ILOpCode.Stind_ref: + case SRM.ILOpCode.Ldnull: return PlatformTypes.Object; + case SRM.ILOpCode.Stobj: return PlatformTypes.ValueType; + case SRM.ILOpCode.Ldstr: return PlatformTypes.String; default: return null; } diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index bb12534e..fdb7e6e6 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -43,7 +43,6 @@ public enum BasicOperation IndirectLoad, LoadArrayElement, LoadArrayElementAddress, - IndirectStore, StoreArrayElement, Breakpoint, Return @@ -514,7 +513,29 @@ public override string ToString() } } - public class StoreInstruction : Instruction + public class StoreIndirectInstruction : Instruction + { + public IType Type { get; set; } + + public StoreIndirectInstruction(uint label, IType type) + : base(label) + { + this.Type = type; + } + + public override void Accept(IInstructionVisitor visitor) + { + base.Accept(visitor); + visitor.Visit(this); + } + + public override string ToString() + { + return this.ToString("indirect store {0}", this.Type); + } + } + + public class StoreInstruction : Instruction { public IVariable Target { get; set; } diff --git a/Model/Bytecode/Visitor/IInstructionVisitor.cs b/Model/Bytecode/Visitor/IInstructionVisitor.cs index 5d647a87..006268b0 100644 --- a/Model/Bytecode/Visitor/IInstructionVisitor.cs +++ b/Model/Bytecode/Visitor/IInstructionVisitor.cs @@ -15,7 +15,8 @@ public interface IInstructionVisitor void Visit(LoadInstruction instruction); void Visit(LoadFieldInstruction instruction); void Visit(LoadMethodAddressInstruction instruction); - void Visit(StoreInstruction instruction); + void Visit(StoreIndirectInstruction instruction); + void Visit(StoreInstruction instruction); void Visit(StoreFieldInstruction instruction); void Visit(ConvertInstruction instruction); void Visit(BranchInstruction instruction); diff --git a/Model/Bytecode/Visitor/InstructionVisitor.cs b/Model/Bytecode/Visitor/InstructionVisitor.cs index 1575ba7a..ad4cd445 100644 --- a/Model/Bytecode/Visitor/InstructionVisitor.cs +++ b/Model/Bytecode/Visitor/InstructionVisitor.cs @@ -23,6 +23,7 @@ public virtual void Visit(BasicInstruction instruction) { } public virtual void Visit(LoadInstruction instruction) { } public virtual void Visit(LoadFieldInstruction instruction) { } public virtual void Visit(LoadMethodAddressInstruction instruction) { } + public virtual void Visit(StoreIndirectInstruction instruction) { } public virtual void Visit(StoreInstruction instruction) { } public virtual void Visit(StoreFieldInstruction instruction) { } public virtual void Visit(ConvertInstruction instruction) { } From c6d51b01799e1ace5983a2fb17ea4b589baa0716 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Fri, 23 Aug 2019 23:45:30 -0300 Subject: [PATCH 029/256] Added load indirect instruction --- Backend/Transformations/Disassembler.cs | 20 +++++++--------- CCIProvider/CodeProvider.cs | 4 +++- CCIProvider/OperationHelper.cs | 16 +++---------- MetadataProvider/AssemblyExtractor.cs | 8 ++++--- MetadataProvider/OperationHelper.cs | 3 ++- Model/Bytecode/Instructions.cs | 24 +++++++++++++++++-- Model/Bytecode/Visitor/IInstructionVisitor.cs | 3 ++- Model/Bytecode/Visitor/InstructionVisitor.cs | 1 + 8 files changed, 47 insertions(+), 32 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 17d51a30..a2547c22 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -359,15 +359,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(); @@ -791,8 +782,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) { diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index 8e8a9d0a..124b6dde 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -687,7 +687,9 @@ 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); + + var instruction = new LoadIndirectInstruction(op.Offset, type); return instruction; } diff --git a/CCIProvider/OperationHelper.cs b/CCIProvider/OperationHelper.cs index 009c3172..e01bff60 100644 --- a/CCIProvider/OperationHelper.cs +++ b/CCIProvider/OperationHelper.cs @@ -57,18 +57,6 @@ public static BasicOperation ToBasicOperation(Cci.OperationCode opcode) 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: @@ -372,9 +360,11 @@ public static IType GetOperationType(Cci.OperationCode opcode) case Cci.OperationCode.Stelem_R8: case Cci.OperationCode.Conv_R8: case Cci.OperationCode.Conv_R_Un: return PlatformTypes.Float64; + case Cci.OperationCode.Ldobj: case Cci.OperationCode.Stobj: return PlatformTypes.ValueType; case Cci.OperationCode.Stind_Ref: - case Cci.OperationCode.Ldnull: return PlatformTypes.Object; + 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/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 33496933..03631b67 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1560,9 +1560,11 @@ private IInstruction ProcessLoadLocal(ILInstruction op) private IInstruction ProcessLoadIndirect(ILInstruction op) { - var instruction = new BasicInstruction(op.Offset, BasicOperation.IndirectLoad); - return instruction; - } + var type = OperationHelper.GetOperationType(op.Opcode); + + var instruction = new LoadIndirectInstruction(op.Offset, type); + return instruction; + } private IInstruction ProcessLoadField(ILInstruction op) { diff --git a/MetadataProvider/OperationHelper.cs b/MetadataProvider/OperationHelper.cs index ed43d97c..780a7a20 100644 --- a/MetadataProvider/OperationHelper.cs +++ b/MetadataProvider/OperationHelper.cs @@ -68,7 +68,6 @@ public static BasicOperation ToBasicOperation(SRM.ILOpCode opcode) case SRM.ILOpCode.Ldind_u1: case SRM.ILOpCode.Ldind_u2: case SRM.ILOpCode.Ldind_u4: - case SRM.ILOpCode.Ldobj: return BasicOperation.IndirectLoad; case SRM.ILOpCode.Ldelem: case SRM.ILOpCode.Ldelem_i: case SRM.ILOpCode.Ldelem_i1: @@ -356,8 +355,10 @@ public static IType GetOperationType(SRM.ILOpCode opcode) case SRM.ILOpCode.Stelem_r8: case SRM.ILOpCode.Conv_r8: case SRM.ILOpCode.Conv_r_un: return PlatformTypes.Float64; + case SRM.ILOpCode.Ldind_ref: case SRM.ILOpCode.Stind_ref: case SRM.ILOpCode.Ldnull: return PlatformTypes.Object; + case SRM.ILOpCode.Ldobj: case SRM.ILOpCode.Stobj: return PlatformTypes.ValueType; case SRM.ILOpCode.Ldstr: return PlatformTypes.String; diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index fdb7e6e6..8edeec0f 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -40,7 +40,6 @@ public enum BasicOperation CopyObject, CopyBlock, LoadArrayLength, - IndirectLoad, LoadArrayElement, LoadArrayElementAddress, StoreArrayElement, @@ -397,8 +396,29 @@ public override string ToString() return this.ToString("sizeof {0}", this.MeasuredType); } } + public class LoadIndirectInstruction : Instruction + { + public IType Type { get; set; } + + public LoadIndirectInstruction(uint label, IType type) + : base(label) + { + this.Type = type; + } + + public override void Accept(IInstructionVisitor visitor) + { + base.Accept(visitor); + visitor.Visit(this); + } + + public override string ToString() + { + return this.ToString("indirect load {0}", this.Type); + } + } - public class LoadInstruction : Instruction + public class LoadInstruction : Instruction { public LoadOperation Operation { get; set; } public IInmediateValue Operand { get; set; } diff --git a/Model/Bytecode/Visitor/IInstructionVisitor.cs b/Model/Bytecode/Visitor/IInstructionVisitor.cs index 006268b0..c5a37e5c 100644 --- a/Model/Bytecode/Visitor/IInstructionVisitor.cs +++ b/Model/Bytecode/Visitor/IInstructionVisitor.cs @@ -13,7 +13,8 @@ public interface IInstructionVisitor void Visit(Instruction instruction); void Visit(BasicInstruction instruction); void Visit(LoadInstruction instruction); - void Visit(LoadFieldInstruction instruction); + void Visit(LoadIndirectInstruction instruction); + void Visit(LoadFieldInstruction instruction); void Visit(LoadMethodAddressInstruction instruction); void Visit(StoreIndirectInstruction instruction); void Visit(StoreInstruction instruction); diff --git a/Model/Bytecode/Visitor/InstructionVisitor.cs b/Model/Bytecode/Visitor/InstructionVisitor.cs index ad4cd445..c744f3bc 100644 --- a/Model/Bytecode/Visitor/InstructionVisitor.cs +++ b/Model/Bytecode/Visitor/InstructionVisitor.cs @@ -20,6 +20,7 @@ public virtual void Visit(IInstructionContainer container) public virtual void Visit(Instruction instruction) { } public virtual void Visit(BasicInstruction instruction) { } + public virtual void Visit(LoadIndirectInstruction instruction) { } public virtual void Visit(LoadInstruction instruction) { } public virtual void Visit(LoadFieldInstruction instruction) { } public virtual void Visit(LoadMethodAddressInstruction instruction) { } From 2249e2c68886a164df39e299e88fe90ab1687167 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Sat, 24 Aug 2019 00:38:20 -0300 Subject: [PATCH 030/256] Extract type from stobj and ldobj. --- Backend/Transformations/Disassembler.cs | 4 ---- CCIProvider/CodeProvider.cs | 6 ++++-- CCIProvider/OperationHelper.cs | 2 -- MetadataProvider/AssemblyExtractor.cs | 15 ++++++++++++--- MetadataProvider/OperationHelper.cs | 2 -- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index a2547c22..1daa51e1 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -188,10 +188,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; diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index 124b6dde..d93b2d8b 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -688,7 +688,8 @@ private IInstruction ProcessLoadLocal(Cci.IOperation op) private IInstruction ProcessLoadIndirect(Cci.IOperation op) { 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; } @@ -748,7 +749,8 @@ private IInstruction ProcessStoreLocal(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; } diff --git a/CCIProvider/OperationHelper.cs b/CCIProvider/OperationHelper.cs index e01bff60..427f5b86 100644 --- a/CCIProvider/OperationHelper.cs +++ b/CCIProvider/OperationHelper.cs @@ -360,8 +360,6 @@ public static IType GetOperationType(Cci.OperationCode opcode) case Cci.OperationCode.Stelem_R8: case Cci.OperationCode.Conv_R8: case Cci.OperationCode.Conv_R_Un: return PlatformTypes.Float64; - case Cci.OperationCode.Ldobj: - case Cci.OperationCode.Stobj: return PlatformTypes.ValueType; case Cci.OperationCode.Stind_Ref: case Cci.OperationCode.Ldind_Ref: case Cci.OperationCode.Ldnull: return PlatformTypes.Object; diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 03631b67..fba2f009 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1177,7 +1177,14 @@ private T GetOperand(ILInstruction op) break; } - case OperandType.TypeReference: + case OperandType.TypeDefinition: + { + var handle = (SRM.TypeDefinitionHandle)op.Operand; + result = (T)(object)GetDefinedType(handle); + break; + } + + case OperandType.TypeReference: { var handle = (SRM.TypeReferenceHandle)op.Operand; result = (T)signatureTypeProvider.GetTypeFromReference(metadata, handle); @@ -1561,7 +1568,8 @@ private IInstruction ProcessLoadLocal(ILInstruction op) private IInstruction ProcessLoadIndirect(ILInstruction op) { var type = OperationHelper.GetOperationType(op.Opcode); - + if (op.Opcode == SRM.ILOpCode.Ldobj) + type = GetOperand(op); var instruction = new LoadIndirectInstruction(op.Offset, type); return instruction; } @@ -1613,7 +1621,8 @@ private IInstruction ProcessStoreLocal(ILInstruction op) private IInstruction ProcessStoreIndirect(ILInstruction op) { var type = OperationHelper.GetOperationType(op.Opcode); - + if (op.Opcode == SRM.ILOpCode.Stobj) + type = GetOperand(op); var instruction = new StoreIndirectInstruction(op.Offset, type); return instruction; } diff --git a/MetadataProvider/OperationHelper.cs b/MetadataProvider/OperationHelper.cs index 780a7a20..9c3e009d 100644 --- a/MetadataProvider/OperationHelper.cs +++ b/MetadataProvider/OperationHelper.cs @@ -358,8 +358,6 @@ public static IType GetOperationType(SRM.ILOpCode opcode) case SRM.ILOpCode.Ldind_ref: case SRM.ILOpCode.Stind_ref: case SRM.ILOpCode.Ldnull: return PlatformTypes.Object; - case SRM.ILOpCode.Ldobj: - case SRM.ILOpCode.Stobj: return PlatformTypes.ValueType; case SRM.ILOpCode.Ldstr: return PlatformTypes.String; default: return null; From e43034874179346d1e683bb6c8f31b433325a1e7 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 25 Aug 2019 18:14:02 -0300 Subject: [PATCH 031/256] better generics --- Examples/Examples.cs | 29 ++++---- MetadataGenerator/AssemblyGenerator.cs | 85 ++++++++++++++-------- MetadataGenerator/Extensions.cs | 15 ++++ MetadataGenerator/MetadataGenerator.csproj | 1 + MetadataGenerator/MethodGenerator.cs | 4 +- MetadataGenerator/TypeEncoder.cs | 17 ++++- 6 files changed, 102 insertions(+), 49 deletions(-) create mode 100644 MetadataGenerator/Extensions.cs diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 04c8e908..bb327afb 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -229,7 +229,7 @@ public class ClassThatUsesDelegate { public delegate void Del(int x); - //FIXME: code is generating Delegates.Del instead of Delegates.ClassThatUsesDelegate.Del + // FIXME: code is generating Delegates.Del instead of Delegates.ClassThatUsesDelegate.Del public Del ReturnsADelegate() => new Del(new SampleClass().DelegateMethod); } } @@ -341,17 +341,19 @@ public void MethodWithRefAndOutParameters(ref string refString, ref Exception re outClass = new Classes.SimpleClass(); } - public unsafe void* UnsafeMethod(int* intPointer, Structs.EmptyStruct* structPointer) + public unsafe void* UnsafeMethod(int* intPointer, Structs.EmptyStruct* structPointer, uint* uintPointer) { return null; } } } +// FIXME generation not entirely correct namespace Generics { - public class Generic + public class Generic { + public C genericClassTypeField; public Dictionary genericField; public IList> listOfListField; @@ -360,18 +362,15 @@ public IList GetExceptionsList(List _) { return new List(); } - /* TODO - public T RecievesAndReturnsGeneric(T param) - { - return param; - } + public E RecievesAndReturnsGenericType(T t, E e) + { + return e; + } - public IList RecievesAndReturnsGenericList(IList param) - { - return param; - } - */ + public IList RecievesAndReturnsGenericTypeList(IList listT) + { + return listT; + } } -} - +} \ No newline at end of file diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index c7addda4..1801a47c 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -59,7 +60,7 @@ public AssemblyGenerator Generate() Generate(namezpace); } - // FIXME args? + // FIXME args metadata.AddAssembly( name: metadata.GetOrAddString(assembly.Name), version: new Version(1, 0, 0, 0), @@ -112,34 +113,12 @@ private TypeDefinitionHandle GenerateTypesOf(Model.Types.TypeDefinition type) private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) { - MethodDefinitionHandle? firstMethodHandle = null; - FieldDefinitionHandle? firstFieldHandle = null; - - var typeAttributes = AttributesProvider.GetTypeAttributesFor(type); - - foreach (var method in type.Methods) - { - var methodHandle = methodGenerator.Generate(method); - - if (!firstMethodHandle.HasValue) - { - firstMethodHandle = methodHandle; - } - - if (method.Name.Equals("Main")) // FIXME can a non entry point be called Main? - { - mainMethodHandle = methodHandle; - } - } + var fieldDefinitionHandles = new List(); + var methodDefinitionHandles = new List(); foreach (var field in type.Fields) { - var fieldDefinitionHandle = fieldGenerator.Generate(field); - - if (!firstFieldHandle.HasValue) - { - firstFieldHandle = fieldDefinitionHandle; - } + fieldDefinitionHandles.Add(fieldGenerator.Generate(field)); } /* TODO Properties: (works) but model is missing Property concept @@ -165,25 +144,73 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); */ + + foreach (var method in type.Methods) + { + var methodHandle = methodGenerator.Generate(method); + + methodDefinitionHandles.Add(methodHandle); + + if (method.Name.Equals("Main")) // FIXME can a non entry point be called Main? + { + mainMethodHandle = methodHandle; + } + } + + var a = fieldDefinitionHandles.DefaultIfEmpty(fieldGenerator.NextFieldHandle()); + var baseType = default(EntityHandle); if (type.Base != null) { baseType = typeReferences.TypeReferenceOf(type.Base); } var typeDefinitionHandle = metadata.AddTypeDefinition( - attributes: typeAttributes, + attributes: AttributesProvider.GetTypeAttributesFor(type), @namespace: metadata.GetOrAddString(type.ContainingNamespace.FullName), name: metadata.GetOrAddString(type.Name), baseType: baseType, - fieldList: firstFieldHandle ?? fieldGenerator.NextFieldHandle(), - methodList: firstMethodHandle ?? methodGenerator.NextMethodHandle()); + fieldList: fieldDefinitionHandles.FirstOr(fieldGenerator.NextFieldHandle()), + methodList: methodDefinitionHandles.FirstOr(methodGenerator.NextMethodHandle())); foreach (var interfaze in type.Interfaces) { metadata.AddInterfaceImplementation(type: typeDefinitionHandle, implementedInterface: typeReferences.TypeReferenceOf(interfaze)); } + /* + Generic parameters table must be sorted that's why this is done at the end and not during the method generation. + If done that way, method generic parameters of a type are added before the type's generic parameters and table results + unsorted + */ + + + // generate class generic parameters (Class) + foreach (var genericParamter in type.GenericParameters) + { + metadata.AddGenericParameter( + typeDefinitionHandle, + GenericParameterAttributes.None, // FIXME + metadata.GetOrAddString(genericParamter.Name), + genericParamter.Index); + } + + // generate method generic parameters (public T method(T param)) + for (int i = 0; i < type.Methods.Count; i++) + { + var method = type.Methods[i]; + foreach (var genericParameter in method.GenericParameters) + { + metadata.AddGenericParameter( + methodDefinitionHandles[i], + GenericParameterAttributes.None, // FIXME + metadata.GetOrAddString(genericParameter.Name), + genericParameter.Index); + } + } + return typeDefinitionHandle; } } } + + diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs new file mode 100644 index 00000000..7cef389f --- /dev/null +++ b/MetadataGenerator/Extensions.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Linq; + +namespace MetadataGenerator +{ + public static class Extensions + { + public static T FirstOr(this IEnumerable enumerable, T defaultValue) + { + T first = enumerable.FirstOrDefault(); + return first.Equals(default(T)) ? defaultValue : first; + } + + } +} diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index d4f9fd93..ea845ea4 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -33,6 +33,7 @@ + diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index fedbae61..70995061 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -53,6 +53,7 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) } } }); + var instructions = new InstructionEncoder(new BlobBuilder()); // TODO real body @@ -95,9 +96,6 @@ public MethodParameterGenerator(MetadataBuilder metadata) public ParameterHandle Generate(Model.Types.MethodParameter methodParameter) { nextOffset++; - - // TODO: metadata.AddGenericParameter() + examples - return metadata.AddParameter( AttributesProvider.GetTypeAttributesFor(methodParameter), metadata.GetOrAddString(methodParameter.Name), diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 50812dcc..7e231a04 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -7,8 +7,9 @@ namespace MetadataGenerator { public class TypeEncoder { + // FIXME maybe this should be singleton and not injected? if needed in other place than here. It is already use in the assembly generator + //FIXME and not only to instantiate this class private readonly TypeReferences typeReferences; - public TypeEncoder(TypeReferences typeReferences) { this.typeReferences = typeReferences; @@ -125,9 +126,21 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) Encode(targetType, signatureTypeEncoder.Pointer()); } } + else if (type is GenericParameter genericParameter) + { + switch (genericParameter.Kind) + { + case GenericParameterKind.Type: + signatureTypeEncoder.GenericTypeParameter(genericParameter.Index); + break; + case GenericParameterKind.Method: + signatureTypeEncoder.GenericMethodTypeParameter(genericParameter.Index); + break; + } + } else { - throw new Exception("Type not supported"); + throw new Exception($"Type {type} not supported"); } } } From 4b7b6c7a1c93421d43cbd05c622570a45edf2017 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 26 Aug 2019 22:52:19 -0300 Subject: [PATCH 032/256] solve some FIXMEs --- Examples/Examples.cs | 1 - MetadataGenerator/AssemblyGenerator.cs | 9 +++------ MetadataGenerator/AttributesProvider.cs | 13 ++++++------- MetadataGenerator/Extensions.cs | 1 - MetadataGenerator/FieldGenerator.cs | 6 +++--- MetadataGenerator/Generator.cs | 2 +- MetadataGenerator/MethodGenerator.cs | 6 +++--- MetadataGenerator/TypeEncoder.cs | 3 --- MetadataGenerator/TypeReferences.cs | 7 +++---- 9 files changed, 19 insertions(+), 29 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index bb327afb..70e264ee 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -355,7 +355,6 @@ public class Generic { public C genericClassTypeField; public Dictionary genericField; - public IList> listOfListField; public IList GetExceptionsList(List _) diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index 1801a47c..a49ab9b0 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -19,7 +18,7 @@ public class AssemblyGenerator private MethodDefinitionHandle? mainMethodHandle; public MethodDefinitionHandle? MainMethodHandle => generatedMetadata != null ? mainMethodHandle : throw new Exception("Generate was not called"); - public Boolean Executable => mainMethodHandle != null; + public bool Executable => mainMethodHandle != null; public MetadataBuilder GeneratedMetadata => generatedMetadata ?? throw new Exception("Generate was not called"); public BlobBuilder IlStream => generatedMetadata != null ? methodGenerator.IlStream() : throw new Exception("Generate was not called"); @@ -157,8 +156,6 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) } } - var a = fieldDefinitionHandles.DefaultIfEmpty(fieldGenerator.NextFieldHandle()); - var baseType = default(EntityHandle); if (type.Base != null) { @@ -189,7 +186,7 @@ Generic parameters table must be sorted that's why this is done at the end and n { metadata.AddGenericParameter( typeDefinitionHandle, - GenericParameterAttributes.None, // FIXME + GenericParameterAttributes.None, metadata.GetOrAddString(genericParamter.Name), genericParamter.Index); } @@ -202,7 +199,7 @@ Generic parameters table must be sorted that's why this is done at the end and n { metadata.AddGenericParameter( methodDefinitionHandles[i], - GenericParameterAttributes.None, // FIXME + GenericParameterAttributes.None, metadata.GetOrAddString(genericParameter.Name), genericParameter.Index); } diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs index 1658e772..2f89f14b 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -5,7 +5,6 @@ namespace MetadataGenerator { - // FIXME method names public static class AttributesProvider { public static TypeAttributes GetTypeAttributesFor(TypeDefinition typeDefinition) @@ -17,8 +16,8 @@ public static TypeAttributes GetTypeAttributesFor(TypeDefinition typeDefinition) case TypeDefinitionKind.Interface: return InterfaceTypeAttributes(typeDefinition); case TypeDefinitionKind.Struct: return StructTypeAttributes(typeDefinition); case TypeDefinitionKind.Delegate: return DelegateTypeAttributes(typeDefinition); - default: throw new Exception(); - }; + default: throw new Exception($"TypeDefinition {typeDefinition.Name} not supported"); + } } private static TypeAttributes DelegateTypeAttributes(TypeDefinition typeDefinition) @@ -57,7 +56,7 @@ private static TypeAttributes InterfaceTypeAttributes(TypeDefinition typeDefinit return TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; } - public static FieldAttributes GetTypeAttributesFor(FieldDefinition field) + public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) { var fieldAttributes = (field.IsStatic ? FieldAttributes.Static : 0) | @@ -85,7 +84,7 @@ public static FieldAttributes GetTypeAttributesFor(FieldDefinition field) return fieldAttributes; } - public static MethodAttributes GetTypeAttributesFor(MethodDefinition method) + public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) { var isConstructor = method.IsConstructor || method.Name.Equals(".cctor"); // FIXME maybe MethodDefinition can have a isClassConstructor or isTypeInitializer var methodAttributes = @@ -116,7 +115,7 @@ public static MethodAttributes GetTypeAttributesFor(MethodDefinition method) return methodAttributes; } - public static ParameterAttributes GetTypeAttributesFor(MethodParameter parameter) + public static ParameterAttributes GetParameterAttributesFor(MethodParameter parameter) { var attributes = (parameter.HasDefaultValue ? ParameterAttributes.HasDefault : 0); switch (parameter.Kind) @@ -135,7 +134,7 @@ public static ParameterAttributes GetTypeAttributesFor(MethodParameter parameter return attributes; } - //FIXME + // FIXME private static TypeAttributes VisibilityAttributesFor(TypeDefinition typeDefinition) { if (typeDefinition.ContainingType != null) diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index 7cef389f..b3aa5a0d 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -10,6 +10,5 @@ public static T FirstOr(this IEnumerable enumerable, T defaultValue) T first = enumerable.FirstOrDefault(); return first.Equals(default(T)) ? defaultValue : first; } - } } diff --git a/MetadataGenerator/FieldGenerator.cs b/MetadataGenerator/FieldGenerator.cs index 597f95e9..30174155 100644 --- a/MetadataGenerator/FieldGenerator.cs +++ b/MetadataGenerator/FieldGenerator.cs @@ -12,7 +12,7 @@ public class FieldGenerator public FieldGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) { this.metadata = metadata; - this.nextOffset = 1; + nextOffset = 1; this.typeEncoder = typeEncoder; } @@ -22,7 +22,7 @@ public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) var fieldSignature = new BlobEncoder(fieldSignatureBlobBuilder).FieldSignature(); typeEncoder.Encode(field.Type, fieldSignature); var fieldDefinitionHandle = metadata.AddFieldDefinition( - attributes: AttributesProvider.GetTypeAttributesFor(field), + attributes: AttributesProvider.GetFieldAttributesFor(field), name: metadata.GetOrAddString(field.Name), signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); @@ -41,4 +41,4 @@ public FieldDefinitionHandle NextFieldHandle() return MetadataTokens.FieldDefinitionHandle(nextOffset); } } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 8601c7b5..55ec8d3e 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -23,7 +23,7 @@ public void Generate(Assembly assembly) metadataRootBuilder: new MetadataRootBuilder(assemblyGenerator.GeneratedMetadata), ilStream: assemblyGenerator.IlStream, entryPoint: assemblyGenerator.MainMethodHandle ?? default(MethodDefinitionHandle), - flags: CorFlags.ILOnly //FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll. Requires/prefers 32 bit? + flags: CorFlags.ILOnly // FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll. Requires/prefers 32 bit? ); var peBlob = new BlobBuilder(); var contentId = peBuilder.Serialize(peBlob); diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index 70995061..604122ed 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -63,7 +63,7 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) nextOffset++; return metadata.AddMethodDefinition( - attributes: AttributesProvider.GetTypeAttributesFor(method), + attributes: AttributesProvider.GetMethodAttributesFor(method), implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME name: metadata.GetOrAddString(method.Name), signature: metadata.GetOrAddBlob(methodSignature), @@ -90,14 +90,14 @@ private class MethodParameterGenerator public MethodParameterGenerator(MetadataBuilder metadata) { this.metadata = metadata; - this.nextOffset = 1; + nextOffset = 1; } public ParameterHandle Generate(Model.Types.MethodParameter methodParameter) { nextOffset++; return metadata.AddParameter( - AttributesProvider.GetTypeAttributesFor(methodParameter), + AttributesProvider.GetParameterAttributesFor(methodParameter), metadata.GetOrAddString(methodParameter.Name), methodParameter.Index); } diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 7e231a04..ba9f21d0 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -7,8 +7,6 @@ namespace MetadataGenerator { public class TypeEncoder { - // FIXME maybe this should be singleton and not injected? if needed in other place than here. It is already use in the assembly generator - //FIXME and not only to instantiate this class private readonly TypeReferences typeReferences; public TypeEncoder(TypeReferences typeReferences) { @@ -114,7 +112,6 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) } else if (type is PointerType pointerType) { - // TODO there's also signatureTypeEncode.FunctionPointer()/IntPtr()/UIntPtr var targetType = pointerType.TargetType; if (targetType.Equals(PlatformTypes.Void)) diff --git a/MetadataGenerator/TypeReferences.cs b/MetadataGenerator/TypeReferences.cs index 4d04fe36..de320eb1 100644 --- a/MetadataGenerator/TypeReferences.cs +++ b/MetadataGenerator/TypeReferences.cs @@ -12,7 +12,6 @@ public class TypeReferences private readonly Model.Assembly assembly; private readonly MetadataBuilder metadata; private readonly IDictionary assemblyReferences = new Dictionary(); - // FIXME better name. It's not all the type references but just the ones needed for Base type and interfaces private readonly IDictionary typeReferences = new Dictionary(); public TypeReferences(MetadataBuilder metadata, Model.Assembly assembly) @@ -20,11 +19,11 @@ public TypeReferences(MetadataBuilder metadata, Model.Assembly assembly) this.metadata = metadata; this.assembly = assembly; - //FIXME see references in IlSpy generated vs original - //FIXME: assemblyName => assemblyRef could result in false positive? + // FIXME see references in IlSpy generated vs original + // FIXME: assemblyName => assemblyRef could result in false positive? foreach (var assemblyReference in assembly.References) { - // FIXME parameters depend of assembly info that is not in the model + // FIXME parameters assemblyReferences.Add(assemblyReference.Name, metadata.AddAssemblyReference( name: metadata.GetOrAddString(assemblyReference.Name), version: new Version(4, 0, 0, 0), From 44c38c8398035645dfb2af689cd2b3055026da24 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 29 Aug 2019 22:39:30 -0300 Subject: [PATCH 033/256] correctly resolve nested type references --- Examples/Examples.cs | 10 +++++++--- Examples/Examples.csproj | 9 +++++++++ Examples/packages.config | 5 +++++ MetadataGenerator/TypeReferences.cs | 26 +++++++++++++++++++------- 4 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 Examples/packages.config diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 70e264ee..42d618b6 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -220,7 +220,7 @@ namespace Delegates { public class SampleClass { - public void DelegateMethod(int x) + public void SomeMethod(int x) { } } @@ -229,8 +229,7 @@ public class ClassThatUsesDelegate { public delegate void Del(int x); - // FIXME: code is generating Delegates.Del instead of Delegates.ClassThatUsesDelegate.Del - public Del ReturnsADelegate() => new Del(new SampleClass().DelegateMethod); + public Del ReturnsADelegate() => new Del(new SampleClass().SomeMethod); } } @@ -279,8 +278,13 @@ namespace Nested public class ClassContainingNestedTypes { + public NestedClass ReturnsNestedClass() => new NestedClass(); + public NestedClass.NestedNestedClass ReturnsNestedNestedClass() => new NestedClass.NestedNestedClass(); + public System.Reflection.Metadata.BlobBuilder.Blobs ReturnsNestedClassFromOtherAssembly() => new System.Reflection.Metadata.BlobBuilder.Blobs(); + public class NestedClass { + public class NestedNestedClass { } } public enum NestedEnum diff --git a/Examples/Examples.csproj b/Examples/Examples.csproj index 17c74d1c..f25abb3f 100644 --- a/Examples/Examples.csproj +++ b/Examples/Examples.csproj @@ -31,10 +31,19 @@ + + ..\packages\System.Reflection.Metadata.1.6.0\lib\portable-net45+win8\System.Reflection.Metadata.dll + + + ..\packages\System.Collections.Immutable.1.5.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + + \ No newline at end of file diff --git a/Examples/packages.config b/Examples/packages.config new file mode 100644 index 00000000..3b5ff6d1 --- /dev/null +++ b/Examples/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/MetadataGenerator/TypeReferences.cs b/MetadataGenerator/TypeReferences.cs index de320eb1..515f918d 100644 --- a/MetadataGenerator/TypeReferences.cs +++ b/MetadataGenerator/TypeReferences.cs @@ -35,28 +35,40 @@ public TypeReferences(MetadataBuilder metadata, Model.Assembly assembly) } } + /* + * Returns a TypeReference for type. It stores references because metadata does not have a getOrAddTypeReference. + */ public EntityHandle TypeReferenceOf(Model.Types.IBasicType type) { TypeReferenceHandle typeReference; - var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{type.Name}"; - if (typeReferences.TryGetValue(typeReferenceKey, out var value)) + var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{type.Name}"; + if (typeReferences.TryGetValue(typeReferenceKey, out var value)) // If stored then return that { typeReference = value; } else - { - var resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) - ? default(AssemblyReferenceHandle) - : assemblyReferences[type.ContainingAssembly.Name]; + { // if not add the new type reference to metadata and store it + EntityHandle resolutionScope; + if (type.ContainingType == null) // if defined in the namespace then search there + { + resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) + ? default(AssemblyReferenceHandle) + : assemblyReferences[type.ContainingAssembly.Name]; + } + else + { // if not, recursively get a reference for the containing type and use that as the resolution scopeø + resolutionScope = TypeReferenceOf(type.ContainingType); + } // FIXME: comparing to the name of the current assembly could result in a false positive? typeReference = metadata.AddTypeReference( resolutionScope: resolutionScope, @namespace: metadata.GetOrAddString(type.ContainingNamespace), name: metadata.GetOrAddString(type.Name)); + typeReferences.Add(typeReferenceKey, typeReference); } return typeReference; } } -} +} \ No newline at end of file From c8575bbf3cadfade510853cc31aac0aec6e4faf9 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Fri, 30 Aug 2019 12:18:48 -0300 Subject: [PATCH 034/256] array load/store basic instruction are now mapped to load/store array element instruction --- Backend/Transformations/Disassembler.cs | 12 -- CCIProvider/CodeProvider.cs | 206 ++++++++++++++---------- CCIProvider/OperationHelper.cs | 55 +++---- MetadataProvider/AssemblyExtractor.cs | 34 ++-- MetadataProvider/OperationHelper.cs | 49 +++--- Model/Bytecode/Instructions.cs | 3 - 6 files changed, 181 insertions(+), 178 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 1daa51e1..32c4e97e 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -188,18 +188,6 @@ public override void Visit(Bytecode.BasicInstruction op) ProcessLoadArrayLength(op); break; - case Bytecode.BasicOperation.LoadArrayElement: - ProcessLoadArrayElement(op); - break; - - case Bytecode.BasicOperation.LoadArrayElementAddress: - ProcessLoadArrayElementAddress(op); - break; - - case Bytecode.BasicOperation.StoreArrayElement: - ProcessStoreArrayElement(op); - break; - case Bytecode.BasicOperation.Breakpoint: ProcessBreakpointOperation(op); break; diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index d93b2d8b..6a7807b7 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -128,68 +128,70 @@ 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: @@ -461,19 +463,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: @@ -540,7 +539,57 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) return instruction; } - private IInstruction ProcessSwitch(Cci.IOperation op) + 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; + 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 +608,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); diff --git a/CCIProvider/OperationHelper.cs b/CCIProvider/OperationHelper.cs index 427f5b86..4dd07264 100644 --- a/CCIProvider/OperationHelper.cs +++ b/CCIProvider/OperationHelper.cs @@ -57,28 +57,6 @@ public static BasicOperation ToBasicOperation(Cci.OperationCode opcode) case Cci.OperationCode.Cpobj: return BasicOperation.CopyObject; case Cci.OperationCode.Ret: return BasicOperation.Return; case Cci.OperationCode.Ldlen: return BasicOperation.LoadArrayLength; - 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.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(); @@ -283,28 +261,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: @@ -322,7 +304,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: @@ -333,15 +316,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: @@ -349,17 +335,20 @@ 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.Ldelem_Ref: case Cci.OperationCode.Stind_Ref: case Cci.OperationCode.Ldind_Ref: case Cci.OperationCode.Ldnull: return PlatformTypes.Object; diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index fba2f009..2c30ba11 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -793,12 +793,12 @@ private IInstruction ExtractInstruction(ILInstruction operation) case SRM.ILOpCode.Ldelem_u2: case SRM.ILOpCode.Ldelem_u4: case SRM.ILOpCode.Ldelem_ref: - instruction = ProcessBasic(operation); - break; + instruction = ProcessLoadArrayElement(operation, LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelema: - instruction = ProcessBasic(operation); - break; + instruction = ProcessLoadArrayElement(operation, LoadArrayElementOperation.Address); + break; case SRM.ILOpCode.Beq: case SRM.ILOpCode.Beq_s: @@ -1078,7 +1078,7 @@ private IInstruction ExtractInstruction(ILInstruction operation) case SRM.ILOpCode.Stelem_r4: case SRM.ILOpCode.Stelem_r8: case SRM.ILOpCode.Stelem_ref: - instruction = ProcessBasic(operation); + instruction = ProcessStoreArrayElement(operation); break; case SRM.ILOpCode.Stfld: @@ -1420,15 +1420,25 @@ private IInstruction ProcessCreateArray(ILInstruction op, ArrayType arrayType = return instruction; } - private IInstruction ProcessLoadArrayElement(ILInstruction op, ArrayType arrayType, LoadArrayElementOperation operation) + private IInstruction ProcessLoadArrayElement(ILInstruction op, LoadArrayElementOperation operation, ArrayType arrayType = null) { - var instruction = new LoadArrayElementInstruction(op.Offset, operation, arrayType); - return instruction; - } + if (arrayType == null) + { + IType elementType = op.Opcode == SRM.ILOpCode.Ldelem || op.Opcode == SRM.ILOpCode.Ldelema ? + GetOperand(op) + : OperationHelper.GetOperationType(op.Opcode); + arrayType = new ArrayType(elementType); + } + var instruction = new LoadArrayElementInstruction(op.Offset, operation, arrayType); + return instruction; + } - private IInstruction ProcessStoreArrayElement(ILInstruction op, ArrayType arrayType) + private IInstruction ProcessStoreArrayElement(ILInstruction op, ArrayType arrayType = null) { - var instruction = new StoreArrayElementInstruction(op.Offset, arrayType); + if (arrayType == null) + arrayType = new ArrayType(OperationHelper.GetOperationType(op.Opcode)); + + var instruction = new StoreArrayElementInstruction(op.Offset, arrayType); return instruction; } @@ -1469,7 +1479,7 @@ private IInstruction ProcessMethodCall(ILInstruction op) { var operation = OperationHelper.ToLoadArrayElementOperation(method.Name); - instruction = ProcessLoadArrayElement(op, arrayType.Type, operation); + instruction = ProcessLoadArrayElement(op, operation, arrayType.Type); } } else diff --git a/MetadataProvider/OperationHelper.cs b/MetadataProvider/OperationHelper.cs index 9c3e009d..61804827 100644 --- a/MetadataProvider/OperationHelper.cs +++ b/MetadataProvider/OperationHelper.cs @@ -68,28 +68,6 @@ public static BasicOperation ToBasicOperation(SRM.ILOpCode opcode) case SRM.ILOpCode.Ldind_u1: case SRM.ILOpCode.Ldind_u2: case SRM.ILOpCode.Ldind_u4: - case SRM.ILOpCode.Ldelem: - case SRM.ILOpCode.Ldelem_i: - case SRM.ILOpCode.Ldelem_i1: - case SRM.ILOpCode.Ldelem_i2: - case SRM.ILOpCode.Ldelem_i4: - case SRM.ILOpCode.Ldelem_i8: - case SRM.ILOpCode.Ldelem_r4: - case SRM.ILOpCode.Ldelem_r8: - case SRM.ILOpCode.Ldelem_u1: - case SRM.ILOpCode.Ldelem_u2: - case SRM.ILOpCode.Ldelem_u4: - case SRM.ILOpCode.Ldelem_ref: return BasicOperation.LoadArrayElement; - case SRM.ILOpCode.Ldelema: return BasicOperation.LoadArrayElementAddress; - case SRM.ILOpCode.Stelem: - case SRM.ILOpCode.Stelem_i: - case SRM.ILOpCode.Stelem_i1: - case SRM.ILOpCode.Stelem_i2: - case SRM.ILOpCode.Stelem_i4: - case SRM.ILOpCode.Stelem_i8: - case SRM.ILOpCode.Stelem_r4: - case SRM.ILOpCode.Stelem_r8: - case SRM.ILOpCode.Stelem_ref: return BasicOperation.StoreArrayElement; case SRM.ILOpCode.Break: return BasicOperation.Breakpoint; default: throw opcode.ToUnknownValueException(); @@ -281,25 +259,29 @@ public static IType GetOperationType(SRM.ILOpCode opcode) { switch (opcode) { + case SRM.ILOpCode.Ldelem_i: case SRM.ILOpCode.Ldind_i: case SRM.ILOpCode.Stind_i: case SRM.ILOpCode.Stelem_i: case SRM.ILOpCode.Conv_i: case SRM.ILOpCode.Conv_ovf_i: case SRM.ILOpCode.Conv_ovf_i_un: return PlatformTypes.IntPtr; - case SRM.ILOpCode.Ldind_i1: + case SRM.ILOpCode.Ldelem_i1: + case SRM.ILOpCode.Ldind_i1: case SRM.ILOpCode.Stind_i1: case SRM.ILOpCode.Stelem_i1: case SRM.ILOpCode.Conv_i1: case SRM.ILOpCode.Conv_ovf_i1: case SRM.ILOpCode.Conv_ovf_i1_un: return PlatformTypes.Int8; - case SRM.ILOpCode.Ldind_i2: + case SRM.ILOpCode.Ldelem_i2: + case SRM.ILOpCode.Ldind_i2: case SRM.ILOpCode.Stind_i2: case SRM.ILOpCode.Stelem_i2: case SRM.ILOpCode.Conv_i2: case SRM.ILOpCode.Conv_ovf_i2: case SRM.ILOpCode.Conv_ovf_i2_un: return PlatformTypes.Int16; - case SRM.ILOpCode.Ldc_i4: + case SRM.ILOpCode.Ldelem_i4: + case SRM.ILOpCode.Ldc_i4: case SRM.ILOpCode.Ldc_i4_0: case SRM.ILOpCode.Ldc_i4_1: case SRM.ILOpCode.Ldc_i4_2: @@ -317,7 +299,8 @@ public static IType GetOperationType(SRM.ILOpCode opcode) case SRM.ILOpCode.Conv_i4: case SRM.ILOpCode.Conv_ovf_i4: case SRM.ILOpCode.Conv_ovf_i4_un: return PlatformTypes.Int32; - case SRM.ILOpCode.Ldc_i8: + case SRM.ILOpCode.Ldelem_i8: + case SRM.ILOpCode.Ldc_i8: case SRM.ILOpCode.Ldind_i8: case SRM.ILOpCode.Stind_i8: case SRM.ILOpCode.Stelem_i8: @@ -328,15 +311,18 @@ public static IType GetOperationType(SRM.ILOpCode opcode) case SRM.ILOpCode.Conv_ovf_u: case SRM.ILOpCode.Conv_ovf_u_un: case SRM.ILOpCode.Ldlen: return PlatformTypes.UIntPtr; - case SRM.ILOpCode.Ldind_u1: + case SRM.ILOpCode.Ldelem_u1: + case SRM.ILOpCode.Ldind_u1: case SRM.ILOpCode.Conv_u1: case SRM.ILOpCode.Conv_ovf_u1: case SRM.ILOpCode.Conv_ovf_u1_un: return PlatformTypes.UInt8; - case SRM.ILOpCode.Ldind_u2: + case SRM.ILOpCode.Ldelem_u2: + case SRM.ILOpCode.Ldind_u2: case SRM.ILOpCode.Conv_u2: case SRM.ILOpCode.Conv_ovf_u2: case SRM.ILOpCode.Conv_ovf_u2_un: return PlatformTypes.UInt16; - case SRM.ILOpCode.Ldind_u4: + case SRM.ILOpCode.Ldelem_u4: + case SRM.ILOpCode.Ldind_u4: case SRM.ILOpCode.Conv_u4: case SRM.ILOpCode.Conv_ovf_u4: case SRM.ILOpCode.Conv_ovf_u4_un: @@ -344,12 +330,14 @@ public static IType GetOperationType(SRM.ILOpCode opcode) case SRM.ILOpCode.Conv_u8: case SRM.ILOpCode.Conv_ovf_u8: case SRM.ILOpCode.Conv_ovf_u8_un: return PlatformTypes.UInt64; + case SRM.ILOpCode.Ldelem_r4: case SRM.ILOpCode.Ldc_r4: case SRM.ILOpCode.Ldind_r4: case SRM.ILOpCode.Stind_r4: case SRM.ILOpCode.Stelem_r4: case SRM.ILOpCode.Conv_r4: return PlatformTypes.Float32; - case SRM.ILOpCode.Ldc_r8: + case SRM.ILOpCode.Ldelem_r8: + case SRM.ILOpCode.Ldc_r8: case SRM.ILOpCode.Ldind_r8: case SRM.ILOpCode.Stind_r8: case SRM.ILOpCode.Stelem_r8: @@ -357,6 +345,7 @@ public static IType GetOperationType(SRM.ILOpCode opcode) case SRM.ILOpCode.Conv_r_un: return PlatformTypes.Float64; case SRM.ILOpCode.Ldind_ref: case SRM.ILOpCode.Stind_ref: + case SRM.ILOpCode.Ldelem_ref: case SRM.ILOpCode.Ldnull: return PlatformTypes.Object; case SRM.ILOpCode.Ldstr: return PlatformTypes.String; diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index 8edeec0f..e2225a02 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -40,9 +40,6 @@ public enum BasicOperation CopyObject, CopyBlock, LoadArrayLength, - LoadArrayElement, - LoadArrayElementAddress, - StoreArrayElement, Breakpoint, Return } From a98c6db69c47899643ee5f8917663e22ae970889 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 1 Sep 2019 18:30:20 -0300 Subject: [PATCH 035/256] miscellaneous --- Examples/Examples.cs | 39 ++++++++++++++++++++++++---- MetadataGenerator/Extensions.cs | 4 +++ MetadataGenerator/FieldGenerator.cs | 4 +-- MetadataGenerator/MethodGenerator.cs | 15 ++++++----- 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 42d618b6..ef70b07c 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -110,6 +110,7 @@ public virtual void VirtualMethod() { } public abstract void AbstractMethod(); } + // TODO var arggs, optional parameters, named arguments, public class ClassWithMoreComplexFieldsAndParamtersOrReturnTypes { @@ -119,6 +120,20 @@ public class ClassWithMoreComplexFieldsAndParamtersOrReturnTypes public Exception[] exceptionArrayField; private Nested.NestedNamespace.NestedNestedNamesace.B b; + public void MethodWithOptionalParameters( + string someParam, + int optionalInt = 0, + Structs.EmptyStruct optionalStruct = new Structs.EmptyStruct()) + { } + + public void MethodWithIntVarArgs(params int[] args) + { + } + + public void MethodWithExceptionVarArgs(int someInt, params Exception[] args) + { + } + public Hierarchy.DerivedClass DoSomethingWith(Hierarchy.DerivedClass d) { return d; @@ -332,19 +347,33 @@ public class NestedNestedB { } } -// TODO pointers +// FIXME ref and out are beign generated like type*& instead of type&. That is because the type a & type in the model is represented as a pointer type. +// FIXME generation not entirely correct namespace PointersAndReferences { - - public class ClassWithMethodWithParametersWithKeywords + public class PointersAndReferenceClass { - // FIXME ref and out are beign generated like type* instead of type&. Also the bytecodes needs to include the "out" keyword + private int number = 1; + private Exception exception = new Exception(); + public void MethodWithRefAndOutParameters(ref string refString, ref Exception refException, out int outInt, out Classes.SimpleClass outClass) { outInt = 2; outClass = new Classes.SimpleClass(); } + // FIXME not in the model + public ref int RefInt() + { + return ref number; + } + + // FIXME not in the model + public ref Exception RefException() + { + return ref exception; + } + public unsafe void* UnsafeMethod(int* intPointer, Structs.EmptyStruct* structPointer, uint* uintPointer) { return null; @@ -352,7 +381,7 @@ public void MethodWithRefAndOutParameters(ref string refString, ref Exception re } } -// FIXME generation not entirely correct +// FIXME generation not entirely correct. namespace Generics { public class Generic diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index b3aa5a0d..d27ac443 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; +using Model.Types; namespace MetadataGenerator { @@ -10,5 +12,7 @@ public static T FirstOr(this IEnumerable enumerable, T defaultValue) T first = enumerable.FirstOrDefault(); return first.Equals(default(T)) ? defaultValue : first; } + + public static bool IsOneOf(this MethodParameterKind kind, params MethodParameterKind[] kinds) => ImmutableList.Create(kinds).Contains(kind); } } diff --git a/MetadataGenerator/FieldGenerator.cs b/MetadataGenerator/FieldGenerator.cs index 30174155..74c769ad 100644 --- a/MetadataGenerator/FieldGenerator.cs +++ b/MetadataGenerator/FieldGenerator.cs @@ -19,8 +19,8 @@ public FieldGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) { var fieldSignatureBlobBuilder = new BlobBuilder(); - var fieldSignature = new BlobEncoder(fieldSignatureBlobBuilder).FieldSignature(); - typeEncoder.Encode(field.Type, fieldSignature); + var encoder = new BlobEncoder(fieldSignatureBlobBuilder).FieldSignature(); + typeEncoder.Encode(field.Type, encoder); var fieldDefinitionHandle = metadata.AddFieldDefinition( attributes: AttributesProvider.GetFieldAttributesFor(field), name: metadata.GetOrAddString(field.Name), diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index 604122ed..10d2f628 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -1,6 +1,7 @@ using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using Model.Types; namespace MetadataGenerator { @@ -16,9 +17,9 @@ public MethodGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) { this.metadata = metadata; this.methodBodyStream = new MethodBodyStreamEncoder(new BlobBuilder()); - this.nextOffset = 1; + nextOffset = 1; this.typeEncoder = typeEncoder; - this.methodParameterGenerator = new MethodParameterGenerator(metadata); + methodParameterGenerator = new MethodParameterGenerator(metadata); } public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) @@ -26,18 +27,19 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) ParameterHandle? firstParameterHandle = null; var methodSignature = new BlobBuilder(); new BlobEncoder(methodSignature) - .MethodSignature(isInstanceMethod: !method.IsStatic) + .MethodSignature(isInstanceMethod: !method.IsStatic, genericParameterCount: method.GenericParameters.Count) .Parameters( method.Parameters.Count, returnType => { - if (method.ReturnType.Equals(Model.Types.PlatformTypes.Void)) + if (method.ReturnType.Equals(PlatformTypes.Void)) { returnType.Void(); } else { - typeEncoder.Encode(method.ReturnType, returnType.Type()); + var encoder = returnType.Type(); // FIXME pass isByRef param. ref return type is not in the model + typeEncoder.Encode(method.ReturnType, encoder); } }, @@ -45,12 +47,13 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) { foreach (var parameter in method.Parameters) { - typeEncoder.Encode(parameter.Type, parameters.AddParameter().Type()); var parameterHandle = methodParameterGenerator.Generate(parameter); if (!firstParameterHandle.HasValue) { firstParameterHandle = parameterHandle; } + var encoder = parameters.AddParameter().Type(isByRef: parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref)); + typeEncoder.Encode(parameter.Type, encoder); } }); From 2bef2481fcffaa9910d2bf765e0671fd84020127 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 9 Sep 2019 22:22:26 -0300 Subject: [PATCH 036/256] some method body generation. Pending refactor --- Examples/Examples.cs | 110 ++++++++- MetadataGenerator/AssemblyGenerator.cs | 1 - MetadataGenerator/Extensions.cs | 9 + MetadataGenerator/MethodGenerator.cs | 317 +++++++++++++++++++++---- MetadataGenerator/TypeEncoder.cs | 7 +- 5 files changed, 397 insertions(+), 47 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index ef70b07c..c6dc43e4 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -75,6 +75,10 @@ public class SimpleClass public string unassignedString; public const string CONST_STRING = "const"; + public SimpleClass(int x, string y) + { + } + public void DoNothing() { } private int Sum(int arg1, int arg2) @@ -359,7 +363,7 @@ public class PointersAndReferenceClass public void MethodWithRefAndOutParameters(ref string refString, ref Exception refException, out int outInt, out Classes.SimpleClass outClass) { outInt = 2; - outClass = new Classes.SimpleClass(); + outClass = new Classes.SimpleClass(1, ""); } // FIXME not in the model @@ -392,6 +396,11 @@ public class Generic public IList GetExceptionsList(List _) { + var a = 1 + 2; + if (a == 3) + { + + } return new List(); } public E RecievesAndReturnsGenericType(T t, E e) @@ -405,4 +414,103 @@ public IList RecievesAndReturnsGenericTypeList(IList listT) } } +} + +namespace MethodBody +{ + public abstract class ContainingClass + { + public void HelloWorld() + { + Console.WriteLine("Hello World!"); + } + + public int ReturnsOne() + { + return 1; + } + + public int ReturnsArg(int x) + { + return x; + } + + public int Arithmetics(int x, int y) + { + var z = x + y; + z = x - y; + z = x * y; + z = x / y; + z = x % 2; + + return z; + } + + public void Logic(bool x, bool y) + { + var z = x && y; + z = x || y; + z = !x; + z = x ^ y; + } + + public void BitwiseOperations(int x) + { + var z = x & x; + z = x | x; + z = x ^ x; + z = x >> 1; + z = z << 1; + } + + public void Comparison(int x) + { + var z = x > 1; + z = x < 1; + z = x == 1; + } + + public void ExceptionHandling(Exception e, int x) + { + try + { + var y = 1 / x; + } + catch (Exception ex) when (ex.Message.Contains("by zero")) + { + + } + + try + { + throw e; + } + catch + { + throw; // rethrow + } + finally + { + Console.WriteLine("finally"); + } + + } + + public abstract void NoBody(); + + public void Alloc() + { + unsafe + { + var x = stackalloc int[3]; + } + } + + public void Calls(Classes.SimpleClass simpleClass) + { + Console.WriteLine("A method call"); // static + simpleClass.DoNothing(); // virtual + Alloc(); // normal + } + } } \ No newline at end of file diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index a49ab9b0..55592027 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -180,7 +180,6 @@ Generic parameters table must be sorted that's why this is done at the end and n unsorted */ - // generate class generic parameters (Class) foreach (var genericParamter in type.GenericParameters) { diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index d27ac443..83cee249 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -1,8 +1,11 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using Model.Types; +// TODO separate in namespaces? is there a convention for extensions? namespace MetadataGenerator { public static class Extensions @@ -14,5 +17,11 @@ public static T FirstOr(this IEnumerable enumerable, T defaultValue) } public static bool IsOneOf(this MethodParameterKind kind, params MethodParameterKind[] kinds) => ImmutableList.Create(kinds).Contains(kind); + + public static void CallVirtual(this InstructionEncoder encoder, EntityHandle methodReference) + { + encoder.OpCode(ILOpCode.Callvirt); + encoder.Token(methodReference); + } } } diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index 10d2f628..1ec2ef32 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -1,8 +1,11 @@ -using System.Reflection; +using System.Collections.Generic; +using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using Model.Types; + +// FIXME lo de method referneces anda bien para lo de Call() y demas pero ver como implementarlo bien namespace MetadataGenerator { public class MethodGenerator @@ -10,58 +13,41 @@ public class MethodGenerator private readonly MetadataBuilder metadata; private readonly MethodBodyStreamEncoder methodBodyStream; private int nextOffset; - private readonly TypeEncoder typeEncoder; + private readonly MethodSignatureGenerator methodSignatureGenerator; + private readonly MethodBodyGenerator methodBodyGenerator; private readonly MethodParameterGenerator methodParameterGenerator; + private readonly MethodReferencesAndSignatures methodReferencesAndSignatures; public MethodGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) { this.metadata = metadata; - this.methodBodyStream = new MethodBodyStreamEncoder(new BlobBuilder()); + methodBodyStream = new MethodBodyStreamEncoder(new BlobBuilder()); nextOffset = 1; - this.typeEncoder = typeEncoder; methodParameterGenerator = new MethodParameterGenerator(metadata); + methodReferencesAndSignatures = new MethodReferencesAndSignatures(metadata, typeEncoder); + methodSignatureGenerator = new MethodSignatureGenerator(methodReferencesAndSignatures); + methodBodyGenerator = new MethodBodyGenerator(methodReferencesAndSignatures); } public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) { - ParameterHandle? firstParameterHandle = null; - var methodSignature = new BlobBuilder(); - new BlobEncoder(methodSignature) - .MethodSignature(isInstanceMethod: !method.IsStatic, genericParameterCount: method.GenericParameters.Count) - .Parameters( - method.Parameters.Count, - returnType => - { - if (method.ReturnType.Equals(PlatformTypes.Void)) - { - returnType.Void(); - } - else - { - var encoder = returnType.Type(); // FIXME pass isByRef param. ref return type is not in the model - typeEncoder.Encode(method.ReturnType, encoder); - } - }, - parameters => - { - foreach (var parameter in method.Parameters) - { - var parameterHandle = methodParameterGenerator.Generate(parameter); - if (!firstParameterHandle.HasValue) - { - firstParameterHandle = parameterHandle; - } - var encoder = parameters.AddParameter().Type(isByRef: parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref)); - typeEncoder.Encode(parameter.Type, encoder); - } - }); + var methodSignature = methodSignatureGenerator.Generate(method); - var instructions = new InstructionEncoder(new BlobBuilder()); + ParameterHandle? firstParameterHandle = null; + foreach (var parameter in method.Parameters) + { + var parameterHandle = methodParameterGenerator.Generate(parameter); + if (!firstParameterHandle.HasValue) + { + firstParameterHandle = parameterHandle; + } + } - // TODO real body - instructions.OpCode(ILOpCode.Nop); - instructions.OpCode(ILOpCode.Ret); + // FIXME several addMethodBody variants with different arguments + var methodBody = method.HasBody + ? methodBodyStream.AddMethodBody(methodBodyGenerator.Generate(method.Body)) + : default(int); nextOffset++; @@ -70,7 +56,7 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME name: metadata.GetOrAddString(method.Name), signature: metadata.GetOrAddBlob(methodSignature), - bodyOffset: methodBodyStream.AddMethodBody(instructions), + bodyOffset: methodBody, parameterList: firstParameterHandle ?? methodParameterGenerator.NextParameterHandle()); } @@ -85,6 +71,20 @@ public MethodDefinitionHandle NextMethodHandle() } + // FIXME al pedo esta clase + private class MethodSignatureGenerator + { + private readonly MethodReferencesAndSignatures methodReferencesAndSignatures; + + public MethodSignatureGenerator(MethodReferencesAndSignatures methodReferencesAndSignatures) + { + this.methodReferencesAndSignatures = methodReferencesAndSignatures; + } + + public BlobBuilder Generate(Model.Types.MethodDefinition method) => + methodReferencesAndSignatures.MethodReferenceAndSignatureOf(method).methodSignature; + } + private class MethodParameterGenerator { private readonly MetadataBuilder metadata; @@ -96,7 +96,7 @@ public MethodParameterGenerator(MetadataBuilder metadata) nextOffset = 1; } - public ParameterHandle Generate(Model.Types.MethodParameter methodParameter) + public ParameterHandle Generate(MethodParameter methodParameter) { nextOffset++; return metadata.AddParameter( @@ -109,10 +109,243 @@ public ParameterHandle NextParameterHandle() { return MetadataTokens.ParameterHandle(nextOffset); } + } + private class MethodBodyGenerator + { + private readonly MethodReferencesAndSignatures methodReferencesAndSignatures; + + public MethodBodyGenerator(MethodReferencesAndSignatures methodReferencesAndSignatures) + { + this.methodReferencesAndSignatures = methodReferencesAndSignatures; + } + public InstructionEncoder Generate(Model.Types.MethodBody body) + { + var encoder = new InstructionEncoder(new BlobBuilder()); + + foreach (var instruction in body.Instructions) + { + // TODO implement all of them + + if (instruction is Model.Bytecode.BasicInstruction basicInstruction) + { + switch (basicInstruction.Operation) + { + // TODO + // check overflow for variants (ej: add, add_ovf, add_ovf_un) + // see all IlOpCode constants + + case Model.Bytecode.BasicOperation.Nop: + encoder.OpCode(ILOpCode.Nop); + break; + case Model.Bytecode.BasicOperation.Add: + encoder.OpCode(ILOpCode.Add); + break; + case Model.Bytecode.BasicOperation.Sub: + encoder.OpCode(ILOpCode.Sub); + break; + case Model.Bytecode.BasicOperation.Mul: + encoder.OpCode(ILOpCode.Mul); + break; + case Model.Bytecode.BasicOperation.Div: + encoder.OpCode(ILOpCode.Div); + break; + case Model.Bytecode.BasicOperation.Rem: + encoder.OpCode(ILOpCode.Rem); + break; + case Model.Bytecode.BasicOperation.And: + encoder.OpCode(ILOpCode.And); + break; + case Model.Bytecode.BasicOperation.Or: + encoder.OpCode(ILOpCode.Or); + break; + case Model.Bytecode.BasicOperation.Xor: + encoder.OpCode(ILOpCode.Xor); + break; + case Model.Bytecode.BasicOperation.Shl: + encoder.OpCode(ILOpCode.Shl); + break; + case Model.Bytecode.BasicOperation.Shr: + encoder.OpCode(ILOpCode.Shr); + break; + case Model.Bytecode.BasicOperation.Eq: + break; + case Model.Bytecode.BasicOperation.Lt: + break; + case Model.Bytecode.BasicOperation.Gt: + break; + case Model.Bytecode.BasicOperation.Throw: + encoder.OpCode(ILOpCode.Throw); + break; + case Model.Bytecode.BasicOperation.Rethrow: + encoder.OpCode(ILOpCode.Rethrow); + break; + case Model.Bytecode.BasicOperation.Not: + encoder.OpCode(ILOpCode.Not); + break; + case Model.Bytecode.BasicOperation.Neg: + encoder.OpCode(ILOpCode.Neg); + break; + case Model.Bytecode.BasicOperation.Pop: + break; + case Model.Bytecode.BasicOperation.Dup: + break; + case Model.Bytecode.BasicOperation.EndFinally: + encoder.OpCode(ILOpCode.Endfinally); + break; + case Model.Bytecode.BasicOperation.EndFilter: + encoder.OpCode(ILOpCode.Endfilter); + break; + case Model.Bytecode.BasicOperation.LocalAllocation: + encoder.OpCode(ILOpCode.Localloc); + break; + case Model.Bytecode.BasicOperation.InitBlock: + break; + case Model.Bytecode.BasicOperation.InitObject: + break; + case Model.Bytecode.BasicOperation.CopyObject: + break; + case Model.Bytecode.BasicOperation.CopyBlock: + break; + case Model.Bytecode.BasicOperation.LoadArrayLength: + break; + case Model.Bytecode.BasicOperation.IndirectLoad: + break; + case Model.Bytecode.BasicOperation.LoadArrayElement: + break; + case Model.Bytecode.BasicOperation.LoadArrayElementAddress: + break; + case Model.Bytecode.BasicOperation.IndirectStore: + break; + case Model.Bytecode.BasicOperation.StoreArrayElement: + break; + case Model.Bytecode.BasicOperation.Breakpoint: + break; + case Model.Bytecode.BasicOperation.Return: + encoder.OpCode(ILOpCode.Ret); + break; + } + } + else if (instruction is Model.Bytecode.BranchInstruction branchInstruction) + { + } + else if (instruction is Model.Bytecode.ConvertInstruction convertInstruction) { } + else if (instruction is Model.Bytecode.MethodCallInstruction methodCallInstruction) + { + switch (methodCallInstruction.Operation) + { + case Model.Bytecode.MethodCallOperation.Virtual: + encoder.CallVirtual(methodReferencesAndSignatures.MethodReferenceAndSignatureOf(methodCallInstruction.Method).methodReference); + break; + case Model.Bytecode.MethodCallOperation.Static: + case Model.Bytecode.MethodCallOperation.Jump: + encoder.Call(methodReferencesAndSignatures.MethodReferenceAndSignatureOf(methodCallInstruction.Method).methodReference); + break; + } + } + else if (instruction is Model.Bytecode.LoadInstruction loadlInstruction) + { + + // TODO implement + + switch (loadlInstruction.Operation) + { + case Model.Bytecode.LoadOperation.Address: + break; + case Model.Bytecode.LoadOperation.Value: + break; + case Model.Bytecode.LoadOperation.Content: + break; + } + } + else if (instruction is Model.Bytecode.LoadFieldInstruction loadFieldInstruction) { } + else if (instruction is Model.Bytecode.LoadArrayElementInstruction loadArrayElementInstruction) { } + else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) { } + + } + + + return encoder; + } + } + + private class MethodReferencesAndSignatures + { + + public class MethodReferenceAndSignature + { + public readonly MemberReferenceHandle methodReference; + public readonly BlobBuilder methodSignature; + + public MethodReferenceAndSignature(MemberReferenceHandle methodReference, BlobBuilder methodSignature) + { + this.methodReference = methodReference; + this.methodSignature = methodSignature; + } + } + + private readonly IDictionary methodReferencesAndSignatures = new Dictionary(); + private MetadataBuilder metadata; + private readonly TypeEncoder typeEncoder; + + public MethodReferencesAndSignatures(MetadataBuilder metadata, TypeEncoder typeEncoder) + { + this.metadata = metadata; + this.typeEncoder = typeEncoder; + } + + public MethodReferenceAndSignature MethodReferenceAndSignatureOf(IMethodReference method) + { + MethodReferenceAndSignature methodReferenceAndSignature; + var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; + if (methodReferencesAndSignatures.TryGetValue(key, out var value)) + { + methodReferenceAndSignature = value; + } + else + { + var methodSignature = new BlobBuilder(); + new BlobEncoder(methodSignature) + .MethodSignature(isInstanceMethod: !method.IsStatic, genericParameterCount: method.GenericParameterCount) + .Parameters( + method.Parameters.Count, + returnType => + { + if (method.ReturnType.Equals(PlatformTypes.Void)) + { + returnType.Void(); + } + else + { + var encoder = returnType.Type(); // FIXME pass isByRef param. ref return type is not in the model + typeEncoder.Encode(method.ReturnType, encoder); + } + + }, + parameters => + { + foreach (var parameter in method.Parameters) + { + var encoder = parameters.AddParameter().Type(isByRef: parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref)); + typeEncoder.Encode(parameter.Type, encoder); + } + }); + + + methodReferenceAndSignature = new MethodReferenceAndSignature( + methodReference: metadata.AddMemberReference( + parent: typeEncoder.typeReferences.TypeReferenceOf(method.ContainingType), // FIXME cualquiera esto + name: metadata.GetOrAddString(method.Name), + signature: metadata.GetOrAddBlob(methodSignature)), + methodSignature: methodSignature); + methodReferencesAndSignatures.Add(key, methodReferenceAndSignature); + + } + return methodReferenceAndSignature; + } } } -} +} \ No newline at end of file diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index ba9f21d0..4d8008bc 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -7,7 +7,8 @@ namespace MetadataGenerator { public class TypeEncoder { - private readonly TypeReferences typeReferences; + // FIXME not public + public readonly TypeReferences typeReferences; public TypeEncoder(TypeReferences typeReferences) { this.typeReferences = typeReferences; @@ -76,11 +77,11 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) { if (type is IBasicType basicType) { - if (basicType.GenericArguments.Count > 0) + if (basicType.GenericType != null) { var genericInstantiation = signatureTypeEncoder.GenericInstantiation( typeReferences.TypeReferenceOf(basicType), - basicType.GenericArguments.Count, + basicType.GenericParameterCount, type.TypeKind == TypeKind.ValueType ); foreach (var genericArg in basicType.GenericArguments) From 0940310aa572671048a8aa2b91657a3b015309b1 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 14 Sep 2019 12:12:31 -0300 Subject: [PATCH 037/256] stop counting offsets, use metadata.getRowCount. Partial refactor --- Examples/Examples.cs | 23 +++- MetadataGenerator/AssemblyGenerator.cs | 4 +- MetadataGenerator/Extensions.cs | 5 +- MetadataGenerator/FieldGenerator.cs | 9 -- MetadataGenerator/MethodGenerator.cs | 154 ++++++++++--------------- 5 files changed, 91 insertions(+), 104 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index c6dc43e4..f03c4161 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -52,6 +52,7 @@ public void get_ShouldNotHaveSpecialname() { } } } +//TODO implicit, explicit, operator keywords for methods namespace Classes { public class EmptyClass @@ -512,5 +513,25 @@ public void Calls(Classes.SimpleClass simpleClass) simpleClass.DoNothing(); // virtual Alloc(); // normal } + + // TODO unboxPtr??? + public void Convert() + { + int i = 123; + object o = i; // boxing + + o = 123; + i = (int)o; // unboxing + + // Implicit conversion. A long can + // hold any value an int can hold, and more! + int num = 2147483647; + long bigNum = num; + + double x = 1234.7; + int a; + // Cast double to int. + a = (int)x; + } } -} \ No newline at end of file +} diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index 55592027..887747e5 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -166,8 +166,8 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) @namespace: metadata.GetOrAddString(type.ContainingNamespace.FullName), name: metadata.GetOrAddString(type.Name), baseType: baseType, - fieldList: fieldDefinitionHandles.FirstOr(fieldGenerator.NextFieldHandle()), - methodList: methodDefinitionHandles.FirstOr(methodGenerator.NextMethodHandle())); + fieldList: fieldDefinitionHandles.FirstOr(MetadataTokens.FieldDefinitionHandle(metadata.NextRowFor(TableIndex.Field))), + methodList: methodDefinitionHandles.FirstOr(MetadataTokens.MethodDefinitionHandle(metadata.NextRowFor(TableIndex.MethodDef)))); foreach (var interfaze in type.Interfaces) { diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index 83cee249..91da0e60 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -5,7 +5,7 @@ using System.Reflection.Metadata.Ecma335; using Model.Types; -// TODO separate in namespaces? is there a convention for extensions? +// TODO separate in namespaces (Collection, Metadata, etc)? is there a convention for extensions? namespace MetadataGenerator { public static class Extensions @@ -23,5 +23,8 @@ public static void CallVirtual(this InstructionEncoder encoder, EntityHandle met encoder.OpCode(ILOpCode.Callvirt); encoder.Token(methodReference); } + + // The next available slot in the corresponding table. If nothing is defined in the module then use row number 1 for the corresponding table + public static int NextRowFor(this MetadataBuilder metadata, TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; } } diff --git a/MetadataGenerator/FieldGenerator.cs b/MetadataGenerator/FieldGenerator.cs index 74c769ad..068f2306 100644 --- a/MetadataGenerator/FieldGenerator.cs +++ b/MetadataGenerator/FieldGenerator.cs @@ -6,13 +6,11 @@ namespace MetadataGenerator public class FieldGenerator { private readonly MetadataBuilder metadata; - private int nextOffset; private readonly TypeEncoder typeEncoder; public FieldGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) { this.metadata = metadata; - nextOffset = 1; this.typeEncoder = typeEncoder; } @@ -31,14 +29,7 @@ public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) metadata.AddConstant(fieldDefinitionHandle, field.Value.Value); } - nextOffset++; - return fieldDefinitionHandle; } - - public FieldDefinitionHandle NextFieldHandle() - { - return MetadataTokens.FieldDefinitionHandle(nextOffset); - } } } \ No newline at end of file diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index 1ec2ef32..24070329 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -4,28 +4,24 @@ using System.Reflection.Metadata.Ecma335; using Model.Types; - -// FIXME lo de method referneces anda bien para lo de Call() y demas pero ver como implementarlo bien namespace MetadataGenerator { public class MethodGenerator { private readonly MetadataBuilder metadata; private readonly MethodBodyStreamEncoder methodBodyStream; - private int nextOffset; private readonly MethodSignatureGenerator methodSignatureGenerator; private readonly MethodBodyGenerator methodBodyGenerator; private readonly MethodParameterGenerator methodParameterGenerator; - private readonly MethodReferencesAndSignatures methodReferencesAndSignatures; + private readonly MethodReferences methodReferencesAndSignatures; public MethodGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) { this.metadata = metadata; methodBodyStream = new MethodBodyStreamEncoder(new BlobBuilder()); - nextOffset = 1; methodParameterGenerator = new MethodParameterGenerator(metadata); - methodReferencesAndSignatures = new MethodReferencesAndSignatures(metadata, typeEncoder); - methodSignatureGenerator = new MethodSignatureGenerator(methodReferencesAndSignatures); + methodSignatureGenerator = new MethodSignatureGenerator(typeEncoder); + methodReferencesAndSignatures = new MethodReferences(metadata, typeEncoder, methodSignatureGenerator); methodBodyGenerator = new MethodBodyGenerator(methodReferencesAndSignatures); } @@ -49,15 +45,13 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) ? methodBodyStream.AddMethodBody(methodBodyGenerator.Generate(method.Body)) : default(int); - nextOffset++; - return metadata.AddMethodDefinition( attributes: AttributesProvider.GetMethodAttributesFor(method), implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME name: metadata.GetOrAddString(method.Name), signature: metadata.GetOrAddBlob(methodSignature), bodyOffset: methodBody, - parameterList: firstParameterHandle ?? methodParameterGenerator.NextParameterHandle()); + parameterList: firstParameterHandle ?? MetadataTokens.ParameterHandle(metadata.NextRowFor(TableIndex.Param))); } public BlobBuilder IlStream() @@ -65,57 +59,72 @@ public BlobBuilder IlStream() return methodBodyStream.Builder; } - public MethodDefinitionHandle NextMethodHandle() - { - return MetadataTokens.MethodDefinitionHandle(nextOffset); - } - - - // FIXME al pedo esta clase private class MethodSignatureGenerator { - private readonly MethodReferencesAndSignatures methodReferencesAndSignatures; + private readonly TypeEncoder typeEncoder; - public MethodSignatureGenerator(MethodReferencesAndSignatures methodReferencesAndSignatures) + public MethodSignatureGenerator(TypeEncoder typeEncoder) { - this.methodReferencesAndSignatures = methodReferencesAndSignatures; + this.typeEncoder = typeEncoder; } - public BlobBuilder Generate(Model.Types.MethodDefinition method) => - methodReferencesAndSignatures.MethodReferenceAndSignatureOf(method).methodSignature; + public BlobBuilder Generate(IMethodReference method) + { + var methodSignature = new BlobBuilder(); + new BlobEncoder(methodSignature) + .MethodSignature(isInstanceMethod: !method.IsStatic, genericParameterCount: method.GenericParameterCount) + .Parameters( + method.Parameters.Count, + returnType => + { + if (method.ReturnType.Equals(PlatformTypes.Void)) + { + returnType.Void(); + } + else + { + var encoder = returnType.Type(); // FIXME pass isByRef param. ref return type is not in the model + typeEncoder.Encode(method.ReturnType, encoder); + } + + }, + parameters => + { + foreach (var parameter in method.Parameters) + { + var encoder = parameters.AddParameter().Type(isByRef: parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref)); + typeEncoder.Encode(parameter.Type, encoder); + } + }); + + return methodSignature; + } } private class MethodParameterGenerator { private readonly MetadataBuilder metadata; - private int nextOffset; public MethodParameterGenerator(MetadataBuilder metadata) { this.metadata = metadata; - nextOffset = 1; } public ParameterHandle Generate(MethodParameter methodParameter) { - nextOffset++; return metadata.AddParameter( AttributesProvider.GetParameterAttributesFor(methodParameter), metadata.GetOrAddString(methodParameter.Name), methodParameter.Index); } - public ParameterHandle NextParameterHandle() - { - return MetadataTokens.ParameterHandle(nextOffset); - } } private class MethodBodyGenerator { - private readonly MethodReferencesAndSignatures methodReferencesAndSignatures; + private readonly MethodReferences methodReferencesAndSignatures; - public MethodBodyGenerator(MethodReferencesAndSignatures methodReferencesAndSignatures) + public MethodBodyGenerator(MethodReferences methodReferencesAndSignatures) { this.methodReferencesAndSignatures = methodReferencesAndSignatures; } @@ -230,17 +239,20 @@ public InstructionEncoder Generate(Model.Types.MethodBody body) else if (instruction is Model.Bytecode.BranchInstruction branchInstruction) { } - else if (instruction is Model.Bytecode.ConvertInstruction convertInstruction) { } + else if (instruction is Model.Bytecode.ConvertInstruction convertInstruction) + { + + } else if (instruction is Model.Bytecode.MethodCallInstruction methodCallInstruction) { switch (methodCallInstruction.Operation) { case Model.Bytecode.MethodCallOperation.Virtual: - encoder.CallVirtual(methodReferencesAndSignatures.MethodReferenceAndSignatureOf(methodCallInstruction.Method).methodReference); + encoder.CallVirtual(methodReferencesAndSignatures.MethodReferenceOf(methodCallInstruction.Method)); break; case Model.Bytecode.MethodCallOperation.Static: case Model.Bytecode.MethodCallOperation.Jump: - encoder.Call(methodReferencesAndSignatures.MethodReferenceAndSignatureOf(methodCallInstruction.Method).methodReference); + encoder.Call(methodReferencesAndSignatures.MethodReferenceOf(methodCallInstruction.Method)); break; } } @@ -264,85 +276,45 @@ public InstructionEncoder Generate(Model.Types.MethodBody body) else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) { } } - - return encoder; } } - private class MethodReferencesAndSignatures + private class MethodReferences { - - public class MethodReferenceAndSignature - { - public readonly MemberReferenceHandle methodReference; - public readonly BlobBuilder methodSignature; - - public MethodReferenceAndSignature(MemberReferenceHandle methodReference, BlobBuilder methodSignature) - { - this.methodReference = methodReference; - this.methodSignature = methodSignature; - } - } - - private readonly IDictionary methodReferencesAndSignatures = new Dictionary(); + private readonly IDictionary methodReferences = new Dictionary(); private MetadataBuilder metadata; private readonly TypeEncoder typeEncoder; + private readonly MethodSignatureGenerator methodSignatureGenerator; - public MethodReferencesAndSignatures(MetadataBuilder metadata, TypeEncoder typeEncoder) + public MethodReferences(MetadataBuilder metadata, TypeEncoder typeEncoder, MethodSignatureGenerator methodSignatureGenerator) { this.metadata = metadata; this.typeEncoder = typeEncoder; + this.methodSignatureGenerator = methodSignatureGenerator; } - public MethodReferenceAndSignature MethodReferenceAndSignatureOf(IMethodReference method) + public MemberReferenceHandle MethodReferenceOf(IMethodReference method) { - MethodReferenceAndSignature methodReferenceAndSignature; + MemberReferenceHandle memberReferenceHandle; var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; - if (methodReferencesAndSignatures.TryGetValue(key, out var value)) + if (methodReferences.TryGetValue(key, out var value)) { - methodReferenceAndSignature = value; + memberReferenceHandle = value; } else { - var methodSignature = new BlobBuilder(); - new BlobEncoder(methodSignature) - .MethodSignature(isInstanceMethod: !method.IsStatic, genericParameterCount: method.GenericParameterCount) - .Parameters( - method.Parameters.Count, - returnType => - { - if (method.ReturnType.Equals(PlatformTypes.Void)) - { - returnType.Void(); - } - else - { - var encoder = returnType.Type(); // FIXME pass isByRef param. ref return type is not in the model - typeEncoder.Encode(method.ReturnType, encoder); - } - - }, - parameters => - { - foreach (var parameter in method.Parameters) - { - var encoder = parameters.AddParameter().Type(isByRef: parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref)); - typeEncoder.Encode(parameter.Type, encoder); - } - }); - - - methodReferenceAndSignature = new MethodReferenceAndSignature( - methodReference: metadata.AddMemberReference( + var methodSignature = methodSignatureGenerator.Generate(method); + memberReferenceHandle = metadata.AddMemberReference( parent: typeEncoder.typeReferences.TypeReferenceOf(method.ContainingType), // FIXME cualquiera esto name: metadata.GetOrAddString(method.Name), - signature: metadata.GetOrAddBlob(methodSignature)), - methodSignature: methodSignature); - methodReferencesAndSignatures.Add(key, methodReferenceAndSignature); - + signature: metadata.GetOrAddBlob(methodSignature)); + methodReferences.Add(key, memberReferenceHandle); } - return methodReferenceAndSignature; + + + + return memberReferenceHandle; } } From c9075f0eeab62eb25ca746d19def070f89fe027b Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 30 Sep 2019 08:33:58 -0300 Subject: [PATCH 038/256] method body draft --- Examples/Examples.cs | 48 +++- MetadataGenerator/AssemblyGenerator.cs | 18 +- MetadataGenerator/Extensions.cs | 2 + MetadataGenerator/MetadataGenerator.csproj | 2 +- MetadataGenerator/MethodGenerator.cs | 205 +++++++++++------- ...ypeReferences.cs => ReferencesProvider.cs} | 34 ++- MetadataGenerator/TypeEncoder.cs | 11 +- 7 files changed, 216 insertions(+), 104 deletions(-) rename MetadataGenerator/{TypeReferences.cs => ReferencesProvider.cs} (69%) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index f03c4161..e471fc69 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -471,7 +471,30 @@ public void Comparison(int x) z = x == 1; } - public void ExceptionHandling(Exception e, int x) + public void ExceptionHandlingTryCatch(int x) + { + try + { + var y = 1 / x; + } + catch + { + + } + } + public void ExceptionHandlingTryCatchSpecific(int x) + { + try + { + var y = 1 / x; + } + catch (Exception ex) + { + + } + } + + public void ExceptionHandlingTryCatchFilter(int x) { try { @@ -481,7 +504,10 @@ public void ExceptionHandling(Exception e, int x) { } + } + public void ExceptionHandlingTryCatchFinally(Exception e) + { try { throw e; @@ -494,7 +520,6 @@ public void ExceptionHandling(Exception e, int x) { Console.WriteLine("finally"); } - } public abstract void NoBody(); @@ -514,6 +539,18 @@ public void Calls(Classes.SimpleClass simpleClass) Alloc(); // normal } + public void Arrays() + { + var intArray = new int[5]; + var ExceptionArray = new Exception[2]; + var stringInitializedArray = new string[] { "hello", "world", "!" }; + unsafe + { + var m = new int*[5]; + var k = new int**[2]; + } + } + // TODO unboxPtr??? public void Convert() { @@ -533,5 +570,12 @@ public void Convert() // Cast double to int. a = (int)x; } + + public void Branch() + { + if (!true) + { + } + } } } diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index 887747e5..6eac42a6 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -11,7 +11,7 @@ public class AssemblyGenerator { private readonly Model.Assembly assembly; private readonly MetadataBuilder metadata; - private readonly TypeReferences typeReferences; + private readonly ReferencesProvider referencesProvider; private readonly MethodGenerator methodGenerator; private readonly FieldGenerator fieldGenerator; private MetadataBuilder generatedMetadata; @@ -23,10 +23,10 @@ public class AssemblyGenerator public MetadataBuilder GeneratedMetadata => generatedMetadata ?? throw new Exception("Generate was not called"); public BlobBuilder IlStream => generatedMetadata != null ? methodGenerator.IlStream() : throw new Exception("Generate was not called"); - private AssemblyGenerator(Model.Assembly assembly, MetadataBuilder metadata, TypeReferences typeReferences, MethodGenerator methodGenerator, FieldGenerator fieldGenerator) + private AssemblyGenerator(Model.Assembly assembly, MetadataBuilder metadata, ReferencesProvider referencesProvider, MethodGenerator methodGenerator, FieldGenerator fieldGenerator) { this.metadata = metadata; - this.typeReferences = typeReferences; + this.referencesProvider = referencesProvider; this.methodGenerator = methodGenerator; this.fieldGenerator = fieldGenerator; this.assembly = assembly; @@ -35,14 +35,14 @@ private AssemblyGenerator(Model.Assembly assembly, MetadataBuilder metadata, Typ public static AssemblyGenerator For(Model.Assembly assembly) { var metadata = new MetadataBuilder(); - var typeReferences = new TypeReferences(metadata, assembly); - var typeEncoder = new TypeEncoder(typeReferences); - var methodGenerator = new MethodGenerator(metadata, typeEncoder); + var referencesProvider = new ReferencesProvider(metadata, assembly); + var typeEncoder = new TypeEncoder(referencesProvider); + var methodGenerator = new MethodGenerator(metadata, typeEncoder, referencesProvider); var fieldGenerator = new FieldGenerator(metadata, typeEncoder); return new AssemblyGenerator( assembly, metadata, - typeReferences, + referencesProvider, methodGenerator, fieldGenerator); } @@ -159,7 +159,7 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) var baseType = default(EntityHandle); if (type.Base != null) { - baseType = typeReferences.TypeReferenceOf(type.Base); + baseType = referencesProvider.TypeReferenceOf(type.Base); } var typeDefinitionHandle = metadata.AddTypeDefinition( attributes: AttributesProvider.GetTypeAttributesFor(type), @@ -171,7 +171,7 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) foreach (var interfaze in type.Interfaces) { - metadata.AddInterfaceImplementation(type: typeDefinitionHandle, implementedInterface: typeReferences.TypeReferenceOf(interfaze)); + metadata.AddInterfaceImplementation(type: typeDefinitionHandle, implementedInterface: referencesProvider.TypeReferenceOf(interfaze)); } /* diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index 91da0e60..821104dd 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -26,5 +26,7 @@ public static void CallVirtual(this InstructionEncoder encoder, EntityHandle met // The next available slot in the corresponding table. If nothing is defined in the module then use row number 1 for the corresponding table public static int NextRowFor(this MetadataBuilder metadata, TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; + + public static string CurrentLabelString(this InstructionEncoder instructionEncoder) => string.Format("L_{0:x4}", instructionEncoder.Offset); } } diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index ea845ea4..c09e55ab 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -31,7 +31,7 @@ - + diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index 24070329..9cea7178 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -13,16 +13,14 @@ public class MethodGenerator private readonly MethodSignatureGenerator methodSignatureGenerator; private readonly MethodBodyGenerator methodBodyGenerator; private readonly MethodParameterGenerator methodParameterGenerator; - private readonly MethodReferences methodReferencesAndSignatures; - public MethodGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) + public MethodGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder, ReferencesProvider referencesProvider) { this.metadata = metadata; methodBodyStream = new MethodBodyStreamEncoder(new BlobBuilder()); methodParameterGenerator = new MethodParameterGenerator(metadata); methodSignatureGenerator = new MethodSignatureGenerator(typeEncoder); - methodReferencesAndSignatures = new MethodReferences(metadata, typeEncoder, methodSignatureGenerator); - methodBodyGenerator = new MethodBodyGenerator(methodReferencesAndSignatures); + methodBodyGenerator = new MethodBodyGenerator(referencesProvider, methodSignatureGenerator); } public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) @@ -122,21 +120,74 @@ public ParameterHandle Generate(MethodParameter methodParameter) private class MethodBodyGenerator { - private readonly MethodReferences methodReferencesAndSignatures; + private readonly ReferencesProvider referencesProvider; + private readonly MethodSignatureGenerator methodSignatureGenerator; - public MethodBodyGenerator(MethodReferences methodReferencesAndSignatures) + public MethodBodyGenerator(ReferencesProvider referencesProvider, MethodSignatureGenerator methodSignatureGenerator) { - this.methodReferencesAndSignatures = methodReferencesAndSignatures; + this.referencesProvider = referencesProvider; + this.methodSignatureGenerator = methodSignatureGenerator; } public InstructionEncoder Generate(Model.Types.MethodBody body) { - var encoder = new InstructionEncoder(new BlobBuilder()); + var controlFlowBuilder = new ControlFlowBuilder(); + var instructionEncoder = new InstructionEncoder(new BlobBuilder(), controlFlowBuilder); + + /** Exception handling, uncomment once al other instructions are generated correctly. If not, labels don't match (because operations are missing) + var exceptionMapping = new Dictionary>(); + LabelHandle addMapping(string label) + { + var labelHandle = instructionsEncoder.DefineLabel(); + if (exceptionMapping.TryGetValue(label, out var labelHandles)) + { + labelHandles.Add(labelHandle); + } + else + { + exceptionMapping.Add(label, new List { labelHandle }); + } + return labelHandle; + } + + foreach (var protectedBlock in body.ExceptionInformation) + { + var tryStart = addMapping(protectedBlock.Start); + var tryEnd = addMapping(protectedBlock.End); + var handlerStart = addMapping(protectedBlock.Handler.Start); + var handlerEnd = addMapping(protectedBlock.Handler.End); + + switch (protectedBlock.Handler.Kind) + { + case Model.ExceptionHandlerBlockKind.Filter: // TODO + break; + case Model.ExceptionHandlerBlockKind.Catch: + EntityHandle catchType = referencesProvider.TypeReferenceOf(PlatformTypes.Object); // FIXME + controlFlowBuilder.AddCatchRegion(tryStart, tryEnd, handlerStart, handlerEnd, catchType); + break; + case Model.ExceptionHandlerBlockKind.Fault: // TODO + break; + case Model.ExceptionHandlerBlockKind.Finally: // TODO + break; + } + }*/ foreach (var instruction in body.Instructions) { - // TODO implement all of them + /** Exception handling, uncomment once al other instructions are generated correctly. If not, labels don't match (because operations are missing) + * FIXME instruction has offset field. maybe that can be used with instructionsEncoder.offset instead of mapping labels (and using the extension method) + if (exceptionMapping.TryGetValue(instructionsEncoder.CurrentLabelString(), out var labels)) + { + foreach (var label in labels) + { + instructionsEncoder.MarkLabel(label); + } + } + */ + + + // FIXME visitor like in the model? or something better than this ifs? if (instruction is Model.Bytecode.BasicInstruction basicInstruction) { switch (basicInstruction.Operation) @@ -146,37 +197,37 @@ public InstructionEncoder Generate(Model.Types.MethodBody body) // see all IlOpCode constants case Model.Bytecode.BasicOperation.Nop: - encoder.OpCode(ILOpCode.Nop); + instructionEncoder.OpCode(ILOpCode.Nop); break; case Model.Bytecode.BasicOperation.Add: - encoder.OpCode(ILOpCode.Add); + instructionEncoder.OpCode(ILOpCode.Add); break; case Model.Bytecode.BasicOperation.Sub: - encoder.OpCode(ILOpCode.Sub); + instructionEncoder.OpCode(ILOpCode.Sub); break; case Model.Bytecode.BasicOperation.Mul: - encoder.OpCode(ILOpCode.Mul); + instructionEncoder.OpCode(ILOpCode.Mul); break; case Model.Bytecode.BasicOperation.Div: - encoder.OpCode(ILOpCode.Div); + instructionEncoder.OpCode(ILOpCode.Div); break; case Model.Bytecode.BasicOperation.Rem: - encoder.OpCode(ILOpCode.Rem); + instructionEncoder.OpCode(ILOpCode.Rem); break; case Model.Bytecode.BasicOperation.And: - encoder.OpCode(ILOpCode.And); + instructionEncoder.OpCode(ILOpCode.And); break; case Model.Bytecode.BasicOperation.Or: - encoder.OpCode(ILOpCode.Or); + instructionEncoder.OpCode(ILOpCode.Or); break; case Model.Bytecode.BasicOperation.Xor: - encoder.OpCode(ILOpCode.Xor); + instructionEncoder.OpCode(ILOpCode.Xor); break; case Model.Bytecode.BasicOperation.Shl: - encoder.OpCode(ILOpCode.Shl); + instructionEncoder.OpCode(ILOpCode.Shl); break; case Model.Bytecode.BasicOperation.Shr: - encoder.OpCode(ILOpCode.Shr); + instructionEncoder.OpCode(ILOpCode.Shr); break; case Model.Bytecode.BasicOperation.Eq: break; @@ -185,33 +236,37 @@ public InstructionEncoder Generate(Model.Types.MethodBody body) case Model.Bytecode.BasicOperation.Gt: break; case Model.Bytecode.BasicOperation.Throw: - encoder.OpCode(ILOpCode.Throw); + instructionEncoder.OpCode(ILOpCode.Throw); break; case Model.Bytecode.BasicOperation.Rethrow: - encoder.OpCode(ILOpCode.Rethrow); + instructionEncoder.OpCode(ILOpCode.Rethrow); break; case Model.Bytecode.BasicOperation.Not: - encoder.OpCode(ILOpCode.Not); + instructionEncoder.OpCode(ILOpCode.Not); break; case Model.Bytecode.BasicOperation.Neg: - encoder.OpCode(ILOpCode.Neg); + instructionEncoder.OpCode(ILOpCode.Neg); break; case Model.Bytecode.BasicOperation.Pop: + instructionEncoder.OpCode(ILOpCode.Pop); break; case Model.Bytecode.BasicOperation.Dup: + instructionEncoder.OpCode(ILOpCode.Dup); break; case Model.Bytecode.BasicOperation.EndFinally: - encoder.OpCode(ILOpCode.Endfinally); + instructionEncoder.OpCode(ILOpCode.Endfinally); break; case Model.Bytecode.BasicOperation.EndFilter: - encoder.OpCode(ILOpCode.Endfilter); + instructionEncoder.OpCode(ILOpCode.Endfilter); break; case Model.Bytecode.BasicOperation.LocalAllocation: - encoder.OpCode(ILOpCode.Localloc); + instructionEncoder.OpCode(ILOpCode.Localloc); break; case Model.Bytecode.BasicOperation.InitBlock: + instructionEncoder.OpCode(ILOpCode.Initblk); break; case Model.Bytecode.BasicOperation.InitObject: + instructionEncoder.OpCode(ILOpCode.Initobj); break; case Model.Bytecode.BasicOperation.CopyObject: break; @@ -232,35 +287,57 @@ public InstructionEncoder Generate(Model.Types.MethodBody body) case Model.Bytecode.BasicOperation.Breakpoint: break; case Model.Bytecode.BasicOperation.Return: - encoder.OpCode(ILOpCode.Ret); + instructionEncoder.OpCode(ILOpCode.Ret); break; } } else if (instruction is Model.Bytecode.BranchInstruction branchInstruction) { + + switch (branchInstruction.Operation) + { + // TODO + case Model.Bytecode.BranchOperation.False: + break; + case Model.Bytecode.BranchOperation.True: + break; + case Model.Bytecode.BranchOperation.Eq: + break; + case Model.Bytecode.BranchOperation.Neq: + break; + case Model.Bytecode.BranchOperation.Lt: + break; + case Model.Bytecode.BranchOperation.Le: + break; + case Model.Bytecode.BranchOperation.Gt: + break; + case Model.Bytecode.BranchOperation.Ge: + break; + case Model.Bytecode.BranchOperation.Branch: + break; + case Model.Bytecode.BranchOperation.Leave: + break; + } } else if (instruction is Model.Bytecode.ConvertInstruction convertInstruction) { - } else if (instruction is Model.Bytecode.MethodCallInstruction methodCallInstruction) { + var methodSignature = methodSignatureGenerator.Generate(methodCallInstruction.Method); switch (methodCallInstruction.Operation) { case Model.Bytecode.MethodCallOperation.Virtual: - encoder.CallVirtual(methodReferencesAndSignatures.MethodReferenceOf(methodCallInstruction.Method)); + instructionEncoder.CallVirtual(referencesProvider.MethodReferenceOf(methodCallInstruction.Method, methodSignature)); break; case Model.Bytecode.MethodCallOperation.Static: case Model.Bytecode.MethodCallOperation.Jump: - encoder.Call(methodReferencesAndSignatures.MethodReferenceOf(methodCallInstruction.Method)); + instructionEncoder.Call(referencesProvider.MethodReferenceOf(methodCallInstruction.Method, methodSignature)); break; } } else if (instruction is Model.Bytecode.LoadInstruction loadlInstruction) { - - // TODO implement - switch (loadlInstruction.Operation) { case Model.Bytecode.LoadOperation.Address: @@ -274,50 +351,30 @@ public InstructionEncoder Generate(Model.Types.MethodBody body) else if (instruction is Model.Bytecode.LoadFieldInstruction loadFieldInstruction) { } else if (instruction is Model.Bytecode.LoadArrayElementInstruction loadArrayElementInstruction) { } else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) { } + else if (instruction is Model.Bytecode.CreateArrayInstruction createArrayInstruction) + { + var size = 1; // FIXME array size not in the model (ArrayType) + instructionEncoder.LoadConstantI4(size); // FIXME I4 = int, I8 = long. Could it be long? + instructionEncoder.OpCode(ILOpCode.Newarr); + // FIXME (cast). ElementsType could be Pointer or BasicType. MultiDimensional Arrays are handled by newObj insteado of newArr + instructionEncoder.Token(referencesProvider.TypeReferenceOf(createArrayInstruction.Type.ElementsType as IBasicType)); + } + else if (instruction is Model.Bytecode.CreateObjectInstruction createObjectInstruction) { } + else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAddressInstruction) { } + else if (instruction is Model.Bytecode.StoreInstruction storeInstruction) { } + else if (instruction is Model.Bytecode.StoreFieldInstruction storeFieldInstruction) { } + else if (instruction is Model.Bytecode.SwitchInstruction switchInstruction) { } + else if (instruction is Model.Bytecode.SizeofInstruction sizeofInstruction) { } + else if (instruction is Model.Bytecode.LoadTokenInstruction loadTokenInstruction) { } + else if (instruction is Model.Bytecode.IndirectMethodCallInstruction indirectMethodCallInstruction) { } + else if (instruction is Model.Bytecode.StoreArrayElementInstruction storeArrayElementInstruction) { } + else throw new Exception("instruction type not handled"); } - return encoder; - } - } - - private class MethodReferences - { - private readonly IDictionary methodReferences = new Dictionary(); - private MetadataBuilder metadata; - private readonly TypeEncoder typeEncoder; - private readonly MethodSignatureGenerator methodSignatureGenerator; - - public MethodReferences(MetadataBuilder metadata, TypeEncoder typeEncoder, MethodSignatureGenerator methodSignatureGenerator) - { - this.metadata = metadata; - this.typeEncoder = typeEncoder; - this.methodSignatureGenerator = methodSignatureGenerator; - } - - public MemberReferenceHandle MethodReferenceOf(IMethodReference method) - { - MemberReferenceHandle memberReferenceHandle; - var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; - if (methodReferences.TryGetValue(key, out var value)) - { - memberReferenceHandle = value; - } - else - { - var methodSignature = methodSignatureGenerator.Generate(method); - memberReferenceHandle = metadata.AddMemberReference( - parent: typeEncoder.typeReferences.TypeReferenceOf(method.ContainingType), // FIXME cualquiera esto - name: metadata.GetOrAddString(method.Name), - signature: metadata.GetOrAddBlob(methodSignature)); - methodReferences.Add(key, memberReferenceHandle); - } - - - return memberReferenceHandle; + return instructionEncoder; } } - } } \ No newline at end of file diff --git a/MetadataGenerator/TypeReferences.cs b/MetadataGenerator/ReferencesProvider.cs similarity index 69% rename from MetadataGenerator/TypeReferences.cs rename to MetadataGenerator/ReferencesProvider.cs index 515f918d..0b8feea6 100644 --- a/MetadataGenerator/TypeReferences.cs +++ b/MetadataGenerator/ReferencesProvider.cs @@ -4,17 +4,19 @@ using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using Model.Types; namespace MetadataGenerator { - public class TypeReferences + public class ReferencesProvider { private readonly Model.Assembly assembly; private readonly MetadataBuilder metadata; private readonly IDictionary assemblyReferences = new Dictionary(); private readonly IDictionary typeReferences = new Dictionary(); + private readonly IDictionary methodReferences = new Dictionary(); - public TypeReferences(MetadataBuilder metadata, Model.Assembly assembly) + public ReferencesProvider(MetadataBuilder metadata, Model.Assembly assembly) { this.metadata = metadata; this.assembly = assembly; @@ -38,15 +40,11 @@ public TypeReferences(MetadataBuilder metadata, Model.Assembly assembly) /* * Returns a TypeReference for type. It stores references because metadata does not have a getOrAddTypeReference. */ - public EntityHandle TypeReferenceOf(Model.Types.IBasicType type) + public EntityHandle TypeReferenceOf(IBasicType type) { - TypeReferenceHandle typeReference; + // FIXME: is this key unique? var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{type.Name}"; - if (typeReferences.TryGetValue(typeReferenceKey, out var value)) // If stored then return that - { - typeReference = value; - } - else + if (!typeReferences.TryGetValue(typeReferenceKey, out TypeReferenceHandle typeReference)) // If stored then return that { // if not add the new type reference to metadata and store it EntityHandle resolutionScope; if (type.ContainingType == null) // if defined in the namespace then search there @@ -59,16 +57,28 @@ public EntityHandle TypeReferenceOf(Model.Types.IBasicType type) { // if not, recursively get a reference for the containing type and use that as the resolution scopeø resolutionScope = TypeReferenceOf(type.ContainingType); } - - // FIXME: comparing to the name of the current assembly could result in a false positive? typeReference = metadata.AddTypeReference( resolutionScope: resolutionScope, @namespace: metadata.GetOrAddString(type.ContainingNamespace), name: metadata.GetOrAddString(type.Name)); - typeReferences.Add(typeReferenceKey, typeReference); } return typeReference; } + + public MemberReferenceHandle MethodReferenceOf(IMethodReference method, BlobBuilder methodSignature) + { + // FIXME: is this key unique? + var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; + if (!methodReferences.TryGetValue(key, out MemberReferenceHandle memberReferenceHandle)) + { + memberReferenceHandle = metadata.AddMemberReference( + parent: TypeReferenceOf(method.ContainingType), + name: metadata.GetOrAddString(method.Name), + signature: metadata.GetOrAddBlob(methodSignature)); + methodReferences.Add(key, memberReferenceHandle); + } + return memberReferenceHandle; + } } } \ No newline at end of file diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 4d8008bc..16eb38b7 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -7,11 +7,10 @@ namespace MetadataGenerator { public class TypeEncoder { - // FIXME not public - public readonly TypeReferences typeReferences; - public TypeEncoder(TypeReferences typeReferences) + private readonly ReferencesProvider referencesProvider; + public TypeEncoder(ReferencesProvider referencesProvider) { - this.typeReferences = typeReferences; + this.referencesProvider = referencesProvider; } // FIXME signatureTypeEncoder should be by reference? or value? @@ -80,7 +79,7 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) if (basicType.GenericType != null) { var genericInstantiation = signatureTypeEncoder.GenericInstantiation( - typeReferences.TypeReferenceOf(basicType), + referencesProvider.TypeReferenceOf(basicType), basicType.GenericParameterCount, type.TypeKind == TypeKind.ValueType ); @@ -91,7 +90,7 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) } else { - signatureTypeEncoder.Type(typeReferences.TypeReferenceOf(basicType), type.TypeKind == TypeKind.ValueType); + signatureTypeEncoder.Type(referencesProvider.TypeReferenceOf(basicType), type.TypeKind == TypeKind.ValueType); } } else if (type is ArrayType arrayType) From b0a89d6c15f4932e1917f3943db6c1ceacf54c2f Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 5 Oct 2019 19:05:02 -0300 Subject: [PATCH 039/256] cleaning --- Examples/Examples.cs | 24 ++- MetadataGenerator/AssemblyGenerator.cs | 89 +++++------ MetadataGenerator/AttributesProvider.cs | 31 ++-- MetadataGenerator/Extensions.cs | 13 +- MetadataGenerator/FieldGenerator.cs | 21 +-- MetadataGenerator/Generator.cs | 24 ++- MetadataGenerator/MethodGenerator.cs | 191 +++++++++++++++--------- MetadataGenerator/ReferencesProvider.cs | 36 ++--- MetadataGenerator/TypeEncoder.cs | 46 +++--- 9 files changed, 268 insertions(+), 207 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index e471fc69..0a8c54ee 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -560,13 +560,13 @@ public void Convert() o = 123; i = (int)o; // unboxing - // Implicit conversion. A long can - // hold any value an int can hold, and more! + // Implicit conversion. A long can hold any value an int can hold, and more! int num = 2147483647; long bigNum = num; double x = 1234.7; int a; + // Cast double to int. a = (int)x; } @@ -577,5 +577,25 @@ public void Branch() { } } + + public void LoadConstant() + { + string s = "hello world!"; // ldstr + int zero = 0; // ldc.i4.0 + int one = 1; // ldc.i4.1 + int two = 2; // ldc.i4.2 + int three = 3; // ldc.i4.3 + int four = 4; // ldc.i4.4 + int five = 5; // ldc.i4.5 + int six = 6; // ldc.i4.6 + int seven = 7; // ldc.i4.7 + int eight = 8; // ldc.i4.8 + int minusOne = -1; // ldc.i4.m1 + int i = 20; // ldc.i4.s 20 + int k = int.MaxValue; // ldc.i4 + long l = long.MinValue; // ldc.i8 + float f = float.MinValue; // ldc.r4 + double d = double.MinValue; // ldc.r8 + } } } diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs index 6eac42a6..7522f701 100644 --- a/MetadataGenerator/AssemblyGenerator.cs +++ b/MetadataGenerator/AssemblyGenerator.cs @@ -1,29 +1,31 @@ using System; using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; using Model; +using Model.Types; +using static MetadataGenerator.AttributesProvider; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SR = System.Reflection; +using SRM = System.Reflection.Metadata; namespace MetadataGenerator { public class AssemblyGenerator { - private readonly Model.Assembly assembly; - private readonly MetadataBuilder metadata; + private readonly Assembly assembly; + private readonly ECMA335.MetadataBuilder metadata; private readonly ReferencesProvider referencesProvider; private readonly MethodGenerator methodGenerator; private readonly FieldGenerator fieldGenerator; - private MetadataBuilder generatedMetadata; - private MethodDefinitionHandle? mainMethodHandle; - public MethodDefinitionHandle? MainMethodHandle => generatedMetadata != null ? mainMethodHandle : throw new Exception("Generate was not called"); + private T CheckMetadataWasGeneratedAndReturn(T value) => generatedMetadata != null ? value : throw new Exception("Generate was not called"); + private ECMA335.MetadataBuilder generatedMetadata; + public ECMA335.MetadataBuilder GeneratedMetadata { get => CheckMetadataWasGeneratedAndReturn(generatedMetadata); } + private SRM.MethodDefinitionHandle? mainMethodHandle; + public SRM.MethodDefinitionHandle? MainMethodHandle { get => CheckMetadataWasGeneratedAndReturn(mainMethodHandle); } public bool Executable => mainMethodHandle != null; + public SRM.BlobBuilder IlStream => CheckMetadataWasGeneratedAndReturn(methodGenerator.IlStream()); - public MetadataBuilder GeneratedMetadata => generatedMetadata ?? throw new Exception("Generate was not called"); - public BlobBuilder IlStream => generatedMetadata != null ? methodGenerator.IlStream() : throw new Exception("Generate was not called"); - - private AssemblyGenerator(Model.Assembly assembly, MetadataBuilder metadata, ReferencesProvider referencesProvider, MethodGenerator methodGenerator, FieldGenerator fieldGenerator) + private AssemblyGenerator(Assembly assembly, ECMA335.MetadataBuilder metadata, ReferencesProvider referencesProvider, MethodGenerator methodGenerator, FieldGenerator fieldGenerator) { this.metadata = metadata; this.referencesProvider = referencesProvider; @@ -32,27 +34,19 @@ private AssemblyGenerator(Model.Assembly assembly, MetadataBuilder metadata, Ref this.assembly = assembly; } - public static AssemblyGenerator For(Model.Assembly assembly) + public static AssemblyGenerator For(Assembly assembly) { - var metadata = new MetadataBuilder(); + var metadata = new ECMA335.MetadataBuilder(); var referencesProvider = new ReferencesProvider(metadata, assembly); var typeEncoder = new TypeEncoder(referencesProvider); var methodGenerator = new MethodGenerator(metadata, typeEncoder, referencesProvider); var fieldGenerator = new FieldGenerator(metadata, typeEncoder); - return new AssemblyGenerator( - assembly, - metadata, - referencesProvider, - methodGenerator, - fieldGenerator); + return new AssemblyGenerator(assembly, metadata, referencesProvider, methodGenerator, fieldGenerator); } public AssemblyGenerator Generate() { - if (generatedMetadata != null) - { - throw new Exception("Generate was already called for this generator"); - } + if (generatedMetadata != null) throw new Exception("Generate was already called for this generator"); foreach (var namezpace in assembly.RootNamespace.Namespaces) { @@ -63,10 +57,10 @@ public AssemblyGenerator Generate() metadata.AddAssembly( name: metadata.GetOrAddString(assembly.Name), version: new Version(1, 0, 0, 0), - culture: default(StringHandle), - publicKey: default(BlobHandle), - flags: AssemblyFlags.PublicKey, - hashAlgorithm: AssemblyHashAlgorithm.Sha1); + culture: default, + publicKey: default, + flags: SR.AssemblyFlags.PublicKey, + hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1); metadata.AddModule( generation: 0, @@ -89,16 +83,16 @@ private void Generate(Namespace namezpace) foreach (var type in namezpace.Types) { - GenerateTypesOf(type); + GenerateTypes(type); } } - private TypeDefinitionHandle GenerateTypesOf(Model.Types.TypeDefinition type) + private SRM.TypeDefinitionHandle GenerateTypes(TypeDefinition type) { - var nestedTypes = new List(); + var nestedTypes = new List(); foreach (var nestedType in type.Types) { - nestedTypes.Add(GenerateTypesOf(nestedType)); + nestedTypes.Add(GenerateTypes(nestedType)); } var typeDefinitionHandle = Generate(type); @@ -110,10 +104,10 @@ private TypeDefinitionHandle GenerateTypesOf(Model.Types.TypeDefinition type) return typeDefinitionHandle; } - private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) + private SRM.TypeDefinitionHandle Generate(TypeDefinition type) { - var fieldDefinitionHandles = new List(); - var methodDefinitionHandles = new List(); + var fieldDefinitionHandles = new List(); + var methodDefinitionHandles = new List(); foreach (var field in type.Fields) { @@ -143,31 +137,23 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); */ - foreach (var method in type.Methods) { var methodHandle = methodGenerator.Generate(method); - methodDefinitionHandles.Add(methodHandle); - - if (method.Name.Equals("Main")) // FIXME can a non entry point be called Main? + if (method.Name.Equals("Main")) { mainMethodHandle = methodHandle; } } - var baseType = default(EntityHandle); - if (type.Base != null) - { - baseType = referencesProvider.TypeReferenceOf(type.Base); - } var typeDefinitionHandle = metadata.AddTypeDefinition( - attributes: AttributesProvider.GetTypeAttributesFor(type), + attributes: GetTypeAttributesFor(type), @namespace: metadata.GetOrAddString(type.ContainingNamespace.FullName), name: metadata.GetOrAddString(type.Name), - baseType: baseType, - fieldList: fieldDefinitionHandles.FirstOr(MetadataTokens.FieldDefinitionHandle(metadata.NextRowFor(TableIndex.Field))), - methodList: methodDefinitionHandles.FirstOr(MetadataTokens.MethodDefinitionHandle(metadata.NextRowFor(TableIndex.MethodDef)))); + baseType: type.Base != null ? referencesProvider.TypeReferenceOf(type.Base) : default, + fieldList: fieldDefinitionHandles.FirstOr(ECMA335.MetadataTokens.FieldDefinitionHandle(metadata.NextRowFor(ECMA335.TableIndex.Field))), + methodList: methodDefinitionHandles.FirstOr(ECMA335.MetadataTokens.MethodDefinitionHandle(metadata.NextRowFor(ECMA335.TableIndex.MethodDef)))); foreach (var interfaze in type.Interfaces) { @@ -176,8 +162,7 @@ private TypeDefinitionHandle Generate(Model.Types.TypeDefinition type) /* Generic parameters table must be sorted that's why this is done at the end and not during the method generation. - If done that way, method generic parameters of a type are added before the type's generic parameters and table results - unsorted + If done that way, method generic parameters of a type are added before the type's generic parameters and table results unsorted */ // generate class generic parameters (Class) @@ -185,7 +170,7 @@ Generic parameters table must be sorted that's why this is done at the end and n { metadata.AddGenericParameter( typeDefinitionHandle, - GenericParameterAttributes.None, + SR.GenericParameterAttributes.None, metadata.GetOrAddString(genericParamter.Name), genericParamter.Index); } @@ -198,7 +183,7 @@ Generic parameters table must be sorted that's why this is done at the end and n { metadata.AddGenericParameter( methodDefinitionHandles[i], - GenericParameterAttributes.None, + SR.GenericParameterAttributes.None, metadata.GetOrAddString(genericParameter.Name), genericParameter.Index); } diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs index 2f89f14b..ab4125e3 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -13,7 +13,7 @@ public static TypeAttributes GetTypeAttributesFor(TypeDefinition typeDefinition) { case TypeDefinitionKind.Class: return ClassTypeAttributes(typeDefinition); case TypeDefinitionKind.Enum: return EnumTypeAttributes(typeDefinition); - case TypeDefinitionKind.Interface: return InterfaceTypeAttributes(typeDefinition); + case TypeDefinitionKind.Interface: return InterfaceTypeAttributes(); case TypeDefinitionKind.Struct: return StructTypeAttributes(typeDefinition); case TypeDefinitionKind.Delegate: return DelegateTypeAttributes(typeDefinition); default: throw new Exception($"TypeDefinition {typeDefinition.Name} not supported"); @@ -46,12 +46,11 @@ private static TypeAttributes EnumTypeAttributes(TypeDefinition typeDefinition) private static TypeAttributes ClassTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Class | - //TODO: static => abstract & sealed and no BeforeFieldInitBeforeFieldInit TypeAttributes.BeforeFieldInit | //FIXME: when? VisibilityAttributesFor(typeDefinition); } - private static TypeAttributes InterfaceTypeAttributes(TypeDefinition typeDefinition) + private static TypeAttributes InterfaceTypeAttributes() { return TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; } @@ -60,12 +59,10 @@ public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) { var fieldAttributes = (field.IsStatic ? FieldAttributes.Static : 0) | - (field.ContainingType.Kind.Equals(TypeDefinitionKind.Enum) && field.Type.Equals(field.ContainingType) ? FieldAttributes.Literal : 0) | // TODO also applies for const fields. - (field.ContainingType.Kind.Equals(TypeDefinitionKind.Enum) && field.Name.Equals("value__", StringComparison.InvariantCultureIgnoreCase) ? FieldAttributes.RTSpecialName | FieldAttributes.SpecialName : 0); - // (field is readonly ? FieldAttributes.InitOnly : 0); //TODO + (field.ContainingType.Kind is TypeDefinitionKind.Enum && field.Type.Equals(field.ContainingType) ? FieldAttributes.Literal : 0) | + (field.ContainingType.Kind is TypeDefinitionKind.Enum && field.Name.Equals("value__", StringComparison.InvariantCultureIgnoreCase) ? FieldAttributes.RTSpecialName | FieldAttributes.SpecialName : 0); switch (field.Visibility) { - case VisibilityKind.Public: fieldAttributes |= FieldAttributes.Public; break; @@ -86,15 +83,17 @@ public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) { - var isConstructor = method.IsConstructor || method.Name.Equals(".cctor"); // FIXME maybe MethodDefinition can have a isClassConstructor or isTypeInitializer + // FIXME maybe MethodDefinition can have a isClassConstructor or isTypeInitializer + var constructor = method.IsConstructor || method.Name.Equals(".cctor"); var methodAttributes = + MethodAttributes.HideBySig | // FIXME when? (method.IsAbstract ? MethodAttributes.Abstract : 0) | (method.IsStatic ? MethodAttributes.Static : 0) | (method.IsVirtual ? MethodAttributes.Virtual : 0) | - (method.ContainingType.Kind.Equals(TypeDefinitionKind.Interface) ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct - (isConstructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | - (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0) | // FIXME fails if non getter/setter method starts with get__/set__ - MethodAttributes.HideBySig; //FIXME when? + (method.ContainingType.Kind is TypeDefinitionKind.Interface ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct. Model is missing the new keyword + (constructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | + (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0); // FIXME fails if non getter/setter method starts with get_/set_ + switch (method.Visibility) { case VisibilityKind.Public: @@ -117,24 +116,24 @@ public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) public static ParameterAttributes GetParameterAttributesFor(MethodParameter parameter) { - var attributes = (parameter.HasDefaultValue ? ParameterAttributes.HasDefault : 0); + var attributes = parameter.HasDefaultValue ? ParameterAttributes.HasDefault : 0; switch (parameter.Kind) { case MethodParameterKind.In: // attributes |= ParameterAttributes.In; - //FIXME this seems to be always true... and illspy of original is not + // FIXME this seems to be always true... and illspy of original is not break; case MethodParameterKind.Out: attributes |= ParameterAttributes.Out; break; case MethodParameterKind.Ref: - // FIXME + // TODO break; } return attributes; } - // FIXME + // TODO other visibilties? private static TypeAttributes VisibilityAttributesFor(TypeDefinition typeDefinition) { if (typeDefinition.ContainingType != null) diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index 821104dd..c02c0ea6 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; // TODO separate in namespaces (Collection, Metadata, etc)? is there a convention for extensions? namespace MetadataGenerator @@ -18,15 +18,16 @@ public static T FirstOr(this IEnumerable enumerable, T defaultValue) public static bool IsOneOf(this MethodParameterKind kind, params MethodParameterKind[] kinds) => ImmutableList.Create(kinds).Contains(kind); - public static void CallVirtual(this InstructionEncoder encoder, EntityHandle methodReference) + public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.EntityHandle methodReference) { - encoder.OpCode(ILOpCode.Callvirt); + encoder.OpCode(SRM.ILOpCode.Callvirt); encoder.Token(methodReference); } // The next available slot in the corresponding table. If nothing is defined in the module then use row number 1 for the corresponding table - public static int NextRowFor(this MetadataBuilder metadata, TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; + public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; + + public static string CurrentLabelString(this ECMA335.InstructionEncoder instructionEncoder) => string.Format("L_{0:x4}", instructionEncoder.Offset); - public static string CurrentLabelString(this InstructionEncoder instructionEncoder) => string.Format("L_{0:x4}", instructionEncoder.Offset); } } diff --git a/MetadataGenerator/FieldGenerator.cs b/MetadataGenerator/FieldGenerator.cs index 068f2306..c82ab31b 100644 --- a/MetadataGenerator/FieldGenerator.cs +++ b/MetadataGenerator/FieldGenerator.cs @@ -1,28 +1,29 @@ -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; +using Model.Types; +using static MetadataGenerator.AttributesProvider; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; namespace MetadataGenerator { public class FieldGenerator { - private readonly MetadataBuilder metadata; + private readonly ECMA335.MetadataBuilder metadata; private readonly TypeEncoder typeEncoder; - public FieldGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder) + public FieldGenerator(ECMA335.MetadataBuilder metadata, TypeEncoder typeEncoder) { this.metadata = metadata; this.typeEncoder = typeEncoder; } - public FieldDefinitionHandle Generate(Model.Types.FieldDefinition field) + public SRM.FieldDefinitionHandle Generate(FieldDefinition field) { - var fieldSignatureBlobBuilder = new BlobBuilder(); - var encoder = new BlobEncoder(fieldSignatureBlobBuilder).FieldSignature(); - typeEncoder.Encode(field.Type, encoder); + var fieldSignature = new SRM.BlobBuilder(); + typeEncoder.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); var fieldDefinitionHandle = metadata.AddFieldDefinition( - attributes: AttributesProvider.GetFieldAttributesFor(field), + attributes: GetFieldAttributesFor(field), name: metadata.GetOrAddString(field.Name), - signature: metadata.GetOrAddBlob(fieldSignatureBlobBuilder)); + signature: metadata.GetOrAddBlob(fieldSignature)); if (field.Value != null) { diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 55ec8d3e..99a87ae3 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -1,9 +1,8 @@ using System.IO; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Reflection.PortableExecutable; using Model; -using Assembly = Model.Assembly; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; +using SRPE = System.Reflection.PortableExecutable; namespace MetadataGenerator { @@ -15,18 +14,17 @@ public void Generate(Assembly assembly) // using (var peStream = File.OpenWrite($"./{assembly.Name}.exe")) { var assemblyGenerator = AssemblyGenerator.For(assembly).Generate(); - var peHeaderBuilder = new PEHeaderBuilder( - imageCharacteristics: assemblyGenerator.Executable ? Characteristics.ExecutableImage : Characteristics.Dll + var peHeaderBuilder = new SRPE.PEHeaderBuilder( + imageCharacteristics: assemblyGenerator.Executable ? SRPE.Characteristics.ExecutableImage : SRPE.Characteristics.Dll ); - var peBuilder = new ManagedPEBuilder( + var peBlob = new SRM.BlobBuilder(); + new SRPE.ManagedPEBuilder( header: peHeaderBuilder, - metadataRootBuilder: new MetadataRootBuilder(assemblyGenerator.GeneratedMetadata), + metadataRootBuilder: new ECMA335.MetadataRootBuilder(assemblyGenerator.GeneratedMetadata), ilStream: assemblyGenerator.IlStream, - entryPoint: assemblyGenerator.MainMethodHandle ?? default(MethodDefinitionHandle), - flags: CorFlags.ILOnly // FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll. Requires/prefers 32 bit? - ); - var peBlob = new BlobBuilder(); - var contentId = peBuilder.Serialize(peBlob); + entryPoint: assemblyGenerator.MainMethodHandle ?? default, + // FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll. Requires/prefers 32 bit? + flags: SRPE.CorFlags.ILOnly).Serialize(peBlob); peBlob.WriteContentTo(peStream); } } diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs index 9cea7178..a6181b8c 100644 --- a/MetadataGenerator/MethodGenerator.cs +++ b/MetadataGenerator/MethodGenerator.cs @@ -1,34 +1,33 @@ using System; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; using Model.Types; +using static MetadataGenerator.AttributesProvider; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SR = System.Reflection; +using SRM = System.Reflection.Metadata; namespace MetadataGenerator { public class MethodGenerator { - private readonly MetadataBuilder metadata; - private readonly MethodBodyStreamEncoder methodBodyStream; + private readonly ECMA335.MetadataBuilder metadata; + private readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; private readonly MethodSignatureGenerator methodSignatureGenerator; private readonly MethodBodyGenerator methodBodyGenerator; private readonly MethodParameterGenerator methodParameterGenerator; - public MethodGenerator(MetadataBuilder metadata, TypeEncoder typeEncoder, ReferencesProvider referencesProvider) + public MethodGenerator(ECMA335.MetadataBuilder metadata, TypeEncoder typeEncoder, ReferencesProvider referencesProvider) { this.metadata = metadata; - methodBodyStream = new MethodBodyStreamEncoder(new BlobBuilder()); + methodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); methodParameterGenerator = new MethodParameterGenerator(metadata); methodSignatureGenerator = new MethodSignatureGenerator(typeEncoder); - methodBodyGenerator = new MethodBodyGenerator(referencesProvider, methodSignatureGenerator); + methodBodyGenerator = new MethodBodyGenerator(referencesProvider, methodSignatureGenerator, metadata); } - public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) + public SRM.MethodDefinitionHandle Generate(MethodDefinition method) { - - var methodSignature = methodSignatureGenerator.Generate(method); - - ParameterHandle? firstParameterHandle = null; + var methodSignature = methodSignatureGenerator.GenerateSignatureOf(method); + SRM.ParameterHandle? firstParameterHandle = null; foreach (var parameter in method.Parameters) { var parameterHandle = methodParameterGenerator.Generate(parameter); @@ -38,21 +37,21 @@ public MethodDefinitionHandle Generate(Model.Types.MethodDefinition method) } } - // FIXME several addMethodBody variants with different arguments + // FIXME several addMethodBody variants with different arguments. codeSize, maxStacks, etc var methodBody = method.HasBody ? methodBodyStream.AddMethodBody(methodBodyGenerator.Generate(method.Body)) - : default(int); + : default; return metadata.AddMethodDefinition( - attributes: AttributesProvider.GetMethodAttributesFor(method), - implAttributes: MethodImplAttributes.IL | MethodImplAttributes.Managed, //FIXME + attributes: GetMethodAttributesFor(method), + implAttributes: SR.MethodImplAttributes.IL | SR.MethodImplAttributes.Managed, // FIXME what else? name: metadata.GetOrAddString(method.Name), signature: metadata.GetOrAddBlob(methodSignature), bodyOffset: methodBody, - parameterList: firstParameterHandle ?? MetadataTokens.ParameterHandle(metadata.NextRowFor(TableIndex.Param))); + parameterList: firstParameterHandle ?? ECMA335.MetadataTokens.ParameterHandle(metadata.NextRowFor(ECMA335.TableIndex.Param))); } - public BlobBuilder IlStream() + public SRM.BlobBuilder IlStream() { return methodBodyStream.Builder; } @@ -66,10 +65,10 @@ public MethodSignatureGenerator(TypeEncoder typeEncoder) this.typeEncoder = typeEncoder; } - public BlobBuilder Generate(IMethodReference method) + public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) { - var methodSignature = new BlobBuilder(); - new BlobEncoder(methodSignature) + var methodSignature = new SRM.BlobBuilder(); + new ECMA335.BlobEncoder(methodSignature) .MethodSignature(isInstanceMethod: !method.IsStatic, genericParameterCount: method.GenericParameterCount) .Parameters( method.Parameters.Count, @@ -81,7 +80,8 @@ public BlobBuilder Generate(IMethodReference method) } else { - var encoder = returnType.Type(); // FIXME pass isByRef param. ref return type is not in the model + // TODO isByRef param. ref in return type is not in the model + var encoder = returnType.Type(); typeEncoder.Encode(method.ReturnType, encoder); } @@ -101,40 +101,39 @@ public BlobBuilder Generate(IMethodReference method) private class MethodParameterGenerator { - private readonly MetadataBuilder metadata; + private readonly ECMA335.MetadataBuilder metadata; - public MethodParameterGenerator(MetadataBuilder metadata) + public MethodParameterGenerator(ECMA335.MetadataBuilder metadata) { this.metadata = metadata; } - public ParameterHandle Generate(MethodParameter methodParameter) - { - return metadata.AddParameter( - AttributesProvider.GetParameterAttributesFor(methodParameter), - metadata.GetOrAddString(methodParameter.Name), - methodParameter.Index); - } - + public SRM.ParameterHandle Generate(MethodParameter parameter) => + metadata.AddParameter(GetParameterAttributesFor(parameter), metadata.GetOrAddString(parameter.Name), parameter.Index); } + #region Method Body + // review all instructions of the ecma pdf + // review overflow and other checks that instructions have private class MethodBodyGenerator { private readonly ReferencesProvider referencesProvider; private readonly MethodSignatureGenerator methodSignatureGenerator; + private readonly ECMA335.MetadataBuilder metadata; - public MethodBodyGenerator(ReferencesProvider referencesProvider, MethodSignatureGenerator methodSignatureGenerator) + public MethodBodyGenerator(ReferencesProvider referencesProvider, MethodSignatureGenerator methodSignatureGenerator, ECMA335.MetadataBuilder metadata) { this.referencesProvider = referencesProvider; this.methodSignatureGenerator = methodSignatureGenerator; + this.metadata = metadata; } - public InstructionEncoder Generate(Model.Types.MethodBody body) + public ECMA335.InstructionEncoder Generate(MethodBody body) { - var controlFlowBuilder = new ControlFlowBuilder(); - var instructionEncoder = new InstructionEncoder(new BlobBuilder(), controlFlowBuilder); + var controlFlowBuilder = new ECMA335.ControlFlowBuilder(); + var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), controlFlowBuilder); - /** Exception handling, uncomment once al other instructions are generated correctly. If not, labels don't match (because operations are missing) + /** Exception handling, uncomment once ial other instructions are generated correctly. If not, labels don't match (because operations are missing) var exceptionMapping = new Dictionary>(); LabelHandle addMapping(string label) { @@ -197,37 +196,37 @@ LabelHandle addMapping(string label) // see all IlOpCode constants case Model.Bytecode.BasicOperation.Nop: - instructionEncoder.OpCode(ILOpCode.Nop); + instructionEncoder.OpCode(SRM.ILOpCode.Nop); break; case Model.Bytecode.BasicOperation.Add: - instructionEncoder.OpCode(ILOpCode.Add); + instructionEncoder.OpCode(SRM.ILOpCode.Add); break; case Model.Bytecode.BasicOperation.Sub: - instructionEncoder.OpCode(ILOpCode.Sub); + instructionEncoder.OpCode(SRM.ILOpCode.Sub); break; case Model.Bytecode.BasicOperation.Mul: - instructionEncoder.OpCode(ILOpCode.Mul); + instructionEncoder.OpCode(SRM.ILOpCode.Mul); break; case Model.Bytecode.BasicOperation.Div: - instructionEncoder.OpCode(ILOpCode.Div); + instructionEncoder.OpCode(SRM.ILOpCode.Div); break; case Model.Bytecode.BasicOperation.Rem: - instructionEncoder.OpCode(ILOpCode.Rem); + instructionEncoder.OpCode(SRM.ILOpCode.Rem); break; case Model.Bytecode.BasicOperation.And: - instructionEncoder.OpCode(ILOpCode.And); + instructionEncoder.OpCode(SRM.ILOpCode.And); break; case Model.Bytecode.BasicOperation.Or: - instructionEncoder.OpCode(ILOpCode.Or); + instructionEncoder.OpCode(SRM.ILOpCode.Or); break; case Model.Bytecode.BasicOperation.Xor: - instructionEncoder.OpCode(ILOpCode.Xor); + instructionEncoder.OpCode(SRM.ILOpCode.Xor); break; case Model.Bytecode.BasicOperation.Shl: - instructionEncoder.OpCode(ILOpCode.Shl); + instructionEncoder.OpCode(SRM.ILOpCode.Shl); break; case Model.Bytecode.BasicOperation.Shr: - instructionEncoder.OpCode(ILOpCode.Shr); + instructionEncoder.OpCode(SRM.ILOpCode.Shr); break; case Model.Bytecode.BasicOperation.Eq: break; @@ -236,37 +235,39 @@ LabelHandle addMapping(string label) case Model.Bytecode.BasicOperation.Gt: break; case Model.Bytecode.BasicOperation.Throw: - instructionEncoder.OpCode(ILOpCode.Throw); + instructionEncoder.OpCode(SRM.ILOpCode.Throw); break; case Model.Bytecode.BasicOperation.Rethrow: - instructionEncoder.OpCode(ILOpCode.Rethrow); + instructionEncoder.OpCode(SRM.ILOpCode.Rethrow); break; case Model.Bytecode.BasicOperation.Not: - instructionEncoder.OpCode(ILOpCode.Not); + instructionEncoder.OpCode(SRM.ILOpCode.Not); break; case Model.Bytecode.BasicOperation.Neg: - instructionEncoder.OpCode(ILOpCode.Neg); + instructionEncoder.OpCode(SRM.ILOpCode.Neg); break; case Model.Bytecode.BasicOperation.Pop: - instructionEncoder.OpCode(ILOpCode.Pop); + instructionEncoder.OpCode(SRM.ILOpCode.Pop); break; case Model.Bytecode.BasicOperation.Dup: - instructionEncoder.OpCode(ILOpCode.Dup); + instructionEncoder.OpCode(SRM.ILOpCode.Dup); break; case Model.Bytecode.BasicOperation.EndFinally: - instructionEncoder.OpCode(ILOpCode.Endfinally); + instructionEncoder.OpCode(SRM.ILOpCode.Endfinally); break; case Model.Bytecode.BasicOperation.EndFilter: - instructionEncoder.OpCode(ILOpCode.Endfilter); + instructionEncoder.OpCode(SRM.ILOpCode.Endfilter); break; case Model.Bytecode.BasicOperation.LocalAllocation: - instructionEncoder.OpCode(ILOpCode.Localloc); + instructionEncoder.OpCode(SRM.ILOpCode.Localloc); break; case Model.Bytecode.BasicOperation.InitBlock: - instructionEncoder.OpCode(ILOpCode.Initblk); + instructionEncoder.OpCode(SRM.ILOpCode.Initblk); break; case Model.Bytecode.BasicOperation.InitObject: - instructionEncoder.OpCode(ILOpCode.Initobj); + // FIXME basicInstruction is missing type. Should be initObj type + // instructionEncoder.OpCode(ILOpCode.Initobj); + // instructionEncoder.Token(type) break; case Model.Bytecode.BasicOperation.CopyObject: break; @@ -287,7 +288,7 @@ LabelHandle addMapping(string label) case Model.Bytecode.BasicOperation.Breakpoint: break; case Model.Bytecode.BasicOperation.Return: - instructionEncoder.OpCode(ILOpCode.Ret); + instructionEncoder.OpCode(SRM.ILOpCode.Ret); break; } } @@ -321,10 +322,26 @@ LabelHandle addMapping(string label) } else if (instruction is Model.Bytecode.ConvertInstruction convertInstruction) { + switch (convertInstruction.Operation) + { + case Model.Bytecode.ConvertOperation.Conv: + break; + case Model.Bytecode.ConvertOperation.Cast: + break; + case Model.Bytecode.ConvertOperation.Box: + instructionEncoder.OpCode(SRM.ILOpCode.Box); + // FIXME ConversionType is IType. It can be IBasicType, ArrayType or PointerType. + instructionEncoder.Token(referencesProvider.TypeReferenceOf(convertInstruction.ConversionType as IBasicType)); + break; + case Model.Bytecode.ConvertOperation.Unbox: + break; + case Model.Bytecode.ConvertOperation.UnboxPtr: + break; + } } else if (instruction is Model.Bytecode.MethodCallInstruction methodCallInstruction) { - var methodSignature = methodSignatureGenerator.Generate(methodCallInstruction.Method); + var methodSignature = methodSignatureGenerator.GenerateSignatureOf(methodCallInstruction.Method); switch (methodCallInstruction.Operation) { case Model.Bytecode.MethodCallOperation.Virtual: @@ -343,6 +360,44 @@ LabelHandle addMapping(string label) case Model.Bytecode.LoadOperation.Address: break; case Model.Bytecode.LoadOperation.Value: + //FIXME TAC, CASTS? + if (loadlInstruction.Operand.Type.Equals(PlatformTypes.String)) + { + var value = (string)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.LoadString(metadata.GetOrAddUserString(value)); + } + + // TODO see ECMA ldc instruction. It says some cases should be follow by conv.i8 operations but the bytecode (original) does not have that + else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Int8) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt8)) + { + var value = (int)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); + instructionEncoder.Token(value); + } + else if ( + loadlInstruction.Operand.Type.Equals(PlatformTypes.Int16) || + loadlInstruction.Operand.Type.Equals(PlatformTypes.Int32) || + loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt16) || + loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt32)) + { + var value = (int)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.LoadConstantI4(value); + } + else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Int64) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt64)) + { + var value = (long)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.LoadConstantI8(value); + } + else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Float32)) + { + var value = (float)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.LoadConstantR4(value); + } + else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Float64)) + { + var value = (double)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.LoadConstantR8(value); + } break; case Model.Bytecode.LoadOperation.Content: break; @@ -353,11 +408,11 @@ LabelHandle addMapping(string label) else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) { } else if (instruction is Model.Bytecode.CreateArrayInstruction createArrayInstruction) { - var size = 1; // FIXME array size not in the model (ArrayType) - instructionEncoder.LoadConstantI4(size); // FIXME I4 = int, I8 = long. Could it be long? - instructionEncoder.OpCode(ILOpCode.Newarr); + // var size = 1; // FIXME array size not in the model (ArrayType) + // instructionEncoder.LoadConstantI4(size); // FIXME I4 = int, I8 = long. Could it be long? + // instructionEncoder.OpCode(ILOpCode.Newarr); // FIXME (cast). ElementsType could be Pointer or BasicType. MultiDimensional Arrays are handled by newObj insteado of newArr - instructionEncoder.Token(referencesProvider.TypeReferenceOf(createArrayInstruction.Type.ElementsType as IBasicType)); + // instructionEncoder.Token(referencesProvider.TypeReferenceOf(createArrayInstruction.Type.ElementsType as IBasicType)); } else if (instruction is Model.Bytecode.CreateObjectInstruction createObjectInstruction) { } else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAddressInstruction) { } @@ -375,6 +430,6 @@ LabelHandle addMapping(string label) return instructionEncoder; } } + #endregion } - -} \ No newline at end of file +} diff --git a/MetadataGenerator/ReferencesProvider.cs b/MetadataGenerator/ReferencesProvider.cs index 0b8feea6..ef0de8ee 100644 --- a/MetadataGenerator/ReferencesProvider.cs +++ b/MetadataGenerator/ReferencesProvider.cs @@ -1,22 +1,24 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; +using Model; using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; +// FIXME extend MetadataBuilder with getOrAddTypereference, getOrAddMethodReferenceOf? is it possible? If it is +// then there is no need to store mappings and this class can be static (would make typeEncoder static as well) simplifiying everything namespace MetadataGenerator { public class ReferencesProvider { - private readonly Model.Assembly assembly; - private readonly MetadataBuilder metadata; - private readonly IDictionary assemblyReferences = new Dictionary(); - private readonly IDictionary typeReferences = new Dictionary(); - private readonly IDictionary methodReferences = new Dictionary(); + private readonly Assembly assembly; + private readonly ECMA335.MetadataBuilder metadata; + private readonly IDictionary assemblyReferences = new Dictionary(); + private readonly IDictionary typeReferences = new Dictionary(); + private readonly IDictionary methodReferences = new Dictionary(); - public ReferencesProvider(MetadataBuilder metadata, Model.Assembly assembly) + public ReferencesProvider(ECMA335.MetadataBuilder metadata, Assembly assembly) { this.metadata = metadata; this.assembly = assembly; @@ -31,8 +33,8 @@ public ReferencesProvider(MetadataBuilder metadata, Model.Assembly assembly) version: new Version(4, 0, 0, 0), culture: metadata.GetOrAddString("neutral"), publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), - flags: default(AssemblyFlags), - hashValue: default(BlobHandle)) + flags: default, + hashValue: default) ); } } @@ -40,17 +42,17 @@ public ReferencesProvider(MetadataBuilder metadata, Model.Assembly assembly) /* * Returns a TypeReference for type. It stores references because metadata does not have a getOrAddTypeReference. */ - public EntityHandle TypeReferenceOf(IBasicType type) + public SRM.EntityHandle TypeReferenceOf(IBasicType type) { // FIXME: is this key unique? var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{type.Name}"; - if (!typeReferences.TryGetValue(typeReferenceKey, out TypeReferenceHandle typeReference)) // If stored then return that + if (!typeReferences.TryGetValue(typeReferenceKey, out SRM.TypeReferenceHandle typeReference)) // If stored then return that { // if not add the new type reference to metadata and store it - EntityHandle resolutionScope; + SRM.EntityHandle resolutionScope; if (type.ContainingType == null) // if defined in the namespace then search there { resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) - ? default(AssemblyReferenceHandle) + ? default : assemblyReferences[type.ContainingAssembly.Name]; } else @@ -66,11 +68,11 @@ public EntityHandle TypeReferenceOf(IBasicType type) return typeReference; } - public MemberReferenceHandle MethodReferenceOf(IMethodReference method, BlobBuilder methodSignature) + public SRM.MemberReferenceHandle MethodReferenceOf(IMethodReference method, SRM.BlobBuilder methodSignature) { // FIXME: is this key unique? var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; - if (!methodReferences.TryGetValue(key, out MemberReferenceHandle memberReferenceHandle)) + if (!methodReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) { memberReferenceHandle = metadata.AddMemberReference( parent: TypeReferenceOf(method.ContainingType), diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 16eb38b7..9156bab7 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Immutable; -using System.Reflection.Metadata.Ecma335; using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; namespace MetadataGenerator { @@ -14,63 +14,63 @@ public TypeEncoder(ReferencesProvider referencesProvider) } // FIXME signatureTypeEncoder should be by reference? or value? - public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) + public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { if (type.Equals(PlatformTypes.Boolean)) { - signatureTypeEncoder.Boolean(); + encoder.Boolean(); } else if (type.Equals(PlatformTypes.Byte)) { - signatureTypeEncoder.Byte(); + encoder.Byte(); } else if (type.Equals(PlatformTypes.SByte)) { - signatureTypeEncoder.SByte(); + encoder.SByte(); } else if (type.Equals(PlatformTypes.Char)) { - signatureTypeEncoder.Char(); + encoder.Char(); } else if (type.Equals(PlatformTypes.Double)) { - signatureTypeEncoder.Double(); + encoder.Double(); } else if (type.Equals(PlatformTypes.Int16)) { - signatureTypeEncoder.Int16(); + encoder.Int16(); } else if (type.Equals(PlatformTypes.UInt16)) { - signatureTypeEncoder.UInt16(); + encoder.UInt16(); } else if (type.Equals(PlatformTypes.Int32)) { - signatureTypeEncoder.Int32(); + encoder.Int32(); } else if (type.Equals(PlatformTypes.UInt32)) { - signatureTypeEncoder.UInt32(); + encoder.UInt32(); } else if (type.Equals(PlatformTypes.Int64)) { - signatureTypeEncoder.Int64(); + encoder.Int64(); } else if (type.Equals(PlatformTypes.UInt64)) { - signatureTypeEncoder.UInt64(); + encoder.UInt64(); } else if (type.Equals(PlatformTypes.String)) { - signatureTypeEncoder.String(); + encoder.String(); } else if (type.Equals(PlatformTypes.Single)) { - signatureTypeEncoder.Single(); + encoder.Single(); } else if (type.Equals(PlatformTypes.Object)) { - signatureTypeEncoder.Object(); + encoder.Object(); } else { @@ -78,7 +78,7 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) { if (basicType.GenericType != null) { - var genericInstantiation = signatureTypeEncoder.GenericInstantiation( + var genericInstantiation = encoder.GenericInstantiation( referencesProvider.TypeReferenceOf(basicType), basicType.GenericParameterCount, type.TypeKind == TypeKind.ValueType @@ -90,12 +90,12 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) } else { - signatureTypeEncoder.Type(referencesProvider.TypeReferenceOf(basicType), type.TypeKind == TypeKind.ValueType); + encoder.Type(referencesProvider.TypeReferenceOf(basicType), type.TypeKind == TypeKind.ValueType); } } else if (type is ArrayType arrayType) { - signatureTypeEncoder.Array( + encoder.Array( elementTypeEncoder => { Encode(arrayType.ElementsType, elementTypeEncoder); @@ -116,11 +116,11 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) var targetType = pointerType.TargetType; if (targetType.Equals(PlatformTypes.Void)) { - signatureTypeEncoder.VoidPointer(); + encoder.VoidPointer(); } else { - Encode(targetType, signatureTypeEncoder.Pointer()); + Encode(targetType, encoder.Pointer()); } } else if (type is GenericParameter genericParameter) @@ -128,10 +128,10 @@ public void Encode(IType type, SignatureTypeEncoder signatureTypeEncoder) switch (genericParameter.Kind) { case GenericParameterKind.Type: - signatureTypeEncoder.GenericTypeParameter(genericParameter.Index); + encoder.GenericTypeParameter(genericParameter.Index); break; case GenericParameterKind.Method: - signatureTypeEncoder.GenericMethodTypeParameter(genericParameter.Index); + encoder.GenericMethodTypeParameter(genericParameter.Index); break; } } From d2125fae9e1da097d9ae9a6b7805d6d1a6737714 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 6 Oct 2019 11:31:28 -0300 Subject: [PATCH 040/256] formatting --- MetadataGenerator/ReferencesProvider.cs | 4 -- MetadataGenerator/TypeEncoder.cs | 80 +++++-------------------- 2 files changed, 16 insertions(+), 68 deletions(-) diff --git a/MetadataGenerator/ReferencesProvider.cs b/MetadataGenerator/ReferencesProvider.cs index ef0de8ee..b9831b42 100644 --- a/MetadataGenerator/ReferencesProvider.cs +++ b/MetadataGenerator/ReferencesProvider.cs @@ -6,8 +6,6 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -// FIXME extend MetadataBuilder with getOrAddTypereference, getOrAddMethodReferenceOf? is it possible? If it is -// then there is no need to store mappings and this class can be static (would make typeEncoder static as well) simplifiying everything namespace MetadataGenerator { public class ReferencesProvider @@ -44,7 +42,6 @@ public ReferencesProvider(ECMA335.MetadataBuilder metadata, Assembly assembly) */ public SRM.EntityHandle TypeReferenceOf(IBasicType type) { - // FIXME: is this key unique? var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{type.Name}"; if (!typeReferences.TryGetValue(typeReferenceKey, out SRM.TypeReferenceHandle typeReference)) // If stored then return that { // if not add the new type reference to metadata and store it @@ -70,7 +67,6 @@ public SRM.EntityHandle TypeReferenceOf(IBasicType type) public SRM.MemberReferenceHandle MethodReferenceOf(IMethodReference method, SRM.BlobBuilder methodSignature) { - // FIXME: is this key unique? var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; if (!methodReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) { diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 9156bab7..59ee290c 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -16,62 +16,20 @@ public TypeEncoder(ReferencesProvider referencesProvider) // FIXME signatureTypeEncoder should be by reference? or value? public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { - if (type.Equals(PlatformTypes.Boolean)) - { - encoder.Boolean(); - } - else if (type.Equals(PlatformTypes.Byte)) - { - encoder.Byte(); - } - else if (type.Equals(PlatformTypes.SByte)) - { - encoder.SByte(); - } - else if (type.Equals(PlatformTypes.Char)) - { - encoder.Char(); - } - else if (type.Equals(PlatformTypes.Double)) - { - encoder.Double(); - } - else if (type.Equals(PlatformTypes.Int16)) - { - encoder.Int16(); - } - else if (type.Equals(PlatformTypes.UInt16)) - { - encoder.UInt16(); - } - else if (type.Equals(PlatformTypes.Int32)) - { - encoder.Int32(); - } - else if (type.Equals(PlatformTypes.UInt32)) - { - encoder.UInt32(); - } - else if (type.Equals(PlatformTypes.Int64)) - { - encoder.Int64(); - } - else if (type.Equals(PlatformTypes.UInt64)) - { - encoder.UInt64(); - } - else if (type.Equals(PlatformTypes.String)) - { - encoder.String(); - } - else if (type.Equals(PlatformTypes.Single)) - { - encoder.Single(); - } - else if (type.Equals(PlatformTypes.Object)) - { - encoder.Object(); - } + if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); + else if (type.Equals(PlatformTypes.Byte)) encoder.Byte(); + else if (type.Equals(PlatformTypes.SByte)) encoder.SByte(); + else if (type.Equals(PlatformTypes.Char)) encoder.Char(); + else if (type.Equals(PlatformTypes.Double)) encoder.Double(); + else if (type.Equals(PlatformTypes.Int16)) encoder.Int16(); + else if (type.Equals(PlatformTypes.UInt16)) encoder.UInt16(); + else if (type.Equals(PlatformTypes.Int32)) encoder.Int32(); + else if (type.Equals(PlatformTypes.UInt32)) encoder.UInt32(); + else if (type.Equals(PlatformTypes.Int64)) encoder.Int64(); + else if (type.Equals(PlatformTypes.UInt64)) encoder.UInt64(); + else if (type.Equals(PlatformTypes.String)) encoder.String(); + else if (type.Equals(PlatformTypes.Single)) encoder.Single(); + else if (type.Equals(PlatformTypes.Object)) encoder.Object(); else { if (type is IBasicType basicType) @@ -96,10 +54,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) else if (type is ArrayType arrayType) { encoder.Array( - elementTypeEncoder => - { - Encode(arrayType.ElementsType, elementTypeEncoder); - }, + elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), arrayShapeEncoder => { // FIXME real values for sizes and lowerBounds @@ -135,10 +90,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) break; } } - else - { - throw new Exception($"Type {type} not supported"); - } + else throw new Exception($"Type {type} not supported"); } } } From f9b2fe37eebb7e236590b2f904afe1093037ba67 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Sun, 6 Oct 2019 19:05:16 -0300 Subject: [PATCH 041/256] Added Constraints set to GenericParameter class. --- CCIProvider/TypeExtractor.cs | 3 ++- MetadataProvider/AssemblyExtractor.cs | 6 +++++- Model/Types/Types.cs | 6 ++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CCIProvider/TypeExtractor.cs b/CCIProvider/TypeExtractor.cs index 19e64dda..39e813c8 100644 --- a/CCIProvider/TypeExtractor.cs +++ b/CCIProvider/TypeExtractor.cs @@ -818,7 +818,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) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..9b7ec757 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -459,7 +459,11 @@ private void ExtractGenericParameter(GenericParameterKind parameterKind, IGeneri } genericContainer.GenericParameters.Add(genericParameter); - } + var constraints = genericParameterdef.GetConstraints().Select( + constraint => signatureTypeProvider.GetTypeFromHandle(metadata, defGenericContext, metadata.GetGenericParameterConstraint(constraint).Type + )); + genericParameter.Constraints.AddRange(constraints); + } private void ExtractField(SRM.FieldDefinitionHandle handle) { diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index 0d6934db..8999b4e9 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -539,7 +539,8 @@ private static string GetName(GenericParameterKind kind, ushort index) public class GenericParameter : IGenericParameterReference { public ISet Attributes { get; private set; } - public TypeKind TypeKind { get; set; } + public ISet Constraints { get; private set; } + public TypeKind TypeKind { get; set; } public IGenericDefinition GenericContainer { get; set; } public GenericParameterKind Kind { get; set; } public ushort Index { get; set; } @@ -552,7 +553,8 @@ public GenericParameter(GenericParameterKind kind, ushort index, string name, Ty this.Name = name; this.TypeKind = typeKind; this.Attributes = new HashSet(); - } + this.Constraints = new HashSet(); + } #region IGenericParameterReference members From 6f53f98dc86caf853c4473b65ae04146158e8649 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Sun, 6 Oct 2019 19:21:27 -0300 Subject: [PATCH 042/256] Added new bytecode instruction Constrained. --- CCIProvider/CodeProvider.cs | 17 +++++++++---- MetadataProvider/AssemblyExtractor.cs | 14 +++++++---- Model/Bytecode/Instructions.cs | 24 ++++++++++++++++++- Model/Bytecode/Visitor/IInstructionVisitor.cs | 3 ++- Model/Bytecode/Visitor/InstructionVisitor.cs | 3 ++- 5 files changed, 49 insertions(+), 12 deletions(-) diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index ffdcfffa..cdff1a7f 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -303,9 +303,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); @@ -538,9 +538,16 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) } return instruction; - } + } + + 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 ProcessSwitch(Cci.IOperation op) + private IInstruction ProcessSwitch(Cci.IOperation op) { var targets = op.Value as uint[]; diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..a8c40ee9 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -912,9 +912,9 @@ private IInstruction ExtractInstruction(ILInstruction operation) // expression = new MethodCall() { Arguments = new List(1) { operand }, IsStaticCall = true, Type = operand.Type, MethodToCall = chkfinite }; // break; - //case SRM.ILOpCode.Constrained_: - // // This prefix is redundant and is not represented in the code model. - // break; + case SRM.ILOpCode.Constrained: + instruction = ProcessConstrained(operation); + break; case SRM.ILOpCode.Cpblk: instruction = ProcessBasic(operation); @@ -1391,8 +1391,14 @@ private void BindGenericParameterReferences(GenericParameterKind kind, IGenericR parameters.Clear(); } + private IInstruction ProcessConstrained(ILInstruction op) + { + var thisType = GetOperand(op); + var ins = new ConstrainedInstruction(op.Offset, thisType); + return ins; + } - private IInstruction ProcessSwitch(ILInstruction op) + private IInstruction ProcessSwitch(ILInstruction op) { var targets = GetOperand(op); diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index bb12534e..1fb67942 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -238,7 +238,29 @@ public override string ToString() var targets = string.Join(", ", this.Targets); return this.ToString("switch {0}", targets); } - } + } + + public class ConstrainedInstruction : Instruction + { + public IType ThisType { get; private set; } + + public ConstrainedInstruction(uint label, IType thisType) + : base(label) + { + this.ThisType = thisType; + } + + public override void Accept(IInstructionVisitor visitor) + { + base.Accept(visitor); + visitor.Visit(this); + } + + public override string ToString() + { + return String.Format("constrain virtual call to type: {0}", ThisType.ToString()); + } + } public class CreateArrayInstruction : Instruction { diff --git a/Model/Bytecode/Visitor/IInstructionVisitor.cs b/Model/Bytecode/Visitor/IInstructionVisitor.cs index 5d647a87..c1a39838 100644 --- a/Model/Bytecode/Visitor/IInstructionVisitor.cs +++ b/Model/Bytecode/Visitor/IInstructionVisitor.cs @@ -12,7 +12,8 @@ public interface IInstructionVisitor void Visit(IInstructionContainer container); void Visit(Instruction instruction); void Visit(BasicInstruction instruction); - void Visit(LoadInstruction instruction); + void Visit(ConstrainedInstruction instruction); + void Visit(LoadInstruction instruction); void Visit(LoadFieldInstruction instruction); void Visit(LoadMethodAddressInstruction instruction); void Visit(StoreInstruction instruction); diff --git a/Model/Bytecode/Visitor/InstructionVisitor.cs b/Model/Bytecode/Visitor/InstructionVisitor.cs index 1575ba7a..f8140c9c 100644 --- a/Model/Bytecode/Visitor/InstructionVisitor.cs +++ b/Model/Bytecode/Visitor/InstructionVisitor.cs @@ -20,7 +20,8 @@ public virtual void Visit(IInstructionContainer container) public virtual void Visit(Instruction instruction) { } public virtual void Visit(BasicInstruction instruction) { } - public virtual void Visit(LoadInstruction instruction) { } + public virtual void Visit(ConstrainedInstruction instruction) { } + public virtual void Visit(LoadInstruction instruction) { } public virtual void Visit(LoadFieldInstruction instruction) { } public virtual void Visit(LoadMethodAddressInstruction instruction) { } public virtual void Visit(StoreInstruction instruction) { } From d31fca1df2b8b487433fa98ce86ea76c35f19189 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 7 Oct 2019 23:01:30 -0300 Subject: [PATCH 043/256] some keywords and cleaning --- Examples/Examples.cs | 44 ++++++++++++++++++------- MetadataGenerator/AttributesProvider.cs | 8 +++-- MetadataGenerator/ReferencesProvider.cs | 1 - MetadataGenerator/TypeEncoder.cs | 5 +-- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 0a8c54ee..2a2de82a 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -3,7 +3,6 @@ namespace Enums { - public enum DefaultEnum { CONSTANT1, @@ -28,7 +27,6 @@ public enum EnumOfUShorts : ushort USHORT1 = 1, USHORT2 = 2 } - } // TODO no yet supported in the framework model @@ -52,12 +50,9 @@ public void get_ShouldNotHaveSpecialname() { } } } -//TODO implicit, explicit, operator keywords for methods namespace Classes { - public class EmptyClass - { - } + public class EmptyClass { } public static class StaticClass { @@ -163,9 +158,7 @@ public Exception[] GetExceptionArray() namespace Structs { - public struct EmptyStruct - { - } + public struct EmptyStruct { } public struct NonEmptyStruct { @@ -191,9 +184,35 @@ public void ModifiesField(int value) } } + public readonly struct StructWithImplicitExplicitKeywords + { + private readonly byte digit; + + public StructWithImplicitExplicitKeywords(byte digit) + { + this.digit = digit; + } + + public static implicit operator byte(StructWithImplicitExplicitKeywords d) => d.digit; + public static explicit operator StructWithImplicitExplicitKeywords(byte b) => new StructWithImplicitExplicitKeywords(b); + } + + public readonly struct Fraction + { + private readonly int num; + private readonly int den; + + public Fraction(int numerator, int denominator) + { + num = numerator; + den = denominator; + } + + public static Fraction operator +(Fraction a) => a; + public static Fraction operator -(Fraction a) => new Fraction(-a.num, a.den); + } } -// TODO interface can have properties namespace Interfaces { public class ClassImplementingInterface : IExtendingSampleInterface, IComparable @@ -236,6 +255,8 @@ public int CompareTo(object obj) } +// FIXME is generating [Examples.dll]Delegates.ClassThatUsesDelegate/Del ReturnsADelegate instead of Delegates.ClassThatUsesDelegate/Del ReturnsADelegate +// (same assembly) namespace Delegates { public class SampleClass @@ -353,7 +374,6 @@ public class NestedNestedB { } } // FIXME ref and out are beign generated like type*& instead of type&. That is because the type a & type in the model is represented as a pointer type. -// FIXME generation not entirely correct namespace PointersAndReferences { public class PointersAndReferenceClass @@ -386,7 +406,7 @@ public ref Exception RefException() } } -// FIXME generation not entirely correct. +// FIXME generation almost correct. namespace Generics { public class Generic diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs index ab4125e3..3bce24db 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -83,8 +83,10 @@ public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) { - // FIXME maybe MethodDefinition can have a isClassConstructor or isTypeInitializer - var constructor = method.IsConstructor || method.Name.Equals(".cctor"); + var constructor = method.IsConstructor || method.Name.Equals(".cctor"); // FIXME maybe MethodDefinition can have a isClassConstructor or isTypeInitializer + bool specialName = + method.Name.StartsWith("get_", StringComparison.Ordinal) || method.Name.StartsWith("set_", StringComparison.Ordinal) || + method.Name.StartsWith("op_", StringComparison.Ordinal); var methodAttributes = MethodAttributes.HideBySig | // FIXME when? (method.IsAbstract ? MethodAttributes.Abstract : 0) | @@ -92,7 +94,7 @@ public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) (method.IsVirtual ? MethodAttributes.Virtual : 0) | (method.ContainingType.Kind is TypeDefinitionKind.Interface ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct. Model is missing the new keyword (constructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | - (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ? MethodAttributes.SpecialName : 0); // FIXME fails if non getter/setter method starts with get_/set_ + (specialName ? MethodAttributes.SpecialName : 0); // FIXME fails if non getter/setter method starts with get_/set_ switch (method.Visibility) { diff --git a/MetadataGenerator/ReferencesProvider.cs b/MetadataGenerator/ReferencesProvider.cs index b9831b42..ee80e186 100644 --- a/MetadataGenerator/ReferencesProvider.cs +++ b/MetadataGenerator/ReferencesProvider.cs @@ -21,7 +21,6 @@ public ReferencesProvider(ECMA335.MetadataBuilder metadata, Assembly assembly) this.metadata = metadata; this.assembly = assembly; - // FIXME see references in IlSpy generated vs original // FIXME: assemblyName => assemblyRef could result in false positive? foreach (var assemblyReference in assembly.References) { diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/TypeEncoder.cs index 59ee290c..1e3d286f 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/TypeEncoder.cs @@ -13,7 +13,8 @@ public TypeEncoder(ReferencesProvider referencesProvider) this.referencesProvider = referencesProvider; } - // FIXME signatureTypeEncoder should be by reference? or value? + // SignatureTypeEncoder is a struct but it is not necessary to pass it by reference since + // it operates on its Builder (BlobBuilber) which is a class (tha means the builder refernece is always the same) public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); @@ -94,4 +95,4 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) } } } -} +} \ No newline at end of file From 5a31bd68f7d362bff038e8f980a62747b6752dd1 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Mon, 14 Oct 2019 23:23:52 -0300 Subject: [PATCH 044/256] Added missing case --- CCIProvider/CodeProvider.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index 6a7807b7..e0731c42 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -548,6 +548,10 @@ private IInstruction ProcessStoreArrayElement(Cci.IOperation op) 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; From 3004e93b10691c6608f30fdd557420d95b80a6b4 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 17 Oct 2019 22:59:29 -0300 Subject: [PATCH 045/256] major refactor --- Examples/Examples.cs | 1 + ExamplesEXE/Program.cs | 4 +- MetadataGenerator/AssemblyGenerator.cs | 197 -------- MetadataGenerator/FieldGenerator.cs | 36 -- .../Generators/AssemblyGenerator.cs | 42 ++ .../Generators/FieldGenerator.cs | 34 ++ .../{ => Generators}/Generator.cs | 10 +- .../Generators/Methods/MethodBodyGenerator.cs | 323 +++++++++++++ .../Generators/Methods/MethodGenerator.cs | 63 +++ .../Methods/MethodSignatureGenerator.cs | 50 ++ .../Generators/NamespaceGenerator.cs | 50 ++ MetadataGenerator/Generators/TypeGenerator.cs | 115 +++++ .../Metadata/MetadataContainer.cs | 41 ++ .../ReferenceHandleResolver.cs} | 12 +- .../{ => Metadata}/TypeEncoder.cs | 14 +- MetadataGenerator/MetadataGenerator.csproj | 22 +- MetadataGenerator/MethodGenerator.cs | 435 ------------------ 17 files changed, 756 insertions(+), 693 deletions(-) delete mode 100644 MetadataGenerator/AssemblyGenerator.cs delete mode 100644 MetadataGenerator/FieldGenerator.cs create mode 100644 MetadataGenerator/Generators/AssemblyGenerator.cs create mode 100644 MetadataGenerator/Generators/FieldGenerator.cs rename MetadataGenerator/{ => Generators}/Generator.cs (77%) create mode 100644 MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs create mode 100644 MetadataGenerator/Generators/Methods/MethodGenerator.cs create mode 100644 MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs create mode 100644 MetadataGenerator/Generators/NamespaceGenerator.cs create mode 100644 MetadataGenerator/Generators/TypeGenerator.cs create mode 100644 MetadataGenerator/Metadata/MetadataContainer.cs rename MetadataGenerator/{ReferencesProvider.cs => Metadata/ReferenceHandleResolver.cs} (90%) rename MetadataGenerator/{ => Metadata}/TypeEncoder.cs (88%) delete mode 100644 MetadataGenerator/MethodGenerator.cs diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 2a2de82a..3daf046d 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -613,6 +613,7 @@ public void LoadConstant() int minusOne = -1; // ldc.i4.m1 int i = 20; // ldc.i4.s 20 int k = int.MaxValue; // ldc.i4 + long q = int.MaxValue; // ldc.i4 + conv.i8 long l = long.MinValue; // ldc.i8 float f = float.MinValue; // ldc.r4 double d = double.MinValue; // ldc.r8 diff --git a/ExamplesEXE/Program.cs b/ExamplesEXE/Program.cs index de46f74c..c95e6119 100644 --- a/ExamplesEXE/Program.cs +++ b/ExamplesEXE/Program.cs @@ -1,4 +1,4 @@ -using Classes; +using System; namespace ExamplesEXE { @@ -6,7 +6,7 @@ public class MainClass { public static void Main(string[] args) { - _ = new SimpleClass(); + Console.WriteLine("Hola"); } } } diff --git a/MetadataGenerator/AssemblyGenerator.cs b/MetadataGenerator/AssemblyGenerator.cs deleted file mode 100644 index 7522f701..00000000 --- a/MetadataGenerator/AssemblyGenerator.cs +++ /dev/null @@ -1,197 +0,0 @@ -using System; -using System.Collections.Generic; -using Model; -using Model.Types; -using static MetadataGenerator.AttributesProvider; -using ECMA335 = System.Reflection.Metadata.Ecma335; -using SR = System.Reflection; -using SRM = System.Reflection.Metadata; - -namespace MetadataGenerator -{ - public class AssemblyGenerator - { - private readonly Assembly assembly; - private readonly ECMA335.MetadataBuilder metadata; - private readonly ReferencesProvider referencesProvider; - private readonly MethodGenerator methodGenerator; - private readonly FieldGenerator fieldGenerator; - - private T CheckMetadataWasGeneratedAndReturn(T value) => generatedMetadata != null ? value : throw new Exception("Generate was not called"); - private ECMA335.MetadataBuilder generatedMetadata; - public ECMA335.MetadataBuilder GeneratedMetadata { get => CheckMetadataWasGeneratedAndReturn(generatedMetadata); } - private SRM.MethodDefinitionHandle? mainMethodHandle; - public SRM.MethodDefinitionHandle? MainMethodHandle { get => CheckMetadataWasGeneratedAndReturn(mainMethodHandle); } - public bool Executable => mainMethodHandle != null; - public SRM.BlobBuilder IlStream => CheckMetadataWasGeneratedAndReturn(methodGenerator.IlStream()); - - private AssemblyGenerator(Assembly assembly, ECMA335.MetadataBuilder metadata, ReferencesProvider referencesProvider, MethodGenerator methodGenerator, FieldGenerator fieldGenerator) - { - this.metadata = metadata; - this.referencesProvider = referencesProvider; - this.methodGenerator = methodGenerator; - this.fieldGenerator = fieldGenerator; - this.assembly = assembly; - } - - public static AssemblyGenerator For(Assembly assembly) - { - var metadata = new ECMA335.MetadataBuilder(); - var referencesProvider = new ReferencesProvider(metadata, assembly); - var typeEncoder = new TypeEncoder(referencesProvider); - var methodGenerator = new MethodGenerator(metadata, typeEncoder, referencesProvider); - var fieldGenerator = new FieldGenerator(metadata, typeEncoder); - return new AssemblyGenerator(assembly, metadata, referencesProvider, methodGenerator, fieldGenerator); - } - - public AssemblyGenerator Generate() - { - if (generatedMetadata != null) throw new Exception("Generate was already called for this generator"); - - foreach (var namezpace in assembly.RootNamespace.Namespaces) - { - Generate(namezpace); - } - - // FIXME args - metadata.AddAssembly( - name: metadata.GetOrAddString(assembly.Name), - version: new Version(1, 0, 0, 0), - culture: default, - publicKey: default, - flags: SR.AssemblyFlags.PublicKey, - hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1); - - metadata.AddModule( - generation: 0, - moduleName: metadata.GetOrAddString($"{assembly.Name}.{(Executable ? "exe" : "dll")}"), - mvid: metadata.GetOrAddGuid(Guid.NewGuid()), - encId: metadata.GetOrAddGuid(Guid.Empty), - encBaseId: metadata.GetOrAddGuid(Guid.Empty)); - - generatedMetadata = metadata; - - return this; - } - - private void Generate(Namespace namezpace) - { - foreach (var nestedNamespace in namezpace.Namespaces) - { - Generate(nestedNamespace); - } - - foreach (var type in namezpace.Types) - { - GenerateTypes(type); - } - } - - private SRM.TypeDefinitionHandle GenerateTypes(TypeDefinition type) - { - var nestedTypes = new List(); - foreach (var nestedType in type.Types) - { - nestedTypes.Add(GenerateTypes(nestedType)); - } - - var typeDefinitionHandle = Generate(type); - foreach (var nestedType in nestedTypes) - { - metadata.AddNestedType(nestedType, typeDefinitionHandle); - } - - return typeDefinitionHandle; - } - - private SRM.TypeDefinitionHandle Generate(TypeDefinition type) - { - var fieldDefinitionHandles = new List(); - var methodDefinitionHandles = new List(); - - foreach (var field in type.Fields) - { - fieldDefinitionHandles.Add(fieldGenerator.Generate(field)); - } - - /* TODO Properties: (works) but model is missing Property concept - - var propertySignatureBlogBuilder = new BlobBuilder(); - new BlobEncoder(propertySignatureBlogBuilder) - .PropertySignature(isInstanceProperty: true) //FIXME when false - .Parameters( - 0, - returnType => returnType.Type().Int32(), //FIXME backingField type - parameters => { }); - - var propertyDefinitionHandle = metadata.AddProperty( - attributes: PropertyAttributes.None, //FIXME - name: metadata.GetOrAddString(""), //FIXME property name - signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); - - // asociate methods (get, set) to property - metadata.AddMethodSemantics( - propertyDefinitionHandle, - method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, - methodHandle); //getter/setter - metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); - */ - - foreach (var method in type.Methods) - { - var methodHandle = methodGenerator.Generate(method); - methodDefinitionHandles.Add(methodHandle); - if (method.Name.Equals("Main")) - { - mainMethodHandle = methodHandle; - } - } - - var typeDefinitionHandle = metadata.AddTypeDefinition( - attributes: GetTypeAttributesFor(type), - @namespace: metadata.GetOrAddString(type.ContainingNamespace.FullName), - name: metadata.GetOrAddString(type.Name), - baseType: type.Base != null ? referencesProvider.TypeReferenceOf(type.Base) : default, - fieldList: fieldDefinitionHandles.FirstOr(ECMA335.MetadataTokens.FieldDefinitionHandle(metadata.NextRowFor(ECMA335.TableIndex.Field))), - methodList: methodDefinitionHandles.FirstOr(ECMA335.MetadataTokens.MethodDefinitionHandle(metadata.NextRowFor(ECMA335.TableIndex.MethodDef)))); - - foreach (var interfaze in type.Interfaces) - { - metadata.AddInterfaceImplementation(type: typeDefinitionHandle, implementedInterface: referencesProvider.TypeReferenceOf(interfaze)); - } - - /* - Generic parameters table must be sorted that's why this is done at the end and not during the method generation. - If done that way, method generic parameters of a type are added before the type's generic parameters and table results unsorted - */ - - // generate class generic parameters (Class) - foreach (var genericParamter in type.GenericParameters) - { - metadata.AddGenericParameter( - typeDefinitionHandle, - SR.GenericParameterAttributes.None, - metadata.GetOrAddString(genericParamter.Name), - genericParamter.Index); - } - - // generate method generic parameters (public T method(T param)) - for (int i = 0; i < type.Methods.Count; i++) - { - var method = type.Methods[i]; - foreach (var genericParameter in method.GenericParameters) - { - metadata.AddGenericParameter( - methodDefinitionHandles[i], - SR.GenericParameterAttributes.None, - metadata.GetOrAddString(genericParameter.Name), - genericParameter.Index); - } - } - - return typeDefinitionHandle; - } - } -} - - diff --git a/MetadataGenerator/FieldGenerator.cs b/MetadataGenerator/FieldGenerator.cs deleted file mode 100644 index c82ab31b..00000000 --- a/MetadataGenerator/FieldGenerator.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Model.Types; -using static MetadataGenerator.AttributesProvider; -using ECMA335 = System.Reflection.Metadata.Ecma335; -using SRM = System.Reflection.Metadata; - -namespace MetadataGenerator -{ - public class FieldGenerator - { - private readonly ECMA335.MetadataBuilder metadata; - private readonly TypeEncoder typeEncoder; - - public FieldGenerator(ECMA335.MetadataBuilder metadata, TypeEncoder typeEncoder) - { - this.metadata = metadata; - this.typeEncoder = typeEncoder; - } - - public SRM.FieldDefinitionHandle Generate(FieldDefinition field) - { - var fieldSignature = new SRM.BlobBuilder(); - typeEncoder.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); - var fieldDefinitionHandle = metadata.AddFieldDefinition( - attributes: GetFieldAttributesFor(field), - name: metadata.GetOrAddString(field.Name), - signature: metadata.GetOrAddBlob(fieldSignature)); - - if (field.Value != null) - { - metadata.AddConstant(fieldDefinitionHandle, field.Value.Value); - } - - return fieldDefinitionHandle; - } - } -} \ No newline at end of file diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs new file mode 100644 index 00000000..99f6bcf3 --- /dev/null +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -0,0 +1,42 @@ +using System; +using MetadataGenerator.Generators; +using Model; +using SR = System.Reflection; + +namespace MetadataGenerator +{ + static class AssemblyGenerator + { + public static MetadataContainer Generate(Assembly assembly) + { + var metadataContainer = new MetadataContainer(assembly); + var namespaceGenerator = new NamespaceGenerator(metadataContainer); + var metadataBuilder = metadataContainer.metadataBuilder; + + foreach (var namezpace in assembly.RootNamespace.Namespaces) + { + namespaceGenerator.Generate(namezpace); + } + + // FIXME args + metadataBuilder.AddAssembly( + name: metadataBuilder.GetOrAddString(assembly.Name), + version: new Version(1, 0, 0, 0), + culture: default, + publicKey: default, + flags: SR.AssemblyFlags.PublicKey, + hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1); + + metadataBuilder.AddModule( + generation: 0, + moduleName: metadataBuilder.GetOrAddString($"{assembly.Name}.{(metadataContainer.Executable ? "exe" : "dll")}"), + mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), + encId: metadataBuilder.GetOrAddGuid(Guid.Empty), + encBaseId: metadataBuilder.GetOrAddGuid(Guid.Empty)); + + return metadataContainer; + } + } +} + + diff --git a/MetadataGenerator/Generators/FieldGenerator.cs b/MetadataGenerator/Generators/FieldGenerator.cs new file mode 100644 index 00000000..d15ffb62 --- /dev/null +++ b/MetadataGenerator/Generators/FieldGenerator.cs @@ -0,0 +1,34 @@ +using Model.Types; +using static MetadataGenerator.AttributesProvider; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator +{ + class FieldGenerator + { + private readonly MetadataContainer metadataContainer; + + public FieldGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public SRM.FieldDefinitionHandle Generate(FieldDefinition field) + { + var fieldSignature = new SRM.BlobBuilder(); + metadataContainer.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); + var fieldDefinitionHandle = metadataContainer.metadataBuilder.AddFieldDefinition( + attributes: GetFieldAttributesFor(field), + name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), + signature: metadataContainer.metadataBuilder.GetOrAddBlob(fieldSignature)); + + if (field.Value != null) + { + metadataContainer.metadataBuilder.AddConstant(fieldDefinitionHandle, field.Value.Value); + } + + return fieldDefinitionHandle; + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generators/Generator.cs similarity index 77% rename from MetadataGenerator/Generator.cs rename to MetadataGenerator/Generators/Generator.cs index 99a87ae3..91f5cb2a 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generators/Generator.cs @@ -13,16 +13,16 @@ public void Generate(Assembly assembly) using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) // using (var peStream = File.OpenWrite($"./{assembly.Name}.exe")) { - var assemblyGenerator = AssemblyGenerator.For(assembly).Generate(); + var metadataContainer = AssemblyGenerator.Generate(assembly); var peHeaderBuilder = new SRPE.PEHeaderBuilder( - imageCharacteristics: assemblyGenerator.Executable ? SRPE.Characteristics.ExecutableImage : SRPE.Characteristics.Dll + imageCharacteristics: metadataContainer.Executable ? SRPE.Characteristics.ExecutableImage : SRPE.Characteristics.Dll ); var peBlob = new SRM.BlobBuilder(); new SRPE.ManagedPEBuilder( header: peHeaderBuilder, - metadataRootBuilder: new ECMA335.MetadataRootBuilder(assemblyGenerator.GeneratedMetadata), - ilStream: assemblyGenerator.IlStream, - entryPoint: assemblyGenerator.MainMethodHandle ?? default, + metadataRootBuilder: new ECMA335.MetadataRootBuilder(metadataContainer.metadataBuilder), + ilStream: metadataContainer.methodBodyStream.Builder, + entryPoint: metadataContainer.MainMethodHandle ?? default, // FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll. Requires/prefers 32 bit? flags: SRPE.CorFlags.ILOnly).Serialize(peBlob); peBlob.WriteContentTo(peStream); diff --git a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs new file mode 100644 index 00000000..cae6be8d --- /dev/null +++ b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs @@ -0,0 +1,323 @@ +using System; +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generators.Methods +{ + // review all instructions of the ecma pdf + // review overflow and other checks that instructions have + class MethodBodyGenerator + { + private readonly MetadataContainer metadataContainer; + private readonly MethodSignatureGenerator methodSignatureGenerator; + + public MethodBodyGenerator(MetadataContainer metadataContainer, MethodSignatureGenerator methodSignatureGenerator) + { + this.metadataContainer = metadataContainer; + this.methodSignatureGenerator = methodSignatureGenerator; + } + + public ECMA335.InstructionEncoder Generate(MethodBody body) + { + var controlFlowBuilder = new ECMA335.ControlFlowBuilder(); + var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), controlFlowBuilder); + + /** Exception handling, uncomment once ial other instructions are generated correctly. If not, labels don't match (because operations are missing) + var exceptionMapping = new Dictionary>(); + LabelHandle addMapping(string label) + { + var labelHandle = instructionsEncoder.DefineLabel(); + if (exceptionMapping.TryGetValue(label, out var labelHandles)) + { + labelHandles.Add(labelHandle); + } + else + { + exceptionMapping.Add(label, new List { labelHandle }); + } + return labelHandle; + } + + foreach (var protectedBlock in body.ExceptionInformation) + { + var tryStart = addMapping(protectedBlock.Start); + var tryEnd = addMapping(protectedBlock.End); + var handlerStart = addMapping(protectedBlock.Handler.Start); + var handlerEnd = addMapping(protectedBlock.Handler.End); + + switch (protectedBlock.Handler.Kind) + { + case Model.ExceptionHandlerBlockKind.Filter: // TODO + break; + case Model.ExceptionHandlerBlockKind.Catch: + EntityHandle catchType = referenceHandleResolver.TypeReferenceOf(PlatformTypes.Object); // FIXME + controlFlowBuilder.AddCatchRegion(tryStart, tryEnd, handlerStart, handlerEnd, catchType); + break; + case Model.ExceptionHandlerBlockKind.Fault: // TODO + break; + case Model.ExceptionHandlerBlockKind.Finally: // TODO + break; + } + }*/ + + foreach (var instruction in body.Instructions) + { + + /** Exception handling, uncomment once al other instructions are generated correctly. If not, labels don't match (because operations are missing) + * FIXME instruction has offset field. maybe that can be used with instructionsEncoder.offset instead of mapping labels (and using the extension method) + if (exceptionMapping.TryGetValue(instructionsEncoder.CurrentLabelString(), out var labels)) + { + foreach (var label in labels) + { + instructionsEncoder.MarkLabel(label); + } + } + */ + + + // FIXME visitor like in the model? or something better than this ifs? + if (instruction is Model.Bytecode.BasicInstruction basicInstruction) + { + switch (basicInstruction.Operation) + { + // TODO + // check overflow for variants (ej: add, add_ovf, add_ovf_un) + // see all IlOpCode constants + + case Model.Bytecode.BasicOperation.Nop: + instructionEncoder.OpCode(SRM.ILOpCode.Nop); + break; + case Model.Bytecode.BasicOperation.Add: + instructionEncoder.OpCode(SRM.ILOpCode.Add); + break; + case Model.Bytecode.BasicOperation.Sub: + instructionEncoder.OpCode(SRM.ILOpCode.Sub); + break; + case Model.Bytecode.BasicOperation.Mul: + instructionEncoder.OpCode(SRM.ILOpCode.Mul); + break; + case Model.Bytecode.BasicOperation.Div: + instructionEncoder.OpCode(SRM.ILOpCode.Div); + break; + case Model.Bytecode.BasicOperation.Rem: + instructionEncoder.OpCode(SRM.ILOpCode.Rem); + break; + case Model.Bytecode.BasicOperation.And: + instructionEncoder.OpCode(SRM.ILOpCode.And); + break; + case Model.Bytecode.BasicOperation.Or: + instructionEncoder.OpCode(SRM.ILOpCode.Or); + break; + case Model.Bytecode.BasicOperation.Xor: + instructionEncoder.OpCode(SRM.ILOpCode.Xor); + break; + case Model.Bytecode.BasicOperation.Shl: + instructionEncoder.OpCode(SRM.ILOpCode.Shl); + break; + case Model.Bytecode.BasicOperation.Shr: + instructionEncoder.OpCode(SRM.ILOpCode.Shr); + break; + case Model.Bytecode.BasicOperation.Eq: + break; + case Model.Bytecode.BasicOperation.Lt: + break; + case Model.Bytecode.BasicOperation.Gt: + break; + case Model.Bytecode.BasicOperation.Throw: + instructionEncoder.OpCode(SRM.ILOpCode.Throw); + break; + case Model.Bytecode.BasicOperation.Rethrow: + instructionEncoder.OpCode(SRM.ILOpCode.Rethrow); + break; + case Model.Bytecode.BasicOperation.Not: + instructionEncoder.OpCode(SRM.ILOpCode.Not); + break; + case Model.Bytecode.BasicOperation.Neg: + instructionEncoder.OpCode(SRM.ILOpCode.Neg); + break; + case Model.Bytecode.BasicOperation.Pop: + instructionEncoder.OpCode(SRM.ILOpCode.Pop); + break; + case Model.Bytecode.BasicOperation.Dup: + instructionEncoder.OpCode(SRM.ILOpCode.Dup); + break; + case Model.Bytecode.BasicOperation.EndFinally: + instructionEncoder.OpCode(SRM.ILOpCode.Endfinally); + break; + case Model.Bytecode.BasicOperation.EndFilter: + instructionEncoder.OpCode(SRM.ILOpCode.Endfilter); + break; + case Model.Bytecode.BasicOperation.LocalAllocation: + instructionEncoder.OpCode(SRM.ILOpCode.Localloc); + break; + case Model.Bytecode.BasicOperation.InitBlock: + instructionEncoder.OpCode(SRM.ILOpCode.Initblk); + break; + case Model.Bytecode.BasicOperation.InitObject: + // FIXME basicInstruction is missing type. Should be initObj type + // instructionEncoder.OpCode(ILOpCode.Initobj); + // instructionEncoder.Token(type) + break; + case Model.Bytecode.BasicOperation.CopyObject: + break; + case Model.Bytecode.BasicOperation.CopyBlock: + break; + case Model.Bytecode.BasicOperation.LoadArrayLength: + break; + case Model.Bytecode.BasicOperation.IndirectLoad: + break; + case Model.Bytecode.BasicOperation.LoadArrayElement: + break; + case Model.Bytecode.BasicOperation.LoadArrayElementAddress: + break; + case Model.Bytecode.BasicOperation.IndirectStore: + break; + case Model.Bytecode.BasicOperation.StoreArrayElement: + break; + case Model.Bytecode.BasicOperation.Breakpoint: + break; + case Model.Bytecode.BasicOperation.Return: + instructionEncoder.OpCode(SRM.ILOpCode.Ret); + break; + } + } + else if (instruction is Model.Bytecode.BranchInstruction branchInstruction) + { + + switch (branchInstruction.Operation) + { + // TODO + case Model.Bytecode.BranchOperation.False: + break; + case Model.Bytecode.BranchOperation.True: + break; + case Model.Bytecode.BranchOperation.Eq: + break; + case Model.Bytecode.BranchOperation.Neq: + break; + case Model.Bytecode.BranchOperation.Lt: + break; + case Model.Bytecode.BranchOperation.Le: + break; + case Model.Bytecode.BranchOperation.Gt: + break; + case Model.Bytecode.BranchOperation.Ge: + break; + case Model.Bytecode.BranchOperation.Branch: + break; + case Model.Bytecode.BranchOperation.Leave: + break; + } + } + else if (instruction is Model.Bytecode.ConvertInstruction convertInstruction) + { + switch (convertInstruction.Operation) + { + case Model.Bytecode.ConvertOperation.Conv: + break; + case Model.Bytecode.ConvertOperation.Cast: + break; + case Model.Bytecode.ConvertOperation.Box: + instructionEncoder.OpCode(SRM.ILOpCode.Box); + // FIXME ConversionType is IType. It can be IBasicType, ArrayType or PointerType. + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType as IBasicType)); + break; + case Model.Bytecode.ConvertOperation.Unbox: + break; + case Model.Bytecode.ConvertOperation.UnboxPtr: + break; + } + } + else if (instruction is Model.Bytecode.MethodCallInstruction methodCallInstruction) + { + var methodSignature = methodSignatureGenerator.GenerateSignatureOf(methodCallInstruction.Method); + switch (methodCallInstruction.Operation) + { + case Model.Bytecode.MethodCallOperation.Virtual: + instructionEncoder.CallVirtual(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method, methodSignature)); + break; + case Model.Bytecode.MethodCallOperation.Static: + case Model.Bytecode.MethodCallOperation.Jump: + instructionEncoder.Call(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method, methodSignature)); + break; + } + } + else if (instruction is Model.Bytecode.LoadInstruction loadlInstruction) + { + switch (loadlInstruction.Operation) + { + case Model.Bytecode.LoadOperation.Address: + break; + case Model.Bytecode.LoadOperation.Value: + //FIXME TAC, CASTS? + if (loadlInstruction.Operand.Type.Equals(PlatformTypes.String)) + { + var value = (string)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.LoadString(metadataContainer.metadataBuilder.GetOrAddUserString(value)); + } + + // TODO see ECMA ldc instruction. It says some cases should be follow by conv.i8 operations but the bytecode (original) does not have that + else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Int8) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt8)) + { + var value = (int)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); + instructionEncoder.Token(value); + } + else if ( + loadlInstruction.Operand.Type.Equals(PlatformTypes.Int16) || + loadlInstruction.Operand.Type.Equals(PlatformTypes.Int32) || + loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt16) || + loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt32)) + { + var value = (int)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.LoadConstantI4(value); + } + else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Int64) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt64)) + { + var value = (long)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.LoadConstantI8(value); + } + else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Float32)) + { + var value = (float)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.LoadConstantR4(value); + } + else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Float64)) + { + var value = (double)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + instructionEncoder.LoadConstantR8(value); + } + break; + case Model.Bytecode.LoadOperation.Content: + break; + } + } + else if (instruction is Model.Bytecode.LoadFieldInstruction loadFieldInstruction) { } + else if (instruction is Model.Bytecode.LoadArrayElementInstruction loadArrayElementInstruction) { } + else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) { } + else if (instruction is Model.Bytecode.CreateArrayInstruction createArrayInstruction) + { + // var size = 1; // FIXME array size not in the model (ArrayType) + // instructionEncoder.LoadConstantI4(size); // FIXME I4 = int, I8 = long. Could it be long? + // instructionEncoder.OpCode(ILOpCode.Newarr); + // FIXME (cast). ElementsType could be Pointer or BasicType. MultiDimensional Arrays are handled by newObj insteado of newArr + // instructionEncoder.Token(referenceHandleResolver.TypeReferenceOf(createArrayInstruction.Type.ElementsType as IBasicType)); + } + else if (instruction is Model.Bytecode.CreateObjectInstruction createObjectInstruction) { } + else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAddressInstruction) { } + else if (instruction is Model.Bytecode.StoreInstruction storeInstruction) { } + else if (instruction is Model.Bytecode.StoreFieldInstruction storeFieldInstruction) { } + else if (instruction is Model.Bytecode.SwitchInstruction switchInstruction) { } + else if (instruction is Model.Bytecode.SizeofInstruction sizeofInstruction) { } + else if (instruction is Model.Bytecode.LoadTokenInstruction loadTokenInstruction) { } + else if (instruction is Model.Bytecode.IndirectMethodCallInstruction indirectMethodCallInstruction) { } + else if (instruction is Model.Bytecode.StoreArrayElementInstruction storeArrayElementInstruction) { } + else throw new Exception("instruction type not handled"); + + } + + return instructionEncoder; + } + } +} diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs new file mode 100644 index 00000000..d79c0d8a --- /dev/null +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -0,0 +1,63 @@ +using MetadataGenerator.Generators.Methods; +using Model.Types; +using static MetadataGenerator.AttributesProvider; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SR = System.Reflection; +using SRM = System.Reflection.Metadata; + +//FIXME namespaces, use packages? MetadataGenerator.generators.methods? MetadataGenerator.generators? +//FIXME todas estas clases deberiuan ser internal no? los generators, salvo el entry point de todo. +//FIXME ver que onda la visibilidad de los metodos, el deafult es public creo quiza tienen que ser internal tambien. Que pasa si son public y la clase es internal? +//FIXME ver todo esto para los demas generators tmb (no solo methods) + +namespace MetadataGenerator +{ + class MethodGenerator + { + private readonly MetadataContainer metadataContainer; + private readonly MethodSignatureGenerator methodSignatureGenerator; + private readonly MethodBodyGenerator methodBodyGenerator; + + public MethodGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); + methodBodyGenerator = new MethodBodyGenerator(metadataContainer, methodSignatureGenerator); + } + + public SRM.MethodDefinitionHandle Generate(MethodDefinition method) + { + var methodSignature = methodSignatureGenerator.GenerateSignatureOf(method); + SRM.ParameterHandle? firstParameterHandle = null; + foreach (var parameter in method.Parameters) + { + var parameterHandle = metadataContainer.metadataBuilder.AddParameter( + GetParameterAttributesFor(parameter), + metadataContainer.metadataBuilder.GetOrAddString(parameter.Name), + parameter.Index); + if (!firstParameterHandle.HasValue) + { + firstParameterHandle = parameterHandle; + } + } + + // FIXME several addMethodBody variants with different arguments. codeSize, maxStacks, etc + // FIXME maxStack should be computed from instructions. When a dll is read, the maxStrack will be available (Model) but if code is generated + // programatically then the maxStack is gonna be missing + var methodBody = method.HasBody + ? metadataContainer.methodBodyStream.AddMethodBody( + instructionEncoder: methodBodyGenerator.Generate(method.Body), + maxStack: method.Body.MaxStack) + : default; + + var nextParameterHandle = ECMA335.MetadataTokens.ParameterHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); + return metadataContainer.metadataBuilder.AddMethodDefinition( + attributes: GetMethodAttributesFor(method), + implAttributes: SR.MethodImplAttributes.IL | SR.MethodImplAttributes.Managed, // FIXME what else? + name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), + signature: metadataContainer.metadataBuilder.GetOrAddBlob(methodSignature), + bodyOffset: methodBody, + parameterList: firstParameterHandle ?? nextParameterHandle); + } + } +} diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs new file mode 100644 index 00000000..8df33ba6 --- /dev/null +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -0,0 +1,50 @@ +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generators.Methods +{ + class MethodSignatureGenerator + { + private readonly MetadataContainer metadataContainer; + + public MethodSignatureGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) + { + var methodSignature = new SRM.BlobBuilder(); + new ECMA335.BlobEncoder(methodSignature) + .MethodSignature(isInstanceMethod: !method.IsStatic, genericParameterCount: method.GenericParameterCount) + .Parameters( + method.Parameters.Count, + returnType => + { + if (method.ReturnType.Equals(PlatformTypes.Void)) + { + returnType.Void(); + } + else + { + // TODO isByRef param. ref in return type is not in the model + var encoder = returnType.Type(); + metadataContainer.Encode(method.ReturnType, encoder); + } + + }, + parameters => + { + foreach (var parameter in method.Parameters) + { + bool isByRef = parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref); + var type = isByRef ? (parameter.Type as PointerType).TargetType : parameter.Type; + var encoder = parameters.AddParameter().Type(isByRef); + metadataContainer.Encode(type, encoder); + } + }); + return methodSignature; + } + } +} diff --git a/MetadataGenerator/Generators/NamespaceGenerator.cs b/MetadataGenerator/Generators/NamespaceGenerator.cs new file mode 100644 index 00000000..7a60f959 --- /dev/null +++ b/MetadataGenerator/Generators/NamespaceGenerator.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using Model; +using Model.Types; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generators +{ + class NamespaceGenerator + { + private readonly MetadataContainer metadataContainer; + private readonly TypeGenerator typeGenerator; + + public NamespaceGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + typeGenerator = new TypeGenerator(metadataContainer); + } + + public void Generate(Namespace namezpace) + { + foreach (var nestedNamespace in namezpace.Namespaces) + { + Generate(nestedNamespace); + } + + foreach (var type in namezpace.Types) + { + GenerateTypes(type); + } + } + + private SRM.TypeDefinitionHandle GenerateTypes(TypeDefinition type) + { + var nestedTypes = new List(); + foreach (var nestedType in type.Types) + { + nestedTypes.Add(GenerateTypes(nestedType)); + } + + var typeDefinitionHandle = typeGenerator.Generate(type); + foreach (var nestedType in nestedTypes) + { + metadataContainer.metadataBuilder.AddNestedType(nestedType, typeDefinitionHandle); + } + + return typeDefinitionHandle; + } + + } +} diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs new file mode 100644 index 00000000..3375cc44 --- /dev/null +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using Model.Types; +using static MetadataGenerator.AttributesProvider; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SR = System.Reflection; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generators +{ + class TypeGenerator + { + private readonly MetadataContainer metadataContainer; + private readonly MethodGenerator methodGenerator; + private readonly FieldGenerator fieldGenerator; + + public TypeGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + methodGenerator = new MethodGenerator(metadataContainer); + fieldGenerator = new FieldGenerator(metadataContainer); + } + + public SRM.TypeDefinitionHandle Generate(TypeDefinition type) + { + var fieldDefinitionHandles = new List(); + var methodDefinitionHandles = new List(); + var metadataBuilder = metadataContainer.metadataBuilder; + + foreach (var field in type.Fields) + { + fieldDefinitionHandles.Add(fieldGenerator.Generate(field)); + } + + /* TODO Properties: (works) but model is missing Property concept + * extrack to PropertiesGenerator + + var propertySignatureBlogBuilder = new BlobBuilder(); + new BlobEncoder(propertySignatureBlogBuilder) + .PropertySignature(isInstanceProperty: true) //FIXME when false + .Parameters( + 0, + returnType => returnType.Type().Int32(), //FIXME backingField type + parameters => { }); + + var propertyDefinitionHandle = metadata.AddProperty( + attributes: PropertyAttributes.None, //FIXME + name: metadata.GetOrAddString(""), //FIXME property name + signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); + + // asociate methods (get, set) to property + metadata.AddMethodSemantics( + propertyDefinitionHandle, + method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, + methodHandle); //getter/setter + metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); + */ + + foreach (var method in type.Methods) + { + var methodHandle = methodGenerator.Generate(method); + methodDefinitionHandles.Add(methodHandle); + if (method.Name.Equals("Main")) + { + metadataContainer.MainMethodHandle = methodHandle; + } + } + + var nextFieldDefinitionHandle = ECMA335.MetadataTokens.FieldDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.Field)); + var nextMethodDefinitionHandle = ECMA335.MetadataTokens.MethodDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.MethodDef)); + var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( + attributes: GetTypeAttributesFor(type), + @namespace: metadataBuilder.GetOrAddString(type.ContainingNamespace.FullName), + name: metadataBuilder.GetOrAddString(type.Name), + baseType: type.Base != null ? metadataContainer.ResolveReferenceHandleFor(type.Base) : default, + fieldList: fieldDefinitionHandles.FirstOr(nextFieldDefinitionHandle), + methodList: methodDefinitionHandles.FirstOr(nextMethodDefinitionHandle)); + + foreach (var interfaze in type.Interfaces) + { + metadataBuilder.AddInterfaceImplementation(type: typeDefinitionHandle, implementedInterface: metadataContainer.ResolveReferenceHandleFor(interfaze)); + } + + /* + Generic parameters table must be sorted that's why this is done at the end and not during the method generation. + If done that way, method generic parameters of a type are added before the type's generic parameters and table results unsorted + */ + + // generate class generic parameters (Class) + foreach (var genericParamter in type.GenericParameters) + { + metadataBuilder.AddGenericParameter( + typeDefinitionHandle, + SR.GenericParameterAttributes.None, + metadataBuilder.GetOrAddString(genericParamter.Name), + genericParamter.Index); + } + + // generate method generic parameters (public T method(T param)) + for (int i = 0; i < type.Methods.Count; i++) + { + var method = type.Methods[i]; + foreach (var genericParameter in method.GenericParameters) + { + metadataBuilder.AddGenericParameter( + methodDefinitionHandles[i], + SR.GenericParameterAttributes.None, + metadataBuilder.GetOrAddString(genericParameter.Name), + genericParameter.Index); + } + } + + return typeDefinitionHandle; + } + } +} diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs new file mode 100644 index 00000000..e5eb9890 --- /dev/null +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -0,0 +1,41 @@ +using System; +using Model; +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +//FIXME name, package, visibilities, etc +namespace MetadataGenerator +{ + class MetadataContainer + { + public readonly ECMA335.MetadataBuilder metadataBuilder; + private readonly TypeEncoder typeEncoder; + private readonly ReferenceHandleResolver referenceHandleResolver; + public readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; + private SRM.MethodDefinitionHandle? mainMethodHandle; + public SRM.MethodDefinitionHandle? MainMethodHandle + { + get => mainMethodHandle; + set + { + if (mainMethodHandle != null) throw new Exception("Assembly has more than one main method"); + mainMethodHandle = value; + } + } + public bool Executable => mainMethodHandle != null; + + public MetadataContainer(Assembly assembly) + { + metadataBuilder = new ECMA335.MetadataBuilder(); + referenceHandleResolver = new ReferenceHandleResolver(metadataBuilder, assembly); + typeEncoder = new TypeEncoder(referenceHandleResolver); + methodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); + } + + public SRM.EntityHandle ResolveReferenceHandleFor(IBasicType type) => referenceHandleResolver.ReferenceHandleOf(type); + public SRM.MemberReferenceHandle ResolveReferenceHandleFor(IMethodReference method, SRM.BlobBuilder signature) => referenceHandleResolver.ReferenceHandleOf(method, signature); + //FIXME name + public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) => typeEncoder.Encode(type, encoder); + } +} diff --git a/MetadataGenerator/ReferencesProvider.cs b/MetadataGenerator/Metadata/ReferenceHandleResolver.cs similarity index 90% rename from MetadataGenerator/ReferencesProvider.cs rename to MetadataGenerator/Metadata/ReferenceHandleResolver.cs index ee80e186..724e0e59 100644 --- a/MetadataGenerator/ReferencesProvider.cs +++ b/MetadataGenerator/Metadata/ReferenceHandleResolver.cs @@ -8,7 +8,7 @@ namespace MetadataGenerator { - public class ReferencesProvider + class ReferenceHandleResolver { private readonly Assembly assembly; private readonly ECMA335.MetadataBuilder metadata; @@ -16,7 +16,7 @@ public class ReferencesProvider private readonly IDictionary typeReferences = new Dictionary(); private readonly IDictionary methodReferences = new Dictionary(); - public ReferencesProvider(ECMA335.MetadataBuilder metadata, Assembly assembly) + public ReferenceHandleResolver(ECMA335.MetadataBuilder metadata, Assembly assembly) { this.metadata = metadata; this.assembly = assembly; @@ -39,7 +39,7 @@ public ReferencesProvider(ECMA335.MetadataBuilder metadata, Assembly assembly) /* * Returns a TypeReference for type. It stores references because metadata does not have a getOrAddTypeReference. */ - public SRM.EntityHandle TypeReferenceOf(IBasicType type) + public SRM.TypeReferenceHandle ReferenceHandleOf(IBasicType type) { var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{type.Name}"; if (!typeReferences.TryGetValue(typeReferenceKey, out SRM.TypeReferenceHandle typeReference)) // If stored then return that @@ -53,7 +53,7 @@ public SRM.EntityHandle TypeReferenceOf(IBasicType type) } else { // if not, recursively get a reference for the containing type and use that as the resolution scopeø - resolutionScope = TypeReferenceOf(type.ContainingType); + resolutionScope = ReferenceHandleOf(type.ContainingType); } typeReference = metadata.AddTypeReference( resolutionScope: resolutionScope, @@ -64,13 +64,13 @@ public SRM.EntityHandle TypeReferenceOf(IBasicType type) return typeReference; } - public SRM.MemberReferenceHandle MethodReferenceOf(IMethodReference method, SRM.BlobBuilder methodSignature) + public SRM.MemberReferenceHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder methodSignature) { var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; if (!methodReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) { memberReferenceHandle = metadata.AddMemberReference( - parent: TypeReferenceOf(method.ContainingType), + parent: ReferenceHandleOf(method.ContainingType), name: metadata.GetOrAddString(method.Name), signature: metadata.GetOrAddBlob(methodSignature)); methodReferences.Add(key, memberReferenceHandle); diff --git a/MetadataGenerator/TypeEncoder.cs b/MetadataGenerator/Metadata/TypeEncoder.cs similarity index 88% rename from MetadataGenerator/TypeEncoder.cs rename to MetadataGenerator/Metadata/TypeEncoder.cs index 1e3d286f..b7fe8af2 100644 --- a/MetadataGenerator/TypeEncoder.cs +++ b/MetadataGenerator/Metadata/TypeEncoder.cs @@ -5,12 +5,13 @@ namespace MetadataGenerator { - public class TypeEncoder + // fixme name + class TypeEncoder { - private readonly ReferencesProvider referencesProvider; - public TypeEncoder(ReferencesProvider referencesProvider) + private readonly ReferenceHandleResolver referenceHandleResolver; + public TypeEncoder(ReferenceHandleResolver referenceHandleResolver) { - this.referencesProvider = referencesProvider; + this.referenceHandleResolver = referenceHandleResolver; } // SignatureTypeEncoder is a struct but it is not necessary to pass it by reference since @@ -38,7 +39,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) if (basicType.GenericType != null) { var genericInstantiation = encoder.GenericInstantiation( - referencesProvider.TypeReferenceOf(basicType), + referenceHandleResolver.ReferenceHandleOf(basicType), basicType.GenericParameterCount, type.TypeKind == TypeKind.ValueType ); @@ -49,7 +50,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) } else { - encoder.Type(referencesProvider.TypeReferenceOf(basicType), type.TypeKind == TypeKind.ValueType); + encoder.Type(referenceHandleResolver.ReferenceHandleOf(basicType), type.TypeKind == TypeKind.ValueType); } } else if (type is ArrayType arrayType) @@ -59,6 +60,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) arrayShapeEncoder => { // FIXME real values for sizes and lowerBounds + // size cannot be known (example: int[]) arrayShapeEncoder.Shape( rank: (int)arrayType.Rank, sizes: ImmutableArray.Empty, diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index c09e55ab..76a35da1 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -26,14 +26,19 @@ - - - - - - + + + + + + + + + + + @@ -49,5 +54,10 @@ ..\packages\System.Reflection.Metadata.1.6.0\lib\portable-net45+win8\System.Reflection.Metadata.dll + + + + + \ No newline at end of file diff --git a/MetadataGenerator/MethodGenerator.cs b/MetadataGenerator/MethodGenerator.cs deleted file mode 100644 index a6181b8c..00000000 --- a/MetadataGenerator/MethodGenerator.cs +++ /dev/null @@ -1,435 +0,0 @@ -using System; -using Model.Types; -using static MetadataGenerator.AttributesProvider; -using ECMA335 = System.Reflection.Metadata.Ecma335; -using SR = System.Reflection; -using SRM = System.Reflection.Metadata; - -namespace MetadataGenerator -{ - public class MethodGenerator - { - private readonly ECMA335.MetadataBuilder metadata; - private readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; - private readonly MethodSignatureGenerator methodSignatureGenerator; - private readonly MethodBodyGenerator methodBodyGenerator; - private readonly MethodParameterGenerator methodParameterGenerator; - - public MethodGenerator(ECMA335.MetadataBuilder metadata, TypeEncoder typeEncoder, ReferencesProvider referencesProvider) - { - this.metadata = metadata; - methodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); - methodParameterGenerator = new MethodParameterGenerator(metadata); - methodSignatureGenerator = new MethodSignatureGenerator(typeEncoder); - methodBodyGenerator = new MethodBodyGenerator(referencesProvider, methodSignatureGenerator, metadata); - } - - public SRM.MethodDefinitionHandle Generate(MethodDefinition method) - { - var methodSignature = methodSignatureGenerator.GenerateSignatureOf(method); - SRM.ParameterHandle? firstParameterHandle = null; - foreach (var parameter in method.Parameters) - { - var parameterHandle = methodParameterGenerator.Generate(parameter); - if (!firstParameterHandle.HasValue) - { - firstParameterHandle = parameterHandle; - } - } - - // FIXME several addMethodBody variants with different arguments. codeSize, maxStacks, etc - var methodBody = method.HasBody - ? methodBodyStream.AddMethodBody(methodBodyGenerator.Generate(method.Body)) - : default; - - return metadata.AddMethodDefinition( - attributes: GetMethodAttributesFor(method), - implAttributes: SR.MethodImplAttributes.IL | SR.MethodImplAttributes.Managed, // FIXME what else? - name: metadata.GetOrAddString(method.Name), - signature: metadata.GetOrAddBlob(methodSignature), - bodyOffset: methodBody, - parameterList: firstParameterHandle ?? ECMA335.MetadataTokens.ParameterHandle(metadata.NextRowFor(ECMA335.TableIndex.Param))); - } - - public SRM.BlobBuilder IlStream() - { - return methodBodyStream.Builder; - } - - private class MethodSignatureGenerator - { - private readonly TypeEncoder typeEncoder; - - public MethodSignatureGenerator(TypeEncoder typeEncoder) - { - this.typeEncoder = typeEncoder; - } - - public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) - { - var methodSignature = new SRM.BlobBuilder(); - new ECMA335.BlobEncoder(methodSignature) - .MethodSignature(isInstanceMethod: !method.IsStatic, genericParameterCount: method.GenericParameterCount) - .Parameters( - method.Parameters.Count, - returnType => - { - if (method.ReturnType.Equals(PlatformTypes.Void)) - { - returnType.Void(); - } - else - { - // TODO isByRef param. ref in return type is not in the model - var encoder = returnType.Type(); - typeEncoder.Encode(method.ReturnType, encoder); - } - - }, - parameters => - { - foreach (var parameter in method.Parameters) - { - var encoder = parameters.AddParameter().Type(isByRef: parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref)); - typeEncoder.Encode(parameter.Type, encoder); - } - }); - - return methodSignature; - } - } - - private class MethodParameterGenerator - { - private readonly ECMA335.MetadataBuilder metadata; - - public MethodParameterGenerator(ECMA335.MetadataBuilder metadata) - { - this.metadata = metadata; - } - - public SRM.ParameterHandle Generate(MethodParameter parameter) => - metadata.AddParameter(GetParameterAttributesFor(parameter), metadata.GetOrAddString(parameter.Name), parameter.Index); - } - - #region Method Body - // review all instructions of the ecma pdf - // review overflow and other checks that instructions have - private class MethodBodyGenerator - { - private readonly ReferencesProvider referencesProvider; - private readonly MethodSignatureGenerator methodSignatureGenerator; - private readonly ECMA335.MetadataBuilder metadata; - - public MethodBodyGenerator(ReferencesProvider referencesProvider, MethodSignatureGenerator methodSignatureGenerator, ECMA335.MetadataBuilder metadata) - { - this.referencesProvider = referencesProvider; - this.methodSignatureGenerator = methodSignatureGenerator; - this.metadata = metadata; - } - - public ECMA335.InstructionEncoder Generate(MethodBody body) - { - var controlFlowBuilder = new ECMA335.ControlFlowBuilder(); - var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), controlFlowBuilder); - - /** Exception handling, uncomment once ial other instructions are generated correctly. If not, labels don't match (because operations are missing) - var exceptionMapping = new Dictionary>(); - LabelHandle addMapping(string label) - { - var labelHandle = instructionsEncoder.DefineLabel(); - if (exceptionMapping.TryGetValue(label, out var labelHandles)) - { - labelHandles.Add(labelHandle); - } - else - { - exceptionMapping.Add(label, new List { labelHandle }); - } - return labelHandle; - } - - foreach (var protectedBlock in body.ExceptionInformation) - { - var tryStart = addMapping(protectedBlock.Start); - var tryEnd = addMapping(protectedBlock.End); - var handlerStart = addMapping(protectedBlock.Handler.Start); - var handlerEnd = addMapping(protectedBlock.Handler.End); - - switch (protectedBlock.Handler.Kind) - { - case Model.ExceptionHandlerBlockKind.Filter: // TODO - break; - case Model.ExceptionHandlerBlockKind.Catch: - EntityHandle catchType = referencesProvider.TypeReferenceOf(PlatformTypes.Object); // FIXME - controlFlowBuilder.AddCatchRegion(tryStart, tryEnd, handlerStart, handlerEnd, catchType); - break; - case Model.ExceptionHandlerBlockKind.Fault: // TODO - break; - case Model.ExceptionHandlerBlockKind.Finally: // TODO - break; - } - }*/ - - foreach (var instruction in body.Instructions) - { - - /** Exception handling, uncomment once al other instructions are generated correctly. If not, labels don't match (because operations are missing) - * FIXME instruction has offset field. maybe that can be used with instructionsEncoder.offset instead of mapping labels (and using the extension method) - if (exceptionMapping.TryGetValue(instructionsEncoder.CurrentLabelString(), out var labels)) - { - foreach (var label in labels) - { - instructionsEncoder.MarkLabel(label); - } - } - */ - - - // FIXME visitor like in the model? or something better than this ifs? - if (instruction is Model.Bytecode.BasicInstruction basicInstruction) - { - switch (basicInstruction.Operation) - { - // TODO - // check overflow for variants (ej: add, add_ovf, add_ovf_un) - // see all IlOpCode constants - - case Model.Bytecode.BasicOperation.Nop: - instructionEncoder.OpCode(SRM.ILOpCode.Nop); - break; - case Model.Bytecode.BasicOperation.Add: - instructionEncoder.OpCode(SRM.ILOpCode.Add); - break; - case Model.Bytecode.BasicOperation.Sub: - instructionEncoder.OpCode(SRM.ILOpCode.Sub); - break; - case Model.Bytecode.BasicOperation.Mul: - instructionEncoder.OpCode(SRM.ILOpCode.Mul); - break; - case Model.Bytecode.BasicOperation.Div: - instructionEncoder.OpCode(SRM.ILOpCode.Div); - break; - case Model.Bytecode.BasicOperation.Rem: - instructionEncoder.OpCode(SRM.ILOpCode.Rem); - break; - case Model.Bytecode.BasicOperation.And: - instructionEncoder.OpCode(SRM.ILOpCode.And); - break; - case Model.Bytecode.BasicOperation.Or: - instructionEncoder.OpCode(SRM.ILOpCode.Or); - break; - case Model.Bytecode.BasicOperation.Xor: - instructionEncoder.OpCode(SRM.ILOpCode.Xor); - break; - case Model.Bytecode.BasicOperation.Shl: - instructionEncoder.OpCode(SRM.ILOpCode.Shl); - break; - case Model.Bytecode.BasicOperation.Shr: - instructionEncoder.OpCode(SRM.ILOpCode.Shr); - break; - case Model.Bytecode.BasicOperation.Eq: - break; - case Model.Bytecode.BasicOperation.Lt: - break; - case Model.Bytecode.BasicOperation.Gt: - break; - case Model.Bytecode.BasicOperation.Throw: - instructionEncoder.OpCode(SRM.ILOpCode.Throw); - break; - case Model.Bytecode.BasicOperation.Rethrow: - instructionEncoder.OpCode(SRM.ILOpCode.Rethrow); - break; - case Model.Bytecode.BasicOperation.Not: - instructionEncoder.OpCode(SRM.ILOpCode.Not); - break; - case Model.Bytecode.BasicOperation.Neg: - instructionEncoder.OpCode(SRM.ILOpCode.Neg); - break; - case Model.Bytecode.BasicOperation.Pop: - instructionEncoder.OpCode(SRM.ILOpCode.Pop); - break; - case Model.Bytecode.BasicOperation.Dup: - instructionEncoder.OpCode(SRM.ILOpCode.Dup); - break; - case Model.Bytecode.BasicOperation.EndFinally: - instructionEncoder.OpCode(SRM.ILOpCode.Endfinally); - break; - case Model.Bytecode.BasicOperation.EndFilter: - instructionEncoder.OpCode(SRM.ILOpCode.Endfilter); - break; - case Model.Bytecode.BasicOperation.LocalAllocation: - instructionEncoder.OpCode(SRM.ILOpCode.Localloc); - break; - case Model.Bytecode.BasicOperation.InitBlock: - instructionEncoder.OpCode(SRM.ILOpCode.Initblk); - break; - case Model.Bytecode.BasicOperation.InitObject: - // FIXME basicInstruction is missing type. Should be initObj type - // instructionEncoder.OpCode(ILOpCode.Initobj); - // instructionEncoder.Token(type) - break; - case Model.Bytecode.BasicOperation.CopyObject: - break; - case Model.Bytecode.BasicOperation.CopyBlock: - break; - case Model.Bytecode.BasicOperation.LoadArrayLength: - break; - case Model.Bytecode.BasicOperation.IndirectLoad: - break; - case Model.Bytecode.BasicOperation.LoadArrayElement: - break; - case Model.Bytecode.BasicOperation.LoadArrayElementAddress: - break; - case Model.Bytecode.BasicOperation.IndirectStore: - break; - case Model.Bytecode.BasicOperation.StoreArrayElement: - break; - case Model.Bytecode.BasicOperation.Breakpoint: - break; - case Model.Bytecode.BasicOperation.Return: - instructionEncoder.OpCode(SRM.ILOpCode.Ret); - break; - } - } - else if (instruction is Model.Bytecode.BranchInstruction branchInstruction) - { - - switch (branchInstruction.Operation) - { - // TODO - case Model.Bytecode.BranchOperation.False: - break; - case Model.Bytecode.BranchOperation.True: - break; - case Model.Bytecode.BranchOperation.Eq: - break; - case Model.Bytecode.BranchOperation.Neq: - break; - case Model.Bytecode.BranchOperation.Lt: - break; - case Model.Bytecode.BranchOperation.Le: - break; - case Model.Bytecode.BranchOperation.Gt: - break; - case Model.Bytecode.BranchOperation.Ge: - break; - case Model.Bytecode.BranchOperation.Branch: - break; - case Model.Bytecode.BranchOperation.Leave: - break; - } - } - else if (instruction is Model.Bytecode.ConvertInstruction convertInstruction) - { - switch (convertInstruction.Operation) - { - case Model.Bytecode.ConvertOperation.Conv: - break; - case Model.Bytecode.ConvertOperation.Cast: - break; - case Model.Bytecode.ConvertOperation.Box: - instructionEncoder.OpCode(SRM.ILOpCode.Box); - // FIXME ConversionType is IType. It can be IBasicType, ArrayType or PointerType. - instructionEncoder.Token(referencesProvider.TypeReferenceOf(convertInstruction.ConversionType as IBasicType)); - break; - case Model.Bytecode.ConvertOperation.Unbox: - break; - case Model.Bytecode.ConvertOperation.UnboxPtr: - break; - } - } - else if (instruction is Model.Bytecode.MethodCallInstruction methodCallInstruction) - { - var methodSignature = methodSignatureGenerator.GenerateSignatureOf(methodCallInstruction.Method); - switch (methodCallInstruction.Operation) - { - case Model.Bytecode.MethodCallOperation.Virtual: - instructionEncoder.CallVirtual(referencesProvider.MethodReferenceOf(methodCallInstruction.Method, methodSignature)); - break; - case Model.Bytecode.MethodCallOperation.Static: - case Model.Bytecode.MethodCallOperation.Jump: - instructionEncoder.Call(referencesProvider.MethodReferenceOf(methodCallInstruction.Method, methodSignature)); - break; - } - } - else if (instruction is Model.Bytecode.LoadInstruction loadlInstruction) - { - switch (loadlInstruction.Operation) - { - case Model.Bytecode.LoadOperation.Address: - break; - case Model.Bytecode.LoadOperation.Value: - //FIXME TAC, CASTS? - if (loadlInstruction.Operand.Type.Equals(PlatformTypes.String)) - { - var value = (string)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; - instructionEncoder.LoadString(metadata.GetOrAddUserString(value)); - } - - // TODO see ECMA ldc instruction. It says some cases should be follow by conv.i8 operations but the bytecode (original) does not have that - else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Int8) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt8)) - { - var value = (int)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; - instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); - instructionEncoder.Token(value); - } - else if ( - loadlInstruction.Operand.Type.Equals(PlatformTypes.Int16) || - loadlInstruction.Operand.Type.Equals(PlatformTypes.Int32) || - loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt16) || - loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt32)) - { - var value = (int)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; - instructionEncoder.LoadConstantI4(value); - } - else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Int64) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt64)) - { - var value = (long)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; - instructionEncoder.LoadConstantI8(value); - } - else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Float32)) - { - var value = (float)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; - instructionEncoder.LoadConstantR4(value); - } - else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Float64)) - { - var value = (double)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; - instructionEncoder.LoadConstantR8(value); - } - break; - case Model.Bytecode.LoadOperation.Content: - break; - } - } - else if (instruction is Model.Bytecode.LoadFieldInstruction loadFieldInstruction) { } - else if (instruction is Model.Bytecode.LoadArrayElementInstruction loadArrayElementInstruction) { } - else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) { } - else if (instruction is Model.Bytecode.CreateArrayInstruction createArrayInstruction) - { - // var size = 1; // FIXME array size not in the model (ArrayType) - // instructionEncoder.LoadConstantI4(size); // FIXME I4 = int, I8 = long. Could it be long? - // instructionEncoder.OpCode(ILOpCode.Newarr); - // FIXME (cast). ElementsType could be Pointer or BasicType. MultiDimensional Arrays are handled by newObj insteado of newArr - // instructionEncoder.Token(referencesProvider.TypeReferenceOf(createArrayInstruction.Type.ElementsType as IBasicType)); - } - else if (instruction is Model.Bytecode.CreateObjectInstruction createObjectInstruction) { } - else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAddressInstruction) { } - else if (instruction is Model.Bytecode.StoreInstruction storeInstruction) { } - else if (instruction is Model.Bytecode.StoreFieldInstruction storeFieldInstruction) { } - else if (instruction is Model.Bytecode.SwitchInstruction switchInstruction) { } - else if (instruction is Model.Bytecode.SizeofInstruction sizeofInstruction) { } - else if (instruction is Model.Bytecode.LoadTokenInstruction loadTokenInstruction) { } - else if (instruction is Model.Bytecode.IndirectMethodCallInstruction indirectMethodCallInstruction) { } - else if (instruction is Model.Bytecode.StoreArrayElementInstruction storeArrayElementInstruction) { } - else throw new Exception("instruction type not handled"); - - } - - return instructionEncoder; - } - } - #endregion - } -} From 0964dc7091c5ba0af9bb57f546b12657a2a6c67e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 23 Oct 2019 00:14:05 -0300 Subject: [PATCH 046/256] some load instructions --- Examples/Examples.cs | 82 ++++++++++++++- .../Generators/Methods/MethodBodyGenerator.cs | 99 +++++++++++++------ 2 files changed, 149 insertions(+), 32 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 3daf046d..41e8436e 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -591,11 +591,12 @@ public void Convert() a = (int)x; } - public void Branch() + public void Branch(bool b) { - if (!true) - { - } + + if (false) { } // br.s $target + + } public void LoadConstant() @@ -612,11 +613,84 @@ public void LoadConstant() int eight = 8; // ldc.i4.8 int minusOne = -1; // ldc.i4.m1 int i = 20; // ldc.i4.s 20 + long c = (char)9; // ldc.i4.s 9 + conv.i8 int k = int.MaxValue; // ldc.i4 long q = int.MaxValue; // ldc.i4 + conv.i8 long l = long.MinValue; // ldc.i8 float f = float.MinValue; // ldc.r4 double d = double.MinValue; // ldc.r8 } + + public void LoadArgument(int arg1, string arg2, bool arg3, int arg4) + { + var i0 = this; // ldarg.0 + var i1 = arg1; // ldarg.1 + var i2 = arg2; // ldarg.2 + var i3 = arg3; // ldarg.3 + var i4 = arg4; // ldarg.s $value + // TODO ldarg $value (see ecma) + } + + public void LoadLocal() + { + var x0 = 10; + var x1 = 12; + var x2 = 23; + var x3 = 23; + var x4 = 14; + + var y0 = x0; // ldloc.0 + var y1 = x1; // ldloc.1 + var y2 = x2; // ldloc.2 + var y3 = x3; // ldloc.3 + var y4 = x4; // ldloc.s $index (=4) + // TODO ldloc $index (see ecma) + } + + public void LoadAddress(int x) + { + unsafe + { + var p = default(int*); // ldloca.s 0 + // TODO ldloca $argNum + var q = &x; // ldarga.s 0 + // TODO ldarga $argNum + } + } + + public void LoadPointer() + { + Action x = LoadAddress; // ldftn $method + Action y = null; // ldnull + } + + public void LoadIndirect(ref object g) + { + unsafe + { + sbyte a_1 = sbyte.MinValue; + byte a_2 = byte.MinValue; + short b_1 = short.MinValue; + ushort b_2 = ushort.MinValue; + int c_1 = int.MinValue; + uint c_2 = uint.MinValue; + long d = long.MinValue; + float e = float.MinValue; + double f = double.MinValue; + IntPtr h = default; + + var x1 = *&a_1; // ldind.i1 + var x2 = *&a_2; // ldind.u1 + var x3 = *&b_1; // ldind.i2 + var x4 = *&b_2; // ldind.u2 + var x5 = *&c_1; // ldind.i4 + var x6 = *&c_2; // ldind.u4 + var x7 = *&d; // ldind.i8 (ldind.u8 is alias for ldind.i8) + var x8 = *&e; // ldind.r4 + var x9 = *&f; // ldind.r8 + var x10 = *&h; // ldind.i + var x11 = g; // ldind.ref + } + } } } diff --git a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs index cae6be8d..6ab89560 100644 --- a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs @@ -1,4 +1,5 @@ using System; +using Model.ThreeAddressCode.Values; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -22,22 +23,22 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { var controlFlowBuilder = new ECMA335.ControlFlowBuilder(); var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), controlFlowBuilder); + /* var labelMapping = new Dictionary>(); + ECMA335.LabelHandle labelHandleFor(string label) + { + var labelHandle = instructionEncoder.DefineLabel(); + if (labelMapping.TryGetValue(label, out var labelHandles)) + { + labelHandles.Add(labelHandle); + } + else + { + labelMapping.Add(label, new List { labelHandle }); + } + return labelHandle; + }*/ /** Exception handling, uncomment once ial other instructions are generated correctly. If not, labels don't match (because operations are missing) - var exceptionMapping = new Dictionary>(); - LabelHandle addMapping(string label) - { - var labelHandle = instructionsEncoder.DefineLabel(); - if (exceptionMapping.TryGetValue(label, out var labelHandles)) - { - labelHandles.Add(labelHandle); - } - else - { - exceptionMapping.Add(label, new List { labelHandle }); - } - return labelHandle; - } foreach (var protectedBlock in body.ExceptionInformation) { @@ -64,13 +65,13 @@ LabelHandle addMapping(string label) foreach (var instruction in body.Instructions) { - /** Exception handling, uncomment once al other instructions are generated correctly. If not, labels don't match (because operations are missing) + /** uncomment once al other instructions are generated correctly. If not, labels don't match (because operations are missing) * FIXME instruction has offset field. maybe that can be used with instructionsEncoder.offset instead of mapping labels (and using the extension method) - if (exceptionMapping.TryGetValue(instructionsEncoder.CurrentLabelString(), out var labels)) + if (labelMapping.TryGetValue(instructionEncoder.CurrentLabelString(), out var labels)) { foreach (var label in labels) { - instructionsEncoder.MarkLabel(label); + instructionEncoder.MarkLabel(label); } } */ @@ -155,17 +156,21 @@ LabelHandle addMapping(string label) instructionEncoder.OpCode(SRM.ILOpCode.Initblk); break; case Model.Bytecode.BasicOperation.InitObject: - // FIXME basicInstruction is missing type. Should be initObj type + // FIXME InitObject needs an operand (should not be BasicInstruction) // instructionEncoder.OpCode(ILOpCode.Initobj); // instructionEncoder.Token(type) break; case Model.Bytecode.BasicOperation.CopyObject: break; case Model.Bytecode.BasicOperation.CopyBlock: + instructionEncoder.OpCode(SRM.ILOpCode.Cpblk); break; case Model.Bytecode.BasicOperation.LoadArrayLength: break; case Model.Bytecode.BasicOperation.IndirectLoad: + // FIXME IndirectLoad needs an operand (should not be BasicInstruction) + // TODO depending on type of operand instructionEncoder.OpCode(SRM.ILOpCode.Ldind_X); + // example is already generated for all variants break; case Model.Bytecode.BasicOperation.LoadArrayElement: break; @@ -176,6 +181,7 @@ LabelHandle addMapping(string label) case Model.Bytecode.BasicOperation.StoreArrayElement: break; case Model.Bytecode.BasicOperation.Breakpoint: + instructionEncoder.OpCode(SRM.ILOpCode.Break); break; case Model.Bytecode.BasicOperation.Return: instructionEncoder.OpCode(SRM.ILOpCode.Ret); @@ -188,6 +194,8 @@ LabelHandle addMapping(string label) switch (branchInstruction.Operation) { // TODO + // This relies on marking labels and that depends on generating all instructions correctly (if not labels don't match) + // There is only one example and it is not tested case Model.Bytecode.BranchOperation.False: break; case Model.Bytecode.BranchOperation.True: @@ -205,6 +213,9 @@ LabelHandle addMapping(string label) case Model.Bytecode.BranchOperation.Ge: break; case Model.Bytecode.BranchOperation.Branch: + // FIXME + // instructionEncoder.Branch(SRM.ILOpCode.Br, labelHandleFor(branchInstruction.Target)); + // instructionEncoder.Branch(SRM.ILOpCode.Br_s, labelHandleFor(branchInstruction.Target)); break; case Model.Bytecode.BranchOperation.Leave: break; @@ -248,21 +259,37 @@ LabelHandle addMapping(string label) switch (loadlInstruction.Operation) { case Model.Bytecode.LoadOperation.Address: + // FIXME CAST + //FIXME duplicated code with LoadOperation.Content + var operandVariable = (IVariable)loadlInstruction.Operand; + if (operandVariable.IsParameter) + { + instructionEncoder.LoadArgumentAddress(body.Parameters.IndexOf(operandVariable)); + } + else + { + instructionEncoder.LoadLocalAddress(body.LocalVariables.IndexOf(operandVariable)); + } break; case Model.Bytecode.LoadOperation.Value: - //FIXME TAC, CASTS? + if (((Constant)loadlInstruction.Operand).Value == null) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); + } if (loadlInstruction.Operand.Type.Equals(PlatformTypes.String)) { - var value = (string)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + var value = (string)(loadlInstruction.Operand as Constant).Value; instructionEncoder.LoadString(metadataContainer.metadataBuilder.GetOrAddUserString(value)); } // TODO see ECMA ldc instruction. It says some cases should be follow by conv.i8 operations but the bytecode (original) does not have that else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Int8) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt8)) { - var value = (int)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + var value = (int)(loadlInstruction.Operand as Constant).Value; instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); instructionEncoder.Token(value); + // FIXME: do only if value variable storing the 8 bit number is 8 byte integer. + // instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); } else if ( loadlInstruction.Operand.Type.Equals(PlatformTypes.Int16) || @@ -270,42 +297,58 @@ LabelHandle addMapping(string label) loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt16) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt32)) { - var value = (int)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + var value = (int)(loadlInstruction.Operand as Constant).Value; instructionEncoder.LoadConstantI4(value); + // FIXME: do only if value variable storing the 16/32 bit number is 8 byte integer. + // instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); } else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Int64) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt64)) { - var value = (long)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + var value = (long)(loadlInstruction.Operand as Constant).Value; instructionEncoder.LoadConstantI8(value); } else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Float32)) { - var value = (float)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + var value = (float)(loadlInstruction.Operand as Constant).Value; instructionEncoder.LoadConstantR4(value); } else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Float64)) { - var value = (double)(loadlInstruction.Operand as Model.ThreeAddressCode.Values.Constant).Value; + var value = (double)(loadlInstruction.Operand as Constant).Value; instructionEncoder.LoadConstantR8(value); } break; case Model.Bytecode.LoadOperation.Content: + // FIXME CAST + operandVariable = (IVariable)loadlInstruction.Operand; + if (operandVariable.IsParameter) + { + instructionEncoder.LoadArgument(body.Parameters.IndexOf(operandVariable)); + } + else + { + instructionEncoder.LoadLocal(body.LocalVariables.IndexOf(operandVariable)); + } break; } } else if (instruction is Model.Bytecode.LoadFieldInstruction loadFieldInstruction) { } else if (instruction is Model.Bytecode.LoadArrayElementInstruction loadArrayElementInstruction) { } - else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) { } + else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); + var signature = methodSignatureGenerator.GenerateSignatureOf(loadMethodAdressInstruction.Method); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadMethodAdressInstruction.Method, signature)); + } else if (instruction is Model.Bytecode.CreateArrayInstruction createArrayInstruction) { - // var size = 1; // FIXME array size not in the model (ArrayType) + // var size = 1; // FIXME array size cannot be known ([]) // instructionEncoder.LoadConstantI4(size); // FIXME I4 = int, I8 = long. Could it be long? // instructionEncoder.OpCode(ILOpCode.Newarr); // FIXME (cast). ElementsType could be Pointer or BasicType. MultiDimensional Arrays are handled by newObj insteado of newArr // instructionEncoder.Token(referenceHandleResolver.TypeReferenceOf(createArrayInstruction.Type.ElementsType as IBasicType)); } else if (instruction is Model.Bytecode.CreateObjectInstruction createObjectInstruction) { } - else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAddressInstruction) { } else if (instruction is Model.Bytecode.StoreInstruction storeInstruction) { } else if (instruction is Model.Bytecode.StoreFieldInstruction storeFieldInstruction) { } else if (instruction is Model.Bytecode.SwitchInstruction switchInstruction) { } From 6296842571b11ef9395b6ced6d80ba06213f1367 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Wed, 23 Oct 2019 21:47:23 -0300 Subject: [PATCH 047/256] InitObj is no longer a basic operation. --- Backend/Transformations/Disassembler.cs | 11 +++++----- CCIProvider/CodeProvider.cs | 9 ++++++-- CCIProvider/OperationHelper.cs | 1 - MetadataProvider/AssemblyExtractor.cs | 9 ++++++-- MetadataProvider/OperationHelper.cs | 1 - Model/Bytecode/Instructions.cs | 21 ++++++++++++++++++- Model/Bytecode/Visitor/IInstructionVisitor.cs | 1 + Model/Bytecode/Visitor/InstructionVisitor.cs | 1 + 8 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index f8e0b8c9..c971cf50 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -110,7 +110,10 @@ public InstructionTranslator(OperandStack stack, MethodBody body, IType returnTy this.body = body; this.returnType = returnType; } - + public override void Visit(Bytecode.InitObjInstruction op) + { + ProcessInitializeObject(op); + } public override void Visit(Bytecode.BasicInstruction op) { switch (op.Operation) @@ -172,10 +175,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; @@ -328,7 +327,7 @@ private void ProcessInitializeMemory(Bytecode.BasicInstruction op) body.Instructions.Add(instruction); } - private void ProcessInitializeObject(Bytecode.BasicInstruction op) + private void ProcessInitializeObject(Bytecode.InitObjInstruction op) { var targetAddress = stack.Pop(); var instruction = new Tac.InitializeObjectInstruction(op.Offset, targetAddress); diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index ffdcfffa..8c88a96e 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -329,7 +329,7 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) break; case Cci.OperationCode.Initobj: - instruction = ProcessBasic(operation); + instruction = ProcessInitObj(operation); break; case Cci.OperationCode.Ldarg: @@ -751,7 +751,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..a2bf3d30 100644 --- a/CCIProvider/OperationHelper.cs +++ b/CCIProvider/OperationHelper.cs @@ -52,7 +52,6 @@ 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; diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..d84a2e79 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -938,7 +938,7 @@ private IInstruction ExtractInstruction(ILInstruction operation) break; case SRM.ILOpCode.Initobj: - instruction = ProcessBasic(operation); + instruction = ProcessInitObj(operation); break; case SRM.ILOpCode.Ldarg: @@ -1615,7 +1615,12 @@ private IInstruction ProcessStoreField(ILInstruction op) var instruction = new StoreFieldInstruction(op.Offset, field); return instruction; } - + private IInstruction ProcessInitObj(ILInstruction op) + { + var type = GetOperand(op); + var instruction = new InitObjInstruction(op.Offset, type); + return instruction; + } private IInstruction ProcessBasic(ILInstruction op) { var operation = OperationHelper.ToBasicOperation(op.Opcode); diff --git a/MetadataProvider/OperationHelper.cs b/MetadataProvider/OperationHelper.cs index c4999197..a7d801c9 100644 --- a/MetadataProvider/OperationHelper.cs +++ b/MetadataProvider/OperationHelper.cs @@ -52,7 +52,6 @@ public static BasicOperation ToBasicOperation(SRM.ILOpCode opcode) case SRM.ILOpCode.Dup: return BasicOperation.Dup; case SRM.ILOpCode.Localloc: return BasicOperation.LocalAllocation; case SRM.ILOpCode.Initblk: return BasicOperation.InitBlock; - case SRM.ILOpCode.Initobj: return BasicOperation.InitObject; case SRM.ILOpCode.Cpblk: return BasicOperation.CopyBlock; case SRM.ILOpCode.Cpobj: return BasicOperation.CopyObject; case SRM.ILOpCode.Ret: return BasicOperation.Return; diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index bb12534e..33b1393e 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -36,7 +36,6 @@ public enum BasicOperation EndFilter, LocalAllocation, InitBlock, - InitObject, CopyObject, CopyBlock, LoadArrayLength, @@ -167,7 +166,27 @@ protected string ToString(object argument) return this.ToString("{0}", argument); } } + public class InitObjInstruction : Instruction + { + public IType Type { get; } + + public InitObjInstruction(uint label, IType type) + : base(label) + { + this.Type = type; + } + public override void Accept(IInstructionVisitor visitor) + { + base.Accept(visitor); + visitor.Visit(this); + } + + public override string ToString() + { + return "init obj of type " + Type.ToString(); + } + } public class BasicInstruction : Instruction { public BasicOperation Operation { get; set; } diff --git a/Model/Bytecode/Visitor/IInstructionVisitor.cs b/Model/Bytecode/Visitor/IInstructionVisitor.cs index 5d647a87..de6a7363 100644 --- a/Model/Bytecode/Visitor/IInstructionVisitor.cs +++ b/Model/Bytecode/Visitor/IInstructionVisitor.cs @@ -11,6 +11,7 @@ public interface IInstructionVisitor { void Visit(IInstructionContainer container); void Visit(Instruction instruction); + void Visit(InitObjInstruction instruction); void Visit(BasicInstruction instruction); void Visit(LoadInstruction instruction); void Visit(LoadFieldInstruction instruction); diff --git a/Model/Bytecode/Visitor/InstructionVisitor.cs b/Model/Bytecode/Visitor/InstructionVisitor.cs index 1575ba7a..7504d1c8 100644 --- a/Model/Bytecode/Visitor/InstructionVisitor.cs +++ b/Model/Bytecode/Visitor/InstructionVisitor.cs @@ -19,6 +19,7 @@ public virtual void Visit(IInstructionContainer container) } public virtual void Visit(Instruction instruction) { } + public virtual void Visit(InitObjInstruction instruction) { } public virtual void Visit(BasicInstruction instruction) { } public virtual void Visit(LoadInstruction instruction) { } public virtual void Visit(LoadFieldInstruction instruction) { } From 5a5dbf6d9ab3f9d6800669449034231c9326ad9a Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Thu, 24 Oct 2019 14:56:51 -0300 Subject: [PATCH 048/256] Correctly model in/ref/out keywords. --- CCIProvider/TypeExtractor.cs | 9 +++++---- MetadataProvider/AssemblyExtractor.cs | 7 ++++++- Model/ThreeAddressCode/Instructions.cs | 6 ++++-- Model/Types/TypeDefinitions.cs | 17 ++++++++++------- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/CCIProvider/TypeExtractor.cs b/CCIProvider/TypeExtractor.cs index 19e64dda..b340fd52 100644 --- a/CCIProvider/TypeExtractor.cs +++ b/CCIProvider/TypeExtractor.cs @@ -972,7 +972,7 @@ private void ExtractParameters(IList dest, IEnumerable signature, SRM.Paramete private static MethodParameterKind GetParameterKind(SR.ParameterAttributes attributes, IType type) { - var result = MethodParameterKind.In; + var result = MethodParameterKind.Normal; var isOut = attributes.HasFlag(SR.ParameterAttributes.Out); + var isIn = attributes.HasFlag(SR.ParameterAttributes.In); if (isOut) { result = MethodParameterKind.Out; } + else if (isIn) + { + result = MethodParameterKind.In; + } else if (type.IsPointer()) { result = MethodParameterKind.Ref; diff --git a/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index 270fde50..d38675a3 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -936,7 +936,8 @@ public override ISet ModifiedVariables // We don't care here if the objects referenced by arguments could be modified. foreach (var parameterInfo in this.Method.Parameters) { - if (parameterInfo.Kind == MethodParameterKind.Ref) + if (parameterInfo.Kind == MethodParameterKind.Ref || + parameterInfo.Kind == MethodParameterKind.Out) { var argument = this.Arguments[argumentIndex++]; result.Add(argument); @@ -1017,7 +1018,8 @@ public override ISet ModifiedVariables // We don't care here if the objects referenced by arguments could be modified. foreach (var parameterInfo in this.Function.Parameters) { - if (parameterInfo.Kind == MethodParameterKind.Ref) + if (parameterInfo.Kind == MethodParameterKind.Ref || + parameterInfo.Kind == MethodParameterKind.Out) { var argument = this.Arguments[argumentIndex++]; result.Add(argument); diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 27062ea7..34c59619 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -161,9 +161,10 @@ public override string ToString() public enum MethodParameterKind { - In, - Out, - Ref + Normal, // none + In, // in keyword + Out, // out keyword + Ref // ref keyword } public interface IMethodParameterReference @@ -183,7 +184,7 @@ public MethodParameterReference(ushort index, IType type) { this.Index = index; this.Type = type; - this.Kind = MethodParameterKind.In; + this.Kind = MethodParameterKind.Normal; } public override string ToString() @@ -192,7 +193,8 @@ public override string ToString() switch (this.Kind) { - case MethodParameterKind.In: kind = string.Empty; break; + case MethodParameterKind.Normal: kind = String.Empty; break; + case MethodParameterKind.In: kind = "in "; break; case MethodParameterKind.Out: kind = "out "; break; case MethodParameterKind.Ref: kind = "ref "; break; @@ -233,7 +235,7 @@ public MethodParameter(ushort index, string name, IType type) this.Index = index; this.Name = name; this.Type = type; - this.Kind = MethodParameterKind.In; + this.Kind = MethodParameterKind.Normal; this.Attributes = new HashSet(); } @@ -265,7 +267,8 @@ public override string ToString() switch (this.Kind) { - case MethodParameterKind.In: kind = string.Empty; break; + case MethodParameterKind.Normal: kind = string.Empty; break; + case MethodParameterKind.In: kind = "in "; break; case MethodParameterKind.Out: kind = "out "; break; case MethodParameterKind.Ref: kind = "ref "; break; From 6a58955288c968d994620c7bb99ce74720bb2be6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 24 Oct 2019 22:29:14 -0300 Subject: [PATCH 049/256] some load instructions --- Examples/Examples.cs | 65 +++++++++++++++- .../Generators/Methods/MethodBodyGenerator.cs | 74 +++++++++++++++---- .../Metadata/MetadataContainer.cs | 1 + .../Metadata/ReferenceHandleResolver.cs | 19 ++++- 4 files changed, 142 insertions(+), 17 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 41e8436e..e9a26f5f 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -67,7 +67,7 @@ static StaticClass() public class SimpleClass { - private readonly int readOnlyIntField = 212; + public readonly int readOnlyIntField = 212; public string unassignedString; public const string CONST_STRING = "const"; @@ -118,7 +118,7 @@ public class ClassWithMoreComplexFieldsAndParamtersOrReturnTypes public string[][] stringArrayArrayField; public string[,,] stringJaggedArrayField; public Exception[] exceptionArrayField; - private Nested.NestedNamespace.NestedNestedNamesace.B b; + public Nested.NestedNamespace.NestedNestedNamesace.B b; public void MethodWithOptionalParameters( string someParam, @@ -692,5 +692,66 @@ public void LoadIndirect(ref object g) var x11 = g; // ldind.ref } } + + public void Compare(int b) + { + var a = b == 2; // ceq + a = b > 2; // cgt + a = b < 2; // clt + } + + public void Create() + { + new Classes.SimpleClass(1, "a"); // newobj $methodCall + var a = new int[] { 1, 2, 3 }; // newarr int + var b = new Exception[] { }; // newarr Clases.SimpleClass + unsafe + { + var c = new int*[] { }; // newarr int* + var d = new int**[] { }; // newarr int** + } + } + public void LoadArray(Exception[] x, int[] q) + { + var a = x[1]; // ldelem.ref + var b = (new sbyte[] { })[0]; // ldelem.i1 + var c = (new byte[] { })[0]; // ldelem.u1 + var d = (new short[] { })[0]; // ldelem.i2 + var e = (new ushort[] { })[0]; // ldelem.u2 + var f = (new int[] { })[0]; // ldelem.i4 + var g = (new uint[] { })[0];// ldelem.u4 + var h = (new long[] { })[0]; // ldelem.i8 -- ldelem.u8 (alias) + var j = (new float[] { })[0];// ldelem.r4 + var k = (new double[] { })[0];// ldelem.r8 + + // TODO ldelem.i ??? + // TODO ldelem typeTok ??? + /* + * FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? + unsafe + { + fixed (int* p = &q[0]) // ldelema $type + { + } + } + */ + + var l = (new int[] { 1, 2, 3 }).Length; // ldlen + } + + public void LoadField() + { + var a = new Classes.SimpleClass(1, "b").unassignedString; // ldfld string $field + var b = new Classes.SimpleClass(1, "b").readOnlyIntField; // ldfld int $field + var c = new Classes.ClassWithMoreComplexFieldsAndParamtersOrReturnTypes().b; // ldfld class $field + + /* FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? + unsafe + { + fixed (int* d = &(new Classes.SimpleClass(1, "b")).readOnlyIntField) // ldflda int32 $field + { } + } + */ + } } } diff --git a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs index 6ab89560..90651b5e 100644 --- a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs @@ -11,7 +11,7 @@ namespace MetadataGenerator.Generators.Methods class MethodBodyGenerator { private readonly MetadataContainer metadataContainer; - private readonly MethodSignatureGenerator methodSignatureGenerator; + private readonly MethodSignatureGenerator methodSignatureGenerator; // FIXME maybe this can be used inside MetadataContainer? public MethodBodyGenerator(MetadataContainer metadataContainer, MethodSignatureGenerator methodSignatureGenerator) { @@ -84,7 +84,7 @@ ECMA335.LabelHandle labelHandleFor(string label) { // TODO // check overflow for variants (ej: add, add_ovf, add_ovf_un) - // see all IlOpCode constants + // see all IlOpCode constants and ECMA case Model.Bytecode.BasicOperation.Nop: instructionEncoder.OpCode(SRM.ILOpCode.Nop); @@ -120,10 +120,13 @@ ECMA335.LabelHandle labelHandleFor(string label) instructionEncoder.OpCode(SRM.ILOpCode.Shr); break; case Model.Bytecode.BasicOperation.Eq: + instructionEncoder.OpCode(SRM.ILOpCode.Ceq); break; case Model.Bytecode.BasicOperation.Lt: + instructionEncoder.OpCode(SRM.ILOpCode.Clt); break; case Model.Bytecode.BasicOperation.Gt: + instructionEncoder.OpCode(SRM.ILOpCode.Cgt); break; case Model.Bytecode.BasicOperation.Throw: instructionEncoder.OpCode(SRM.ILOpCode.Throw); @@ -161,11 +164,13 @@ ECMA335.LabelHandle labelHandleFor(string label) // instructionEncoder.Token(type) break; case Model.Bytecode.BasicOperation.CopyObject: + // FIXME CopyObject needs an operand (should not be BasicInstruction) break; case Model.Bytecode.BasicOperation.CopyBlock: instructionEncoder.OpCode(SRM.ILOpCode.Cpblk); break; case Model.Bytecode.BasicOperation.LoadArrayLength: + instructionEncoder.OpCode(SRM.ILOpCode.Ldlen); break; case Model.Bytecode.BasicOperation.IndirectLoad: // FIXME IndirectLoad needs an operand (should not be BasicInstruction) @@ -173,12 +178,27 @@ ECMA335.LabelHandle labelHandleFor(string label) // example is already generated for all variants break; case Model.Bytecode.BasicOperation.LoadArrayElement: + // FIXME LoadArrayElement needs an operand (should not be BasicInstruction) + // TODO depending on type of operand instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_X); + // example is already generated break; case Model.Bytecode.BasicOperation.LoadArrayElementAddress: + // FIXME LoadArrayElementAddress needs an operand (should not be BasicInstruction) + // instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); + // instructionEncoder.token(type); + // example is already generated break; case Model.Bytecode.BasicOperation.IndirectStore: + // FIXME IndirectStore needs an operand (should not be BasicInstruction) + // instructionEncoder.OpCode(SRM.ILOpCode.Stobj); + // instructionEncoder.token(); break; case Model.Bytecode.BasicOperation.StoreArrayElement: + // FIXME StoreArrayElement needs an operand (should not be BasicInstruction) + // instructionEncoder.OpCode(SRM.ILOpCode.Stelem_X); + + // instructionEncoder.OpCode(SRM.ILOpCode.Stelem); + // instructionEncoder.token(); break; case Model.Bytecode.BasicOperation.Breakpoint: instructionEncoder.OpCode(SRM.ILOpCode.Break); @@ -230,9 +250,9 @@ ECMA335.LabelHandle labelHandleFor(string label) case Model.Bytecode.ConvertOperation.Cast: break; case Model.Bytecode.ConvertOperation.Box: - instructionEncoder.OpCode(SRM.ILOpCode.Box); // FIXME ConversionType is IType. It can be IBasicType, ArrayType or PointerType. - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType as IBasicType)); + // instructionEncoder.OpCode(SRM.ILOpCode.Box); + // instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType as IBasicType)); break; case Model.Bytecode.ConvertOperation.Unbox: break; @@ -332,23 +352,51 @@ ECMA335.LabelHandle labelHandleFor(string label) break; } } - else if (instruction is Model.Bytecode.LoadFieldInstruction loadFieldInstruction) { } + else if (instruction is Model.Bytecode.LoadFieldInstruction loadFieldInstruction) + { + // TODO handle ldflda. Example present but not supported in model? + + //FIXME this logic is the same as in FieldGenerator. Maybe FieldSignatureGenerator? + var fieldSignature = new SRM.BlobBuilder(); + metadataContainer.Encode(loadFieldInstruction.Field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); + // + instructionEncoder.OpCode(SRM.ILOpCode.Ldfld); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field, fieldSignature)); + } else if (instruction is Model.Bytecode.LoadArrayElementInstruction loadArrayElementInstruction) { } else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) { + var methodSignature = methodSignatureGenerator.GenerateSignatureOf(loadMethodAdressInstruction.Method); instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); - var signature = methodSignatureGenerator.GenerateSignatureOf(loadMethodAdressInstruction.Method); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadMethodAdressInstruction.Method, signature)); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadMethodAdressInstruction.Method, methodSignature)); } else if (instruction is Model.Bytecode.CreateArrayInstruction createArrayInstruction) { - // var size = 1; // FIXME array size cannot be known ([]) - // instructionEncoder.LoadConstantI4(size); // FIXME I4 = int, I8 = long. Could it be long? - // instructionEncoder.OpCode(ILOpCode.Newarr); - // FIXME (cast). ElementsType could be Pointer or BasicType. MultiDimensional Arrays are handled by newObj insteado of newArr - // instructionEncoder.Token(referenceHandleResolver.TypeReferenceOf(createArrayInstruction.Type.ElementsType as IBasicType)); + if (createArrayInstruction.Type.IsVector) + { + if (createArrayInstruction.Type.ElementsType is IBasicType basicType) + { + instructionEncoder.OpCode(SRM.ILOpCode.Newarr); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(basicType)); + } + else + { // PointerType + // TODO could be multiple levels (*, **, *******, etc) + } + + } + else + { + throw new Exception("newarr only handles one dimension and zero based arrays"); + } + } + else if (instruction is Model.Bytecode.CreateObjectInstruction createObjectInstruction) + { + var methodSignature = methodSignatureGenerator.GenerateSignatureOf(createObjectInstruction.Constructor); + var method = metadataContainer.ResolveReferenceHandleFor(createObjectInstruction.Constructor, methodSignature); + instructionEncoder.OpCode(SRM.ILOpCode.Newobj); + instructionEncoder.Token(method); } - else if (instruction is Model.Bytecode.CreateObjectInstruction createObjectInstruction) { } else if (instruction is Model.Bytecode.StoreInstruction storeInstruction) { } else if (instruction is Model.Bytecode.StoreFieldInstruction storeFieldInstruction) { } else if (instruction is Model.Bytecode.SwitchInstruction switchInstruction) { } diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index e5eb9890..0fcb78f3 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -35,6 +35,7 @@ public MetadataContainer(Assembly assembly) public SRM.EntityHandle ResolveReferenceHandleFor(IBasicType type) => referenceHandleResolver.ReferenceHandleOf(type); public SRM.MemberReferenceHandle ResolveReferenceHandleFor(IMethodReference method, SRM.BlobBuilder signature) => referenceHandleResolver.ReferenceHandleOf(method, signature); + public SRM.MemberReferenceHandle ResolveReferenceHandleFor(IFieldReference field, SRM.BlobBuilder signature) => referenceHandleResolver.ReferenceHandleOf(field, signature); //FIXME name public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) => typeEncoder.Encode(type, encoder); } diff --git a/MetadataGenerator/Metadata/ReferenceHandleResolver.cs b/MetadataGenerator/Metadata/ReferenceHandleResolver.cs index 724e0e59..596d401d 100644 --- a/MetadataGenerator/Metadata/ReferenceHandleResolver.cs +++ b/MetadataGenerator/Metadata/ReferenceHandleResolver.cs @@ -64,7 +64,7 @@ public SRM.TypeReferenceHandle ReferenceHandleOf(IBasicType type) return typeReference; } - public SRM.MemberReferenceHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder methodSignature) + public SRM.MemberReferenceHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder signature) { var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; if (!methodReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) @@ -72,7 +72,22 @@ public SRM.MemberReferenceHandle ReferenceHandleOf(IMethodReference method, SRM. memberReferenceHandle = metadata.AddMemberReference( parent: ReferenceHandleOf(method.ContainingType), name: metadata.GetOrAddString(method.Name), - signature: metadata.GetOrAddBlob(methodSignature)); + signature: metadata.GetOrAddBlob(signature)); + methodReferences.Add(key, memberReferenceHandle); + } + return memberReferenceHandle; + } + + // FIXME extract method for both method and field? identical + public SRM.MemberReferenceHandle ReferenceHandleOf(IFieldReference field, SRM.BlobBuilder signature) + { + var key = $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.Name}.{field.Name}"; + if (!methodReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) + { + memberReferenceHandle = metadata.AddMemberReference( + parent: ReferenceHandleOf(field.ContainingType), + name: metadata.GetOrAddString(field.Name), + signature: metadata.GetOrAddBlob(signature)); methodReferences.Add(key, memberReferenceHandle); } return memberReferenceHandle; From afbcb925e4052421ac7c4fedc4b194ebb0e77e56 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Fri, 25 Oct 2019 16:16:14 -0300 Subject: [PATCH 050/256] Added model for property definitions. --- Model/Types/TypeDefinitions.cs | 61 +++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 27062ea7..637db38d 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -397,7 +397,65 @@ public override bool Equals(object obj) return result; } } + public class PropertyDefinition : ITypeMemberDefinition + { + public PropertyDefinition(string name, IType propType) + { + PropertyType = propType; + Name = name; + Attributes = new HashSet(); + } + + public ISet Attributes { get; private set; } + public IType PropertyType { get; set; } + public string Name { get; set; } + public MethodDefinition Getter { get; set; } + public MethodDefinition Setter { get; set; } + public TypeDefinition ContainingType { get; set; } + IBasicType ITypeMemberReference.ContainingType + { + get { return this.ContainingType; } + } + public bool MatchReference(ITypeMemberReference member) + { + if (member is PropertyDefinition) + return member.Equals(this); + return false; + } + public override bool Equals(object obj) + { + if (obj is PropertyDefinition propertyDef) + { + bool hasSetter = (propertyDef.Setter != null) == (this.Setter != null); + bool hasGetter = (propertyDef.Getter != null) == (this.Getter != null); + return propertyDef.Name.Equals(this.Name) && + propertyDef.PropertyType.Equals(this.PropertyType) && + hasSetter && hasGetter && + (propertyDef.Getter == null || propertyDef.Getter.Equals(this.Getter)) && + (propertyDef.Setter == null || propertyDef.Setter.Equals(this.Setter)) && + (propertyDef.ContainingType.Equals(this.ContainingType)); + } + return false; + } + public override string ToString() + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("Property definition"); + stringBuilder.AppendLine(String.Format("Name: {0}", Name)); + stringBuilder.AppendLine(String.Format("Property type: {0}", PropertyType)); + stringBuilder.AppendLine(String.Format("Containing type: {0}", ContainingType)); + if (Getter != null) + stringBuilder.AppendLine(String.Format("Getter: {0}", Getter.ToSignatureString())); + if (Setter != null) + stringBuilder.AppendLine(String.Format("Setter: {0}", Setter.ToSignatureString())); + return stringBuilder.ToString(); + } + public override int GetHashCode() + { + return this.Name.GetHashCode(); + } + } public class MethodDefinition : ITypeMemberDefinition, IMethodReference, IGenericDefinition { public VisibilityKind Visibility { get; set; } @@ -623,7 +681,7 @@ public class TypeDefinition : IBasicType, IGenericDefinition, ITypeMemberDefinit public IList Methods { get; private set; } public IList Types { get; private set; } public IBasicType UnderlayingType { get; set; } - + public ISet PropertyDefinitions { get; private set; } public TypeDefinition(string name, TypeKind typeKind = TypeKind.Unknown, TypeDefinitionKind kind = TypeDefinitionKind.Unknown) { this.Name = name; @@ -635,6 +693,7 @@ public TypeDefinition(string name, TypeKind typeKind = TypeKind.Unknown, TypeDef this.Fields = new List(); this.Methods = new List(); this.Types = new List(); + this.PropertyDefinitions = new HashSet(); } public string GenericName From 978ec0f0a1d802bc757c53f2c5ceb88e16f5042b Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Fri, 25 Oct 2019 16:19:34 -0300 Subject: [PATCH 051/256] Added model for layout information --- Model/Types/TypeDefinitions.cs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 27062ea7..6a2d1bde 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -605,7 +605,25 @@ public enum VisibilityKind Internal = 4, Public = 8 } - + public enum LayoutKind + { + Unknown, + AutoLayout, // Class fields are auto-laid out + SequentialLayout, // Class fields are laid out sequentially + ExplicitLayout, // Layout is supplied explicitly + } + public class LayoutInformation + { + public LayoutKind Kind { get; set; } + public short PackingSize { get; set; } + public int ClassSize { get; set; } + public LayoutInformation(LayoutKind kind = LayoutKind.Unknown) + { + Kind = kind; + PackingSize = -1; + ClassSize = -1; + } + } public class TypeDefinition : IBasicType, IGenericDefinition, ITypeMemberDefinition, ITypeDefinitionContainer { public TypeKind TypeKind { get; set; } @@ -623,7 +641,7 @@ public class TypeDefinition : IBasicType, IGenericDefinition, ITypeMemberDefinit public IList Methods { get; private set; } public IList Types { get; private set; } public IBasicType UnderlayingType { get; set; } - + public LayoutInformation LayoutInformation { get; set; } public TypeDefinition(string name, TypeKind typeKind = TypeKind.Unknown, TypeDefinitionKind kind = TypeDefinitionKind.Unknown) { this.Name = name; @@ -635,6 +653,7 @@ public TypeDefinition(string name, TypeKind typeKind = TypeKind.Unknown, TypeDef this.Fields = new List(); this.Methods = new List(); this.Types = new List(); + this.LayoutInformation = new LayoutInformation(); } public string GenericName From f44c79e3a5a7d6c08404fecc44289f27b22ccdee Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 26 Oct 2019 19:21:04 -0300 Subject: [PATCH 052/256] more instructions and some refactors --- Examples/Examples.cs | 60 ++++++++++++++----- .../Generators/{ => Fields}/FieldGenerator.cs | 10 ++-- .../Fields/FieldSignatureGenerator.cs | 22 +++++++ .../Generators/Methods/MethodBodyGenerator.cs | 52 +++++++++++++--- .../Metadata/ReferenceHandleResolver.cs | 10 ++-- MetadataGenerator/MetadataGenerator.csproj | 4 +- 6 files changed, 124 insertions(+), 34 deletions(-) rename MetadataGenerator/Generators/{ => Fields}/FieldGenerator.cs (77%) create mode 100644 MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs diff --git a/Examples/Examples.cs b/Examples/Examples.cs index e9a26f5f..9dd3c96b 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -57,11 +57,15 @@ public class EmptyClass { } public static class StaticClass { static readonly double StaticDouble; + public static Exception e; + public static int i; static StaticClass() { StaticDouble = 0.5; } + + public static void DoNothing(int x) { } } @@ -557,6 +561,8 @@ public void Calls(Classes.SimpleClass simpleClass) Console.WriteLine("A method call"); // static simpleClass.DoNothing(); // virtual Alloc(); // normal + + // TODO calli (indirect) } public void Arrays() @@ -571,24 +577,17 @@ public void Arrays() } } - // TODO unboxPtr??? - public void Convert() + public void Convert(object o) { - int i = 123; - object o = i; // boxing - - o = 123; - i = (int)o; // unboxing + string s = (string)(object)"asd"; // castclass $class - // Implicit conversion. A long can hold any value an int can hold, and more! - int num = 2147483647; - long bigNum = num; + // FIXME framework read not working. + // var b = o is Classes.SimpleClass; // isinst $class - double x = 1234.7; - int a; + object l = 1; // box int + int i = (int)l; // unbox.any int - // Cast double to int. - a = (int)x; + // TODO unbox (unbox ptr) } public void Branch(bool b) @@ -753,5 +752,38 @@ public void LoadField() } */ } + + public void StoreField() + { + new Classes.SimpleClass(1, "b").unassignedString = ""; // stfld string $field + Classes.StaticClass.i = 1; // stsfld int $field + Classes.StaticClass.e = new Exception(); // stsfld Exception $field + } + + public void StoreValue(int arg) + { + int l0, l1, l2, l3, l4; + l0 = 1; // stloc.0 + l1 = 1; // stloc.1 + l2 = 1; // stloc.2 + l3 = 1; // stloc.3 + l4 = 1; // stloc.s 4 + // TODO stloc indx (not short form) + + arg = 1; // starg.s arg + // TODO starg arg (not short form) + } + + public void SizeOf() + { + unsafe + { + // FIXME framework read not working + // var x = sizeof(Structs.NonEmptyStruct); // sizeof $type + var z = sizeof(Structs.NonEmptyStruct***); // sizeof $type*** + var y = sizeof(int*); // sizeof int* + } + } + } } diff --git a/MetadataGenerator/Generators/FieldGenerator.cs b/MetadataGenerator/Generators/Fields/FieldGenerator.cs similarity index 77% rename from MetadataGenerator/Generators/FieldGenerator.cs rename to MetadataGenerator/Generators/Fields/FieldGenerator.cs index d15ffb62..0b2c1a2e 100644 --- a/MetadataGenerator/Generators/FieldGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldGenerator.cs @@ -1,23 +1,23 @@ -using Model.Types; +using MetadataGenerator.Generators.Fields; +using Model.Types; using static MetadataGenerator.AttributesProvider; -using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; - namespace MetadataGenerator { class FieldGenerator { private readonly MetadataContainer metadataContainer; + private readonly FieldSignatureGenerator fieldSignatureGenerator; public FieldGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; + fieldSignatureGenerator = new FieldSignatureGenerator(metadataContainer); } public SRM.FieldDefinitionHandle Generate(FieldDefinition field) { - var fieldSignature = new SRM.BlobBuilder(); - metadataContainer.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); + var fieldSignature = fieldSignatureGenerator.Generate(field); var fieldDefinitionHandle = metadataContainer.metadataBuilder.AddFieldDefinition( attributes: GetFieldAttributesFor(field), name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), diff --git a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs new file mode 100644 index 00000000..6f33a7f4 --- /dev/null +++ b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs @@ -0,0 +1,22 @@ +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; +namespace MetadataGenerator.Generators.Fields +{ + class FieldSignatureGenerator + { + private readonly MetadataContainer metadataContainer; + + public FieldSignatureGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public SRM.BlobBuilder Generate(IFieldReference field) + { + var fieldSignature = new SRM.BlobBuilder(); + metadataContainer.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); + return fieldSignature; + } + } +} diff --git a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs index 90651b5e..9025a550 100644 --- a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs @@ -1,4 +1,5 @@ using System; +using MetadataGenerator.Generators.Fields; using Model.ThreeAddressCode.Values; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -12,11 +13,13 @@ class MethodBodyGenerator { private readonly MetadataContainer metadataContainer; private readonly MethodSignatureGenerator methodSignatureGenerator; // FIXME maybe this can be used inside MetadataContainer? + private readonly FieldSignatureGenerator fieldSignatureGenerator; // FIXME maybe this can be used inside MetadataContainer? public MethodBodyGenerator(MetadataContainer metadataContainer, MethodSignatureGenerator methodSignatureGenerator) { this.metadataContainer = metadataContainer; this.methodSignatureGenerator = methodSignatureGenerator; + fieldSignatureGenerator = new FieldSignatureGenerator(metadataContainer); } public ECMA335.InstructionEncoder Generate(MethodBody body) @@ -248,6 +251,9 @@ ECMA335.LabelHandle labelHandleFor(string label) case Model.Bytecode.ConvertOperation.Conv: break; case Model.Bytecode.ConvertOperation.Cast: + // FIXME ConversionType is IType. It can be IBasicType, ArrayType or PointerType. + // instructionEncoder.OpCode(SRM.ILOpCode.Castclass); + // instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); break; case Model.Bytecode.ConvertOperation.Box: // FIXME ConversionType is IType. It can be IBasicType, ArrayType or PointerType. @@ -356,10 +362,7 @@ ECMA335.LabelHandle labelHandleFor(string label) { // TODO handle ldflda. Example present but not supported in model? - //FIXME this logic is the same as in FieldGenerator. Maybe FieldSignatureGenerator? - var fieldSignature = new SRM.BlobBuilder(); - metadataContainer.Encode(loadFieldInstruction.Field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); - // + var fieldSignature = fieldSignatureGenerator.Generate(loadFieldInstruction.Field); instructionEncoder.OpCode(SRM.ILOpCode.Ldfld); instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field, fieldSignature)); } @@ -383,7 +386,6 @@ ECMA335.LabelHandle labelHandleFor(string label) { // PointerType // TODO could be multiple levels (*, **, *******, etc) } - } else { @@ -397,15 +399,47 @@ ECMA335.LabelHandle labelHandleFor(string label) instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); } - else if (instruction is Model.Bytecode.StoreInstruction storeInstruction) { } - else if (instruction is Model.Bytecode.StoreFieldInstruction storeFieldInstruction) { } + else if (instruction is Model.Bytecode.StoreInstruction storeInstruction) + { + if (storeInstruction.Target.IsParameter) + { + instructionEncoder.StoreArgument(body.Parameters.IndexOf(storeInstruction.Target)); + } + else + { + instructionEncoder.StoreLocal(body.LocalVariables.IndexOf(storeInstruction.Target)); + } + } + else if (instruction is Model.Bytecode.StoreFieldInstruction storeFieldInstruction) + { + var fieldSignature = fieldSignatureGenerator.Generate(storeFieldInstruction.Field); + instructionEncoder.OpCode(storeFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeFieldInstruction.Field, fieldSignature)); + } else if (instruction is Model.Bytecode.SwitchInstruction switchInstruction) { } - else if (instruction is Model.Bytecode.SizeofInstruction sizeofInstruction) { } + else if (instruction is Model.Bytecode.SizeofInstruction sizeofInstruction) + { + instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); + if (sizeofInstruction.MeasuredType is IBasicType basicType) + { + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(basicType)); + + } + else if (sizeofInstruction.MeasuredType is PointerType pointerType) + { + // TODO could be multiple indirections + // example already generated + } + else + { + // FIXME check if array type is really possible with sizeof. I think not + throw new Exception(); + } + } else if (instruction is Model.Bytecode.LoadTokenInstruction loadTokenInstruction) { } else if (instruction is Model.Bytecode.IndirectMethodCallInstruction indirectMethodCallInstruction) { } else if (instruction is Model.Bytecode.StoreArrayElementInstruction storeArrayElementInstruction) { } else throw new Exception("instruction type not handled"); - } return instructionEncoder; diff --git a/MetadataGenerator/Metadata/ReferenceHandleResolver.cs b/MetadataGenerator/Metadata/ReferenceHandleResolver.cs index 596d401d..10dc3730 100644 --- a/MetadataGenerator/Metadata/ReferenceHandleResolver.cs +++ b/MetadataGenerator/Metadata/ReferenceHandleResolver.cs @@ -14,7 +14,7 @@ class ReferenceHandleResolver private readonly ECMA335.MetadataBuilder metadata; private readonly IDictionary assemblyReferences = new Dictionary(); private readonly IDictionary typeReferences = new Dictionary(); - private readonly IDictionary methodReferences = new Dictionary(); + private readonly IDictionary memberReferences = new Dictionary(); public ReferenceHandleResolver(ECMA335.MetadataBuilder metadata, Assembly assembly) { @@ -67,13 +67,13 @@ public SRM.TypeReferenceHandle ReferenceHandleOf(IBasicType type) public SRM.MemberReferenceHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder signature) { var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; - if (!methodReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) + if (!memberReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) { memberReferenceHandle = metadata.AddMemberReference( parent: ReferenceHandleOf(method.ContainingType), name: metadata.GetOrAddString(method.Name), signature: metadata.GetOrAddBlob(signature)); - methodReferences.Add(key, memberReferenceHandle); + memberReferences.Add(key, memberReferenceHandle); } return memberReferenceHandle; } @@ -82,13 +82,13 @@ public SRM.MemberReferenceHandle ReferenceHandleOf(IMethodReference method, SRM. public SRM.MemberReferenceHandle ReferenceHandleOf(IFieldReference field, SRM.BlobBuilder signature) { var key = $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.Name}.{field.Name}"; - if (!methodReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) + if (!memberReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) { memberReferenceHandle = metadata.AddMemberReference( parent: ReferenceHandleOf(field.ContainingType), name: metadata.GetOrAddString(field.Name), signature: metadata.GetOrAddBlob(signature)); - methodReferences.Add(key, memberReferenceHandle); + memberReferences.Add(key, memberReferenceHandle); } return memberReferenceHandle; } diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 76a35da1..93a05dfc 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -29,7 +29,6 @@ - @@ -39,6 +38,8 @@ + + @@ -58,6 +59,7 @@ + \ No newline at end of file From af3b8da977f7b622196a4c109b4bbe2959eed53a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 2 Nov 2019 17:43:53 -0300 Subject: [PATCH 053/256] refactor typeEncoder+referenceHandleResolver --- Examples/Examples.cs | 12 +- .../Generators/Fields/FieldGenerator.cs | 2 +- .../Fields/FieldSignatureGenerator.cs | 2 +- .../Generators/Methods/MethodBodyGenerator.cs | 96 +++---- .../Generators/Methods/MethodGenerator.cs | 2 +- .../Metadata/MetadataContainer.cs | 13 +- .../Metadata/MetadataResolver.cs | 239 ++++++++++++++++++ .../Metadata/ReferenceHandleResolver.cs | 96 ------- MetadataGenerator/Metadata/TypeEncoder.cs | 100 -------- MetadataGenerator/MetadataGenerator.csproj | 3 +- 10 files changed, 291 insertions(+), 274 deletions(-) create mode 100644 MetadataGenerator/Metadata/MetadataResolver.cs delete mode 100644 MetadataGenerator/Metadata/ReferenceHandleResolver.cs delete mode 100644 MetadataGenerator/Metadata/TypeEncoder.cs diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 9dd3c96b..818df5b0 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -580,9 +580,11 @@ public void Arrays() public void Convert(object o) { string s = (string)(object)"asd"; // castclass $class + var x = (int[])(object)new int[] { }; + // FIXME framework read not working. - // var b = o is Classes.SimpleClass; // isinst $class + // var b = o is Classes.SimpleClass; // isinst $class object l = 1; // box int int i = (int)l; // unbox.any int @@ -784,6 +786,12 @@ public void SizeOf() var y = sizeof(int*); // sizeof int* } } - + /* + * doesnt work yet + // TODO other cases + public void LoadToken() + { + var x = typeof(T); + }*/ } } diff --git a/MetadataGenerator/Generators/Fields/FieldGenerator.cs b/MetadataGenerator/Generators/Fields/FieldGenerator.cs index 0b2c1a2e..b7a4f8a7 100644 --- a/MetadataGenerator/Generators/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldGenerator.cs @@ -17,7 +17,7 @@ public FieldGenerator(MetadataContainer metadataContainer) public SRM.FieldDefinitionHandle Generate(FieldDefinition field) { - var fieldSignature = fieldSignatureGenerator.Generate(field); + var fieldSignature = fieldSignatureGenerator.GenerateSignatureOf(field); var fieldDefinitionHandle = metadataContainer.metadataBuilder.AddFieldDefinition( attributes: GetFieldAttributesFor(field), name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), diff --git a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs index 6f33a7f4..bb88ba98 100644 --- a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs @@ -12,7 +12,7 @@ public FieldSignatureGenerator(MetadataContainer metadataContainer) this.metadataContainer = metadataContainer; } - public SRM.BlobBuilder Generate(IFieldReference field) + public SRM.BlobBuilder GenerateSignatureOf(IFieldReference field) { var fieldSignature = new SRM.BlobBuilder(); metadataContainer.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); diff --git a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs index 9025a550..6ddf3372 100644 --- a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs @@ -1,5 +1,4 @@ using System; -using MetadataGenerator.Generators.Fields; using Model.ThreeAddressCode.Values; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -12,14 +11,9 @@ namespace MetadataGenerator.Generators.Methods class MethodBodyGenerator { private readonly MetadataContainer metadataContainer; - private readonly MethodSignatureGenerator methodSignatureGenerator; // FIXME maybe this can be used inside MetadataContainer? - private readonly FieldSignatureGenerator fieldSignatureGenerator; // FIXME maybe this can be used inside MetadataContainer? - - public MethodBodyGenerator(MetadataContainer metadataContainer, MethodSignatureGenerator methodSignatureGenerator) + public MethodBodyGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; - this.methodSignatureGenerator = methodSignatureGenerator; - fieldSignatureGenerator = new FieldSignatureGenerator(metadataContainer); } public ECMA335.InstructionEncoder Generate(MethodBody body) @@ -249,34 +243,34 @@ ECMA335.LabelHandle labelHandleFor(string label) switch (convertInstruction.Operation) { case Model.Bytecode.ConvertOperation.Conv: + // TODO break; case Model.Bytecode.ConvertOperation.Cast: - // FIXME ConversionType is IType. It can be IBasicType, ArrayType or PointerType. - // instructionEncoder.OpCode(SRM.ILOpCode.Castclass); - // instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); + instructionEncoder.OpCode(SRM.ILOpCode.Castclass); + // FIXME could also be instructionEncoder.OpCode(SRM.ILOpCode.Isinst); break; case Model.Bytecode.ConvertOperation.Box: - // FIXME ConversionType is IType. It can be IBasicType, ArrayType or PointerType. - // instructionEncoder.OpCode(SRM.ILOpCode.Box); - // instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType as IBasicType)); + instructionEncoder.OpCode(SRM.ILOpCode.Box); break; case Model.Bytecode.ConvertOperation.Unbox: + instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); break; case Model.Bytecode.ConvertOperation.UnboxPtr: + instructionEncoder.OpCode(SRM.ILOpCode.Unbox); break; } + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); } else if (instruction is Model.Bytecode.MethodCallInstruction methodCallInstruction) { - var methodSignature = methodSignatureGenerator.GenerateSignatureOf(methodCallInstruction.Method); switch (methodCallInstruction.Operation) { case Model.Bytecode.MethodCallOperation.Virtual: - instructionEncoder.CallVirtual(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method, methodSignature)); + instructionEncoder.CallVirtual(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method)); break; case Model.Bytecode.MethodCallOperation.Static: case Model.Bytecode.MethodCallOperation.Jump: - instructionEncoder.Call(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method, methodSignature)); + instructionEncoder.Call(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method)); break; } } @@ -286,7 +280,6 @@ ECMA335.LabelHandle labelHandleFor(string label) { case Model.Bytecode.LoadOperation.Address: // FIXME CAST - //FIXME duplicated code with LoadOperation.Content var operandVariable = (IVariable)loadlInstruction.Operand; if (operandVariable.IsParameter) { @@ -297,6 +290,18 @@ ECMA335.LabelHandle labelHandleFor(string label) instructionEncoder.LoadLocalAddress(body.LocalVariables.IndexOf(operandVariable)); } break; + case Model.Bytecode.LoadOperation.Content: + // FIXME CAST + operandVariable = (IVariable)loadlInstruction.Operand; + if (operandVariable.IsParameter) + { + instructionEncoder.LoadArgument(body.Parameters.IndexOf(operandVariable)); + } + else + { + instructionEncoder.LoadLocal(body.LocalVariables.IndexOf(operandVariable)); + } + break; case Model.Bytecode.LoadOperation.Value: if (((Constant)loadlInstruction.Operand).Value == null) { @@ -344,48 +349,27 @@ ECMA335.LabelHandle labelHandleFor(string label) instructionEncoder.LoadConstantR8(value); } break; - case Model.Bytecode.LoadOperation.Content: - // FIXME CAST - operandVariable = (IVariable)loadlInstruction.Operand; - if (operandVariable.IsParameter) - { - instructionEncoder.LoadArgument(body.Parameters.IndexOf(operandVariable)); - } - else - { - instructionEncoder.LoadLocal(body.LocalVariables.IndexOf(operandVariable)); - } - break; } } else if (instruction is Model.Bytecode.LoadFieldInstruction loadFieldInstruction) { // TODO handle ldflda. Example present but not supported in model? - var fieldSignature = fieldSignatureGenerator.Generate(loadFieldInstruction.Field); instructionEncoder.OpCode(SRM.ILOpCode.Ldfld); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field, fieldSignature)); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field)); } else if (instruction is Model.Bytecode.LoadArrayElementInstruction loadArrayElementInstruction) { } else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) { - var methodSignature = methodSignatureGenerator.GenerateSignatureOf(loadMethodAdressInstruction.Method); instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadMethodAdressInstruction.Method, methodSignature)); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadMethodAdressInstruction.Method)); } else if (instruction is Model.Bytecode.CreateArrayInstruction createArrayInstruction) { if (createArrayInstruction.Type.IsVector) { - if (createArrayInstruction.Type.ElementsType is IBasicType basicType) - { - instructionEncoder.OpCode(SRM.ILOpCode.Newarr); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(basicType)); - } - else - { // PointerType - // TODO could be multiple levels (*, **, *******, etc) - } + instructionEncoder.OpCode(SRM.ILOpCode.Newarr); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(createArrayInstruction.Type.ElementsType)); } else { @@ -394,8 +378,7 @@ ECMA335.LabelHandle labelHandleFor(string label) } else if (instruction is Model.Bytecode.CreateObjectInstruction createObjectInstruction) { - var methodSignature = methodSignatureGenerator.GenerateSignatureOf(createObjectInstruction.Constructor); - var method = metadataContainer.ResolveReferenceHandleFor(createObjectInstruction.Constructor, methodSignature); + var method = metadataContainer.ResolveReferenceHandleFor(createObjectInstruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); } @@ -412,31 +395,20 @@ ECMA335.LabelHandle labelHandleFor(string label) } else if (instruction is Model.Bytecode.StoreFieldInstruction storeFieldInstruction) { - var fieldSignature = fieldSignatureGenerator.Generate(storeFieldInstruction.Field); instructionEncoder.OpCode(storeFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeFieldInstruction.Field, fieldSignature)); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeFieldInstruction.Field)); } else if (instruction is Model.Bytecode.SwitchInstruction switchInstruction) { } else if (instruction is Model.Bytecode.SizeofInstruction sizeofInstruction) { instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); - if (sizeofInstruction.MeasuredType is IBasicType basicType) - { - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(basicType)); - - } - else if (sizeofInstruction.MeasuredType is PointerType pointerType) - { - // TODO could be multiple indirections - // example already generated - } - else - { - // FIXME check if array type is really possible with sizeof. I think not - throw new Exception(); - } + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(sizeofInstruction.MeasuredType)); + } + else if (instruction is Model.Bytecode.LoadTokenInstruction loadTokenInstruction) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadTokenInstruction.Token)); } - else if (instruction is Model.Bytecode.LoadTokenInstruction loadTokenInstruction) { } else if (instruction is Model.Bytecode.IndirectMethodCallInstruction indirectMethodCallInstruction) { } else if (instruction is Model.Bytecode.StoreArrayElementInstruction storeArrayElementInstruction) { } else throw new Exception("instruction type not handled"); diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index d79c0d8a..f47043ed 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -22,7 +22,7 @@ public MethodGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); - methodBodyGenerator = new MethodBodyGenerator(metadataContainer, methodSignatureGenerator); + methodBodyGenerator = new MethodBodyGenerator(metadataContainer); } public SRM.MethodDefinitionHandle Generate(MethodDefinition method) diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 0fcb78f3..41122f2f 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -10,8 +10,7 @@ namespace MetadataGenerator class MetadataContainer { public readonly ECMA335.MetadataBuilder metadataBuilder; - private readonly TypeEncoder typeEncoder; - private readonly ReferenceHandleResolver referenceHandleResolver; + private readonly MetadataResolver metadataResolver; public readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; private SRM.MethodDefinitionHandle? mainMethodHandle; public SRM.MethodDefinitionHandle? MainMethodHandle @@ -28,15 +27,11 @@ public SRM.MethodDefinitionHandle? MainMethodHandle public MetadataContainer(Assembly assembly) { metadataBuilder = new ECMA335.MetadataBuilder(); - referenceHandleResolver = new ReferenceHandleResolver(metadataBuilder, assembly); - typeEncoder = new TypeEncoder(referenceHandleResolver); methodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); + metadataResolver = new MetadataResolver(this, assembly); } - public SRM.EntityHandle ResolveReferenceHandleFor(IBasicType type) => referenceHandleResolver.ReferenceHandleOf(type); - public SRM.MemberReferenceHandle ResolveReferenceHandleFor(IMethodReference method, SRM.BlobBuilder signature) => referenceHandleResolver.ReferenceHandleOf(method, signature); - public SRM.MemberReferenceHandle ResolveReferenceHandleFor(IFieldReference field, SRM.BlobBuilder signature) => referenceHandleResolver.ReferenceHandleOf(field, signature); - //FIXME name - public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) => typeEncoder.Encode(type, encoder); + public SRM.EntityHandle ResolveReferenceHandleFor(IMetadataReference metadataReference) => metadataResolver.ReferenceHandleOf(metadataReference); + public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) => metadataResolver.Encode(type, encoder); } } diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs new file mode 100644 index 00000000..c2c6e0ed --- /dev/null +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using MetadataGenerator.Generators.Fields; +using MetadataGenerator.Generators.Methods; +using Model; +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator +{ + class MetadataResolver + { + private readonly Assembly assembly; + private readonly MetadataContainer metadataContainer; + private readonly IDictionary assemblyReferences = new Dictionary(); + private readonly IDictionary typeReferences = new Dictionary(); + private readonly IDictionary memberReferences = new Dictionary(); + private readonly FieldSignatureGenerator fieldSignatureGenerator; + private readonly MethodSignatureGenerator methodSignatureGenerator; + + public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) + { + this.metadataContainer = metadataContainer; + this.assembly = assembly; + + // FIXME: assemblyName => assemblyRef could result in false positive? + foreach (var assemblyReference in assembly.References) + { + // FIXME parameters + assemblyReferences.Add(assemblyReference.Name, metadataContainer.metadataBuilder.AddAssemblyReference( + name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), + version: new Version(4, 0, 0, 0), + culture: metadataContainer.metadataBuilder.GetOrAddString("neutral"), + publicKeyOrToken: metadataContainer.metadataBuilder.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), + flags: default, + hashValue: default) + ); + } + fieldSignatureGenerator = new FieldSignatureGenerator(metadataContainer); + methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); + } + + + public SRM.EntityHandle ReferenceHandleOf(IMetadataReference metadataReference) + { + if (metadataReference is IFieldReference field) + { + var signature = fieldSignatureGenerator.GenerateSignatureOf(field); + return ReferenceHandleOf(field, signature); + } + else if (metadataReference is IMethodReference method) + { + var signature = methodSignatureGenerator.GenerateSignatureOf(method); + return ReferenceHandleOf(method, signature); + } + else if (metadataReference is IType type) + { + return ReferenceHandleOf(type); + } + else + { + throw new Exception(); // FIXME + } + } + + private SRM.EntityHandle ReferenceHandleOf(IType type) + { + if (type is IBasicType basicType) + { + return ReferenceHandleOf(basicType, basicType.Name); + } + // FIXME rompe porque queda desordenada la tabla de genericParam. + else if (type is IGenericParameterReference genericParameterReference) + { + return ReferenceHandleOf(genericParameterReference.GenericContainer.ContainingType, genericParameterReference.Name); + } + else if (type is ArrayType arrayType) + { + var signature = new SRM.BlobBuilder(); + var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); + Encode(arrayType, encoder); + return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + } + else if (type is PointerType pointerType) + { + var signature = new SRM.BlobBuilder(); + var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); + Encode(pointerType, encoder); + return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + } + else + { + throw new Exception("not yet supported"); + } + } + + /* + * Returns a TypeReference for type. It stores references because metadata does not have a getOrAddTypeReference. + */ + private SRM.TypeReferenceHandle ReferenceHandleOf(IBasicType type, string typeName) + { + var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{type.Name}"; + if (!typeReferences.TryGetValue(typeReferenceKey, out SRM.TypeReferenceHandle typeReference)) // If stored then return that + { // if not add the new type reference to metadata and store it + SRM.EntityHandle resolutionScope; + if (type.ContainingType == null) // if defined in the namespace then search there + { + resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) + ? default + : assemblyReferences[type.ContainingAssembly.Name]; + } + else + { // if not, recursively get a reference for the containing type and use that as the resolution scopeø + resolutionScope = ReferenceHandleOf(type.ContainingType); + } + typeReference = metadataContainer.metadataBuilder.AddTypeReference( + resolutionScope: resolutionScope, + @namespace: metadataContainer.metadataBuilder.GetOrAddString(type.ContainingNamespace), + name: metadataContainer.metadataBuilder.GetOrAddString(typeName)); + typeReferences.Add(typeReferenceKey, typeReference); + } + return typeReference; + } + + private SRM.MemberReferenceHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder signature) + { + var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; + if (!memberReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) + { + memberReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( + parent: ReferenceHandleOf(method.ContainingType), + name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), + signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + memberReferences.Add(key, memberReferenceHandle); + } + return memberReferenceHandle; + } + + // FIXME extract method for both method and field? identical + private SRM.MemberReferenceHandle ReferenceHandleOf(IFieldReference field, SRM.BlobBuilder signature) + { + var key = $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.Name}.{field.Name}"; + if (!memberReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) + { + memberReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( + parent: ReferenceHandleOf(field.ContainingType), + name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), + signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + memberReferences.Add(key, memberReferenceHandle); + } + return memberReferenceHandle; + } + + // SignatureTypeEncoder is a struct but it is not necessary to pass it by reference since + // it operates on its Builder (BlobBuilber) which is a class (tha means the builder refernece is always the same) + public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) + { + if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); + else if (type.Equals(PlatformTypes.Byte)) encoder.Byte(); + else if (type.Equals(PlatformTypes.SByte)) encoder.SByte(); + else if (type.Equals(PlatformTypes.Char)) encoder.Char(); + else if (type.Equals(PlatformTypes.Double)) encoder.Double(); + else if (type.Equals(PlatformTypes.Int16)) encoder.Int16(); + else if (type.Equals(PlatformTypes.UInt16)) encoder.UInt16(); + else if (type.Equals(PlatformTypes.Int32)) encoder.Int32(); + else if (type.Equals(PlatformTypes.UInt32)) encoder.UInt32(); + else if (type.Equals(PlatformTypes.Int64)) encoder.Int64(); + else if (type.Equals(PlatformTypes.UInt64)) encoder.UInt64(); + else if (type.Equals(PlatformTypes.String)) encoder.String(); + else if (type.Equals(PlatformTypes.Single)) encoder.Single(); + else if (type.Equals(PlatformTypes.Object)) encoder.Object(); + else + { + if (type is IBasicType basicType) + { + if (basicType.GenericType != null) + { + var genericInstantiation = encoder.GenericInstantiation( + ReferenceHandleOf(basicType), + basicType.GenericParameterCount, + type.TypeKind == TypeKind.ValueType + ); + foreach (var genericArg in basicType.GenericArguments) + { + Encode(genericArg, genericInstantiation.AddArgument()); + } + } + else + { + encoder.Type(ReferenceHandleOf(basicType), type.TypeKind == TypeKind.ValueType); + } + } + else if (type is ArrayType arrayType) + { + encoder.Array( + elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), + arrayShapeEncoder => + { + // FIXME real values for sizes and lowerBounds + // size cannot be known (example: int[]) + arrayShapeEncoder.Shape( + rank: (int)arrayType.Rank, + sizes: ImmutableArray.Empty, + lowerBounds: ImmutableArray.Empty); + }); + + } + else if (type is PointerType pointerType) + { + // TODO there's also signatureTypeEncode.FunctionPointer()/IntPtr()/UIntPtr + var targetType = pointerType.TargetType; + if (targetType.Equals(PlatformTypes.Void)) + { + encoder.VoidPointer(); + } + else + { + Encode(targetType, encoder.Pointer()); + } + } + else if (type is GenericParameter genericParameter) + { + switch (genericParameter.Kind) + { + case GenericParameterKind.Type: + encoder.GenericTypeParameter(genericParameter.Index); + break; + case GenericParameterKind.Method: + encoder.GenericMethodTypeParameter(genericParameter.Index); + break; + } + } + else throw new Exception($"Type {type} not supported"); + } + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Metadata/ReferenceHandleResolver.cs b/MetadataGenerator/Metadata/ReferenceHandleResolver.cs deleted file mode 100644 index 10dc3730..00000000 --- a/MetadataGenerator/Metadata/ReferenceHandleResolver.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using Model; -using Model.Types; -using ECMA335 = System.Reflection.Metadata.Ecma335; -using SRM = System.Reflection.Metadata; - -namespace MetadataGenerator -{ - class ReferenceHandleResolver - { - private readonly Assembly assembly; - private readonly ECMA335.MetadataBuilder metadata; - private readonly IDictionary assemblyReferences = new Dictionary(); - private readonly IDictionary typeReferences = new Dictionary(); - private readonly IDictionary memberReferences = new Dictionary(); - - public ReferenceHandleResolver(ECMA335.MetadataBuilder metadata, Assembly assembly) - { - this.metadata = metadata; - this.assembly = assembly; - - // FIXME: assemblyName => assemblyRef could result in false positive? - foreach (var assemblyReference in assembly.References) - { - // FIXME parameters - assemblyReferences.Add(assemblyReference.Name, metadata.AddAssemblyReference( - name: metadata.GetOrAddString(assemblyReference.Name), - version: new Version(4, 0, 0, 0), - culture: metadata.GetOrAddString("neutral"), - publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), - flags: default, - hashValue: default) - ); - } - } - - /* - * Returns a TypeReference for type. It stores references because metadata does not have a getOrAddTypeReference. - */ - public SRM.TypeReferenceHandle ReferenceHandleOf(IBasicType type) - { - var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{type.Name}"; - if (!typeReferences.TryGetValue(typeReferenceKey, out SRM.TypeReferenceHandle typeReference)) // If stored then return that - { // if not add the new type reference to metadata and store it - SRM.EntityHandle resolutionScope; - if (type.ContainingType == null) // if defined in the namespace then search there - { - resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) - ? default - : assemblyReferences[type.ContainingAssembly.Name]; - } - else - { // if not, recursively get a reference for the containing type and use that as the resolution scopeø - resolutionScope = ReferenceHandleOf(type.ContainingType); - } - typeReference = metadata.AddTypeReference( - resolutionScope: resolutionScope, - @namespace: metadata.GetOrAddString(type.ContainingNamespace), - name: metadata.GetOrAddString(type.Name)); - typeReferences.Add(typeReferenceKey, typeReference); - } - return typeReference; - } - - public SRM.MemberReferenceHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder signature) - { - var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; - if (!memberReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) - { - memberReferenceHandle = metadata.AddMemberReference( - parent: ReferenceHandleOf(method.ContainingType), - name: metadata.GetOrAddString(method.Name), - signature: metadata.GetOrAddBlob(signature)); - memberReferences.Add(key, memberReferenceHandle); - } - return memberReferenceHandle; - } - - // FIXME extract method for both method and field? identical - public SRM.MemberReferenceHandle ReferenceHandleOf(IFieldReference field, SRM.BlobBuilder signature) - { - var key = $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.Name}.{field.Name}"; - if (!memberReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) - { - memberReferenceHandle = metadata.AddMemberReference( - parent: ReferenceHandleOf(field.ContainingType), - name: metadata.GetOrAddString(field.Name), - signature: metadata.GetOrAddBlob(signature)); - memberReferences.Add(key, memberReferenceHandle); - } - return memberReferenceHandle; - } - } -} \ No newline at end of file diff --git a/MetadataGenerator/Metadata/TypeEncoder.cs b/MetadataGenerator/Metadata/TypeEncoder.cs deleted file mode 100644 index b7fe8af2..00000000 --- a/MetadataGenerator/Metadata/TypeEncoder.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Collections.Immutable; -using Model.Types; -using ECMA335 = System.Reflection.Metadata.Ecma335; - -namespace MetadataGenerator -{ - // fixme name - class TypeEncoder - { - private readonly ReferenceHandleResolver referenceHandleResolver; - public TypeEncoder(ReferenceHandleResolver referenceHandleResolver) - { - this.referenceHandleResolver = referenceHandleResolver; - } - - // SignatureTypeEncoder is a struct but it is not necessary to pass it by reference since - // it operates on its Builder (BlobBuilber) which is a class (tha means the builder refernece is always the same) - public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) - { - if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); - else if (type.Equals(PlatformTypes.Byte)) encoder.Byte(); - else if (type.Equals(PlatformTypes.SByte)) encoder.SByte(); - else if (type.Equals(PlatformTypes.Char)) encoder.Char(); - else if (type.Equals(PlatformTypes.Double)) encoder.Double(); - else if (type.Equals(PlatformTypes.Int16)) encoder.Int16(); - else if (type.Equals(PlatformTypes.UInt16)) encoder.UInt16(); - else if (type.Equals(PlatformTypes.Int32)) encoder.Int32(); - else if (type.Equals(PlatformTypes.UInt32)) encoder.UInt32(); - else if (type.Equals(PlatformTypes.Int64)) encoder.Int64(); - else if (type.Equals(PlatformTypes.UInt64)) encoder.UInt64(); - else if (type.Equals(PlatformTypes.String)) encoder.String(); - else if (type.Equals(PlatformTypes.Single)) encoder.Single(); - else if (type.Equals(PlatformTypes.Object)) encoder.Object(); - else - { - if (type is IBasicType basicType) - { - if (basicType.GenericType != null) - { - var genericInstantiation = encoder.GenericInstantiation( - referenceHandleResolver.ReferenceHandleOf(basicType), - basicType.GenericParameterCount, - type.TypeKind == TypeKind.ValueType - ); - foreach (var genericArg in basicType.GenericArguments) - { - Encode(genericArg, genericInstantiation.AddArgument()); - } - } - else - { - encoder.Type(referenceHandleResolver.ReferenceHandleOf(basicType), type.TypeKind == TypeKind.ValueType); - } - } - else if (type is ArrayType arrayType) - { - encoder.Array( - elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), - arrayShapeEncoder => - { - // FIXME real values for sizes and lowerBounds - // size cannot be known (example: int[]) - arrayShapeEncoder.Shape( - rank: (int)arrayType.Rank, - sizes: ImmutableArray.Empty, - lowerBounds: ImmutableArray.Empty); - }); - - } - else if (type is PointerType pointerType) - { - // TODO there's also signatureTypeEncode.FunctionPointer()/IntPtr()/UIntPtr - var targetType = pointerType.TargetType; - if (targetType.Equals(PlatformTypes.Void)) - { - encoder.VoidPointer(); - } - else - { - Encode(targetType, encoder.Pointer()); - } - } - else if (type is GenericParameter genericParameter) - { - switch (genericParameter.Kind) - { - case GenericParameterKind.Type: - encoder.GenericTypeParameter(genericParameter.Index); - break; - case GenericParameterKind.Method: - encoder.GenericMethodTypeParameter(genericParameter.Index); - break; - } - } - else throw new Exception($"Type {type} not supported"); - } - } - } -} \ No newline at end of file diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 93a05dfc..23810121 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -36,8 +36,7 @@ - - + From 928ec4685c0af8aec7d110a493d2f3055564b0ca Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 4 Nov 2019 19:59:26 -0300 Subject: [PATCH 054/256] local variables --- .../Generators/Methods/MethodBodyGenerator.cs | 1 + .../Generators/Methods/MethodGenerator.cs | 9 ++- .../Methods/MethodLocalsGenerator.cs | 73 +++++++++++++++++++ MetadataGenerator/MetadataGenerator.csproj | 1 + 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 MetadataGenerator/Generators/Methods/MethodLocalsGenerator.cs diff --git a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs index 6ddf3372..b2f18402 100644 --- a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs @@ -20,6 +20,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { var controlFlowBuilder = new ECMA335.ControlFlowBuilder(); var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), controlFlowBuilder); + /* var labelMapping = new Dictionary>(); ECMA335.LabelHandle labelHandleFor(string label) { diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index f47043ed..b2c5dd92 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -17,12 +17,14 @@ class MethodGenerator private readonly MetadataContainer metadataContainer; private readonly MethodSignatureGenerator methodSignatureGenerator; private readonly MethodBodyGenerator methodBodyGenerator; + private readonly MethodLocalsGenerator methodLocalsGenerator; public MethodGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); methodBodyGenerator = new MethodBodyGenerator(metadataContainer); + methodLocalsGenerator = new MethodLocalsGenerator(metadataContainer); } public SRM.MethodDefinitionHandle Generate(MethodDefinition method) @@ -47,17 +49,22 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var methodBody = method.HasBody ? metadataContainer.methodBodyStream.AddMethodBody( instructionEncoder: methodBodyGenerator.Generate(method.Body), + localVariablesSignature: methodLocalsGenerator.GenerateLocalVariablesSignatureFor(method.Body), maxStack: method.Body.MaxStack) : default; var nextParameterHandle = ECMA335.MetadataTokens.ParameterHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); - return metadataContainer.metadataBuilder.AddMethodDefinition( + var methodDefinitionHandle = metadataContainer.metadataBuilder.AddMethodDefinition( attributes: GetMethodAttributesFor(method), implAttributes: SR.MethodImplAttributes.IL | SR.MethodImplAttributes.Managed, // FIXME what else? name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), signature: metadataContainer.metadataBuilder.GetOrAddBlob(methodSignature), bodyOffset: methodBody, parameterList: firstParameterHandle ?? nextParameterHandle); + + methodLocalsGenerator.GenerateLocalVariables(method.Body, methodDefinitionHandle); + + return methodDefinitionHandle; } } } diff --git a/MetadataGenerator/Generators/Methods/MethodLocalsGenerator.cs b/MetadataGenerator/Generators/Methods/MethodLocalsGenerator.cs new file mode 100644 index 00000000..11f5d387 --- /dev/null +++ b/MetadataGenerator/Generators/Methods/MethodLocalsGenerator.cs @@ -0,0 +1,73 @@ +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; +namespace MetadataGenerator.Generators.Methods +{ + class MethodLocalsGenerator + { + private readonly MetadataContainer metadataContainer; + + public MethodLocalsGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public SRM.StandaloneSignatureHandle GenerateLocalVariablesSignatureFor(MethodBody body) + { + SRM.StandaloneSignatureHandle localVariablesSignature = default; + if (body?.LocalVariables?.Count > 0) + { + var signature = new SRM.BlobBuilder(); + var encoder = new ECMA335.BlobEncoder(signature).LocalVariableSignature(body.LocalVariables.Count); + foreach (var localVariable in body.LocalVariables) + { + metadataContainer.Encode( + localVariable.Type, + encoder.AddVariable().Type(isByRef: false, isPinned: false) // FIXME hardcoded false + ); + } + // FIXME this adds ad signature everytime? getOrAddBlob though. Locals are most likely different for each method though + localVariablesSignature = metadataContainer.metadataBuilder.AddStandaloneSignature(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + } + return localVariablesSignature; + } + + public void GenerateLocalVariables(MethodBody body, SRM.MethodDefinitionHandle containingMethodHandle) + { + /* FIXME GenerateLocalVariablesSignatureFor solo genera la firma (que se usa para hacer el addMethodBody) + y no agrega las variables por lo que no deberia andar. Sin embargo parece que anda solo con eso. + Ver si es necesario este codigo de abajo o no + No aparecen los nombres de las variables locales (similar a lo que pasaba con los parameters cuadno solo ponia la firma) + Asi que tiene gustito a que es necesario hacer esto. Sin embargo al hacerlo no cambia nada. + Quiza estan mal algunos de los valores de addLocalScope y por eso no anda + */ + if (body?.LocalVariables?.Count > 0) + { + SRM.LocalVariableHandle? firstLocalVariableHandle = null; + foreach (var localVariable in body.LocalVariables) + { + var localVariableHandle = metadataContainer.metadataBuilder.AddLocalVariable( + attributes: SRM.LocalVariableAttributes.None, + index: body.LocalVariables.IndexOf(localVariable), + name: metadataContainer.metadataBuilder.GetOrAddString(localVariable.Name)); + if (!firstLocalVariableHandle.HasValue) + { + firstLocalVariableHandle = localVariableHandle; + } + } + var nextLocalVariableHandle = ECMA335.MetadataTokens.LocalVariableHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalVariable)); + + // FIXME ?? + var nextLocalConstantHandle = ECMA335.MetadataTokens.LocalConstantHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalConstant)); + + metadataContainer.metadataBuilder.AddLocalScope( + method: containingMethodHandle, + importScope: default, // FIXME ?? + variableList: firstLocalVariableHandle ?? nextLocalVariableHandle, + constantList: nextLocalConstantHandle, // FIXME addLocalConstant() + startOffset: default, // FIXME ?? + length: default); // FIXME ?? + } + } + } +} diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 23810121..56336d95 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -39,6 +39,7 @@ + From 95b88086564db0bba4d6d3be90ade0b4008ebfff Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 8 Nov 2019 22:00:06 -0300 Subject: [PATCH 055/256] control flow --- Examples/Examples.cs | 215 +++++++++++------- MetadataGenerator/Extensions.cs | 2 +- .../Body/MethodBodyControlFlowGenerator.cs | 102 +++++++++ .../Methods/{ => Body}/MethodBodyGenerator.cs | 83 ++----- .../{ => Body}/MethodLocalsGenerator.cs | 3 +- MetadataGenerator/MetadataGenerator.csproj | 6 +- 6 files changed, 265 insertions(+), 146 deletions(-) create mode 100644 MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs rename MetadataGenerator/Generators/Methods/{ => Body}/MethodBodyGenerator.cs (86%) rename MetadataGenerator/Generators/Methods/{ => Body}/MethodLocalsGenerator.cs (96%) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 818df5b0..30db80a2 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1,4 +1,5 @@ -using System; +#region metadata +using System; using System.Collections.Generic; namespace Enums @@ -440,7 +441,9 @@ public IList RecievesAndReturnsGenericTypeList(IList listT) } } +#endregion +#region method body namespace MethodBody { public abstract class ContainingClass @@ -495,56 +498,6 @@ public void Comparison(int x) z = x == 1; } - public void ExceptionHandlingTryCatch(int x) - { - try - { - var y = 1 / x; - } - catch - { - - } - } - public void ExceptionHandlingTryCatchSpecific(int x) - { - try - { - var y = 1 / x; - } - catch (Exception ex) - { - - } - } - - public void ExceptionHandlingTryCatchFilter(int x) - { - try - { - var y = 1 / x; - } - catch (Exception ex) when (ex.Message.Contains("by zero")) - { - - } - } - - public void ExceptionHandlingTryCatchFinally(Exception e) - { - try - { - throw e; - } - catch - { - throw; // rethrow - } - finally - { - Console.WriteLine("finally"); - } - } public abstract void NoBody(); @@ -592,14 +545,6 @@ public void Convert(object o) // TODO unbox (unbox ptr) } - public void Branch(bool b) - { - - if (false) { } // br.s $target - - - } - public void LoadConstant() { string s = "hello world!"; // ldstr @@ -727,15 +672,15 @@ public void LoadArray(Exception[] x, int[] q) // TODO ldelem.i ??? // TODO ldelem typeTok ??? - /* - * FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? - unsafe - { - fixed (int* p = &q[0]) // ldelema $type - { - } - } - */ + // + // FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? + // unsafe + // { + // fixed (int* p = &q[0]) // ldelema $type + // { + // } + // } + var l = (new int[] { 1, 2, 3 }).Length; // ldlen } @@ -746,13 +691,12 @@ public void LoadField() var b = new Classes.SimpleClass(1, "b").readOnlyIntField; // ldfld int $field var c = new Classes.ClassWithMoreComplexFieldsAndParamtersOrReturnTypes().b; // ldfld class $field - /* FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? - unsafe - { - fixed (int* d = &(new Classes.SimpleClass(1, "b")).readOnlyIntField) // ldflda int32 $field - { } - } - */ + //FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? + // unsafe + // { + // fixed (int* d = &(new Classes.SimpleClass(1, "b")).readOnlyIntField) // ldflda int32 $field + // { } + // } } public void StoreField() @@ -786,12 +730,123 @@ public void SizeOf() var y = sizeof(int*); // sizeof int* } } - /* - * doesnt work yet + + // doesnt work yet // TODO other cases - public void LoadToken() + // public void LoadToken() + //{ + //var x = typeof(T); + //} + } +} +#endregion + + +// branch and exception handling +#region method body (labels) +namespace MethodBodyBranchesAndExceptionHandling +{ + + public class ContainerClass + { + public void Branch(int a, int b, Exception e) + { + // TODO + // beq + // bge, bge.s + // bge.un, bge.un.s + // bgt, bgt.s + // bgt.un, bgt.un.s + // ble, ble.s + // ble.un, ble.un.s + // blt, blt.s + // blt.un, blt.un.s + // bne, bne.s + // bne.un, bne.un.s + // br (not short form) + // brfalse (not short form) + // brnull.s + // brnull (not short form) + // brzero.s + // brzero (not short form) + // brtrue (not short form) + // brinst.s + // brinst (not short form) + + goto Label; // br.s + Label: + int x; + + if (a > 2) // brfalse.s + { + } + + switch (a) + { + case 2: break; // beq.s + } + + if (e?.Message != null) { } // brtrue.s + + } + + public void ExceptionHandlingTryCatch(int x) { - var x = typeof(T); - }*/ + try + { + var y = 1 / x; + } + catch + { + + } + } + + + public void ExceptionHandlingTryCatchSpecific(int x) + { + try + { + var y = 1 / x; + } + catch (Exception ex) + { + + } + } + + + public void ExceptionHandlingTryCatchFilter(int x) + { + try + { + var y = 1 / x; + } + catch (Exception ex) when (ex.Message.Contains("by zero")) + { + + } + } + + public void ExceptionHandlingTryCatchFinally(Exception e) + { + try + { + throw e; + } + catch + { + throw; // rethrow + } + finally + { + Console.WriteLine("finally"); + } + } + } + } + + +#endregion \ No newline at end of file diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index c02c0ea6..7dea5704 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -27,7 +27,7 @@ public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.Enti // The next available slot in the corresponding table. If nothing is defined in the module then use row number 1 for the corresponding table public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; - public static string CurrentLabelString(this ECMA335.InstructionEncoder instructionEncoder) => string.Format("L_{0:x4}", instructionEncoder.Offset); + public static string CurrentLabelString(this ECMA335.InstructionEncoder instructionEncoder) => string.Format("L_{0:x4}", instructionEncoder.Offset).ToLower(); } } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs new file mode 100644 index 00000000..8d72d651 --- /dev/null +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using Model; +using ECMA335 = System.Reflection.Metadata.Ecma335; + +// This relies on all other instructions are generated correctly. If not, labels don't match (because operations are missing) +namespace MetadataGenerator.Generators.Methods.Body +{ + class MethodBodyControlFlowGenerator + { + private readonly IDictionary labelHandles = new Dictionary(); + private readonly ECMA335.InstructionEncoder instructionEncoder; + private readonly MetadataContainer metadataContainer; + + public MethodBodyControlFlowGenerator(ECMA335.InstructionEncoder instructionEncoder, MetadataContainer metadataContainer) + { + this.instructionEncoder = instructionEncoder; + this.metadataContainer = metadataContainer; + } + + // FIXME hacia afuera quiza no deberia estar esto y en cambio hablar de procesar los branchInstruction o algo asi + // FIXME hay que pensar toda esta clase + public ECMA335.LabelHandle LabelHandleFor(string label) + { + label = label.ToLower(); + if (labelHandles.TryGetValue(label, out var labelHandle)) + { + return labelHandle; + } + else + { + labelHandle = instructionEncoder.DefineLabel(); + labelHandles.Add(label, labelHandle); + + + // FIXME remove + unmarkedLabels.Add(labelHandle); + // + + + } + return labelHandle; + } + + + public void MarkCurrentLabel() + { + if (labelHandles.TryGetValue(instructionEncoder.CurrentLabelString(), out var labelHandle)) + { + instructionEncoder.MarkLabel(labelHandle); + + //FIXME remove + unmarkedLabels.Remove(labelHandle); + // + + } + } + + // Exception handling, relieson other instructions beign generated correctly. If not, labels don't match (because operations are missing) + // FIXME name + public void ProcessExceptionInformation(IList exceptionInformation) + { + var controlFlowBuilder = instructionEncoder.ControlFlowBuilder; + foreach (var protectedBlock in exceptionInformation) + { + var tryStart = LabelHandleFor(protectedBlock.Start); + var tryEnd = LabelHandleFor(protectedBlock.End); + var handlerStart = LabelHandleFor(protectedBlock.Handler.Start); + var handlerEnd = LabelHandleFor(protectedBlock.Handler.End); + + switch (protectedBlock.Handler.Kind) + { + case ExceptionHandlerBlockKind.Filter: + var filterStart = LabelHandleFor(((FilterExceptionHandler)protectedBlock.Handler).FilterStart); + controlFlowBuilder.AddFilterRegion(tryStart, tryEnd, handlerStart, handlerEnd, filterStart); + break; + case ExceptionHandlerBlockKind.Catch: + var catchType = ((CatchExceptionHandler)protectedBlock.Handler).ExceptionType; + controlFlowBuilder.AddCatchRegion(tryStart, tryEnd, handlerStart, handlerEnd, metadataContainer.ResolveReferenceHandleFor(catchType)); + break; + case ExceptionHandlerBlockKind.Fault: + case ExceptionHandlerBlockKind.Finally: + controlFlowBuilder.AddFinallyRegion(tryStart, tryEnd, handlerStart, handlerEnd); + break; + } + } + } + + // FIXME only to develop while all instructions are not generated correctly because if some label results unmarked then + // SRM throws an exception. + private readonly IList unmarkedLabels = new List { }; + [Obsolete("Use only to develop while there are still instructions not being generated correclty")] + public void MarkAllUnmarkedLabels() + { + foreach (var label in unmarkedLabels) + { + instructionEncoder.MarkLabel(label); + + } + } + } +} diff --git a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs similarity index 86% rename from MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs rename to MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index b2f18402..21e8f673 100644 --- a/MetadataGenerator/Generators/Methods/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,4 +1,5 @@ using System; +using MetadataGenerator.Generators.Methods.Body; using Model.ThreeAddressCode.Values; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -18,64 +19,15 @@ public MethodBodyGenerator(MetadataContainer metadataContainer) public ECMA335.InstructionEncoder Generate(MethodBody body) { - var controlFlowBuilder = new ECMA335.ControlFlowBuilder(); - var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), controlFlowBuilder); + var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), new ECMA335.ControlFlowBuilder()); + var controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); - /* var labelMapping = new Dictionary>(); - ECMA335.LabelHandle labelHandleFor(string label) - { - var labelHandle = instructionEncoder.DefineLabel(); - if (labelMapping.TryGetValue(label, out var labelHandles)) - { - labelHandles.Add(labelHandle); - } - else - { - labelMapping.Add(label, new List { labelHandle }); - } - return labelHandle; - }*/ - - /** Exception handling, uncomment once ial other instructions are generated correctly. If not, labels don't match (because operations are missing) - - foreach (var protectedBlock in body.ExceptionInformation) - { - var tryStart = addMapping(protectedBlock.Start); - var tryEnd = addMapping(protectedBlock.End); - var handlerStart = addMapping(protectedBlock.Handler.Start); - var handlerEnd = addMapping(protectedBlock.Handler.End); - - switch (protectedBlock.Handler.Kind) - { - case Model.ExceptionHandlerBlockKind.Filter: // TODO - break; - case Model.ExceptionHandlerBlockKind.Catch: - EntityHandle catchType = referenceHandleResolver.TypeReferenceOf(PlatformTypes.Object); // FIXME - controlFlowBuilder.AddCatchRegion(tryStart, tryEnd, handlerStart, handlerEnd, catchType); - break; - case Model.ExceptionHandlerBlockKind.Fault: // TODO - break; - case Model.ExceptionHandlerBlockKind.Finally: // TODO - break; - } - }*/ + controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); foreach (var instruction in body.Instructions) { + controlFlowGenerator.MarkCurrentLabel(); - /** uncomment once al other instructions are generated correctly. If not, labels don't match (because operations are missing) - * FIXME instruction has offset field. maybe that can be used with instructionsEncoder.offset instead of mapping labels (and using the extension method) - if (labelMapping.TryGetValue(instructionEncoder.CurrentLabelString(), out var labels)) - { - foreach (var label in labels) - { - instructionEncoder.MarkLabel(label); - } - } - */ - - - // FIXME visitor like in the model? or something better than this ifs? if (instruction is Model.Bytecode.BasicInstruction basicInstruction) { switch (basicInstruction.Operation) @@ -208,36 +160,43 @@ ECMA335.LabelHandle labelHandleFor(string label) } else if (instruction is Model.Bytecode.BranchInstruction branchInstruction) { - + var opCode = SRM.ILOpCode.Br_s; switch (branchInstruction.Operation) { - // TODO // This relies on marking labels and that depends on generating all instructions correctly (if not labels don't match) - // There is only one example and it is not tested + // TODO all short forms can also be not short form (ex: br and br.s) and there's "un" variants case Model.Bytecode.BranchOperation.False: + opCode = SRM.ILOpCode.Brfalse_s; break; case Model.Bytecode.BranchOperation.True: + opCode = SRM.ILOpCode.Brtrue_s; break; case Model.Bytecode.BranchOperation.Eq: + opCode = SRM.ILOpCode.Beq_s; break; case Model.Bytecode.BranchOperation.Neq: + opCode = SRM.ILOpCode.Bne_un_s; break; case Model.Bytecode.BranchOperation.Lt: + opCode = SRM.ILOpCode.Blt_s; break; case Model.Bytecode.BranchOperation.Le: + opCode = SRM.ILOpCode.Ble_s; break; case Model.Bytecode.BranchOperation.Gt: + opCode = SRM.ILOpCode.Bgt_s; break; case Model.Bytecode.BranchOperation.Ge: + opCode = SRM.ILOpCode.Bge_s; break; case Model.Bytecode.BranchOperation.Branch: - // FIXME - // instructionEncoder.Branch(SRM.ILOpCode.Br, labelHandleFor(branchInstruction.Target)); - // instructionEncoder.Branch(SRM.ILOpCode.Br_s, labelHandleFor(branchInstruction.Target)); + opCode = SRM.ILOpCode.Br_s; break; case Model.Bytecode.BranchOperation.Leave: + opCode = SRM.ILOpCode.Leave_s; break; } + instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(branchInstruction.Target)); } else if (instruction is Model.Bytecode.ConvertInstruction convertInstruction) { @@ -280,7 +239,6 @@ ECMA335.LabelHandle labelHandleFor(string label) switch (loadlInstruction.Operation) { case Model.Bytecode.LoadOperation.Address: - // FIXME CAST var operandVariable = (IVariable)loadlInstruction.Operand; if (operandVariable.IsParameter) { @@ -292,7 +250,6 @@ ECMA335.LabelHandle labelHandleFor(string label) } break; case Model.Bytecode.LoadOperation.Content: - // FIXME CAST operandVariable = (IVariable)loadlInstruction.Operand; if (operandVariable.IsParameter) { @@ -354,7 +311,7 @@ ECMA335.LabelHandle labelHandleFor(string label) } else if (instruction is Model.Bytecode.LoadFieldInstruction loadFieldInstruction) { - // TODO handle ldflda. Example present but not supported in model? + // TODO handle ldflda. Example present but not supported in model instructionEncoder.OpCode(SRM.ILOpCode.Ldfld); instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field)); @@ -415,6 +372,8 @@ ECMA335.LabelHandle labelHandleFor(string label) else throw new Exception("instruction type not handled"); } + controlFlowGenerator.MarkAllUnmarkedLabels(); + return instructionEncoder; } } diff --git a/MetadataGenerator/Generators/Methods/MethodLocalsGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs similarity index 96% rename from MetadataGenerator/Generators/Methods/MethodLocalsGenerator.cs rename to MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs index 11f5d387..9a885077 100644 --- a/MetadataGenerator/Generators/Methods/MethodLocalsGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs @@ -3,6 +3,7 @@ using SRM = System.Reflection.Metadata; namespace MetadataGenerator.Generators.Methods { + // FIXME name class MethodLocalsGenerator { private readonly MetadataContainer metadataContainer; @@ -38,7 +39,7 @@ public void GenerateLocalVariables(MethodBody body, SRM.MethodDefinitionHandle c y no agrega las variables por lo que no deberia andar. Sin embargo parece que anda solo con eso. Ver si es necesario este codigo de abajo o no No aparecen los nombres de las variables locales (similar a lo que pasaba con los parameters cuadno solo ponia la firma) - Asi que tiene gustito a que es necesario hacer esto. Sin embargo al hacerlo no cambia nada. + Asi que tiene pinta a que es necesario hacer esto. Sin embargo al hacerlo no cambia nada. Quiza estan mal algunos de los valores de addLocalScope y por eso no anda */ if (body?.LocalVariables?.Count > 0) diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 56336d95..f752467e 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -32,14 +32,15 @@ - - + + + @@ -60,6 +61,7 @@ + \ No newline at end of file From c3fc9f4360a6bf8353b28189e16560638efb87b9 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 10 Nov 2019 16:49:21 -0300 Subject: [PATCH 056/256] switch and indirect method call instructions --- Examples/Examples.cs | 60 ++++++++++++++++--- ExamplesEXE/ExamplesEXE.cs | 22 +++++++ ExamplesEXE/ExamplesEXE.csproj | 2 +- ExamplesEXE/Program.cs | 12 ---- .../Body/MethodBodyControlFlowGenerator.cs | 1 + .../Methods/Body/MethodBodyGenerator.cs | 29 ++++++++- .../Methods/MethodSignatureGenerator.cs | 44 ++++++++++---- .../Metadata/MetadataContainer.cs | 2 + .../Metadata/MetadataResolver.cs | 6 ++ 9 files changed, 141 insertions(+), 37 deletions(-) create mode 100644 ExamplesEXE/ExamplesEXE.cs delete mode 100644 ExamplesEXE/Program.cs diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 30db80a2..f97805c6 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -429,6 +429,11 @@ public IList GetExceptionsList(List _) } return new List(); } + public void PrintGeneric(T t) + { + Console.WriteLine(t.ToString()); + } + public E RecievesAndReturnsGenericType(T t, E e) { return e; @@ -509,27 +514,64 @@ public void Alloc() } } - public void Calls(Classes.SimpleClass simpleClass) + // FIXME causes genericParamTableNotSorted + // void Nothing(T arg) { } + + public void Calls(Classes.SimpleClass simpleClass, Action f) { Console.WriteLine("A method call"); // static simpleClass.DoNothing(); // virtual Alloc(); // normal + // f(1); //FIXME not working + // TODO calli (indirect) - } - public void Arrays() - { - var intArray = new int[5]; - var ExceptionArray = new Exception[2]; - var stringInitializedArray = new string[] { "hello", "world", "!" }; + /* not working when reading dll + var g = new Generics.Generic(); + g.PrintGeneric("hola"); + g.PrintGeneric(1); + */ + + // FIXME Nothing(""); generic method call (instantiated) not generated correctly (missing instantiation) + + } + + public void Arrays(Structs.EmptyStruct[] structArray) + { + byte y = 1; + short s = 3; + int x = 2; + long l = 5; + float f = 6; + double d = 7; + Structs.EmptyStruct p; + var byteArray = new byte[2]; // newarr + stelem.ref + var shortArray = new short[2]; // newarr + stelem.ref + var intArray = new int[5]; // newarr + stelem.ref + var longArray = new long[2]; // newarr + stelem.ref + var floatArray = new float[2]; // newarr + stelem.ref + var doubleArray = new double[2]; // newarr + stelem.ref + var exceptionArray = new Exception[2]; // newarr + stelem.ref + var stringInitializedArray = new string[] { "hello", "world", "!" }; // newarr + stelem.ref unsafe { - var m = new int*[5]; - var k = new int**[2]; + var m = new int*[5]; // newarr + stelem.ref + var k = new int**[2]; // newarr + stelem.ref } + + byteArray[1] = y; // stelem.i1 + shortArray[1] = s; // stelem.i2 + intArray[1] = x; // stelem.i4 + longArray[1] = l; // stelem.i8 + floatArray[1] = f; // stelem.r4 + doubleArray[1] = d; // stelem.r8 + structArray[0] = p; // stelem + // TODO stelem.i } + public void Empty() { } + public void Convert(object o) { string s = (string)(object)"asd"; // castclass $class diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs new file mode 100644 index 00000000..446c19c1 --- /dev/null +++ b/ExamplesEXE/ExamplesEXE.cs @@ -0,0 +1,22 @@ +namespace ExamplesEXE +{ + public class MainClass + { + public static void Main(string[] args) + { + new Other.SomeClass().Print("hola"); + } + } +} + +namespace Other +{ + + public class SomeClass + { + public void Print(T arg) + { + System.Console.WriteLine(); + } + } +} diff --git a/ExamplesEXE/ExamplesEXE.csproj b/ExamplesEXE/ExamplesEXE.csproj index 7a5d8886..a3c936ba 100644 --- a/ExamplesEXE/ExamplesEXE.csproj +++ b/ExamplesEXE/ExamplesEXE.csproj @@ -30,7 +30,7 @@ - + diff --git a/ExamplesEXE/Program.cs b/ExamplesEXE/Program.cs deleted file mode 100644 index c95e6119..00000000 --- a/ExamplesEXE/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace ExamplesEXE -{ - public class MainClass - { - public static void Main(string[] args) - { - Console.WriteLine("Hola"); - } - } -} diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index 8d72d651..a5472e0d 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -6,6 +6,7 @@ // This relies on all other instructions are generated correctly. If not, labels don't match (because operations are missing) namespace MetadataGenerator.Generators.Methods.Body { + // FIXME name class MethodBodyControlFlowGenerator { private readonly IDictionary labelHandles = new Dictionary(); diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 21e8f673..90843db8 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using MetadataGenerator.Generators.Methods.Body; using Model.ThreeAddressCode.Values; using Model.Types; @@ -356,7 +357,17 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(storeFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeFieldInstruction.Field)); } - else if (instruction is Model.Bytecode.SwitchInstruction switchInstruction) { } + else if (instruction is Model.Bytecode.SwitchInstruction switchInstruction) + { + // TODO test. This instructions that are difficuly to generate in example can be generated programatically (new SwitchInstruction...) + // maybe have an example files that generates all this instructions that are missing + instructionEncoder.OpCode(SRM.ILOpCode.Switch); + instructionEncoder.Token(switchInstruction.Targets.Count); + switchInstruction.Targets + .Select(label => int.Parse(label.Substring(2), System.Globalization.NumberStyles.HexNumber)) + .ToList() + .ForEach(instructionEncoder.Token); + } else if (instruction is Model.Bytecode.SizeofInstruction sizeofInstruction) { instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); @@ -367,8 +378,20 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadTokenInstruction.Token)); } - else if (instruction is Model.Bytecode.IndirectMethodCallInstruction indirectMethodCallInstruction) { } - else if (instruction is Model.Bytecode.StoreArrayElementInstruction storeArrayElementInstruction) { } + else if (instruction is Model.Bytecode.IndirectMethodCallInstruction indirectMethodCallInstruction) + { // TODO test + var methodSignature = metadataContainer.ResolveStandaloneSignatureFor(indirectMethodCallInstruction.Function); + instructionEncoder.CallIndirect(methodSignature); + } + else if (instruction is Model.Bytecode.StoreArrayElementInstruction storeArrayElementInstruction) + { + // FIXME + // Framework currently handles this as a BasicInstruction and this is never generated. Should use this one + // example already generated + // the implementation should be like load instruction + // instructionEncoder.OpCode(SRM.ILOpCode.Stelem_X); + // instructionEncoder.Token(value); + } else throw new Exception("instruction type not handled"); } diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 8df33ba6..c0744d7c 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -1,4 +1,5 @@ -using Model.Types; +using System.Collections.Generic; +using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -14,36 +15,55 @@ public MethodSignatureGenerator(MetadataContainer metadataContainer) } public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) + { + return GenerateMethodSignature(method.IsStatic, method.GenericParameterCount, method.Parameters, method.ReturnType); + } + public SRM.BlobBuilder GenerateSignatureOf(FunctionPointerType method) + { + // FIXME 0 because FunctionPointerType does not have that property (there's a fixme in that class) + return GenerateMethodSignature(method.IsStatic, 0, method.Parameters, method.ReturnType); + } + + private SRM.BlobBuilder GenerateMethodSignature(bool isStatic, int genericParameterCount, IList parameters, IType returnType) { var methodSignature = new SRM.BlobBuilder(); new ECMA335.BlobEncoder(methodSignature) - .MethodSignature(isInstanceMethod: !method.IsStatic, genericParameterCount: method.GenericParameterCount) + .MethodSignature(isInstanceMethod: !isStatic, genericParameterCount: genericParameterCount) .Parameters( - method.Parameters.Count, - returnType => + parameters.Count, + returnTypeEncoder => { - if (method.ReturnType.Equals(PlatformTypes.Void)) + if (returnType.Equals(PlatformTypes.Void)) { - returnType.Void(); + returnTypeEncoder.Void(); } else { // TODO isByRef param. ref in return type is not in the model - var encoder = returnType.Type(); - metadataContainer.Encode(method.ReturnType, encoder); + var encoder = returnTypeEncoder.Type(); + metadataContainer.Encode(returnType, encoder); } - }, - parameters => + parametersEncoder => { - foreach (var parameter in method.Parameters) + foreach (var parameter in parameters) { bool isByRef = parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref); var type = isByRef ? (parameter.Type as PointerType).TargetType : parameter.Type; - var encoder = parameters.AddParameter().Type(isByRef); + var encoder = parametersEncoder.AddParameter().Type(isByRef); metadataContainer.Encode(type, encoder); } }); + + /* // FIXME ???? falta agregar la instanciacion en caso de llamado a un generic method???? algo asi? + if (method.GenericMethod != null) + { + var genericParameterEncoder = new ECMA335.BlobEncoder(methodSignature).MethodSpecificationSignature(method.GenericParameterCount); + foreach (var param in method.GenericMethod.ResolvedMethod.GenericParameters) + { + metadataContainer.Encode(param, genericParameterEncoder.AddArgument()); + } + }*/ return methodSignature; } } diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 41122f2f..4edaba52 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -31,6 +31,8 @@ public MetadataContainer(Assembly assembly) metadataResolver = new MetadataResolver(this, assembly); } + //FIXME name, more generic? only needed for method? + public SRM.StandaloneSignatureHandle ResolveStandaloneSignatureFor(FunctionPointerType method) => metadataResolver.ResolveStandaloneSignatureFor(method); public SRM.EntityHandle ResolveReferenceHandleFor(IMetadataReference metadataReference) => metadataResolver.ReferenceHandleOf(metadataReference); public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) => metadataResolver.Encode(type, encoder); } diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index c2c6e0ed..3b8d9aec 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -42,6 +42,12 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); } + //FIXME name? more generic? only needed for method? + public SRM.StandaloneSignatureHandle ResolveStandaloneSignatureFor(FunctionPointerType method) + { + var signature = methodSignatureGenerator.GenerateSignatureOf(method); + return metadataContainer.metadataBuilder.AddStandaloneSignature(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + } public SRM.EntityHandle ReferenceHandleOf(IMetadataReference metadataReference) { From 545ce5a77cfc48b4fceea56138a6522fd54459e6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 11 Nov 2019 23:37:14 -0300 Subject: [PATCH 057/256] convert instruction --- Examples/Examples.cs | 46 +++++++++---------- .../Methods/Body/MethodBodyGenerator.cs | 44 ++++++++++++++++-- .../Methods/MethodSignatureGenerator.cs | 10 ---- 3 files changed, 64 insertions(+), 36 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index f97805c6..da553afe 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1,5 +1,4 @@ -#region metadata -using System; +using System; using System.Collections.Generic; namespace Enums @@ -414,7 +413,7 @@ public ref Exception RefException() // FIXME generation almost correct. namespace Generics { - public class Generic + public class Generic where D : Exception // FIXME generic constraint not in the model { public C genericClassTypeField; public Dictionary genericField; @@ -434,6 +433,10 @@ public void PrintGeneric(T t) Console.WriteLine(t.ToString()); } + public void MethodWithGenericConstraint(T t) where T : Enum // FIXME generic constraint not in the model + { + } + public E RecievesAndReturnsGenericType(T t, E e) { return e; @@ -446,9 +449,6 @@ public IList RecievesAndReturnsGenericTypeList(IList listT) } } -#endregion - -#region method body namespace MethodBody { public abstract class ContainingClass @@ -574,6 +574,22 @@ public void Empty() { } public void Convert(object o) { + long x1 = 1; + double d = 1.0; + sbyte x2 = (sbyte)x1; // conv.i1 + short x3 = (short)x1; // conv.i2 + int x4 = (int)x1; // conv.i4 + x1 = (long)d; // conv.i8 + float f = (float)d; // conv.r4 + //TODO conv.r8 + byte x5 = (byte)x1; // conv.u1 + ushort x6 = (ushort)x1; // conv.u2 + uint x7 = (uint)x1; // conv.u4 + var x8 = (ulong)d; // conv.u8 + // TODO conv.i + // TODO conv.u + // TODO conv.r.un + string s = (string)(object)"asd"; // castclass $class var x = (int[])(object)new int[] { }; @@ -779,18 +795,7 @@ public void SizeOf() //{ //var x = typeof(T); //} - } -} -#endregion - -// branch and exception handling -#region method body (labels) -namespace MethodBodyBranchesAndExceptionHandling -{ - - public class ContainerClass - { public void Branch(int a, int b, Exception e) { // TODO @@ -885,10 +890,5 @@ public void ExceptionHandlingTryCatchFinally(Exception e) Console.WriteLine("finally"); } } - } - -} - - -#endregion \ No newline at end of file +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 90843db8..2bcb365e 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -8,8 +8,6 @@ namespace MetadataGenerator.Generators.Methods { - // review all instructions of the ecma pdf - // review overflow and other checks that instructions have class MethodBodyGenerator { private readonly MetadataContainer metadataContainer; @@ -203,8 +201,48 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { switch (convertInstruction.Operation) { + // TODO overflow variants and conv.i, conv.u, conv.r.un case Model.Bytecode.ConvertOperation.Conv: - // TODO + if (convertInstruction.ConversionType.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i1); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u1); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i2); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u2); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i4); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u4); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u8); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_r4); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_r8); + } break; case Model.Bytecode.ConvertOperation.Cast: instructionEncoder.OpCode(SRM.ILOpCode.Castclass); diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index c0744d7c..31e44a5a 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -54,16 +54,6 @@ private SRM.BlobBuilder GenerateMethodSignature(bool isStatic, int genericParame metadataContainer.Encode(type, encoder); } }); - - /* // FIXME ???? falta agregar la instanciacion en caso de llamado a un generic method???? algo asi? - if (method.GenericMethod != null) - { - var genericParameterEncoder = new ECMA335.BlobEncoder(methodSignature).MethodSpecificationSignature(method.GenericParameterCount); - foreach (var param in method.GenericMethod.ResolvedMethod.GenericParameters) - { - metadataContainer.Encode(param, genericParameterEncoder.AddArgument()); - } - }*/ return methodSignature; } } From 8214d4ea506e08ed0c8e5d8ac11dc3638182aa5a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 16 Nov 2019 16:28:04 -0300 Subject: [PATCH 058/256] refactor and restyling (rider) --- .gitignore | 1 + Console/Program.cs | 59 +- Examples/Examples.cs | 1 - ExamplesEXE/ExamplesEXE.cs | 14 +- ExamplesEXE/ExamplesEXE.csproj | 2 +- MetadataGenerator/Extensions.cs | 8 +- .../{Generators => }/Generator.cs | 9 +- .../Generators/AssemblyGenerator.cs | 20 +- .../Generators/Fields/FieldGenerator.cs | 15 +- .../Fields/FieldSignatureGenerator.cs | 8 +- .../Body/MethodBodyControlFlowGenerator.cs | 31 +- .../Methods/Body/MethodBodyGenerator.cs | 806 +++++++++--------- .../Methods/Body/MethodLocalsGenerator.cs | 29 +- .../Generators/Methods/MethodGenerator.cs | 18 +- .../Methods/MethodSignatureGenerator.cs | 28 +- .../Generators/NamespaceGenerator.cs | 14 +- MetadataGenerator/Generators/TypeGenerator.cs | 62 +- .../{ => Metadata}/AttributesProvider.cs | 63 +- .../Metadata/MetadataContainer.cs | 18 +- .../Metadata/MetadataResolver.cs | 244 +++--- MetadataGenerator/MetadataGenerator.csproj | 4 +- 21 files changed, 760 insertions(+), 694 deletions(-) rename MetadataGenerator/{Generators => }/Generator.cs (83%) rename MetadataGenerator/{ => Metadata}/AttributesProvider.cs (72%) diff --git a/.gitignore b/.gitignore index b6bf094e..21853cf1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ obj .vs /packages .DS_Store +.idea diff --git a/Console/Program.cs b/Console/Program.cs index d4283981..ab5dbbfa 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -1,20 +1,21 @@ -// Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Linq; -using Backend.Analyses; -using Backend.Model; -using Backend.Serialization; -using Backend.Transformations; -using Backend.Utils; +// Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. + +using System.Linq; +using Backend.Analyses; +using Backend.Model; +using Backend.Serialization; +using Backend.Transformations; +using Backend.Utils; using MetadataGenerator; -//using CCIProvider; -using MetadataProvider; -using Model; -using Model.Types; -using Bytecode = Model.Bytecode; -using Tac = Model.ThreeAddressCode.Instructions; - -namespace Console +using MetadataGenerator.Generators; +//using CCIProvider; +using MetadataProvider; +using Model; +using Model.Types; +using Bytecode = Model.Bytecode; +using Tac = Model.ThreeAddressCode.Instructions; + +namespace Console { class Program { @@ -362,26 +363,23 @@ private static void RunInterPointsToTests() FieldEffectsInfo effectsInfo; ok = effectsResult.TryGetValue(method, out effectsInfo); } - } - + } + private static void DisassembleAndThenAssemble(string input) { - var host = new Host(); - + var host = new Host(); + PlatformTypes.Resolve(host); var loader = new MetadataProvider.Loader(host); loader.LoadAssembly(input); - var generator = new Generator(); - - foreach (var assembly in host.Assemblies) - { - generator.Generate(assembly); - } + var generator = new MetadataGenerator.Generator(); - System.Console.WriteLine("Done!"); - + foreach (var assembly in host.Assemblies) + { + generator.Generate(assembly); + } } @@ -395,7 +393,6 @@ static void Main(string[] args) //RunInterPointsToTests(); System.Console.WriteLine("Done!"); - System.Console.ReadKey(); } - } -} + } +} diff --git a/Examples/Examples.cs b/Examples/Examples.cs index da553afe..4e629e96 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -374,7 +374,6 @@ public class NestedNestedB { } } } } - } // FIXME ref and out are beign generated like type*& instead of type&. That is because the type a & type in the model is represented as a pointer type. diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 446c19c1..e229b79e 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -1,22 +1,24 @@ -namespace ExamplesEXE +using System; +using Other; + +namespace ExamplesEXE { - public class MainClass + public static class MainClass { public static void Main(string[] args) { - new Other.SomeClass().Print("hola"); + new SomeClass().Print("hola"); } } } namespace Other { - public class SomeClass { public void Print(T arg) { - System.Console.WriteLine(); + Console.WriteLine(arg); } } -} +} \ No newline at end of file diff --git a/ExamplesEXE/ExamplesEXE.csproj b/ExamplesEXE/ExamplesEXE.csproj index a3c936ba..5482406b 100644 --- a/ExamplesEXE/ExamplesEXE.csproj +++ b/ExamplesEXE/ExamplesEXE.csproj @@ -7,7 +7,7 @@ Exe ExamplesEXE ExamplesEXE - v4.7 + v4.5 true diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index 7dea5704..c540235d 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -5,14 +5,13 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -// TODO separate in namespaces (Collection, Metadata, etc)? is there a convention for extensions? namespace MetadataGenerator { public static class Extensions { public static T FirstOr(this IEnumerable enumerable, T defaultValue) { - T first = enumerable.FirstOrDefault(); + var first = enumerable.FirstOrDefault(); return first.Equals(default(T)) ? defaultValue : first; } @@ -27,7 +26,6 @@ public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.Enti // The next available slot in the corresponding table. If nothing is defined in the module then use row number 1 for the corresponding table public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; - public static string CurrentLabelString(this ECMA335.InstructionEncoder instructionEncoder) => string.Format("L_{0:x4}", instructionEncoder.Offset).ToLower(); - + public static string CurrentLabelString(this ECMA335.InstructionEncoder instructionEncoder) => $"L_{instructionEncoder.Offset:x4}".ToLower(); } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Generator.cs b/MetadataGenerator/Generator.cs similarity index 83% rename from MetadataGenerator/Generators/Generator.cs rename to MetadataGenerator/Generator.cs index 91f5cb2a..2076926f 100644 --- a/MetadataGenerator/Generators/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -1,4 +1,5 @@ using System.IO; +using MetadataGenerator.Generators; using Model; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -11,12 +12,14 @@ public class Generator : IGenerator public void Generate(Assembly assembly) { using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) - // using (var peStream = File.OpenWrite($"./{assembly.Name}.exe")) + // using (var peStream = File.OpenWrite($"./{assembly.Name}.exe")) { var metadataContainer = AssemblyGenerator.Generate(assembly); var peHeaderBuilder = new SRPE.PEHeaderBuilder( - imageCharacteristics: metadataContainer.Executable ? SRPE.Characteristics.ExecutableImage : SRPE.Characteristics.Dll - ); + imageCharacteristics: metadataContainer.Executable + ? SRPE.Characteristics.ExecutableImage + : SRPE.Characteristics.Dll + ); var peBlob = new SRM.BlobBuilder(); new SRPE.ManagedPEBuilder( header: peHeaderBuilder, diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index 99f6bcf3..b3ec33da 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -1,11 +1,11 @@ using System; -using MetadataGenerator.Generators; +using MetadataGenerator.Metadata; using Model; using SR = System.Reflection; -namespace MetadataGenerator +namespace MetadataGenerator.Generators { - static class AssemblyGenerator + internal static class AssemblyGenerator { public static MetadataContainer Generate(Assembly assembly) { @@ -28,15 +28,13 @@ public static MetadataContainer Generate(Assembly assembly) hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1); metadataBuilder.AddModule( - generation: 0, - moduleName: metadataBuilder.GetOrAddString($"{assembly.Name}.{(metadataContainer.Executable ? "exe" : "dll")}"), - mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), - encId: metadataBuilder.GetOrAddGuid(Guid.Empty), - encBaseId: metadataBuilder.GetOrAddGuid(Guid.Empty)); + generation: 0, + moduleName: metadataBuilder.GetOrAddString($"{assembly.Name}.{(metadataContainer.Executable ? "exe" : "dll")}"), + mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), + encId: metadataBuilder.GetOrAddGuid(Guid.Empty), + encBaseId: metadataBuilder.GetOrAddGuid(Guid.Empty)); return metadataContainer; } } -} - - +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Fields/FieldGenerator.cs b/MetadataGenerator/Generators/Fields/FieldGenerator.cs index b7a4f8a7..82b04d83 100644 --- a/MetadataGenerator/Generators/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldGenerator.cs @@ -1,10 +1,11 @@ -using MetadataGenerator.Generators.Fields; +using MetadataGenerator.Metadata; using Model.Types; -using static MetadataGenerator.AttributesProvider; +using static MetadataGenerator.Metadata.AttributesProvider; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator + +namespace MetadataGenerator.Generators.Fields { - class FieldGenerator + internal class FieldGenerator { private readonly MetadataContainer metadataContainer; private readonly FieldSignatureGenerator fieldSignatureGenerator; @@ -19,9 +20,9 @@ public SRM.FieldDefinitionHandle Generate(FieldDefinition field) { var fieldSignature = fieldSignatureGenerator.GenerateSignatureOf(field); var fieldDefinitionHandle = metadataContainer.metadataBuilder.AddFieldDefinition( - attributes: GetFieldAttributesFor(field), - name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), - signature: metadataContainer.metadataBuilder.GetOrAddBlob(fieldSignature)); + attributes: GetFieldAttributesFor(field), + name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), + signature: metadataContainer.metadataBuilder.GetOrAddBlob(fieldSignature)); if (field.Value != null) { diff --git a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs index bb88ba98..67a79032 100644 --- a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs @@ -1,9 +1,11 @@ -using Model.Types; +using MetadataGenerator.Metadata; +using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; + namespace MetadataGenerator.Generators.Fields { - class FieldSignatureGenerator + internal class FieldSignatureGenerator { private readonly MetadataContainer metadataContainer; @@ -19,4 +21,4 @@ public SRM.BlobBuilder GenerateSignatureOf(IFieldReference field) return fieldSignature; } } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index a5472e0d..d9e4adf1 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -1,13 +1,12 @@ using System; using System.Collections.Generic; +using MetadataGenerator.Metadata; using Model; using ECMA335 = System.Reflection.Metadata.Ecma335; -// This relies on all other instructions are generated correctly. If not, labels don't match (because operations are missing) namespace MetadataGenerator.Generators.Methods.Body { - // FIXME name - class MethodBodyControlFlowGenerator + internal class MethodBodyControlFlowGenerator { private readonly IDictionary labelHandles = new Dictionary(); private readonly ECMA335.InstructionEncoder instructionEncoder; @@ -24,11 +23,7 @@ public MethodBodyControlFlowGenerator(ECMA335.InstructionEncoder instructionEnco public ECMA335.LabelHandle LabelHandleFor(string label) { label = label.ToLower(); - if (labelHandles.TryGetValue(label, out var labelHandle)) - { - return labelHandle; - } - else + if (!labelHandles.TryGetValue(label, out var labelHandle)) { labelHandle = instructionEncoder.DefineLabel(); labelHandles.Add(label, labelHandle); @@ -37,9 +32,8 @@ public ECMA335.LabelHandle LabelHandleFor(string label) // FIXME remove unmarkedLabels.Add(labelHandle); // - - } + return labelHandle; } @@ -53,11 +47,9 @@ public void MarkCurrentLabel() //FIXME remove unmarkedLabels.Remove(labelHandle); // - } } - // Exception handling, relieson other instructions beign generated correctly. If not, labels don't match (because operations are missing) // FIXME name public void ProcessExceptionInformation(IList exceptionInformation) { @@ -72,12 +64,13 @@ public void ProcessExceptionInformation(IList exceptionInformati switch (protectedBlock.Handler.Kind) { case ExceptionHandlerBlockKind.Filter: - var filterStart = LabelHandleFor(((FilterExceptionHandler)protectedBlock.Handler).FilterStart); + var filterStart = LabelHandleFor(((FilterExceptionHandler) protectedBlock.Handler).FilterStart); controlFlowBuilder.AddFilterRegion(tryStart, tryEnd, handlerStart, handlerEnd, filterStart); break; case ExceptionHandlerBlockKind.Catch: - var catchType = ((CatchExceptionHandler)protectedBlock.Handler).ExceptionType; - controlFlowBuilder.AddCatchRegion(tryStart, tryEnd, handlerStart, handlerEnd, metadataContainer.ResolveReferenceHandleFor(catchType)); + var catchType = ((CatchExceptionHandler) protectedBlock.Handler).ExceptionType; + controlFlowBuilder.AddCatchRegion(tryStart, tryEnd, handlerStart, handlerEnd, + metadataContainer.ResolveReferenceHandleFor(catchType)); break; case ExceptionHandlerBlockKind.Fault: case ExceptionHandlerBlockKind.Finally: @@ -89,15 +82,15 @@ public void ProcessExceptionInformation(IList exceptionInformati // FIXME only to develop while all instructions are not generated correctly because if some label results unmarked then // SRM throws an exception. - private readonly IList unmarkedLabels = new List { }; - [Obsolete("Use only to develop while there are still instructions not being generated correclty")] + private readonly IList unmarkedLabels = new List(); + + [Obsolete("Use only to develop while there are still instructions not being generated correctly")] public void MarkAllUnmarkedLabels() { foreach (var label in unmarkedLabels) { instructionEncoder.MarkLabel(label); - } } } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 2bcb365e..a803a32f 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,16 +1,19 @@ using System; +using System.Globalization; using System.Linq; -using MetadataGenerator.Generators.Methods.Body; +using MetadataGenerator.Metadata; +using Model.Bytecode; using Model.ThreeAddressCode.Values; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators.Methods +namespace MetadataGenerator.Generators.Methods.Body { - class MethodBodyGenerator + internal class MethodBodyGenerator { private readonly MetadataContainer metadataContainer; + public MethodBodyGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; @@ -27,415 +30,424 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { controlFlowGenerator.MarkCurrentLabel(); - if (instruction is Model.Bytecode.BasicInstruction basicInstruction) + switch (instruction) { - switch (basicInstruction.Operation) - { - // TODO - // check overflow for variants (ej: add, add_ovf, add_ovf_un) - // see all IlOpCode constants and ECMA + case BasicInstruction basicInstruction: + switch (basicInstruction.Operation) + { + // TODO + // check overflow for variants (ej: add, add_ovf, add_ovf_un) + // see all IlOpCode constants and ECMA - case Model.Bytecode.BasicOperation.Nop: - instructionEncoder.OpCode(SRM.ILOpCode.Nop); - break; - case Model.Bytecode.BasicOperation.Add: - instructionEncoder.OpCode(SRM.ILOpCode.Add); - break; - case Model.Bytecode.BasicOperation.Sub: - instructionEncoder.OpCode(SRM.ILOpCode.Sub); - break; - case Model.Bytecode.BasicOperation.Mul: - instructionEncoder.OpCode(SRM.ILOpCode.Mul); - break; - case Model.Bytecode.BasicOperation.Div: - instructionEncoder.OpCode(SRM.ILOpCode.Div); - break; - case Model.Bytecode.BasicOperation.Rem: - instructionEncoder.OpCode(SRM.ILOpCode.Rem); - break; - case Model.Bytecode.BasicOperation.And: - instructionEncoder.OpCode(SRM.ILOpCode.And); - break; - case Model.Bytecode.BasicOperation.Or: - instructionEncoder.OpCode(SRM.ILOpCode.Or); - break; - case Model.Bytecode.BasicOperation.Xor: - instructionEncoder.OpCode(SRM.ILOpCode.Xor); - break; - case Model.Bytecode.BasicOperation.Shl: - instructionEncoder.OpCode(SRM.ILOpCode.Shl); - break; - case Model.Bytecode.BasicOperation.Shr: - instructionEncoder.OpCode(SRM.ILOpCode.Shr); - break; - case Model.Bytecode.BasicOperation.Eq: - instructionEncoder.OpCode(SRM.ILOpCode.Ceq); - break; - case Model.Bytecode.BasicOperation.Lt: - instructionEncoder.OpCode(SRM.ILOpCode.Clt); - break; - case Model.Bytecode.BasicOperation.Gt: - instructionEncoder.OpCode(SRM.ILOpCode.Cgt); - break; - case Model.Bytecode.BasicOperation.Throw: - instructionEncoder.OpCode(SRM.ILOpCode.Throw); - break; - case Model.Bytecode.BasicOperation.Rethrow: - instructionEncoder.OpCode(SRM.ILOpCode.Rethrow); - break; - case Model.Bytecode.BasicOperation.Not: - instructionEncoder.OpCode(SRM.ILOpCode.Not); - break; - case Model.Bytecode.BasicOperation.Neg: - instructionEncoder.OpCode(SRM.ILOpCode.Neg); - break; - case Model.Bytecode.BasicOperation.Pop: - instructionEncoder.OpCode(SRM.ILOpCode.Pop); - break; - case Model.Bytecode.BasicOperation.Dup: - instructionEncoder.OpCode(SRM.ILOpCode.Dup); - break; - case Model.Bytecode.BasicOperation.EndFinally: - instructionEncoder.OpCode(SRM.ILOpCode.Endfinally); - break; - case Model.Bytecode.BasicOperation.EndFilter: - instructionEncoder.OpCode(SRM.ILOpCode.Endfilter); - break; - case Model.Bytecode.BasicOperation.LocalAllocation: - instructionEncoder.OpCode(SRM.ILOpCode.Localloc); - break; - case Model.Bytecode.BasicOperation.InitBlock: - instructionEncoder.OpCode(SRM.ILOpCode.Initblk); - break; - case Model.Bytecode.BasicOperation.InitObject: - // FIXME InitObject needs an operand (should not be BasicInstruction) - // instructionEncoder.OpCode(ILOpCode.Initobj); - // instructionEncoder.Token(type) - break; - case Model.Bytecode.BasicOperation.CopyObject: - // FIXME CopyObject needs an operand (should not be BasicInstruction) - break; - case Model.Bytecode.BasicOperation.CopyBlock: - instructionEncoder.OpCode(SRM.ILOpCode.Cpblk); - break; - case Model.Bytecode.BasicOperation.LoadArrayLength: - instructionEncoder.OpCode(SRM.ILOpCode.Ldlen); - break; - case Model.Bytecode.BasicOperation.IndirectLoad: - // FIXME IndirectLoad needs an operand (should not be BasicInstruction) - // TODO depending on type of operand instructionEncoder.OpCode(SRM.ILOpCode.Ldind_X); - // example is already generated for all variants - break; - case Model.Bytecode.BasicOperation.LoadArrayElement: - // FIXME LoadArrayElement needs an operand (should not be BasicInstruction) - // TODO depending on type of operand instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_X); - // example is already generated - break; - case Model.Bytecode.BasicOperation.LoadArrayElementAddress: - // FIXME LoadArrayElementAddress needs an operand (should not be BasicInstruction) - // instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); - // instructionEncoder.token(type); - // example is already generated - break; - case Model.Bytecode.BasicOperation.IndirectStore: - // FIXME IndirectStore needs an operand (should not be BasicInstruction) - // instructionEncoder.OpCode(SRM.ILOpCode.Stobj); - // instructionEncoder.token(); - break; - case Model.Bytecode.BasicOperation.StoreArrayElement: - // FIXME StoreArrayElement needs an operand (should not be BasicInstruction) - // instructionEncoder.OpCode(SRM.ILOpCode.Stelem_X); + case BasicOperation.Nop: + instructionEncoder.OpCode(SRM.ILOpCode.Nop); + break; + case BasicOperation.Add: + instructionEncoder.OpCode(SRM.ILOpCode.Add); + break; + case BasicOperation.Sub: + instructionEncoder.OpCode(SRM.ILOpCode.Sub); + break; + case BasicOperation.Mul: + instructionEncoder.OpCode(SRM.ILOpCode.Mul); + break; + case BasicOperation.Div: + instructionEncoder.OpCode(SRM.ILOpCode.Div); + break; + case BasicOperation.Rem: + instructionEncoder.OpCode(SRM.ILOpCode.Rem); + break; + case BasicOperation.And: + instructionEncoder.OpCode(SRM.ILOpCode.And); + break; + case BasicOperation.Or: + instructionEncoder.OpCode(SRM.ILOpCode.Or); + break; + case BasicOperation.Xor: + instructionEncoder.OpCode(SRM.ILOpCode.Xor); + break; + case BasicOperation.Shl: + instructionEncoder.OpCode(SRM.ILOpCode.Shl); + break; + case BasicOperation.Shr: + instructionEncoder.OpCode(SRM.ILOpCode.Shr); + break; + case BasicOperation.Eq: + instructionEncoder.OpCode(SRM.ILOpCode.Ceq); + break; + case BasicOperation.Lt: + instructionEncoder.OpCode(SRM.ILOpCode.Clt); + break; + case BasicOperation.Gt: + instructionEncoder.OpCode(SRM.ILOpCode.Cgt); + break; + case BasicOperation.Throw: + instructionEncoder.OpCode(SRM.ILOpCode.Throw); + break; + case BasicOperation.Rethrow: + instructionEncoder.OpCode(SRM.ILOpCode.Rethrow); + break; + case BasicOperation.Not: + instructionEncoder.OpCode(SRM.ILOpCode.Not); + break; + case BasicOperation.Neg: + instructionEncoder.OpCode(SRM.ILOpCode.Neg); + break; + case BasicOperation.Pop: + instructionEncoder.OpCode(SRM.ILOpCode.Pop); + break; + case BasicOperation.Dup: + instructionEncoder.OpCode(SRM.ILOpCode.Dup); + break; + case BasicOperation.EndFinally: + instructionEncoder.OpCode(SRM.ILOpCode.Endfinally); + break; + case BasicOperation.EndFilter: + instructionEncoder.OpCode(SRM.ILOpCode.Endfilter); + break; + case BasicOperation.LocalAllocation: + instructionEncoder.OpCode(SRM.ILOpCode.Localloc); + break; + case BasicOperation.InitBlock: + instructionEncoder.OpCode(SRM.ILOpCode.Initblk); + break; + case BasicOperation.InitObject: + // FIXME InitObject needs an operand (should not be BasicInstruction) + // instructionEncoder.OpCode(ILOpCode.Initobj); + // instructionEncoder.Token(type) + break; + case BasicOperation.CopyObject: + // FIXME CopyObject needs an operand (should not be BasicInstruction) + break; + case BasicOperation.CopyBlock: + instructionEncoder.OpCode(SRM.ILOpCode.Cpblk); + break; + case BasicOperation.LoadArrayLength: + instructionEncoder.OpCode(SRM.ILOpCode.Ldlen); + break; + case BasicOperation.IndirectLoad: + // FIXME IndirectLoad needs an operand (should not be BasicInstruction) + // TODO depending on type of operand instructionEncoder.OpCode(SRM.ILOpCode.Ldind_X); + // example is already generated for all variants + break; + case BasicOperation.LoadArrayElement: + // FIXME LoadArrayElement needs an operand (should not be BasicInstruction) + // TODO depending on type of operand instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_X); + // example is already generated + break; + case BasicOperation.LoadArrayElementAddress: + // FIXME LoadArrayElementAddress needs an operand (should not be BasicInstruction) + // instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); + // instructionEncoder.token(type); + // example is already generated + break; + case BasicOperation.IndirectStore: + // FIXME IndirectStore needs an operand (should not be BasicInstruction) + // instructionEncoder.OpCode(SRM.ILOpCode.Stobj); + // instructionEncoder.token(); + break; + case BasicOperation.StoreArrayElement: + // FIXME StoreArrayElement needs an operand (should not be BasicInstruction) + // instructionEncoder.OpCode(SRM.ILOpCode.Stelem_X); - // instructionEncoder.OpCode(SRM.ILOpCode.Stelem); - // instructionEncoder.token(); - break; - case Model.Bytecode.BasicOperation.Breakpoint: - instructionEncoder.OpCode(SRM.ILOpCode.Break); - break; - case Model.Bytecode.BasicOperation.Return: - instructionEncoder.OpCode(SRM.ILOpCode.Ret); - break; - } - } - else if (instruction is Model.Bytecode.BranchInstruction branchInstruction) - { - var opCode = SRM.ILOpCode.Br_s; - switch (branchInstruction.Operation) - { - // This relies on marking labels and that depends on generating all instructions correctly (if not labels don't match) - // TODO all short forms can also be not short form (ex: br and br.s) and there's "un" variants - case Model.Bytecode.BranchOperation.False: - opCode = SRM.ILOpCode.Brfalse_s; - break; - case Model.Bytecode.BranchOperation.True: - opCode = SRM.ILOpCode.Brtrue_s; - break; - case Model.Bytecode.BranchOperation.Eq: - opCode = SRM.ILOpCode.Beq_s; - break; - case Model.Bytecode.BranchOperation.Neq: - opCode = SRM.ILOpCode.Bne_un_s; - break; - case Model.Bytecode.BranchOperation.Lt: - opCode = SRM.ILOpCode.Blt_s; - break; - case Model.Bytecode.BranchOperation.Le: - opCode = SRM.ILOpCode.Ble_s; - break; - case Model.Bytecode.BranchOperation.Gt: - opCode = SRM.ILOpCode.Bgt_s; - break; - case Model.Bytecode.BranchOperation.Ge: - opCode = SRM.ILOpCode.Bge_s; - break; - case Model.Bytecode.BranchOperation.Branch: - opCode = SRM.ILOpCode.Br_s; - break; - case Model.Bytecode.BranchOperation.Leave: - opCode = SRM.ILOpCode.Leave_s; - break; - } - instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(branchInstruction.Target)); - } - else if (instruction is Model.Bytecode.ConvertInstruction convertInstruction) - { - switch (convertInstruction.Operation) - { - // TODO overflow variants and conv.i, conv.u, conv.r.un - case Model.Bytecode.ConvertOperation.Conv: - if (convertInstruction.ConversionType.Equals(PlatformTypes.Int8)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i1); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt8)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u1); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int16)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i2); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt16)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u2); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i4); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u4); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int64)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt64)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u8); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.Float32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_r4); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.Float64)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_r8); - } - break; - case Model.Bytecode.ConvertOperation.Cast: - instructionEncoder.OpCode(SRM.ILOpCode.Castclass); - // FIXME could also be instructionEncoder.OpCode(SRM.ILOpCode.Isinst); - break; - case Model.Bytecode.ConvertOperation.Box: - instructionEncoder.OpCode(SRM.ILOpCode.Box); - break; - case Model.Bytecode.ConvertOperation.Unbox: - instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); - break; - case Model.Bytecode.ConvertOperation.UnboxPtr: - instructionEncoder.OpCode(SRM.ILOpCode.Unbox); - break; - } - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); - } - else if (instruction is Model.Bytecode.MethodCallInstruction methodCallInstruction) - { - switch (methodCallInstruction.Operation) - { - case Model.Bytecode.MethodCallOperation.Virtual: - instructionEncoder.CallVirtual(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method)); - break; - case Model.Bytecode.MethodCallOperation.Static: - case Model.Bytecode.MethodCallOperation.Jump: - instructionEncoder.Call(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method)); - break; - } - } - else if (instruction is Model.Bytecode.LoadInstruction loadlInstruction) - { - switch (loadlInstruction.Operation) + // instructionEncoder.OpCode(SRM.ILOpCode.Stelem); + // instructionEncoder.token(); + break; + case BasicOperation.Breakpoint: + instructionEncoder.OpCode(SRM.ILOpCode.Break); + break; + case BasicOperation.Return: + instructionEncoder.OpCode(SRM.ILOpCode.Ret); + break; + } + + break; + case BranchInstruction branchInstruction: { - case Model.Bytecode.LoadOperation.Address: - var operandVariable = (IVariable)loadlInstruction.Operand; - if (operandVariable.IsParameter) - { - instructionEncoder.LoadArgumentAddress(body.Parameters.IndexOf(operandVariable)); - } - else - { - instructionEncoder.LoadLocalAddress(body.LocalVariables.IndexOf(operandVariable)); - } - break; - case Model.Bytecode.LoadOperation.Content: - operandVariable = (IVariable)loadlInstruction.Operand; - if (operandVariable.IsParameter) - { - instructionEncoder.LoadArgument(body.Parameters.IndexOf(operandVariable)); - } - else - { - instructionEncoder.LoadLocal(body.LocalVariables.IndexOf(operandVariable)); - } - break; - case Model.Bytecode.LoadOperation.Value: - if (((Constant)loadlInstruction.Operand).Value == null) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); - } - if (loadlInstruction.Operand.Type.Equals(PlatformTypes.String)) - { - var value = (string)(loadlInstruction.Operand as Constant).Value; - instructionEncoder.LoadString(metadataContainer.metadataBuilder.GetOrAddUserString(value)); - } + var opCode = SRM.ILOpCode.Br_s; + switch (branchInstruction.Operation) + { + // TODO all short forms can also be not short form (ex: br and br.s) and there's "un" variants + case BranchOperation.False: + opCode = SRM.ILOpCode.Brfalse_s; + break; + case BranchOperation.True: + opCode = SRM.ILOpCode.Brtrue_s; + break; + case BranchOperation.Eq: + opCode = SRM.ILOpCode.Beq_s; + break; + case BranchOperation.Neq: + opCode = SRM.ILOpCode.Bne_un_s; + break; + case BranchOperation.Lt: + opCode = SRM.ILOpCode.Blt_s; + break; + case BranchOperation.Le: + opCode = SRM.ILOpCode.Ble_s; + break; + case BranchOperation.Gt: + opCode = SRM.ILOpCode.Bgt_s; + break; + case BranchOperation.Ge: + opCode = SRM.ILOpCode.Bge_s; + break; + case BranchOperation.Branch: + opCode = SRM.ILOpCode.Br_s; + break; + case BranchOperation.Leave: + opCode = SRM.ILOpCode.Leave_s; + break; + } - // TODO see ECMA ldc instruction. It says some cases should be follow by conv.i8 operations but the bytecode (original) does not have that - else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Int8) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt8)) - { - var value = (int)(loadlInstruction.Operand as Constant).Value; - instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); - instructionEncoder.Token(value); - // FIXME: do only if value variable storing the 8 bit number is 8 byte integer. - // instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); - } - else if ( - loadlInstruction.Operand.Type.Equals(PlatformTypes.Int16) || - loadlInstruction.Operand.Type.Equals(PlatformTypes.Int32) || - loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt16) || - loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt32)) - { - var value = (int)(loadlInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantI4(value); - // FIXME: do only if value variable storing the 16/32 bit number is 8 byte integer. - // instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); - } - else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Int64) || loadlInstruction.Operand.Type.Equals(PlatformTypes.UInt64)) - { - var value = (long)(loadlInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantI8(value); - } - else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Float32)) - { - var value = (float)(loadlInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantR4(value); - } - else if (loadlInstruction.Operand.Type.Equals(PlatformTypes.Float64)) - { - var value = (double)(loadlInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantR8(value); - } - break; + instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(branchInstruction.Target)); + break; } - } - else if (instruction is Model.Bytecode.LoadFieldInstruction loadFieldInstruction) - { - // TODO handle ldflda. Example present but not supported in model + case ConvertInstruction convertInstruction: + switch (convertInstruction.Operation) + { + // TODO overflow variants and conv.i, conv.u, conv.r.un + case ConvertOperation.Conv: + if (convertInstruction.ConversionType.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i1); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u1); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i2); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u2); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i4); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u4); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u8); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_r4); + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_r8); + } - instructionEncoder.OpCode(SRM.ILOpCode.Ldfld); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field)); - } - else if (instruction is Model.Bytecode.LoadArrayElementInstruction loadArrayElementInstruction) { } - else if (instruction is Model.Bytecode.LoadMethodAddressInstruction loadMethodAdressInstruction) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadMethodAdressInstruction.Method)); - } - else if (instruction is Model.Bytecode.CreateArrayInstruction createArrayInstruction) - { - if (createArrayInstruction.Type.IsVector) - { - instructionEncoder.OpCode(SRM.ILOpCode.Newarr); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(createArrayInstruction.Type.ElementsType)); - } - else - { - throw new Exception("newarr only handles one dimension and zero based arrays"); - } - } - else if (instruction is Model.Bytecode.CreateObjectInstruction createObjectInstruction) - { - var method = metadataContainer.ResolveReferenceHandleFor(createObjectInstruction.Constructor); - instructionEncoder.OpCode(SRM.ILOpCode.Newobj); - instructionEncoder.Token(method); - } - else if (instruction is Model.Bytecode.StoreInstruction storeInstruction) - { - if (storeInstruction.Target.IsParameter) + break; + case ConvertOperation.Cast: + instructionEncoder.OpCode(SRM.ILOpCode.Castclass); + // FIXME could also be instructionEncoder.OpCode(SRM.ILOpCode.Isinst); + break; + case ConvertOperation.Box: + instructionEncoder.OpCode(SRM.ILOpCode.Box); + break; + case ConvertOperation.Unbox: + instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); + break; + case ConvertOperation.UnboxPtr: + instructionEncoder.OpCode(SRM.ILOpCode.Unbox); + break; + } + + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); + break; + case MethodCallInstruction methodCallInstruction: + switch (methodCallInstruction.Operation) + { + case MethodCallOperation.Virtual: + instructionEncoder.CallVirtual(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method)); + break; + case MethodCallOperation.Static: + case MethodCallOperation.Jump: + instructionEncoder.Call(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method)); + break; + } + + break; + case LoadInstruction loadInstruction: + switch (loadInstruction.Operation) + { + case LoadOperation.Address: + var operandVariable = (IVariable) loadInstruction.Operand; + if (operandVariable.IsParameter) + { + instructionEncoder.LoadArgumentAddress(body.Parameters.IndexOf(operandVariable)); + } + else + { + instructionEncoder.LoadLocalAddress(body.LocalVariables.IndexOf(operandVariable)); + } + + break; + case LoadOperation.Content: + operandVariable = (IVariable) loadInstruction.Operand; + if (operandVariable.IsParameter) + { + instructionEncoder.LoadArgument(body.Parameters.IndexOf(operandVariable)); + } + else + { + instructionEncoder.LoadLocal(body.LocalVariables.IndexOf(operandVariable)); + } + + break; + case LoadOperation.Value: + if (((Constant) loadInstruction.Operand).Value == null) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); + } + + if (loadInstruction.Operand.Type.Equals(PlatformTypes.String)) + { + var value = (string) (loadInstruction.Operand as Constant).Value; + instructionEncoder.LoadString(metadataContainer.metadataBuilder.GetOrAddUserString(value)); + } + + // TODO see ECMA ldc instruction. It says some cases should be follow by conv.i8 operations but the bytecode (original) does not have that + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Int8) || + loadInstruction.Operand.Type.Equals(PlatformTypes.UInt8)) + { + var value = (int) (loadInstruction.Operand as Constant).Value; + instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); + instructionEncoder.Token(value); + // FIXME: do only if value variable storing the 8 bit number is 8 byte integer. + // instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); + } + else if ( + loadInstruction.Operand.Type.Equals(PlatformTypes.Int16) || + loadInstruction.Operand.Type.Equals(PlatformTypes.Int32) || + loadInstruction.Operand.Type.Equals(PlatformTypes.UInt16) || + loadInstruction.Operand.Type.Equals(PlatformTypes.UInt32)) + { + var value = (int) (loadInstruction.Operand as Constant).Value; + instructionEncoder.LoadConstantI4(value); + // FIXME: do only if value variable storing the 16/32 bit number is 8 byte integer. + // instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); + } + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Int64) || + loadInstruction.Operand.Type.Equals(PlatformTypes.UInt64)) + { + var value = (long) (loadInstruction.Operand as Constant).Value; + instructionEncoder.LoadConstantI8(value); + } + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float32)) + { + var value = (float) (loadInstruction.Operand as Constant).Value; + instructionEncoder.LoadConstantR4(value); + } + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float64)) + { + var value = (double) (loadInstruction.Operand as Constant).Value; + instructionEncoder.LoadConstantR8(value); + } + + break; + } + + break; + case LoadFieldInstruction loadFieldInstruction: + // TODO handle ldflda. Example present but not supported in model + + instructionEncoder.OpCode(SRM.ILOpCode.Ldfld); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field)); + break; + case LoadArrayElementInstruction loadArrayElementInstruction: + break; + case LoadMethodAddressInstruction loadMethodAddressInstruction: + instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadMethodAddressInstruction.Method)); + break; + case CreateArrayInstruction createArrayInstruction: + if (createArrayInstruction.Type.IsVector) + { + instructionEncoder.OpCode(SRM.ILOpCode.Newarr); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(createArrayInstruction.Type.ElementsType)); + } + else + { + throw new Exception("newarr only handles one dimension and zero based arrays"); + } + + break; + case CreateObjectInstruction createObjectInstruction: { - instructionEncoder.StoreArgument(body.Parameters.IndexOf(storeInstruction.Target)); + var method = metadataContainer.ResolveReferenceHandleFor(createObjectInstruction.Constructor); + instructionEncoder.OpCode(SRM.ILOpCode.Newobj); + instructionEncoder.Token(method); + break; } - else + case StoreInstruction storeInstruction: + if (storeInstruction.Target.IsParameter) + { + instructionEncoder.StoreArgument(body.Parameters.IndexOf(storeInstruction.Target)); + } + else + { + instructionEncoder.StoreLocal(body.LocalVariables.IndexOf(storeInstruction.Target)); + } + + break; + case StoreFieldInstruction storeFieldInstruction: + instructionEncoder.OpCode(storeFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeFieldInstruction.Field)); + break; + case SwitchInstruction switchInstruction: + // TODO test. This instructions that are difficult to generate in example can be generated programatically (new SwitchInstruction...) + // maybe have an example files that generates all this instructions that are missing + instructionEncoder.OpCode(SRM.ILOpCode.Switch); + instructionEncoder.Token(switchInstruction.Targets.Count); + switchInstruction.Targets + .Select(label => int.Parse(label.Substring(2), NumberStyles.HexNumber)) + .ToList() + .ForEach(instructionEncoder.Token); + break; + case SizeofInstruction sizeofInstruction: + instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(sizeofInstruction.MeasuredType)); + break; + case LoadTokenInstruction loadTokenInstruction: + instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadTokenInstruction.Token)); + break; + case IndirectMethodCallInstruction indirectMethodCallInstruction: { - instructionEncoder.StoreLocal(body.LocalVariables.IndexOf(storeInstruction.Target)); + // TODO test + var methodSignature = metadataContainer.ResolveStandaloneSignatureFor(indirectMethodCallInstruction.Function); + instructionEncoder.CallIndirect(methodSignature); + break; } + case StoreArrayElementInstruction storeArrayElementInstruction: + // FIXME + // Framework currently handles this as a BasicInstruction and this is never generated. Should use this one + // example already generated + // the implementation should be like load instruction + // instructionEncoder.OpCode(SRM.ILOpCode.Stelem_X); + // instructionEncoder.Token(value); + break; + default: + throw new Exception("instruction type not handled"); } - else if (instruction is Model.Bytecode.StoreFieldInstruction storeFieldInstruction) - { - instructionEncoder.OpCode(storeFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeFieldInstruction.Field)); - } - else if (instruction is Model.Bytecode.SwitchInstruction switchInstruction) - { - // TODO test. This instructions that are difficuly to generate in example can be generated programatically (new SwitchInstruction...) - // maybe have an example files that generates all this instructions that are missing - instructionEncoder.OpCode(SRM.ILOpCode.Switch); - instructionEncoder.Token(switchInstruction.Targets.Count); - switchInstruction.Targets - .Select(label => int.Parse(label.Substring(2), System.Globalization.NumberStyles.HexNumber)) - .ToList() - .ForEach(instructionEncoder.Token); - } - else if (instruction is Model.Bytecode.SizeofInstruction sizeofInstruction) - { - instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(sizeofInstruction.MeasuredType)); - } - else if (instruction is Model.Bytecode.LoadTokenInstruction loadTokenInstruction) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadTokenInstruction.Token)); - } - else if (instruction is Model.Bytecode.IndirectMethodCallInstruction indirectMethodCallInstruction) - { // TODO test - var methodSignature = metadataContainer.ResolveStandaloneSignatureFor(indirectMethodCallInstruction.Function); - instructionEncoder.CallIndirect(methodSignature); - } - else if (instruction is Model.Bytecode.StoreArrayElementInstruction storeArrayElementInstruction) - { - // FIXME - // Framework currently handles this as a BasicInstruction and this is never generated. Should use this one - // example already generated - // the implementation should be like load instruction - // instructionEncoder.OpCode(SRM.ILOpCode.Stelem_X); - // instructionEncoder.Token(value); - } - else throw new Exception("instruction type not handled"); } - controlFlowGenerator.MarkAllUnmarkedLabels(); + controlFlowGenerator.MarkAllUnmarkedLabels(); // FIXME return instructionEncoder; } } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs index 9a885077..8a8b1b8a 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs @@ -1,10 +1,11 @@ -using Model.Types; +using MetadataGenerator.Metadata; +using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators.Methods + +namespace MetadataGenerator.Generators.Methods.Body { - // FIXME name - class MethodLocalsGenerator + internal class MethodLocalsGenerator { private readonly MetadataContainer metadataContainer; @@ -24,12 +25,17 @@ public SRM.StandaloneSignatureHandle GenerateLocalVariablesSignatureFor(MethodBo { metadataContainer.Encode( localVariable.Type, - encoder.AddVariable().Type(isByRef: false, isPinned: false) // FIXME hardcoded false - ); + encoder.AddVariable().Type(isPinned: false)); + // FIXME pinned is achieved by the fixed keyword and this is not in the modeled } + // FIXME this adds ad signature everytime? getOrAddBlob though. Locals are most likely different for each method though - localVariablesSignature = metadataContainer.metadataBuilder.AddStandaloneSignature(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + localVariablesSignature = + metadataContainer.metadataBuilder.AddStandaloneSignature(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + + return localVariablesSignature; } + return localVariablesSignature; } @@ -56,10 +62,13 @@ Quiza estan mal algunos de los valores de addLocalScope y por eso no anda firstLocalVariableHandle = localVariableHandle; } } - var nextLocalVariableHandle = ECMA335.MetadataTokens.LocalVariableHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalVariable)); + + var nextLocalVariableHandle = + ECMA335.MetadataTokens.LocalVariableHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalVariable)); // FIXME ?? - var nextLocalConstantHandle = ECMA335.MetadataTokens.LocalConstantHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalConstant)); + var nextLocalConstantHandle = + ECMA335.MetadataTokens.LocalConstantHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalConstant)); metadataContainer.metadataBuilder.AddLocalScope( method: containingMethodHandle, @@ -71,4 +80,4 @@ Quiza estan mal algunos de los valores de addLocalScope y por eso no anda } } } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index b2c5dd92..6545da84 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -1,18 +1,14 @@ -using MetadataGenerator.Generators.Methods; +using MetadataGenerator.Generators.Methods.Body; +using MetadataGenerator.Metadata; using Model.Types; -using static MetadataGenerator.AttributesProvider; +using static MetadataGenerator.Metadata.AttributesProvider; using ECMA335 = System.Reflection.Metadata.Ecma335; using SR = System.Reflection; using SRM = System.Reflection.Metadata; -//FIXME namespaces, use packages? MetadataGenerator.generators.methods? MetadataGenerator.generators? -//FIXME todas estas clases deberiuan ser internal no? los generators, salvo el entry point de todo. -//FIXME ver que onda la visibilidad de los metodos, el deafult es public creo quiza tienen que ser internal tambien. Que pasa si son public y la clase es internal? -//FIXME ver todo esto para los demas generators tmb (no solo methods) - -namespace MetadataGenerator +namespace MetadataGenerator.Generators.Methods { - class MethodGenerator + internal class MethodGenerator { private readonly MetadataContainer metadataContainer; private readonly MethodSignatureGenerator methodSignatureGenerator; @@ -44,7 +40,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) } // FIXME several addMethodBody variants with different arguments. codeSize, maxStacks, etc - // FIXME maxStack should be computed from instructions. When a dll is read, the maxStrack will be available (Model) but if code is generated + // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated // programatically then the maxStack is gonna be missing var methodBody = method.HasBody ? metadataContainer.methodBodyStream.AddMethodBody( @@ -67,4 +63,4 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) return methodDefinitionHandle; } } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 31e44a5a..480f2adc 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; +using MetadataGenerator.Metadata; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; namespace MetadataGenerator.Generators.Methods { - class MethodSignatureGenerator + internal class MethodSignatureGenerator { private readonly MetadataContainer metadataContainer; @@ -14,17 +15,18 @@ public MethodSignatureGenerator(MetadataContainer metadataContainer) this.metadataContainer = metadataContainer; } - public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) - { - return GenerateMethodSignature(method.IsStatic, method.GenericParameterCount, method.Parameters, method.ReturnType); - } - public SRM.BlobBuilder GenerateSignatureOf(FunctionPointerType method) - { - // FIXME 0 because FunctionPointerType does not have that property (there's a fixme in that class) - return GenerateMethodSignature(method.IsStatic, 0, method.Parameters, method.ReturnType); - } + public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) => + GenerateMethodSignature(method.IsStatic, method.GenericParameterCount, method.Parameters, method.ReturnType); + + public SRM.BlobBuilder GenerateSignatureOf(FunctionPointerType method) => + GenerateMethodSignature(method.IsStatic, 0, method.Parameters, method.ReturnType); + // FIXME 0 because FunctionPointerType does not have that property (there's a fixme in that class) - private SRM.BlobBuilder GenerateMethodSignature(bool isStatic, int genericParameterCount, IList parameters, IType returnType) + private SRM.BlobBuilder GenerateMethodSignature( + bool isStatic, + int genericParameterCount, + IList parameters, + IType returnType) { var methodSignature = new SRM.BlobBuilder(); new ECMA335.BlobEncoder(methodSignature) @@ -48,7 +50,7 @@ private SRM.BlobBuilder GenerateMethodSignature(bool isStatic, int genericParame { foreach (var parameter in parameters) { - bool isByRef = parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref); + var isByRef = parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref); var type = isByRef ? (parameter.Type as PointerType).TargetType : parameter.Type; var encoder = parametersEncoder.AddParameter().Type(isByRef); metadataContainer.Encode(type, encoder); @@ -57,4 +59,4 @@ private SRM.BlobBuilder GenerateMethodSignature(bool isStatic, int genericParame return methodSignature; } } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/NamespaceGenerator.cs b/MetadataGenerator/Generators/NamespaceGenerator.cs index 7a60f959..6484efce 100644 --- a/MetadataGenerator/Generators/NamespaceGenerator.cs +++ b/MetadataGenerator/Generators/NamespaceGenerator.cs @@ -1,11 +1,12 @@ -using System.Collections.Generic; +using System.Linq; +using MetadataGenerator.Metadata; using Model; using Model.Types; using SRM = System.Reflection.Metadata; namespace MetadataGenerator.Generators { - class NamespaceGenerator + internal class NamespaceGenerator { private readonly MetadataContainer metadataContainer; private readonly TypeGenerator typeGenerator; @@ -31,11 +32,7 @@ public void Generate(Namespace namezpace) private SRM.TypeDefinitionHandle GenerateTypes(TypeDefinition type) { - var nestedTypes = new List(); - foreach (var nestedType in type.Types) - { - nestedTypes.Add(GenerateTypes(nestedType)); - } + var nestedTypes = type.Types.Select(GenerateTypes).ToList(); var typeDefinitionHandle = typeGenerator.Generate(type); foreach (var nestedType in nestedTypes) @@ -45,6 +42,5 @@ private SRM.TypeDefinitionHandle GenerateTypes(TypeDefinition type) return typeDefinitionHandle; } - } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index 3375cc44..0abdf22b 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -1,13 +1,17 @@ using System.Collections.Generic; +using System.Linq; +using MetadataGenerator.Generators.Fields; +using MetadataGenerator.Generators.Methods; +using MetadataGenerator.Metadata; using Model.Types; -using static MetadataGenerator.AttributesProvider; +using static MetadataGenerator.Metadata.AttributesProvider; using ECMA335 = System.Reflection.Metadata.Ecma335; using SR = System.Reflection; using SRM = System.Reflection.Metadata; namespace MetadataGenerator.Generators { - class TypeGenerator + internal class TypeGenerator { private readonly MetadataContainer metadataContainer; private readonly MethodGenerator methodGenerator; @@ -22,17 +26,12 @@ public TypeGenerator(MetadataContainer metadataContainer) public SRM.TypeDefinitionHandle Generate(TypeDefinition type) { - var fieldDefinitionHandles = new List(); var methodDefinitionHandles = new List(); var metadataBuilder = metadataContainer.metadataBuilder; - - foreach (var field in type.Fields) - { - fieldDefinitionHandles.Add(fieldGenerator.Generate(field)); - } + var fieldDefinitionHandles = type.Fields.Select(field => fieldGenerator.Generate(field)).ToList(); /* TODO Properties: (works) but model is missing Property concept - * extrack to PropertiesGenerator + * extract to PropertiesGenerator var propertySignatureBlogBuilder = new BlobBuilder(); new BlobEncoder(propertySignatureBlogBuilder) @@ -47,7 +46,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) name: metadata.GetOrAddString(""), //FIXME property name signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); - // asociate methods (get, set) to property + // associate methods (get, set) to property metadata.AddMethodSemantics( propertyDefinitionHandle, method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, @@ -77,39 +76,58 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) foreach (var interfaze in type.Interfaces) { - metadataBuilder.AddInterfaceImplementation(type: typeDefinitionHandle, implementedInterface: metadataContainer.ResolveReferenceHandleFor(interfaze)); + metadataBuilder.AddInterfaceImplementation( + type: typeDefinitionHandle, + implementedInterface: metadataContainer.ResolveReferenceHandleFor(interfaze)); } /* - Generic parameters table must be sorted that's why this is done at the end and not during the method generation. - If done that way, method generic parameters of a type are added before the type's generic parameters and table results unsorted + * Generic parameters table must be sorted that's why this is done at the end and not during the method generation. + * If done that way, method generic parameters of a type are added before the type's generic parameters and table results unsorted */ + // generate class generic parameters (Class) - foreach (var genericParamter in type.GenericParameters) + foreach (var genericParameter in type.GenericParameters) { - metadataBuilder.AddGenericParameter( + var genericParameterHandle = metadataBuilder.AddGenericParameter( typeDefinitionHandle, - SR.GenericParameterAttributes.None, - metadataBuilder.GetOrAddString(genericParamter.Name), - genericParamter.Index); + SR.GenericParameterAttributes.None, // FIXME + metadataBuilder.GetOrAddString(genericParameter.Name), + genericParameter.Index); + + /* FIXME generic constraints not in the model + if(genericParameter.hasConstraint()){ + metadataBuilder.AddGenericParameterConstraint( + genericParameterHandle, + metadataContainer.ResolveReferenceHandleFor(genericParameter.contraint)); + } + */ } // generate method generic parameters (public T method(T param)) - for (int i = 0; i < type.Methods.Count; i++) + for (var i = 0; i < type.Methods.Count; i++) { var method = type.Methods[i]; foreach (var genericParameter in method.GenericParameters) { - metadataBuilder.AddGenericParameter( + var genericParameterHandle = metadataBuilder.AddGenericParameter( methodDefinitionHandles[i], - SR.GenericParameterAttributes.None, + SR.GenericParameterAttributes.None, // FIXME metadataBuilder.GetOrAddString(genericParameter.Name), genericParameter.Index); + + /* FIXME generic constraints not in the model + if(genericParameter.hasConstraint()){ + metadataBuilder.AddGenericParameterConstraint( + genericParameterHandle, + metadataContainer.ResolveReferenceHandleFor(genericParameter.contraint)); + } + */ } } return typeDefinitionHandle; } } -} +} \ No newline at end of file diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs similarity index 72% rename from MetadataGenerator/AttributesProvider.cs rename to MetadataGenerator/Metadata/AttributesProvider.cs index 3bce24db..11a5fac4 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -3,7 +3,7 @@ using Model; using Model.Types; -namespace MetadataGenerator +namespace MetadataGenerator.Metadata { public static class AttributesProvider { @@ -23,31 +23,31 @@ public static TypeAttributes GetTypeAttributesFor(TypeDefinition typeDefinition) private static TypeAttributes DelegateTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Class - | TypeAttributes.Sealed - | VisibilityAttributesFor(typeDefinition); + | TypeAttributes.Sealed + | VisibilityAttributesFor(typeDefinition); } private static TypeAttributes StructTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Class | - VisibilityAttributesFor(typeDefinition) | - TypeAttributes.SequentialLayout | - TypeAttributes.Sealed | - TypeAttributes.BeforeFieldInit; //FIXME: when? + VisibilityAttributesFor(typeDefinition) | + TypeAttributes.SequentialLayout | + TypeAttributes.Sealed | + TypeAttributes.BeforeFieldInit; //FIXME: when? } private static TypeAttributes EnumTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Class | - VisibilityAttributesFor(typeDefinition) | - TypeAttributes.Sealed; + VisibilityAttributesFor(typeDefinition) | + TypeAttributes.Sealed; } private static TypeAttributes ClassTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Class | - TypeAttributes.BeforeFieldInit | //FIXME: when? - VisibilityAttributesFor(typeDefinition); + TypeAttributes.BeforeFieldInit | //FIXME: when? + VisibilityAttributesFor(typeDefinition); } private static TypeAttributes InterfaceTypeAttributes() @@ -59,8 +59,13 @@ public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) { var fieldAttributes = (field.IsStatic ? FieldAttributes.Static : 0) | - (field.ContainingType.Kind is TypeDefinitionKind.Enum && field.Type.Equals(field.ContainingType) ? FieldAttributes.Literal : 0) | - (field.ContainingType.Kind is TypeDefinitionKind.Enum && field.Name.Equals("value__", StringComparison.InvariantCultureIgnoreCase) ? FieldAttributes.RTSpecialName | FieldAttributes.SpecialName : 0); + (field.ContainingType.Kind is TypeDefinitionKind.Enum && field.Type.Equals(field.ContainingType) + ? FieldAttributes.Literal + : 0) | + (field.ContainingType.Kind is TypeDefinitionKind.Enum && + field.Name.Equals("value__", StringComparison.InvariantCultureIgnoreCase) + ? FieldAttributes.RTSpecialName | FieldAttributes.SpecialName + : 0); switch (field.Visibility) { case VisibilityKind.Public: @@ -78,23 +83,32 @@ public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) default: throw field.Visibility.ToUnknownValueException(); } + return fieldAttributes; } public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) { - var constructor = method.IsConstructor || method.Name.Equals(".cctor"); // FIXME maybe MethodDefinition can have a isClassConstructor or isTypeInitializer + var constructor = + method.IsConstructor || + method.Name.Equals( + ".cctor"); // FIXME maybe MethodDefinition can have a isClassConstructor or isTypeInitializer bool specialName = - method.Name.StartsWith("get_", StringComparison.Ordinal) || method.Name.StartsWith("set_", StringComparison.Ordinal) || + method.Name.StartsWith("get_", StringComparison.Ordinal) || + method.Name.StartsWith("set_", StringComparison.Ordinal) || method.Name.StartsWith("op_", StringComparison.Ordinal); var methodAttributes = MethodAttributes.HideBySig | // FIXME when? (method.IsAbstract ? MethodAttributes.Abstract : 0) | (method.IsStatic ? MethodAttributes.Static : 0) | (method.IsVirtual ? MethodAttributes.Virtual : 0) | - (method.ContainingType.Kind is TypeDefinitionKind.Interface ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct. Model is missing the new keyword + (method.ContainingType.Kind is TypeDefinitionKind.Interface + ? MethodAttributes.NewSlot + : 0) | // FIXME not entirely correct. Model is missing the new keyword (constructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | - (specialName ? MethodAttributes.SpecialName : 0); // FIXME fails if non getter/setter method starts with get_/set_ + (specialName + ? MethodAttributes.SpecialName + : 0); // FIXME fails if non getter/setter method starts with get_/set_ switch (method.Visibility) { @@ -113,6 +127,7 @@ public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) default: throw method.Visibility.ToUnknownValueException(); } + return methodAttributes; } @@ -132,21 +147,25 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para // TODO break; } + return attributes; } - // TODO other visibilties? + // TODO other visibilities? private static TypeAttributes VisibilityAttributesFor(TypeDefinition typeDefinition) { if (typeDefinition.ContainingType != null) { - return (VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.NestedPublic : TypeAttributes.NestedPrivate); + return VisibilityKind.Public.Equals(typeDefinition.Visibility) + ? TypeAttributes.NestedPublic + : TypeAttributes.NestedPrivate; } else { - return (VisibilityKind.Public.Equals(typeDefinition.Visibility) ? TypeAttributes.Public : TypeAttributes.NotPublic); + return VisibilityKind.Public.Equals(typeDefinition.Visibility) + ? TypeAttributes.Public + : TypeAttributes.NotPublic; } } - } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 4edaba52..9fa98a05 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -4,15 +4,15 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -//FIXME name, package, visibilities, etc -namespace MetadataGenerator +namespace MetadataGenerator.Metadata { - class MetadataContainer + internal class MetadataContainer { public readonly ECMA335.MetadataBuilder metadataBuilder; private readonly MetadataResolver metadataResolver; public readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; private SRM.MethodDefinitionHandle? mainMethodHandle; + public SRM.MethodDefinitionHandle? MainMethodHandle { get => mainMethodHandle; @@ -22,6 +22,7 @@ public SRM.MethodDefinitionHandle? MainMethodHandle mainMethodHandle = value; } } + public bool Executable => mainMethodHandle != null; public MetadataContainer(Assembly assembly) @@ -31,9 +32,12 @@ public MetadataContainer(Assembly assembly) metadataResolver = new MetadataResolver(this, assembly); } - //FIXME name, more generic? only needed for method? - public SRM.StandaloneSignatureHandle ResolveStandaloneSignatureFor(FunctionPointerType method) => metadataResolver.ResolveStandaloneSignatureFor(method); - public SRM.EntityHandle ResolveReferenceHandleFor(IMetadataReference metadataReference) => metadataResolver.ReferenceHandleOf(metadataReference); + public SRM.StandaloneSignatureHandle ResolveStandaloneSignatureFor(FunctionPointerType method) => + metadataResolver.ResolveStandaloneSignatureFor(method); + + public SRM.EntityHandle ResolveReferenceHandleFor(IMetadataReference metadataReference) => + metadataResolver.ReferenceHandleOf(metadataReference); + public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) => metadataResolver.Encode(type, encoder); } -} +} \ No newline at end of file diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 3b8d9aec..79009ab0 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -8,9 +8,9 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator +namespace MetadataGenerator.Metadata { - class MetadataResolver + internal class MetadataResolver { private readonly Assembly assembly; private readonly MetadataContainer metadataContainer; @@ -30,14 +30,16 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) { // FIXME parameters assemblyReferences.Add(assemblyReference.Name, metadataContainer.metadataBuilder.AddAssemblyReference( - name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), - version: new Version(4, 0, 0, 0), - culture: metadataContainer.metadataBuilder.GetOrAddString("neutral"), - publicKeyOrToken: metadataContainer.metadataBuilder.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), - flags: default, - hashValue: default) + name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), + version: new Version(4, 0, 0, 0), + culture: metadataContainer.metadataBuilder.GetOrAddString("neutral"), + publicKeyOrToken: metadataContainer.metadataBuilder.GetOrAddBlob( + ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), + flags: default, + hashValue: default) ); } + fieldSignatureGenerator = new FieldSignatureGenerator(metadataContainer); methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); } @@ -51,54 +53,48 @@ public SRM.StandaloneSignatureHandle ResolveStandaloneSignatureFor(FunctionPoint public SRM.EntityHandle ReferenceHandleOf(IMetadataReference metadataReference) { - if (metadataReference is IFieldReference field) - { - var signature = fieldSignatureGenerator.GenerateSignatureOf(field); - return ReferenceHandleOf(field, signature); - } - else if (metadataReference is IMethodReference method) - { - var signature = methodSignatureGenerator.GenerateSignatureOf(method); - return ReferenceHandleOf(method, signature); - } - else if (metadataReference is IType type) - { - return ReferenceHandleOf(type); - } - else + switch (metadataReference) { - throw new Exception(); // FIXME + case IFieldReference field: + { + var signature = fieldSignatureGenerator.GenerateSignatureOf(field); + return ReferenceHandleOf(field, signature); + } + case IMethodReference method: + { + var signature = methodSignatureGenerator.GenerateSignatureOf(method); + return ReferenceHandleOf(method, signature); + } + case IType type: + return ReferenceHandleOf(type); + default: + throw new Exception(); // FIXME } } private SRM.EntityHandle ReferenceHandleOf(IType type) { - if (type is IBasicType basicType) - { - return ReferenceHandleOf(basicType, basicType.Name); - } - // FIXME rompe porque queda desordenada la tabla de genericParam. - else if (type is IGenericParameterReference genericParameterReference) + switch (type) { - return ReferenceHandleOf(genericParameterReference.GenericContainer.ContainingType, genericParameterReference.Name); - } - else if (type is ArrayType arrayType) - { - var signature = new SRM.BlobBuilder(); - var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); - Encode(arrayType, encoder); - return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); - } - else if (type is PointerType pointerType) - { - var signature = new SRM.BlobBuilder(); - var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); - Encode(pointerType, encoder); - return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); - } - else - { - throw new Exception("not yet supported"); + case IBasicType basicType: return ReferenceHandleOf(basicType, basicType.Name); + case IGenericParameterReference genericParameterReference: + return ReferenceHandleOf(genericParameterReference.GenericContainer.ContainingType, genericParameterReference.Name); + case ArrayType arrayType: + { + var signature = new SRM.BlobBuilder(); + var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); + Encode(arrayType, encoder); + return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + } + case PointerType pointerType: + { + var signature = new SRM.BlobBuilder(); + var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); + Encode(pointerType, encoder); + return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + } + default: + throw new Exception("not yet supported"); } } @@ -107,9 +103,10 @@ private SRM.EntityHandle ReferenceHandleOf(IType type) */ private SRM.TypeReferenceHandle ReferenceHandleOf(IBasicType type, string typeName) { - var typeReferenceKey = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{type.Name}"; - if (!typeReferences.TryGetValue(typeReferenceKey, out SRM.TypeReferenceHandle typeReference)) // If stored then return that - { // if not add the new type reference to metadata and store it + var typeReferenceKey = + $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{type.Name}"; + if (!typeReferences.TryGetValue(typeReferenceKey, out var typeReference)) + { SRM.EntityHandle resolutionScope; if (type.ContainingType == null) // if defined in the namespace then search there { @@ -118,49 +115,63 @@ private SRM.TypeReferenceHandle ReferenceHandleOf(IBasicType type, string typeNa : assemblyReferences[type.ContainingAssembly.Name]; } else - { // if not, recursively get a reference for the containing type and use that as the resolution scopeø + { + // if not, recursively get a reference for the containing type and use that as the resolution scope resolutionScope = ReferenceHandleOf(type.ContainingType); } + typeReference = metadataContainer.metadataBuilder.AddTypeReference( resolutionScope: resolutionScope, @namespace: metadataContainer.metadataBuilder.GetOrAddString(type.ContainingNamespace), name: metadataContainer.metadataBuilder.GetOrAddString(typeName)); typeReferences.Add(typeReferenceKey, typeReference); + + return typeReference; } + + // if not add the new type reference to metadata and store it return typeReference; } private SRM.MemberReferenceHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder signature) { - var key = $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; - if (!memberReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) + var key = + $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; + if (!memberReferences.TryGetValue(key, out var memberReferenceHandle)) { memberReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( - parent: ReferenceHandleOf(method.ContainingType), - name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), - signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + parent: ReferenceHandleOf(method.ContainingType), + name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), + signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); memberReferences.Add(key, memberReferenceHandle); + + return memberReferenceHandle; } + return memberReferenceHandle; } // FIXME extract method for both method and field? identical private SRM.MemberReferenceHandle ReferenceHandleOf(IFieldReference field, SRM.BlobBuilder signature) { - var key = $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.Name}.{field.Name}"; - if (!memberReferences.TryGetValue(key, out SRM.MemberReferenceHandle memberReferenceHandle)) + var key = + $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.Name}.{field.Name}"; + if (!memberReferences.TryGetValue(key, out var memberReferenceHandle)) { memberReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( - parent: ReferenceHandleOf(field.ContainingType), - name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), - signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + parent: ReferenceHandleOf(field.ContainingType), + name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), + signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); memberReferences.Add(key, memberReferenceHandle); + + return memberReferenceHandle; } + return memberReferenceHandle; } // SignatureTypeEncoder is a struct but it is not necessary to pass it by reference since - // it operates on its Builder (BlobBuilber) which is a class (tha means the builder refernece is always the same) + // it operates on its Builder (BlobBuilder) which is a class (tha means the builder reference is always the same) public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); @@ -179,66 +190,71 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) else if (type.Equals(PlatformTypes.Object)) encoder.Object(); else { - if (type is IBasicType basicType) + switch (type) { - if (basicType.GenericType != null) + case IBasicType basicType: { - var genericInstantiation = encoder.GenericInstantiation( - ReferenceHandleOf(basicType), - basicType.GenericParameterCount, - type.TypeKind == TypeKind.ValueType - ); - foreach (var genericArg in basicType.GenericArguments) + if (basicType.GenericType != null) { - Encode(genericArg, genericInstantiation.AddArgument()); + var genericInstantiation = encoder.GenericInstantiation( + ReferenceHandleOf(basicType), + basicType.GenericParameterCount, + type.TypeKind == TypeKind.ValueType); + foreach (var genericArg in basicType.GenericArguments) + { + Encode(genericArg, genericInstantiation.AddArgument()); + } } - } - else - { - encoder.Type(ReferenceHandleOf(basicType), type.TypeKind == TypeKind.ValueType); - } - } - else if (type is ArrayType arrayType) - { - encoder.Array( - elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), - arrayShapeEncoder => + else { - // FIXME real values for sizes and lowerBounds - // size cannot be known (example: int[]) - arrayShapeEncoder.Shape( - rank: (int)arrayType.Rank, - sizes: ImmutableArray.Empty, - lowerBounds: ImmutableArray.Empty); - }); + encoder.Type(ReferenceHandleOf(basicType), type.TypeKind == TypeKind.ValueType); + } - } - else if (type is PointerType pointerType) - { - // TODO there's also signatureTypeEncode.FunctionPointer()/IntPtr()/UIntPtr - var targetType = pointerType.TargetType; - if (targetType.Equals(PlatformTypes.Void)) - { - encoder.VoidPointer(); + break; } - else + case ArrayType arrayType: + encoder.Array( + elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), + arrayShapeEncoder => + { + // FIXME real values for sizes and lowerBounds + // size cannot be known (example: int[]) + arrayShapeEncoder.Shape( + rank: (int) arrayType.Rank, + sizes: ImmutableArray.Empty, + lowerBounds: ImmutableArray.Empty); + }); + break; + case PointerType pointerType: { - Encode(targetType, encoder.Pointer()); - } - } - else if (type is GenericParameter genericParameter) - { - switch (genericParameter.Kind) - { - case GenericParameterKind.Type: - encoder.GenericTypeParameter(genericParameter.Index); - break; - case GenericParameterKind.Method: - encoder.GenericMethodTypeParameter(genericParameter.Index); - break; + // TODO there's also signatureTypeEncode.FunctionPointer()/IntPtr()/UIntPtr + var targetType = pointerType.TargetType; + if (targetType.Equals(PlatformTypes.Void)) + { + encoder.VoidPointer(); + } + else + { + Encode(targetType, encoder.Pointer()); + } + + break; } + case GenericParameter genericParameter: + switch (genericParameter.Kind) + { + case GenericParameterKind.Type: + encoder.GenericTypeParameter(genericParameter.Index); + break; + case GenericParameterKind.Method: + encoder.GenericMethodTypeParameter(genericParameter.Index); + break; + } + + break; + default: + throw new Exception($"Type {type} not supported"); } - else throw new Exception($"Type {type} not supported"); } } } diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index f752467e..7bd19bae 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -26,14 +26,14 @@ - + - + From 6238d56edf7f7eab34e664d53f26d2fc9fea47cc Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 24 Nov 2019 18:09:52 -0300 Subject: [PATCH 059/256] generate generic parameters at the end (sorted table) --- Examples/Examples.cs | 222 ++++++++++-------- MetadataGenerator/Generator.cs | 4 +- .../Generators/AssemblyGenerator.cs | 5 + .../Body/MethodBodyControlFlowGenerator.cs | 2 - .../Methods/Body/MethodBodyGenerator.cs | 11 +- MetadataGenerator/Generators/TypeGenerator.cs | 34 +-- .../Metadata/AttributesProvider.cs | 2 +- .../Metadata/MetadataContainer.cs | 51 +++- .../Metadata/MetadataResolver.cs | 2 +- 9 files changed, 191 insertions(+), 142 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 4e629e96..70ded095 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1,5 +1,11 @@ using System; using System.Collections.Generic; +using System.Reflection.Metadata; +using Accessibility; +using Classes; +using Hierarchy; +using Nested.NestedNamespace.NestedNestedNamesace; +using Structs; namespace Enums { @@ -19,7 +25,6 @@ public enum EnumOfBytes : byte { Byte10 = 10, Byte20 = 20 - } public enum EnumOfUShorts : ushort @@ -29,30 +34,42 @@ public enum EnumOfUShorts : ushort } } -// TODO no yet supported in the framework model +// TODO not yet supported in the framework model // TODO interface with properties // TODO struct with properties namespace PropertiesGettersAndSetters { - public class ClassWithProperties { public double AutoImplementedProperty { get; set; } public char AnotherAutoImplementedProperty { get; } - public int PropertyWithBackingField { get => backingField; set => backingField = value; } + public int PropertyWithBackingField + { + get => backingField; + set => backingField = value; + } + private int backingField; - public string AnotherPropertyWithBackingField { get => otherBackingField; } + public string AnotherPropertyWithBackingField + { + get => otherBackingField; + } + private string otherBackingField; - public void get_ShouldNotHaveSpecialname() { } + public void get_ShouldNotHaveSpecialname() + { + } } } namespace Classes { - public class EmptyClass { } + public class EmptyClass + { + } public static class StaticClass { @@ -65,7 +82,9 @@ static StaticClass() StaticDouble = 0.5; } - public static void DoNothing(int x) { } + public static void DoNothing(int x) + { + } } @@ -79,11 +98,12 @@ public SimpleClass(int x, string y) { } - public void DoNothing() { } + public void DoNothing() + { + } private int Sum(int arg1, int arg2) { - return arg1 + arg2; } @@ -102,33 +122,35 @@ float ReturnAFloat(float arg) return arg; } - static void StaticMethod() { } - + static void StaticMethod() + { + } } public abstract class AbstractClass { - - public virtual void VirtualMethod() { } + public virtual void VirtualMethod() + { + } public abstract void AbstractMethod(); } // TODO var arggs, optional parameters, named arguments, - public class ClassWithMoreComplexFieldsAndParamtersOrReturnTypes + public class ClassWithMoreComplexFieldsAndParametersOrReturnTypes { - public string[] stringArrayField; public string[][] stringArrayArrayField; public string[,,] stringJaggedArrayField; public Exception[] exceptionArrayField; - public Nested.NestedNamespace.NestedNestedNamesace.B b; + public B b; public void MethodWithOptionalParameters( string someParam, int optionalInt = 0, - Structs.EmptyStruct optionalStruct = new Structs.EmptyStruct()) - { } + EmptyStruct optionalStruct = new EmptyStruct()) + { + } public void MethodWithIntVarArgs(params int[] args) { @@ -138,7 +160,7 @@ public void MethodWithExceptionVarArgs(int someInt, params Exception[] args) { } - public Hierarchy.DerivedClass DoSomethingWith(Hierarchy.DerivedClass d) + public DerivedClass DoSomethingWith(DerivedClass d) { return d; } @@ -150,7 +172,7 @@ public Exception DoSomethingWith(Exception e) public string[] GetStringArray() { - return new string[] { "hello", "world" }; + return new string[] {"hello", "world"}; } public Exception[] GetExceptionArray() @@ -162,15 +184,18 @@ public Exception[] GetExceptionArray() namespace Structs { - public struct EmptyStruct { } + public struct EmptyStruct + { + } public struct NonEmptyStruct { - private const string helloMessage = "hello"; private int number; - public void DoNothing() { } + public void DoNothing() + { + } private string Greet() { @@ -256,7 +281,6 @@ public int CompareTo(object obj) return 0; } } - } // FIXME is generating [Examples.dll]Delegates.ClassThatUsesDelegate/Del ReturnsADelegate instead of Delegates.ClassThatUsesDelegate/Del ReturnsADelegate @@ -280,7 +304,6 @@ public class ClassThatUsesDelegate namespace Hierarchy { - public abstract class AbstractBaseClass { public abstract void MustImplement(); @@ -288,14 +311,13 @@ public abstract class AbstractBaseClass public virtual void CanImplement() { } - } public class BaseClass : AbstractBaseClass { public override void MustImplement() { - throw new NotImplementedException(); + throw new Exception("Not implemented"); } protected void NotVisibileToDerivedClass() @@ -305,31 +327,35 @@ protected void NotVisibileToDerivedClass() public class DerivedClass : BaseClass { - public override void CanImplement() { } - + public override void CanImplement() + { + } } public class ClassDerivedFromSystemClass : Exception { } - public class ClassDerivedFromAccessibilityClass : Accessibility.CAccPropServicesClass + public class ClassDerivedFromAccessibilityClass : CAccPropServicesClass { } } namespace Nested { - public class ClassContainingNestedTypes { public NestedClass ReturnsNestedClass() => new NestedClass(); public NestedClass.NestedNestedClass ReturnsNestedNestedClass() => new NestedClass.NestedNestedClass(); - public System.Reflection.Metadata.BlobBuilder.Blobs ReturnsNestedClassFromOtherAssembly() => new System.Reflection.Metadata.BlobBuilder.Blobs(); + + public BlobBuilder.Blobs ReturnsNestedClassFromOtherAssembly() => + new BlobBuilder.Blobs(); public class NestedClass { - public class NestedNestedClass { } + public class NestedNestedClass + { + } } public enum NestedEnum @@ -344,8 +370,9 @@ public struct NestedStruct public struct StructContainingNestedTypes { - - public struct NestedStruct { } + public struct NestedStruct + { + } public enum NestedEnum { @@ -359,8 +386,9 @@ public class NestedClass namespace NestedNamespace { - - public class A { } + public class A + { + } namespace NestedNestedNamesace { @@ -368,8 +396,9 @@ public class B { public class NestedB { - - public class NestedNestedB { } + public class NestedNestedB + { + } } } } @@ -384,10 +413,10 @@ public class PointersAndReferenceClass private int number = 1; private Exception exception = new Exception(); - public void MethodWithRefAndOutParameters(ref string refString, ref Exception refException, out int outInt, out Classes.SimpleClass outClass) + public void MethodWithRefAndOutParameters(ref string refString, ref Exception refException, out int outInt, out SimpleClass outClass) { outInt = 2; - outClass = new Classes.SimpleClass(1, ""); + outClass = new SimpleClass(1, ""); } // FIXME not in the model @@ -402,7 +431,7 @@ public ref Exception RefException() return ref exception; } - public unsafe void* UnsafeMethod(int* intPointer, Structs.EmptyStruct* structPointer, uint* uintPointer) + public unsafe void* UnsafeMethod(int* intPointer, EmptyStruct* structPointer, uint* uintPointer) { return null; } @@ -416,17 +445,20 @@ public class Generic where D : Exception // FIXME generic constraint not i { public C genericClassTypeField; public Dictionary genericField; + public IList> listOfListField; + public readonly List l = new List {"holas"}; public IList GetExceptionsList(List _) { var a = 1 + 2; if (a == 3) { - } + return new List(); } + public void PrintGeneric(T t) { Console.WriteLine(t.ToString()); @@ -446,8 +478,8 @@ public IList RecievesAndReturnsGenericTypeList(IList listT) return listT; } } - } + namespace MethodBody { public abstract class ContainingClass @@ -513,30 +545,33 @@ public void Alloc() } } - // FIXME causes genericParamTableNotSorted - // void Nothing(T arg) { } + public void Nothing(T arg) + { + } - public void Calls(Classes.SimpleClass simpleClass, Action f) + public void + Calls(SimpleClass simpleClass, Action f) // FIXME ilspy method row without name. Probably because of the missing parameter count { Console.WriteLine("A method call"); // static simpleClass.DoNothing(); // virtual Alloc(); // normal - // f(1); //FIXME not working + var l = new List {"holas"}; + + f(1); //FIXME callvirt instance void class. The "class" is not being generated. It seems to be only for generic method refs. Same problem that generic not being correctly? // TODO calli (indirect) /* not working when reading dll - var g = new Generics.Generic(); + var g = new Generics.Generic(); g.PrintGeneric("hola"); g.PrintGeneric(1); */ - // FIXME Nothing(""); generic method call (instantiated) not generated correctly (missing instantiation) - + Nothing(""); // FIXME generic method call (instantiated) not generated correctly (missing instantiation) } - public void Arrays(Structs.EmptyStruct[] structArray) + public void Arrays(EmptyStruct[] structArray) { byte y = 1; short s = 3; @@ -544,7 +579,7 @@ public void Arrays(Structs.EmptyStruct[] structArray) long l = 5; float f = 6; double d = 7; - Structs.EmptyStruct p; + EmptyStruct p; var byteArray = new byte[2]; // newarr + stelem.ref var shortArray = new short[2]; // newarr + stelem.ref var intArray = new int[5]; // newarr + stelem.ref @@ -552,7 +587,7 @@ public void Arrays(Structs.EmptyStruct[] structArray) var floatArray = new float[2]; // newarr + stelem.ref var doubleArray = new double[2]; // newarr + stelem.ref var exceptionArray = new Exception[2]; // newarr + stelem.ref - var stringInitializedArray = new string[] { "hello", "world", "!" }; // newarr + stelem.ref + var stringInitializedArray = new string[] {"hello", "world", "!"}; // newarr + stelem.ref unsafe { var m = new int*[5]; // newarr + stelem.ref @@ -564,40 +599,42 @@ public void Arrays(Structs.EmptyStruct[] structArray) intArray[1] = x; // stelem.i4 longArray[1] = l; // stelem.i8 floatArray[1] = f; // stelem.r4 - doubleArray[1] = d; // stelem.r8 + doubleArray[1] = d; // stelem.r8 structArray[0] = p; // stelem // TODO stelem.i } - public void Empty() { } + public void Empty() + { + } public void Convert(object o) { long x1 = 1; double d = 1.0; - sbyte x2 = (sbyte)x1; // conv.i1 - short x3 = (short)x1; // conv.i2 - int x4 = (int)x1; // conv.i4 - x1 = (long)d; // conv.i8 - float f = (float)d; // conv.r4 + sbyte x2 = (sbyte) x1; // conv.i1 + short x3 = (short) x1; // conv.i2 + int x4 = (int) x1; // conv.i4 + x1 = (long) d; // conv.i8 + float f = (float) d; // conv.r4 //TODO conv.r8 - byte x5 = (byte)x1; // conv.u1 - ushort x6 = (ushort)x1; // conv.u2 - uint x7 = (uint)x1; // conv.u4 - var x8 = (ulong)d; // conv.u8 + byte x5 = (byte) x1; // conv.u1 + ushort x6 = (ushort) x1; // conv.u2 + uint x7 = (uint) x1; // conv.u4 + var x8 = (ulong) d; // conv.u8 // TODO conv.i // TODO conv.u // TODO conv.r.un - string s = (string)(object)"asd"; // castclass $class - var x = (int[])(object)new int[] { }; + string s = (string) (object) "asd"; // castclass $class + var x = (int[]) (object) new int[] { }; // FIXME framework read not working. // var b = o is Classes.SimpleClass; // isinst $class object l = 1; // box int - int i = (int)l; // unbox.any int + int i = (int) l; // unbox.any int // TODO unbox (unbox ptr) } @@ -616,12 +653,12 @@ public void LoadConstant() int eight = 8; // ldc.i4.8 int minusOne = -1; // ldc.i4.m1 int i = 20; // ldc.i4.s 20 - long c = (char)9; // ldc.i4.s 9 + conv.i8 + long c = (char) 9; // ldc.i4.s 9 + conv.i8 int k = int.MaxValue; // ldc.i4 long q = int.MaxValue; // ldc.i4 + conv.i8 - long l = long.MinValue; // ldc.i8 - float f = float.MinValue; // ldc.r4 - double d = double.MinValue; // ldc.r8 + long l = long.MinValue; // ldc.i8 + float f = float.MinValue; // ldc.r4 + double d = double.MinValue; // ldc.r8 } public void LoadArgument(int arg1, string arg2, bool arg3, int arg4) @@ -705,15 +742,16 @@ public void Compare(int b) public void Create() { - new Classes.SimpleClass(1, "a"); // newobj $methodCall - var a = new int[] { 1, 2, 3 }; // newarr int + new SimpleClass(1, "a"); // newobj $methodCall + var a = new int[] {1, 2, 3}; // newarr int var b = new Exception[] { }; // newarr Clases.SimpleClass unsafe { - var c = new int*[] { }; // newarr int* + var c = new int*[] { }; // newarr int* var d = new int**[] { }; // newarr int** } } + public void LoadArray(Exception[] x, int[] q) { var a = x[1]; // ldelem.ref @@ -722,10 +760,10 @@ public void LoadArray(Exception[] x, int[] q) var d = (new short[] { })[0]; // ldelem.i2 var e = (new ushort[] { })[0]; // ldelem.u2 var f = (new int[] { })[0]; // ldelem.i4 - var g = (new uint[] { })[0];// ldelem.u4 + var g = (new uint[] { })[0]; // ldelem.u4 var h = (new long[] { })[0]; // ldelem.i8 -- ldelem.u8 (alias) - var j = (new float[] { })[0];// ldelem.r4 - var k = (new double[] { })[0];// ldelem.r8 + var j = (new float[] { })[0]; // ldelem.r4 + var k = (new double[] { })[0]; // ldelem.r8 // TODO ldelem.i ??? // TODO ldelem typeTok ??? @@ -739,14 +777,14 @@ public void LoadArray(Exception[] x, int[] q) // } - var l = (new int[] { 1, 2, 3 }).Length; // ldlen + var l = (new int[] {1, 2, 3}).Length; // ldlen } public void LoadField() { - var a = new Classes.SimpleClass(1, "b").unassignedString; // ldfld string $field - var b = new Classes.SimpleClass(1, "b").readOnlyIntField; // ldfld int $field - var c = new Classes.ClassWithMoreComplexFieldsAndParamtersOrReturnTypes().b; // ldfld class $field + var a = new SimpleClass(1, "b").unassignedString; // ldfld string $field + var b = new SimpleClass(1, "b").readOnlyIntField; // ldfld int $field + var c = new ClassWithMoreComplexFieldsAndParametersOrReturnTypes().b; // ldfld class $field //FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? // unsafe @@ -758,9 +796,9 @@ public void LoadField() public void StoreField() { - new Classes.SimpleClass(1, "b").unassignedString = ""; // stfld string $field - Classes.StaticClass.i = 1; // stsfld int $field - Classes.StaticClass.e = new Exception(); // stsfld Exception $field + new SimpleClass(1, "b").unassignedString = ""; // stfld string $field + StaticClass.i = 1; // stsfld int $field + StaticClass.e = new Exception(); // stsfld Exception $field } public void StoreValue(int arg) @@ -783,7 +821,7 @@ public void SizeOf() { // FIXME framework read not working // var x = sizeof(Structs.NonEmptyStruct); // sizeof $type - var z = sizeof(Structs.NonEmptyStruct***); // sizeof $type*** + var z = sizeof(NonEmptyStruct***); // sizeof $type*** var y = sizeof(int*); // sizeof int* } } @@ -820,7 +858,7 @@ public void Branch(int a, int b, Exception e) // brinst (not short form) goto Label; // br.s - Label: + Label: int x; if (a > 2) // brfalse.s @@ -832,8 +870,9 @@ public void Branch(int a, int b, Exception e) case 2: break; // beq.s } - if (e?.Message != null) { } // brtrue.s - + if (e?.Message != null) + { + } // brtrue.s } public void ExceptionHandlingTryCatch(int x) @@ -844,7 +883,6 @@ public void ExceptionHandlingTryCatch(int x) } catch { - } } @@ -857,7 +895,6 @@ public void ExceptionHandlingTryCatchSpecific(int x) } catch (Exception ex) { - } } @@ -870,7 +907,6 @@ public void ExceptionHandlingTryCatchFilter(int x) } catch (Exception ex) when (ex.Message.Contains("by zero")) { - } } diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 2076926f..732a10c7 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -11,8 +11,8 @@ public class Generator : IGenerator { public void Generate(Assembly assembly) { - using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) - // using (var peStream = File.OpenWrite($"./{assembly.Name}.exe")) + using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) + // using (var peStream = File.OpenWrite($"./{assembly.Name}.exe")) { var metadataContainer = AssemblyGenerator.Generate(assembly); var peHeaderBuilder = new SRPE.PEHeaderBuilder( diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index b3ec33da..22e8a2c8 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -33,6 +33,11 @@ public static MetadataContainer Generate(Assembly assembly) mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), encId: metadataBuilder.GetOrAddGuid(Guid.Empty), encBaseId: metadataBuilder.GetOrAddGuid(Guid.Empty)); + /* + * Generic parameters table must be sorted by owner (TypeOrMethodDef that owns the generic parameter). Since the dll's methods and types don't follow a + * particular order, the info needed to generate this parameters is stored during type/method generation but not added to the MetadataBuilder until now + */ + metadataContainer.GenerateGenericParameters(); return metadataContainer; } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index d9e4adf1..4c1cfdf2 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -18,8 +18,6 @@ public MethodBodyControlFlowGenerator(ECMA335.InstructionEncoder instructionEnco this.metadataContainer = metadataContainer; } - // FIXME hacia afuera quiza no deberia estar esto y en cambio hablar de procesar los branchInstruction o algo asi - // FIXME hay que pensar toda esta clase public ECMA335.LabelHandle LabelHandleFor(string label) { label = label.ToLower(); diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index a803a32f..f6a5a3f2 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -319,15 +319,12 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.LoadString(metadataContainer.metadataBuilder.GetOrAddUserString(value)); } - // TODO see ECMA ldc instruction. It says some cases should be follow by conv.i8 operations but the bytecode (original) does not have that else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Int8) || loadInstruction.Operand.Type.Equals(PlatformTypes.UInt8)) { var value = (int) (loadInstruction.Operand as Constant).Value; instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); instructionEncoder.Token(value); - // FIXME: do only if value variable storing the 8 bit number is 8 byte integer. - // instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); } else if ( loadInstruction.Operand.Type.Equals(PlatformTypes.Int16) || @@ -337,8 +334,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { var value = (int) (loadInstruction.Operand as Constant).Value; instructionEncoder.LoadConstantI4(value); - // FIXME: do only if value variable storing the 16/32 bit number is 8 byte integer. - // instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); } else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Int64) || loadInstruction.Operand.Type.Equals(PlatformTypes.UInt64)) @@ -363,11 +358,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case LoadFieldInstruction loadFieldInstruction: // TODO handle ldflda. Example present but not supported in model - instructionEncoder.OpCode(SRM.ILOpCode.Ldfld); instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field)); break; case LoadArrayElementInstruction loadArrayElementInstruction: + // TODO this is currently modeled as a basic instruction and this is not used break; case LoadMethodAddressInstruction loadMethodAddressInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); @@ -386,12 +381,10 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case CreateObjectInstruction createObjectInstruction: - { var method = metadataContainer.ResolveReferenceHandleFor(createObjectInstruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); break; - } case StoreInstruction storeInstruction: if (storeInstruction.Target.IsParameter) { @@ -426,12 +419,10 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadTokenInstruction.Token)); break; case IndirectMethodCallInstruction indirectMethodCallInstruction: - { // TODO test var methodSignature = metadataContainer.ResolveStandaloneSignatureFor(indirectMethodCallInstruction.Function); instructionEncoder.CallIndirect(methodSignature); break; - } case StoreArrayElementInstruction storeArrayElementInstruction: // FIXME // Framework currently handles this as a BasicInstruction and this is never generated. Should use this one diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index 0abdf22b..24046d5b 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -81,28 +81,10 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) implementedInterface: metadataContainer.ResolveReferenceHandleFor(interfaze)); } - /* - * Generic parameters table must be sorted that's why this is done at the end and not during the method generation. - * If done that way, method generic parameters of a type are added before the type's generic parameters and table results unsorted - */ - - // generate class generic parameters (Class) foreach (var genericParameter in type.GenericParameters) { - var genericParameterHandle = metadataBuilder.AddGenericParameter( - typeDefinitionHandle, - SR.GenericParameterAttributes.None, // FIXME - metadataBuilder.GetOrAddString(genericParameter.Name), - genericParameter.Index); - - /* FIXME generic constraints not in the model - if(genericParameter.hasConstraint()){ - metadataBuilder.AddGenericParameterConstraint( - genericParameterHandle, - metadataContainer.ResolveReferenceHandleFor(genericParameter.contraint)); - } - */ + metadataContainer.RegisterGenericParameter(typeDefinitionHandle, genericParameter); } // generate method generic parameters (public T method(T param)) @@ -111,19 +93,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) var method = type.Methods[i]; foreach (var genericParameter in method.GenericParameters) { - var genericParameterHandle = metadataBuilder.AddGenericParameter( - methodDefinitionHandles[i], - SR.GenericParameterAttributes.None, // FIXME - metadataBuilder.GetOrAddString(genericParameter.Name), - genericParameter.Index); - - /* FIXME generic constraints not in the model - if(genericParameter.hasConstraint()){ - metadataBuilder.AddGenericParameterConstraint( - genericParameterHandle, - metadataContainer.ResolveReferenceHandleFor(genericParameter.contraint)); - } - */ + metadataContainer.RegisterGenericParameter(methodDefinitionHandles[i], genericParameter); } } diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index 11a5fac4..44c59b1f 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -144,7 +144,7 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para attributes |= ParameterAttributes.Out; break; case MethodParameterKind.Ref: - // TODO + // TODO break; } diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 9fa98a05..4b55264a 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -1,6 +1,9 @@ using System; -using Model; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection; using Model.Types; +using Assembly = Model.Assembly; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -12,6 +15,7 @@ internal class MetadataContainer private readonly MetadataResolver metadataResolver; public readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; private SRM.MethodDefinitionHandle? mainMethodHandle; + private readonly IDictionary> genericParameters = new Dictionary>(); public SRM.MethodDefinitionHandle? MainMethodHandle { @@ -39,5 +43,50 @@ public SRM.EntityHandle ResolveReferenceHandleFor(IMetadataReference metadataRef metadataResolver.ReferenceHandleOf(metadataReference); public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) => metadataResolver.Encode(type, encoder); + + public void RegisterGenericParameter(SRM.TypeDefinitionHandle owner, GenericParameter genericParameter) => + DoRegisterGenericParameter(owner, genericParameter); + + public void RegisterGenericParameter(SRM.MethodDefinitionHandle owner, GenericParameter genericParameter) => + DoRegisterGenericParameter(owner, genericParameter); + + // FIXME name + private void DoRegisterGenericParameter(SRM.EntityHandle owner, GenericParameter genericParameter) + { + void GenerateGenericParameter() => metadataBuilder.AddGenericParameter( + owner, + GenericParameterAttributes.None, // FIXME ? + metadataBuilder.GetOrAddString(genericParameter.Name), genericParameter.Index); + + /* FIXME generic constraints not in the model + if(genericParameter.hasConstraint()){ + metadataBuilder.AddGenericParameterConstraint( + genericParameterHandle, + metadataContainer.ResolveReferenceHandleFor(genericParameter.contraint)); + }*/ + + var key = ECMA335.CodedIndex.TypeOrMethodDef(owner); + if (genericParameters.TryGetValue(key, out var actions)) + { + actions.Add(GenerateGenericParameter); + } + else + { + genericParameters.Add(key, new List {GenerateGenericParameter}); + } + } + + public void GenerateGenericParameters() + { + var sortedOwners = genericParameters.Keys.ToImmutableSortedSet(); + foreach (var owner in sortedOwners) + { + genericParameters.TryGetValue(owner, out var generateGenericParameterOperations); + foreach (var generateGenericParameter in generateGenericParameterOperations) + { + generateGenericParameter(); + } + } + } } } \ No newline at end of file diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 79009ab0..a48dd1cc 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -240,7 +240,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) break; } - case GenericParameter genericParameter: + case IGenericParameterReference genericParameter: switch (genericParameter.Kind) { case GenericParameterKind.Type: From e99c23e412358731274f5f2c09a2a32cbb65726d Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 29 Nov 2019 20:57:27 -0300 Subject: [PATCH 060/256] fix generic instantiation method call generation --- Examples/Examples.cs | 7 +++- MetadataGenerator/Extensions.cs | 3 ++ .../Methods/MethodSignatureGenerator.cs | 20 +++++++++-- .../Metadata/MetadataResolver.cs | 35 ++++++++++++------- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 70ded095..a73a6bdf 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -549,6 +549,10 @@ public void Nothing(T arg) { } + public void Nothing2() + { + } + public void Calls(SimpleClass simpleClass, Action f) // FIXME ilspy method row without name. Probably because of the missing parameter count { @@ -562,13 +566,14 @@ public void // TODO calli (indirect) - /* not working when reading dll + /* not working when reading dll var g = new Generics.Generic(); g.PrintGeneric("hola"); g.PrintGeneric(1); */ Nothing(""); // FIXME generic method call (instantiated) not generated correctly (missing instantiation) + Nothing2(); } public void Arrays(EmptyStruct[] structArray) diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index c540235d..08b1a334 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -27,5 +27,8 @@ public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.Enti public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; public static string CurrentLabelString(this ECMA335.InstructionEncoder instructionEncoder) => $"L_{instructionEncoder.Offset:x4}".ToLower(); + + // FIXME maybe include in model instead of extension? + public static bool IsGenericInstantiation(this IMethodReference method) => method.GenericMethod != null; } } \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 480f2adc..2fc09b72 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -15,8 +15,24 @@ public MethodSignatureGenerator(MetadataContainer metadataContainer) this.metadataContainer = metadataContainer; } - public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) => - GenerateMethodSignature(method.IsStatic, method.GenericParameterCount, method.Parameters, method.ReturnType); + public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) + { + if (method.IsGenericInstantiation()) + { + var signature = new SRM.BlobBuilder(); + var encoder = new ECMA335.BlobEncoder(signature).MethodSpecificationSignature(method.GenericArguments.Count); + foreach (var genericArg in method.GenericArguments) + { + metadataContainer.Encode(genericArg, encoder.AddArgument()); + } + + return signature; + } + else + { + return GenerateMethodSignature(method.IsStatic, method.GenericParameterCount, method.Parameters, method.ReturnType); + } + } public SRM.BlobBuilder GenerateSignatureOf(FunctionPointerType method) => GenerateMethodSignature(method.IsStatic, 0, method.Parameters, method.ReturnType); diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index a48dd1cc..f9440f93 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -133,22 +133,33 @@ private SRM.TypeReferenceHandle ReferenceHandleOf(IBasicType type, string typeNa return typeReference; } - private SRM.MemberReferenceHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder signature) + private SRM.EntityHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder signature) { - var key = - $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; - if (!memberReferences.TryGetValue(key, out var memberReferenceHandle)) + if (method.IsGenericInstantiation()) { - memberReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( - parent: ReferenceHandleOf(method.ContainingType), - name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), - signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); - memberReferences.Add(key, memberReferenceHandle); - - return memberReferenceHandle; + // FIXME should be store and not add a new one each time (like the else branch). + // To do this, the key should have info related to the instantiation that unequivocally identifies that particular instantiation + var methodSpecificationHandle = metadataContainer.metadataBuilder.AddMethodSpecification( + ReferenceHandleOf(method.GenericMethod, methodSignatureGenerator.GenerateSignatureOf(method.GenericMethod)), + metadataContainer.metadataBuilder.GetOrAddBlob(signature) + ); + return methodSpecificationHandle; } + else + { + var key = + $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; + if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) + { + methodReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( + parent: ReferenceHandleOf(method.ContainingType), + name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), + signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + memberReferences.Add(key, methodReferenceHandle); + } - return memberReferenceHandle; + return methodReferenceHandle; + } } // FIXME extract method for both method and field? identical From c09b0bd2027fc71f12536b75b44be01d6e67b53d Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 30 Nov 2019 19:57:27 -0300 Subject: [PATCH 061/256] ensure nested types table is sorted. Generics almost correct --- Examples/Examples.cs | 29 +++++++++++-- MetadataGenerator/Extensions.cs | 3 -- .../Generators/AssemblyGenerator.cs | 3 ++ .../Methods/MethodSignatureGenerator.cs | 2 +- .../Generators/NamespaceGenerator.cs | 2 +- .../Metadata/MetadataContainer.cs | 17 ++++++++ .../Metadata/MetadataResolver.cs | 42 +++++++++++-------- 7 files changed, 71 insertions(+), 27 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index a73a6bdf..e7c0178e 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -447,7 +447,7 @@ public class Generic where D : Exception // FIXME generic constraint not i public Dictionary genericField; public IList> listOfListField; - public readonly List l = new List {"holas"}; + public readonly List stringList = new List {"holas"}; public IList GetExceptionsList(List _) { @@ -478,6 +478,27 @@ public IList RecievesAndReturnsGenericTypeList(IList listT) return listT; } } + + public class GenericClassContainingOtherClasses + { + public class NestedClassThatDoesNotAddNewGenericParameters + { + } + + public class NestedClassThatAddsNewGenericParameters + { + public class NestedNestedClassThatAddsNewGenericParameters + { + } + } + } + + public class ClassThatContainsNestedGenericClass + { + public class NestedGenericClass + { + } + } } namespace MethodBody @@ -553,8 +574,8 @@ public void Nothing2() { } - public void - Calls(SimpleClass simpleClass, Action f) // FIXME ilspy method row without name. Probably because of the missing parameter count + // TODO more generic method calls examples + public void Calls(SimpleClass simpleClass, Action f) { Console.WriteLine("A method call"); // static simpleClass.DoNothing(); // virtual @@ -572,7 +593,7 @@ public void g.PrintGeneric(1); */ - Nothing(""); // FIXME generic method call (instantiated) not generated correctly (missing instantiation) + Nothing(""); Nothing2(); } diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index 08b1a334..c540235d 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -27,8 +27,5 @@ public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.Enti public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; public static string CurrentLabelString(this ECMA335.InstructionEncoder instructionEncoder) => $"L_{instructionEncoder.Offset:x4}".ToLower(); - - // FIXME maybe include in model instead of extension? - public static bool IsGenericInstantiation(this IMethodReference method) => method.GenericMethod != null; } } \ No newline at end of file diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index 22e8a2c8..b97aedef 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -39,6 +39,9 @@ public static MetadataContainer Generate(Assembly assembly) */ metadataContainer.GenerateGenericParameters(); + // nested types table also needs to be sorted + metadataContainer.GenerateNestedTypes(); + return metadataContainer; } } diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 2fc09b72..18e184b6 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -17,7 +17,7 @@ public MethodSignatureGenerator(MetadataContainer metadataContainer) public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) { - if (method.IsGenericInstantiation()) + if (method.GenericMethod != null) { var signature = new SRM.BlobBuilder(); var encoder = new ECMA335.BlobEncoder(signature).MethodSpecificationSignature(method.GenericArguments.Count); diff --git a/MetadataGenerator/Generators/NamespaceGenerator.cs b/MetadataGenerator/Generators/NamespaceGenerator.cs index 6484efce..ac6e787e 100644 --- a/MetadataGenerator/Generators/NamespaceGenerator.cs +++ b/MetadataGenerator/Generators/NamespaceGenerator.cs @@ -37,7 +37,7 @@ private SRM.TypeDefinitionHandle GenerateTypes(TypeDefinition type) var typeDefinitionHandle = typeGenerator.Generate(type); foreach (var nestedType in nestedTypes) { - metadataContainer.metadataBuilder.AddNestedType(nestedType, typeDefinitionHandle); + metadataContainer.RegisterNestedType(nestedType, typeDefinitionHandle); } return typeDefinitionHandle; diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 4b55264a..d910a4f9 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -16,6 +16,7 @@ internal class MetadataContainer public readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; private SRM.MethodDefinitionHandle? mainMethodHandle; private readonly IDictionary> genericParameters = new Dictionary>(); + private readonly IDictionary nestedTypes = new Dictionary(); public SRM.MethodDefinitionHandle? MainMethodHandle { @@ -88,5 +89,21 @@ public void GenerateGenericParameters() } } } + + public void RegisterNestedType(SRM.TypeDefinitionHandle nestedType, SRM.TypeDefinitionHandle enclosingType) + { + var key = ECMA335.CodedIndex.TypeOrMethodDef(nestedType); + nestedTypes.Add(key, () => metadataBuilder.AddNestedType(nestedType, enclosingType)); + } + + public void GenerateNestedTypes() + { + var sortedOwners = nestedTypes.Keys.ToImmutableSortedSet(); + foreach (var owner in sortedOwners) + { + nestedTypes.TryGetValue(owner, out var addNestedType); + addNestedType(); + } + } } } \ No newline at end of file diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index f9440f93..ddca02d4 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -76,35 +76,41 @@ private SRM.EntityHandle ReferenceHandleOf(IType type) { switch (type) { - case IBasicType basicType: return ReferenceHandleOf(basicType, basicType.Name); - case IGenericParameterReference genericParameterReference: - return ReferenceHandleOf(genericParameterReference.GenericContainer.ContainingType, genericParameterReference.Name); - case ArrayType arrayType: + case IBasicType basicType: return ReferenceHandleOf(basicType); + case IType arrayOrPointerType when arrayOrPointerType is ArrayType || arrayOrPointerType is PointerType: { var signature = new SRM.BlobBuilder(); var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); - Encode(arrayType, encoder); - return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); - } - case PointerType pointerType: - { - var signature = new SRM.BlobBuilder(); - var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); - Encode(pointerType, encoder); + Encode(arrayOrPointerType, encoder); return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); } default: - throw new Exception("not yet supported"); + throw new Exception($"type ${type} not yet supported"); } } /* * Returns a TypeReference for type. It stores references because metadata does not have a getOrAddTypeReference. */ - private SRM.TypeReferenceHandle ReferenceHandleOf(IBasicType type, string typeName) + private SRM.EntityHandle ReferenceHandleOf(IBasicType type) { + var typeName = type.Name; + + /** + * CLS-compliant generic type names are encoded using the format “name[`arity]”, where […] indicates that the grave accent character “`” and + * arity together are optional. The encoded name shall follow these rules: + * - name shall be an ID that does not contain the “`” character. + * - arity is specified as an unsigned decimal number without leading zeros or spaces. + * - For a normal generic type, arity is the number of type parameters declared on the type. + * - For a nested generic type, arity is the number of newly introduced type parameters. + */ + if (type.GenericParameterCount > 0) + { + typeName = $"{type.Name}`{type.GenericParameterCount}"; + } + var typeReferenceKey = - $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{type.Name}"; + $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{typeName}"; if (!typeReferences.TryGetValue(typeReferenceKey, out var typeReference)) { SRM.EntityHandle resolutionScope; @@ -135,7 +141,7 @@ private SRM.TypeReferenceHandle ReferenceHandleOf(IBasicType type, string typeNa private SRM.EntityHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder signature) { - if (method.IsGenericInstantiation()) + if (method.GenericMethod != null) { // FIXME should be store and not add a new one each time (like the else branch). // To do this, the key should have info related to the instantiation that unequivocally identifies that particular instantiation @@ -205,10 +211,10 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { case IBasicType basicType: { - if (basicType.GenericType != null) + if (basicType.GenericParameterCount > 0) { var genericInstantiation = encoder.GenericInstantiation( - ReferenceHandleOf(basicType), + ReferenceHandleOf(basicType.GenericType), basicType.GenericParameterCount, type.TypeKind == TypeKind.ValueType); foreach (var genericArg in basicType.GenericArguments) From 732a0f36cadd1e5e046eb32f95523c35619dd1b6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 30 Nov 2019 21:07:43 -0300 Subject: [PATCH 062/256] more of generics --- Examples/Examples.cs | 19 +++++++++-- MetadataGenerator/Generators/TypeGenerator.cs | 33 ++++++++++++++++++- .../Metadata/MetadataResolver.cs | 1 + 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index e7c0178e..6574363d 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -3,6 +3,7 @@ using System.Reflection.Metadata; using Accessibility; using Classes; +using Generics; using Hierarchy; using Nested.NestedNamespace.NestedNestedNamesace; using Structs; @@ -490,6 +491,10 @@ public class NestedClassThatAddsNewGenericParameters public class NestedNestedClassThatAddsNewGenericParameters { } + + public class NestedNestedClassThatDoesNotAddNewGenericParameters + { + } } } @@ -581,13 +586,16 @@ public void Calls(SimpleClass simpleClass, Action f) simpleClass.DoNothing(); // virtual Alloc(); // normal - var l = new List {"holas"}; + var l = new List {"holas"}; // FIXME missing in bytecode - f(1); //FIXME callvirt instance void class. The "class" is not being generated. It seems to be only for generic method refs. Same problem that generic not being correctly? + //FIXME callvirt instance void class. The "class" is not being generated. It seems to be only for generic method refs. + // FIXME missing in bytecode + f(1); // TODO calli (indirect) - /* not working when reading dll + /* FIXME + not working when reading dll var g = new Generics.Generic(); g.PrintGeneric("hola"); g.PrintGeneric(1); @@ -595,6 +603,11 @@ public void Calls(SimpleClass simpleClass, Action f) Nothing(""); Nothing2(); + /* FIXME + not working when reading dll + Nothing2>(); + Nothing2.NestedClassThatAddsNewGenericParameters.NestedNestedClassThatDoesNotAddNewGenericParameters>(); + */ } public void Arrays(EmptyStruct[] structArray) diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index 24046d5b..48be9ae4 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -69,7 +69,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( attributes: GetTypeAttributesFor(type), @namespace: metadataBuilder.GetOrAddString(type.ContainingNamespace.FullName), - name: metadataBuilder.GetOrAddString(type.Name), + name: metadataBuilder.GetOrAddString(TypeNameOf(type)), baseType: type.Base != null ? metadataContainer.ResolveReferenceHandleFor(type.Base) : default, fieldList: fieldDefinitionHandles.FirstOr(nextFieldDefinitionHandle), methodList: methodDefinitionHandles.FirstOr(nextMethodDefinitionHandle)); @@ -99,5 +99,36 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) return typeDefinitionHandle; } + + /** + * CLS-compliant generic type names are encoded using the format “name[`arity]”, where […] indicates that the grave accent character “`” and + * arity together are optional. The encoded name shall follow these rules: + * - name shall be an ID that does not contain the “`” character. + * - arity is specified as an unsigned decimal number without leading zeros or spaces. + * - For a normal generic type, arity is the number of type parameters declared on the type. + * - For a nested generic type, arity is the number of newly introduced type parameters. + */ + private static string TypeNameOf(TypeDefinition type) + { + var typeName = type.Name; + if (type.GenericParameters.Count > 0) + { + if (type.ContainingType != null) + { + var containingTypeGenericParameters = type.ContainingType.GenericParameters.Select(p => p.Name).ToList(); + var parameterCount = type.GenericParameters.Count(parameter => !containingTypeGenericParameters.Contains(parameter.Name)); + if (parameterCount > 0) + { + typeName = $"{typeName}`{parameterCount}"; + } + } + else + { + typeName = $"{typeName}`{type.GenericParameters.Count}"; + } + } + + return typeName; + } } } \ No newline at end of file diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index ddca02d4..ab895df0 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -104,6 +104,7 @@ private SRM.EntityHandle ReferenceHandleOf(IBasicType type) * - For a normal generic type, arity is the number of type parameters declared on the type. * - For a nested generic type, arity is the number of newly introduced type parameters. */ + // FIXME partial logic. See TypeGenerator.TypeNameOf. Needs to be unified with that if (type.GenericParameterCount > 0) { typeName = $"{type.Name}`{type.GenericParameterCount}"; From 6aabbf488fdb15f547d7fc6d96f3fb707dfd2764 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 8 Dec 2019 22:06:34 -0300 Subject: [PATCH 063/256] generics OK --- Examples/Examples.cs | 7 +++-- MetadataGenerator/Extensions.cs | 6 ++++ .../Methods/MethodSignatureGenerator.cs | 2 +- MetadataGenerator/Generators/TypeGenerator.cs | 9 +++--- .../Metadata/MetadataResolver.cs | 31 +++++++++++++------ 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 6574363d..f8331f33 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -439,7 +439,6 @@ public ref Exception RefException() } } -// FIXME generation almost correct. namespace Generics { public class Generic where D : Exception // FIXME generic constraint not in the model @@ -448,6 +447,9 @@ public class Generic where D : Exception // FIXME generic constraint not i public Dictionary genericField; public IList> listOfListField; + + // FIXME the assigment is done in the .ctor with a stfld instruction but i'm generating a stsfld instruction. That's because somehow the field that i recieve is static + // FIXME when in reality it is not. Maybe a fault in the model? public readonly List stringList = new List {"holas"}; public IList GetExceptionsList(List _) @@ -460,6 +462,7 @@ public IList GetExceptionsList(List _) return new List(); } + // TODO this generated a "constrained." instruction. But is not supported in the model (it puts a Nop instruction in its place) public void PrintGeneric(T t) { Console.WriteLine(t.ToString()); @@ -590,7 +593,7 @@ public void Calls(SimpleClass simpleClass, Action f) //FIXME callvirt instance void class. The "class" is not being generated. It seems to be only for generic method refs. // FIXME missing in bytecode - f(1); + f(1); // TODO calli (indirect) diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index c540235d..de37cf22 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -27,5 +27,11 @@ public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.Enti public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; public static string CurrentLabelString(this ECMA335.InstructionEncoder instructionEncoder) => $"L_{instructionEncoder.Offset:x4}".ToLower(); + + public static bool IsGenericInstantiation(this IBasicType type) => type.GenericType != null; + + public static bool IsGenericInstantiation(this IMethodReference method) => method.GenericMethod != null; + + public static bool IsGenericType(this IBasicType type) => type.GenericType == null && type.GenericParameterCount > 0; } } \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 18e184b6..2fc09b72 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -17,7 +17,7 @@ public MethodSignatureGenerator(MetadataContainer metadataContainer) public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) { - if (method.GenericMethod != null) + if (method.IsGenericInstantiation()) { var signature = new SRM.BlobBuilder(); var encoder = new ECMA335.BlobEncoder(signature).MethodSpecificationSignature(method.GenericArguments.Count); diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index 48be9ae4..e52b3def 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -111,15 +111,16 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) private static string TypeNameOf(TypeDefinition type) { var typeName = type.Name; - if (type.GenericParameters.Count > 0) + if (type.IsGenericType()) { if (type.ContainingType != null) { var containingTypeGenericParameters = type.ContainingType.GenericParameters.Select(p => p.Name).ToList(); - var parameterCount = type.GenericParameters.Count(parameter => !containingTypeGenericParameters.Contains(parameter.Name)); - if (parameterCount > 0) + var newlyIntroducedGenericParametersCount = + type.GenericParameters.Count(parameter => !containingTypeGenericParameters.Contains(parameter.Name)); + if (newlyIntroducedGenericParametersCount > 0) { - typeName = $"{typeName}`{parameterCount}"; + typeName = $"{typeName}`{newlyIntroducedGenericParametersCount}"; } } else diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index ab895df0..b086a7d5 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -82,6 +82,7 @@ private SRM.EntityHandle ReferenceHandleOf(IType type) var signature = new SRM.BlobBuilder(); var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); Encode(arrayOrPointerType, encoder); + // FIXME should be stored? or added every time? return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); } default: @@ -94,6 +95,16 @@ private SRM.EntityHandle ReferenceHandleOf(IType type) */ private SRM.EntityHandle ReferenceHandleOf(IBasicType type) { + // TODO rewrite this method better + // FIXME should be stored? or added every time? + if (type.IsGenericInstantiation()) + { + var signature = new SRM.BlobBuilder(); + var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); + Encode(type, encoder); + return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + } + var typeName = type.Name; /** @@ -104,15 +115,16 @@ private SRM.EntityHandle ReferenceHandleOf(IBasicType type) * - For a normal generic type, arity is the number of type parameters declared on the type. * - For a nested generic type, arity is the number of newly introduced type parameters. */ + // FIXME partial logic. See TypeGenerator.TypeNameOf. Needs to be unified with that - if (type.GenericParameterCount > 0) + if (type.IsGenericType()) { typeName = $"{type.Name}`{type.GenericParameterCount}"; } - var typeReferenceKey = + var key = $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{typeName}"; - if (!typeReferences.TryGetValue(typeReferenceKey, out var typeReference)) + if (!typeReferences.TryGetValue(key, out var typeReference)) { SRM.EntityHandle resolutionScope; if (type.ContainingType == null) // if defined in the namespace then search there @@ -131,7 +143,7 @@ private SRM.EntityHandle ReferenceHandleOf(IBasicType type) resolutionScope: resolutionScope, @namespace: metadataContainer.metadataBuilder.GetOrAddString(type.ContainingNamespace), name: metadataContainer.metadataBuilder.GetOrAddString(typeName)); - typeReferences.Add(typeReferenceKey, typeReference); + typeReferences.Add(key, typeReference); return typeReference; } @@ -142,10 +154,10 @@ private SRM.EntityHandle ReferenceHandleOf(IBasicType type) private SRM.EntityHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder signature) { - if (method.GenericMethod != null) + if (method.IsGenericInstantiation()) { - // FIXME should be store and not add a new one each time (like the else branch). - // To do this, the key should have info related to the instantiation that unequivocally identifies that particular instantiation + // FIXME should be stored and not add a new one each time (like the else branch). + // FIXME To do this, the key should have info related to the instantiation that unequivocally identifies that particular instantiation var methodSpecificationHandle = metadataContainer.metadataBuilder.AddMethodSpecification( ReferenceHandleOf(method.GenericMethod, methodSignatureGenerator.GenerateSignatureOf(method.GenericMethod)), metadataContainer.metadataBuilder.GetOrAddBlob(signature) @@ -155,7 +167,7 @@ private SRM.EntityHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuil else { var key = - $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.Name}.{method.Name}"; + $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType}.{method.Name}"; if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) { methodReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( @@ -169,7 +181,6 @@ private SRM.EntityHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuil } } - // FIXME extract method for both method and field? identical private SRM.MemberReferenceHandle ReferenceHandleOf(IFieldReference field, SRM.BlobBuilder signature) { var key = @@ -212,7 +223,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { case IBasicType basicType: { - if (basicType.GenericParameterCount > 0) + if (basicType.IsGenericInstantiation()) { var genericInstantiation = encoder.GenericInstantiation( ReferenceHandleOf(basicType.GenericType), From 5d35333408b0d34f1a11ef9a46d17acfdbb47f4a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 14 Dec 2019 17:28:35 -0300 Subject: [PATCH 064/256] refactors --- .../Body/MethodBodyControlFlowGenerator.cs | 1 - .../Methods/Body/MethodBodyGenerator.cs | 8 +++----- .../Generators/Methods/MethodGenerator.cs | 1 - .../Methods/MethodSignatureGenerator.cs | 2 +- MetadataGenerator/Generators/TypeGenerator.cs | 10 +++++----- MetadataGenerator/Metadata/AttributesProvider.cs | 12 +++--------- MetadataGenerator/Metadata/MetadataContainer.cs | 6 +----- MetadataGenerator/Metadata/MetadataResolver.cs | 15 ++++++--------- 8 files changed, 19 insertions(+), 36 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index 4c1cfdf2..1eb410f5 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -48,7 +48,6 @@ public void MarkCurrentLabel() } } - // FIXME name public void ProcessExceptionInformation(IList exceptionInformation) { var controlFlowBuilder = instructionEncoder.ControlFlowBuilder; diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index f6a5a3f2..ff8e2ccb 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -401,8 +401,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeFieldInstruction.Field)); break; case SwitchInstruction switchInstruction: - // TODO test. This instructions that are difficult to generate in example can be generated programatically (new SwitchInstruction...) - // maybe have an example files that generates all this instructions that are missing instructionEncoder.OpCode(SRM.ILOpCode.Switch); instructionEncoder.Token(switchInstruction.Targets.Count); switchInstruction.Targets @@ -420,8 +418,8 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case IndirectMethodCallInstruction indirectMethodCallInstruction: // TODO test - var methodSignature = metadataContainer.ResolveStandaloneSignatureFor(indirectMethodCallInstruction.Function); - instructionEncoder.CallIndirect(methodSignature); + var methodSignature = metadataContainer.ResolveReferenceHandleFor(indirectMethodCallInstruction.Function); + instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); break; case StoreArrayElementInstruction storeArrayElementInstruction: // FIXME @@ -436,7 +434,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } } - controlFlowGenerator.MarkAllUnmarkedLabels(); // FIXME + controlFlowGenerator.MarkAllUnmarkedLabels(); // FIXME remove return instructionEncoder; } diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 6545da84..7108b87d 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -39,7 +39,6 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) } } - // FIXME several addMethodBody variants with different arguments. codeSize, maxStacks, etc // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated // programatically then the maxStack is gonna be missing var methodBody = method.HasBody diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 2fc09b72..0d7fb06d 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -34,9 +34,9 @@ public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) } } + // FIXME 0 because FunctionPointerType does not have that property (there's a fixme in that class) public SRM.BlobBuilder GenerateSignatureOf(FunctionPointerType method) => GenerateMethodSignature(method.IsStatic, 0, method.Parameters, method.ReturnType); - // FIXME 0 because FunctionPointerType does not have that property (there's a fixme in that class) private SRM.BlobBuilder GenerateMethodSignature( bool isStatic, diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index e52b3def..9626fca2 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -35,21 +35,21 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) var propertySignatureBlogBuilder = new BlobBuilder(); new BlobEncoder(propertySignatureBlogBuilder) - .PropertySignature(isInstanceProperty: true) //FIXME when false + .PropertySignature(isInstanceProperty: true?) .Parameters( 0, - returnType => returnType.Type().Int32(), //FIXME backingField type + returnType => returnType.Type().Int32() (algun type), parameters => { }); var propertyDefinitionHandle = metadata.AddProperty( - attributes: PropertyAttributes.None, //FIXME - name: metadata.GetOrAddString(""), //FIXME property name + attributes: PropertyAttributes.None, + name: metadata.GetOrAddString(""), signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); // associate methods (get, set) to property metadata.AddMethodSemantics( propertyDefinitionHandle, - method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, //FIXME, + method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, methodHandle); //getter/setter metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); */ diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index 44c59b1f..bfd4fc66 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -89,11 +89,8 @@ public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) { - var constructor = - method.IsConstructor || - method.Name.Equals( - ".cctor"); // FIXME maybe MethodDefinition can have a isClassConstructor or isTypeInitializer - bool specialName = + var constructor = method.IsConstructor || method.Name.Equals(".cctor"); + var specialName = method.Name.StartsWith("get_", StringComparison.Ordinal) || method.Name.StartsWith("set_", StringComparison.Ordinal) || method.Name.StartsWith("op_", StringComparison.Ordinal); @@ -106,10 +103,7 @@ public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) ? MethodAttributes.NewSlot : 0) | // FIXME not entirely correct. Model is missing the new keyword (constructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | - (specialName - ? MethodAttributes.SpecialName - : 0); // FIXME fails if non getter/setter method starts with get_/set_ - + (specialName ? MethodAttributes.SpecialName : 0); switch (method.Visibility) { case VisibilityKind.Public: diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index d910a4f9..e2d1776a 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -37,9 +37,6 @@ public MetadataContainer(Assembly assembly) metadataResolver = new MetadataResolver(this, assembly); } - public SRM.StandaloneSignatureHandle ResolveStandaloneSignatureFor(FunctionPointerType method) => - metadataResolver.ResolveStandaloneSignatureFor(method); - public SRM.EntityHandle ResolveReferenceHandleFor(IMetadataReference metadataReference) => metadataResolver.ReferenceHandleOf(metadataReference); @@ -51,12 +48,11 @@ public void RegisterGenericParameter(SRM.TypeDefinitionHandle owner, GenericPara public void RegisterGenericParameter(SRM.MethodDefinitionHandle owner, GenericParameter genericParameter) => DoRegisterGenericParameter(owner, genericParameter); - // FIXME name private void DoRegisterGenericParameter(SRM.EntityHandle owner, GenericParameter genericParameter) { void GenerateGenericParameter() => metadataBuilder.AddGenericParameter( owner, - GenericParameterAttributes.None, // FIXME ? + GenericParameterAttributes.None, metadataBuilder.GetOrAddString(genericParameter.Name), genericParameter.Index); /* FIXME generic constraints not in the model diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index b086a7d5..9e1fda54 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -25,7 +25,6 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) this.metadataContainer = metadataContainer; this.assembly = assembly; - // FIXME: assemblyName => assemblyRef could result in false positive? foreach (var assemblyReference in assembly.References) { // FIXME parameters @@ -44,13 +43,6 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); } - //FIXME name? more generic? only needed for method? - public SRM.StandaloneSignatureHandle ResolveStandaloneSignatureFor(FunctionPointerType method) - { - var signature = methodSignatureGenerator.GenerateSignatureOf(method); - return metadataContainer.metadataBuilder.AddStandaloneSignature(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); - } - public SRM.EntityHandle ReferenceHandleOf(IMetadataReference metadataReference) { switch (metadataReference) @@ -65,10 +57,15 @@ public SRM.EntityHandle ReferenceHandleOf(IMetadataReference metadataReference) var signature = methodSignatureGenerator.GenerateSignatureOf(method); return ReferenceHandleOf(method, signature); } + case FunctionPointerType functionPointer: + { + var signature = methodSignatureGenerator.GenerateSignatureOf(functionPointer); + return metadataContainer.metadataBuilder.AddStandaloneSignature(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + } case IType type: return ReferenceHandleOf(type); default: - throw new Exception(); // FIXME + throw new Exception($"Metadata reference not supported"); } } From 6b6f6beb7f60052a6ea6debdeb11d86b1be4f469 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 15 Dec 2019 14:23:59 -0300 Subject: [PATCH 065/256] LoadArrayElementInstruction not basic operation --- Examples/Examples.cs | 7 +- .../Methods/Body/MethodBodyGenerator.cs | 71 +++++++++++++++---- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index f8331f33..b2db624e 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -806,9 +806,10 @@ public void LoadArray(Exception[] x, int[] q) var h = (new long[] { })[0]; // ldelem.i8 -- ldelem.u8 (alias) var j = (new float[] { })[0]; // ldelem.r4 var k = (new double[] { })[0]; // ldelem.r8 - + // TODO unccoment when LoadArrayElementInstruction PR is merged + // var l = new EmptyStruct[] {new EmptyStruct() }[0]; // ldelem typeTok + // TODO ldelem.i ??? - // TODO ldelem typeTok ??? // // FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? // unsafe @@ -819,7 +820,7 @@ public void LoadArray(Exception[] x, int[] q) // } - var l = (new int[] {1, 2, 3}).Length; // ldlen + var m = (new int[] {1, 2, 3}).Length; // ldlen } public void LoadField() diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index ff8e2ccb..c7fcded1 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -130,17 +130,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) // TODO depending on type of operand instructionEncoder.OpCode(SRM.ILOpCode.Ldind_X); // example is already generated for all variants break; - case BasicOperation.LoadArrayElement: - // FIXME LoadArrayElement needs an operand (should not be BasicInstruction) - // TODO depending on type of operand instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_X); - // example is already generated - break; - case BasicOperation.LoadArrayElementAddress: - // FIXME LoadArrayElementAddress needs an operand (should not be BasicInstruction) - // instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); - // instructionEncoder.token(type); - // example is already generated - break; case BasicOperation.IndirectStore: // FIXME IndirectStore needs an operand (should not be BasicInstruction) // instructionEncoder.OpCode(SRM.ILOpCode.Stobj); @@ -362,7 +351,65 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field)); break; case LoadArrayElementInstruction loadArrayElementInstruction: - // TODO this is currently modeled as a basic instruction and this is not used + switch (loadArrayElementInstruction.Operation) + { + // TODO not doing anything until LoadArrayElementInstruction PR is merged (because right now is treated as BasicOperation) + case LoadArrayElementOperation.Content: + // TODO there are multiple operations with this ifs. Maybe extract method? + if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i1); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u1); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i2); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u2); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i4); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u4); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int64) || + loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i8); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_r4); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_r8); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Object)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_ref); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); + } + + break; + case LoadArrayElementOperation.Address: + instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); + break; + } + + var typeTok = metadataContainer.ResolveReferenceHandleFor(loadArrayElementInstruction.Array.ElementsType); + instructionEncoder.Token(typeTok); break; case LoadMethodAddressInstruction loadMethodAddressInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); From 3ed35783b20c220dd6dbfb40bc9cd4316f5f4394 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 15 Dec 2019 14:26:33 -0300 Subject: [PATCH 066/256] use existing LoadArrayElementInstruction instead of BasicInstruction --- Backend/Transformations/Disassembler.cs | 10 +------- CCIProvider/CodeProvider.cs | 10 ++------ CCIProvider/OperationHelper.cs | 13 ---------- MetadataProvider/AssemblyExtractor.cs | 34 +++++++++++++++++++++---- MetadataProvider/OperationHelper.cs | 13 ---------- Model/Bytecode/Instructions.cs | 3 --- 6 files changed, 32 insertions(+), 51 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index f8e0b8c9..8a8e32fa 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -191,15 +191,7 @@ public override void Visit(Bytecode.BasicInstruction op) 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; diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index ffdcfffa..0c9676bc 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -169,9 +169,6 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) case Cci.OperationCode.Array_Get: case Cci.OperationCode.Array_Addr: - instruction = ProcessLoadArrayElement(operation); - break; - case Cci.OperationCode.Ldelem: case Cci.OperationCode.Ldelem_I: case Cci.OperationCode.Ldelem_I1: @@ -184,12 +181,9 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) case Cci.OperationCode.Ldelem_U2: case Cci.OperationCode.Ldelem_U4: case Cci.OperationCode.Ldelem_Ref: - instruction = ProcessBasic(operation); - break; - case Cci.OperationCode.Ldelema: - instruction = ProcessBasic(operation); - break; + instruction = ProcessLoadArrayElement(operation); + break; case Cci.OperationCode.Beq: case Cci.OperationCode.Beq_S: diff --git a/CCIProvider/OperationHelper.cs b/CCIProvider/OperationHelper.cs index 22dfb724..4edf065c 100644 --- a/CCIProvider/OperationHelper.cs +++ b/CCIProvider/OperationHelper.cs @@ -69,19 +69,6 @@ public static BasicOperation ToBasicOperation(Cci.OperationCode opcode) 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: diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..2312b7d5 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -782,22 +782,40 @@ private IInstruction ExtractInstruction(ILInstruction operation) break; case SRM.ILOpCode.Ldelem: - case SRM.ILOpCode.Ldelem_i: + instruction = ProcessLoadArrayElement(operation, new ArrayType(GetOperand(operation)), LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelem_i1: + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Int8), LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelem_i2: + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Int16), LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelem_i4: + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Int32), LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelem_i8: + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Int64), LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelem_r4: + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Float32), LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelem_r8: + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Float64), LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelem_u1: + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.UInt8), LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelem_u2: + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.UInt16), LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelem_u4: - case SRM.ILOpCode.Ldelem_ref: - instruction = ProcessBasic(operation); + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.UInt32), LoadArrayElementOperation.Content); + break; + case SRM.ILOpCode.Ldelem_ref: + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Object), LoadArrayElementOperation.Content); break; - case SRM.ILOpCode.Ldelema: - instruction = ProcessBasic(operation); + instruction = ProcessLoadArrayElement(operation, new ArrayType(GetOperand(operation)), LoadArrayElementOperation.Address); break; case SRM.ILOpCode.Beq: @@ -1212,6 +1230,12 @@ private T GetOperand(ILInstruction op) break; } + case OperandType.TypeDefinition: + { + var handle = (SRM.TypeDefinitionHandle)op.Operand; + result = (T)(object)GetDefinedType(handle); + break; + } default: throw op.OperandType.ToUnknownValueException(); } diff --git a/MetadataProvider/OperationHelper.cs b/MetadataProvider/OperationHelper.cs index c4999197..5837ac0a 100644 --- a/MetadataProvider/OperationHelper.cs +++ b/MetadataProvider/OperationHelper.cs @@ -69,19 +69,6 @@ public static BasicOperation ToBasicOperation(SRM.ILOpCode opcode) case SRM.ILOpCode.Ldind_u2: case SRM.ILOpCode.Ldind_u4: case SRM.ILOpCode.Ldobj: return BasicOperation.IndirectLoad; - case SRM.ILOpCode.Ldelem: - case SRM.ILOpCode.Ldelem_i: - case SRM.ILOpCode.Ldelem_i1: - case SRM.ILOpCode.Ldelem_i2: - case SRM.ILOpCode.Ldelem_i4: - case SRM.ILOpCode.Ldelem_i8: - case SRM.ILOpCode.Ldelem_r4: - case SRM.ILOpCode.Ldelem_r8: - case SRM.ILOpCode.Ldelem_u1: - case SRM.ILOpCode.Ldelem_u2: - case SRM.ILOpCode.Ldelem_u4: - case SRM.ILOpCode.Ldelem_ref: return BasicOperation.LoadArrayElement; - case SRM.ILOpCode.Ldelema: return BasicOperation.LoadArrayElementAddress; case SRM.ILOpCode.Stind_i: case SRM.ILOpCode.Stind_i1: case SRM.ILOpCode.Stind_i2: diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index bb12534e..88fb48ef 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -41,8 +41,6 @@ public enum BasicOperation CopyBlock, LoadArrayLength, IndirectLoad, - LoadArrayElement, - LoadArrayElementAddress, IndirectStore, StoreArrayElement, Breakpoint, @@ -262,7 +260,6 @@ public override string ToString() return this.ToString("new {0}", this.Type); } } - public class LoadArrayElementInstruction : Instruction { public LoadArrayElementOperation Operation { get; set; } From aef5ce38a2d4e1df638dc2745a57acfb284f7f07 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 15 Dec 2019 14:36:46 -0300 Subject: [PATCH 067/256] remove unused methods --- Backend/Transformations/Disassembler.cs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 8a8e32fa..b7d8f232 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -364,27 +364,6 @@ private void ProcessIndirectLoad(Bytecode.BasicInstruction op) 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(); From 64a711388dd0257f70183b03c7645c0a682e1070 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 15 Dec 2019 14:40:15 -0300 Subject: [PATCH 068/256] whitespace --- Model/Bytecode/Instructions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index 88fb48ef..e9899bad 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -260,6 +260,7 @@ public override string ToString() return this.ToString("new {0}", this.Type); } } + public class LoadArrayElementInstruction : Instruction { public LoadArrayElementOperation Operation { get; set; } From 8ff1d2f2f57f7a01786e36a6d9183b4cb510468a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 16 Dec 2019 23:05:26 -0300 Subject: [PATCH 069/256] handle storeArrayElementInstruction correctly --- .../Methods/Body/MethodBodyGenerator.cs | 62 ++++++++++++++----- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index c7fcded1..7c42df60 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -135,13 +135,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) // instructionEncoder.OpCode(SRM.ILOpCode.Stobj); // instructionEncoder.token(); break; - case BasicOperation.StoreArrayElement: - // FIXME StoreArrayElement needs an operand (should not be BasicInstruction) - // instructionEncoder.OpCode(SRM.ILOpCode.Stelem_X); - - // instructionEncoder.OpCode(SRM.ILOpCode.Stelem); - // instructionEncoder.token(); - break; case BasicOperation.Breakpoint: instructionEncoder.OpCode(SRM.ILOpCode.Break); break; @@ -355,8 +348,12 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { // TODO not doing anything until LoadArrayElementInstruction PR is merged (because right now is treated as BasicOperation) case LoadArrayElementOperation.Content: - // TODO there are multiple operations with this ifs. Maybe extract method? - if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) + // TODO there are multiple instructions with this kind of ifs. Maybe extract method? + if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i1); } @@ -408,8 +405,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; } - var typeTok = metadataContainer.ResolveReferenceHandleFor(loadArrayElementInstruction.Array.ElementsType); - instructionEncoder.Token(typeTok); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadArrayElementInstruction.Array.ElementsType)); break; case LoadMethodAddressInstruction loadMethodAddressInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); @@ -469,12 +465,44 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); break; case StoreArrayElementInstruction storeArrayElementInstruction: - // FIXME - // Framework currently handles this as a BasicInstruction and this is never generated. Should use this one - // example already generated - // the implementation should be like load instruction - // instructionEncoder.OpCode(SRM.ILOpCode.Stelem_X); - // instructionEncoder.Token(value); + if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i1); + } + else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i2); + } + else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i4); + } + else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i8); + } + else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_r4); + } + else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_r8); + } + else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i); + } + else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Object)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_ref); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem); + } + + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeArrayElementInstruction.Array.ElementsType)); break; default: throw new Exception("instruction type not handled"); From d11b97d43e6c05183e7a280d2095df8b3d498acd Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 16 Dec 2019 23:08:27 -0300 Subject: [PATCH 070/256] store array element not a basic instruction anymore --- Backend/Transformations/Disassembler.cs | 16 +--------------- CCIProvider/CodeProvider.cs | 5 +---- CCIProvider/OperationHelper.cs | 9 --------- MetadataProvider/AssemblyExtractor.cs | 25 ++++++++++++++++++++++++- MetadataProvider/OperationHelper.cs | 9 --------- Model/Bytecode/Instructions.cs | 1 - 6 files changed, 26 insertions(+), 39 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index f8e0b8c9..4de65b30 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -204,10 +204,6 @@ public override void Visit(Bytecode.BasicInstruction op) ProcessIndirectStore(op); break; - case Bytecode.BasicOperation.StoreArrayElement: - ProcessStoreArrayElement(op); - break; - case Bytecode.BasicOperation.Breakpoint: ProcessBreakpointOperation(op); break; @@ -401,17 +397,7 @@ private void ProcessIndirectStore(Bytecode.BasicInstruction op) 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); diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index ffdcfffa..ad0de73f 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -461,9 +461,6 @@ 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: @@ -473,7 +470,7 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) case Cci.OperationCode.Stelem_R4: case Cci.OperationCode.Stelem_R8: case Cci.OperationCode.Stelem_Ref: - instruction = ProcessBasic(operation); + instruction = ProcessStoreArrayElement(operation); break; case Cci.OperationCode.Stfld: diff --git a/CCIProvider/OperationHelper.cs b/CCIProvider/OperationHelper.cs index 22dfb724..d7b72298 100644 --- a/CCIProvider/OperationHelper.cs +++ b/CCIProvider/OperationHelper.cs @@ -91,15 +91,6 @@ public static BasicOperation ToBasicOperation(Cci.OperationCode opcode) 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(); diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..3eb27e62 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1070,15 +1070,31 @@ private IInstruction ExtractInstruction(ILInstruction operation) break; case SRM.ILOpCode.Stelem: + instruction = ProcessStoreArrayElement(operation, new ArrayType(GetOperand(operation))); + break; case SRM.ILOpCode.Stelem_i: + instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.IntPtr)); + break; case SRM.ILOpCode.Stelem_i1: + instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Int8)); + break; case SRM.ILOpCode.Stelem_i2: + instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Int16)); + break; case SRM.ILOpCode.Stelem_i4: + instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Int32)); + break; case SRM.ILOpCode.Stelem_i8: + instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Int64)); + break; case SRM.ILOpCode.Stelem_r4: + instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Float32)); + break; case SRM.ILOpCode.Stelem_r8: + instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Float64)); + break; case SRM.ILOpCode.Stelem_ref: - instruction = ProcessBasic(operation); + instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Object)); break; case SRM.ILOpCode.Stfld: @@ -1211,6 +1227,13 @@ private T GetOperand(ILInstruction op) result = (T)GetMethodReference(handle); break; } + + case OperandType.TypeDefinition: + { + var handle = (SRM.TypeDefinitionHandle)op.Operand; + result = (T)(object)GetDefinedType(handle); + break; + } default: throw op.OperandType.ToUnknownValueException(); diff --git a/MetadataProvider/OperationHelper.cs b/MetadataProvider/OperationHelper.cs index c4999197..977f967d 100644 --- a/MetadataProvider/OperationHelper.cs +++ b/MetadataProvider/OperationHelper.cs @@ -91,15 +91,6 @@ public static BasicOperation ToBasicOperation(SRM.ILOpCode opcode) case SRM.ILOpCode.Stind_r8: case SRM.ILOpCode.Stind_ref: case SRM.ILOpCode.Stobj: return BasicOperation.IndirectStore; - case SRM.ILOpCode.Stelem: - case SRM.ILOpCode.Stelem_i: - case SRM.ILOpCode.Stelem_i1: - case SRM.ILOpCode.Stelem_i2: - case SRM.ILOpCode.Stelem_i4: - case SRM.ILOpCode.Stelem_i8: - case SRM.ILOpCode.Stelem_r4: - case SRM.ILOpCode.Stelem_r8: - case SRM.ILOpCode.Stelem_ref: return BasicOperation.StoreArrayElement; case SRM.ILOpCode.Break: return BasicOperation.Breakpoint; default: throw opcode.ToUnknownValueException(); diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index bb12534e..05b5b57b 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -44,7 +44,6 @@ public enum BasicOperation LoadArrayElement, LoadArrayElementAddress, IndirectStore, - StoreArrayElement, Breakpoint, Return } From 150f68d95f2d69a67f2f1cecc37168f1d932f3cd Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 16 Dec 2019 23:16:31 -0300 Subject: [PATCH 071/256] add missing Ldelem_i --- MetadataProvider/AssemblyExtractor.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 2312b7d5..5a1c692d 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -780,10 +780,13 @@ private IInstruction ExtractInstruction(ILInstruction operation) case SRM.ILOpCode.Newarr: instruction = ProcessCreateArray(operation); break; - + case SRM.ILOpCode.Ldelem: instruction = ProcessLoadArrayElement(operation, new ArrayType(GetOperand(operation)), LoadArrayElementOperation.Content); break; + case SRM.ILOpCode.Ldelem_i: + instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.IntPtr), LoadArrayElementOperation.Content); + break; case SRM.ILOpCode.Ldelem_i1: instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Int8), LoadArrayElementOperation.Content); break; From cbc1facf13c1c8b3dcadb49eae43529ed3d9c4ef Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 18 Dec 2019 21:40:09 -0300 Subject: [PATCH 072/256] handle isInst correctly --- Examples/Examples.cs | 12 ++++++------ .../Generators/Methods/Body/MethodBodyGenerator.cs | 7 ++++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index b2db624e..9a386a1f 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -3,7 +3,6 @@ using System.Reflection.Metadata; using Accessibility; using Classes; -using Generics; using Hierarchy; using Nested.NestedNamespace.NestedNestedNamesace; using Structs; @@ -650,6 +649,7 @@ public void Empty() { } + // FIXME not generated correctly public void Convert(object o) { long x1 = 1; @@ -672,8 +672,8 @@ public void Convert(object o) var x = (int[]) (object) new int[] { }; - // FIXME framework read not working. - // var b = o is Classes.SimpleClass; // isinst $class + // FIXME framework read not working (unccoment when isInst PR is merged) + // var b = o is Classes.SimpleClass; // isinst $class object l = 1; // box int int i = (int) l; // unbox.any int @@ -733,7 +733,7 @@ public void LoadAddress(int x) { unsafe { - var p = default(int*); // ldloca.s 0 + var p = default(int*); // ldloca.s 0 + initobj int* // TODO ldloca $argNum var q = &x; // ldarga.s 0 // TODO ldarga $argNum @@ -807,8 +807,8 @@ public void LoadArray(Exception[] x, int[] q) var j = (new float[] { })[0]; // ldelem.r4 var k = (new double[] { })[0]; // ldelem.r8 // TODO unccoment when LoadArrayElementInstruction PR is merged - // var l = new EmptyStruct[] {new EmptyStruct() }[0]; // ldelem typeTok - + // var l = new EmptyStruct[] {new EmptyStruct() }[0]; // ldelem typeTok + // TODO ldelem.i ??? // // FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 7c42df60..53ece77c 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -185,6 +185,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(branchInstruction.Target)); break; } + case ConvertInstruction convertInstruction: switch (convertInstruction.Operation) { @@ -234,8 +235,12 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case ConvertOperation.Cast: instructionEncoder.OpCode(SRM.ILOpCode.Castclass); - // FIXME could also be instructionEncoder.OpCode(SRM.ILOpCode.Isinst); break; + /* FIXMEunccoment when isInst PR is merged + case ConvertOperation.IsInst: + instructionEncoder.OpCode(SRM.ILOpCode.Isinst); + break; + */ case ConvertOperation.Box: instructionEncoder.OpCode(SRM.ILOpCode.Box); break; From 70d3255b430ce080fbcc5c3d8c077c4ce5fcc5ce Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 18 Dec 2019 21:44:21 -0300 Subject: [PATCH 073/256] IsInst is not the same as Cast for convert instructions --- CCIProvider/OperationHelper.cs | 6 +++--- MetadataProvider/AssemblyExtractor.cs | 7 +++++++ MetadataProvider/OperationHelper.cs | 4 ++-- Model/Bytecode/Instructions.cs | 1 + 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CCIProvider/OperationHelper.cs b/CCIProvider/OperationHelper.cs index 22dfb724..5d80f975 100644 --- a/CCIProvider/OperationHelper.cs +++ b/CCIProvider/OperationHelper.cs @@ -109,9 +109,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; diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..ec1c4d8b 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1211,6 +1211,13 @@ private T GetOperand(ILInstruction op) result = (T)GetMethodReference(handle); break; } + + case OperandType.TypeDefinition: + { + var handle = (SRM.TypeDefinitionHandle)op.Operand; + result = (T)(object)GetDefinedType(handle); + break; + } default: throw op.OperandType.ToUnknownValueException(); diff --git a/MetadataProvider/OperationHelper.cs b/MetadataProvider/OperationHelper.cs index c4999197..eb27025a 100644 --- a/MetadataProvider/OperationHelper.cs +++ b/MetadataProvider/OperationHelper.cs @@ -110,8 +110,8 @@ public static ConvertOperation ToConvertOperation(SRM.ILOpCode opcode) { switch (opcode) { - case SRM.ILOpCode.Castclass: - case SRM.ILOpCode.Isinst: return ConvertOperation.Cast; + case SRM.ILOpCode.Isinst: return ConvertOperation.IsInst; + case SRM.ILOpCode.Castclass: return ConvertOperation.Cast; case SRM.ILOpCode.Box: return ConvertOperation.Box; case SRM.ILOpCode.Unbox: return ConvertOperation.UnboxPtr; case SRM.ILOpCode.Unbox_any: return ConvertOperation.Unbox; diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index bb12534e..abca8f56 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -66,6 +66,7 @@ public enum BranchOperation public enum ConvertOperation { Conv, + IsInst, Cast, Box, Unbox, From 00741b77e9ff6cf553793b5a6a2b1ab72ac052f3 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 18 Dec 2019 22:14:31 -0300 Subject: [PATCH 074/256] fix LoadFieldOperation handler --- .../Generators/Methods/Body/MethodBodyGenerator.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 53ece77c..9995cc02 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -344,8 +344,17 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case LoadFieldInstruction loadFieldInstruction: - // TODO handle ldflda. Example present but not supported in model - instructionEncoder.OpCode(SRM.ILOpCode.Ldfld); + switch (loadFieldInstruction.Operation) + { + case LoadFieldOperation.Content: + instructionEncoder.OpCode(SRM.ILOpCode.Ldfld); + break; + case LoadFieldOperation.Address: + // TODO test. Example present but not supported in model + instructionEncoder.OpCode(SRM.ILOpCode.Ldflda); + break; + } + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field)); break; case LoadArrayElementInstruction loadArrayElementInstruction: From 308a83c4051dad8b7f406e9af05cff95bec60e7d Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 22 Dec 2019 15:18:54 -0300 Subject: [PATCH 075/256] remove part that is going to be on other PR --- MetadataProvider/AssemblyExtractor.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index ec1c4d8b..24606648 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1212,13 +1212,6 @@ private T GetOperand(ILInstruction op) break; } - case OperandType.TypeDefinition: - { - var handle = (SRM.TypeDefinitionHandle)op.Operand; - result = (T)(object)GetDefinedType(handle); - break; - } - default: throw op.OperandType.ToUnknownValueException(); } From 75f211523c7bc2a49812652ec0a04f91b36533ee Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 22 Dec 2019 15:20:02 -0300 Subject: [PATCH 076/256] whitespace --- MetadataProvider/AssemblyExtractor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 24606648..66787d90 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1211,7 +1211,7 @@ private T GetOperand(ILInstruction op) result = (T)GetMethodReference(handle); break; } - + default: throw op.OperandType.ToUnknownValueException(); } From f856c3110843d35cc625d073fdd5b4b39f537e5b Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 22 Dec 2019 15:21:43 -0300 Subject: [PATCH 077/256] remove part that is going to be on other PR --- MetadataProvider/AssemblyExtractor.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 3eb27e62..3338e380 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1227,13 +1227,6 @@ private T GetOperand(ILInstruction op) result = (T)GetMethodReference(handle); break; } - - case OperandType.TypeDefinition: - { - var handle = (SRM.TypeDefinitionHandle)op.Operand; - result = (T)(object)GetDefinedType(handle); - break; - } default: throw op.OperandType.ToUnknownValueException(); From 78691dd76148aaa1f7d29a2248a302b8dad4198b Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 22 Dec 2019 15:23:18 -0300 Subject: [PATCH 078/256] remove part that is going to be on other PR --- MetadataProvider/AssemblyExtractor.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 5a1c692d..8e8a1ffd 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1233,12 +1233,6 @@ private T GetOperand(ILInstruction op) break; } - case OperandType.TypeDefinition: - { - var handle = (SRM.TypeDefinitionHandle)op.Operand; - result = (T)(object)GetDefinedType(handle); - break; - } default: throw op.OperandType.ToUnknownValueException(); } From d5546dee4998f32bb6d497318d8ba79f6f2390e9 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 22 Dec 2019 15:26:26 -0300 Subject: [PATCH 079/256] GetOperand supports TypeDefinition --- MetadataProvider/AssemblyExtractor.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..cf1335cf 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1177,6 +1177,13 @@ private T GetOperand(ILInstruction op) break; } + case OperandType.TypeDefinition: + { + var handle = (SRM.TypeDefinitionHandle)op.Operand; + result = (T)(object)GetDefinedType(handle); + break; + } + case OperandType.TypeReference: { var handle = (SRM.TypeReferenceHandle)op.Operand; From af56b6741b6a1255d9987c07a4963ca2f6ce0cb7 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 22 Dec 2019 18:55:53 -0300 Subject: [PATCH 080/256] fixes --- Examples/Examples.cs | 31 +++++++------------ .../Methods/Body/MethodBodyGenerator.cs | 13 +++----- .../Methods/Body/MethodLocalsGenerator.cs | 1 - .../Metadata/AttributesProvider.cs | 5 +++ .../Metadata/MetadataResolver.cs | 4 +-- 5 files changed, 22 insertions(+), 32 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 9a386a1f..cfc2afe8 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -148,7 +148,9 @@ public class ClassWithMoreComplexFieldsAndParametersOrReturnTypes public void MethodWithOptionalParameters( string someParam, int optionalInt = 0, - EmptyStruct optionalStruct = new EmptyStruct()) + EmptyStruct optionalStruct = new EmptyStruct(), + Exception optionalException = null, + string optionalString = "some initial value") { } @@ -555,14 +557,6 @@ public void BitwiseOperations(int x) z = z << 1; } - public void Comparison(int x) - { - var z = x > 1; - z = x < 1; - z = x == 1; - } - - public abstract void NoBody(); public void Alloc() @@ -588,10 +582,8 @@ public void Calls(SimpleClass simpleClass, Action f) simpleClass.DoNothing(); // virtual Alloc(); // normal - var l = new List {"holas"}; // FIXME missing in bytecode + var l = new List {"holas"}; - //FIXME callvirt instance void class. The "class" is not being generated. It seems to be only for generic method refs. - // FIXME missing in bytecode f(1); // TODO calli (indirect) @@ -642,7 +634,6 @@ public void Arrays(EmptyStruct[] structArray) floatArray[1] = f; // stelem.r4 doubleArray[1] = d; // stelem.r8 structArray[0] = p; // stelem - // TODO stelem.i } public void Empty() @@ -775,7 +766,7 @@ public void LoadIndirect(ref object g) } } - public void Compare(int b) + public void Compare(int b, int x) { var a = b == 2; // ceq a = b > 2; // cgt @@ -862,19 +853,19 @@ public void SizeOf() { unsafe { - // FIXME framework read not working + // FIXME unccomment when on of the instructiosn PRs is merged (needs the TypeDefinitionHandle case that is missing) // var x = sizeof(Structs.NonEmptyStruct); // sizeof $type var z = sizeof(NonEmptyStruct***); // sizeof $type*** var y = sizeof(int*); // sizeof int* } } - // doesnt work yet // TODO other cases - // public void LoadToken() - //{ - //var x = typeof(T); - //} + // FIXME generation almost correct + public void LoadToken() + { + var x = typeof(T); + } public void Branch(int a, int b, Exception e) { diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 9995cc02..b4ccccc3 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -23,7 +23,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), new ECMA335.ControlFlowBuilder()); var controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); - controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); foreach (var instruction in body.Instructions) @@ -112,9 +111,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(SRM.ILOpCode.Initblk); break; case BasicOperation.InitObject: - // FIXME InitObject needs an operand (should not be BasicInstruction) - // instructionEncoder.OpCode(ILOpCode.Initobj); - // instructionEncoder.Token(type) + // FIXME InitObject needs an operand (should not be BasicInstruction). There's already a PR that fixes this break; case BasicOperation.CopyObject: // FIXME CopyObject needs an operand (should not be BasicInstruction) @@ -126,14 +123,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(SRM.ILOpCode.Ldlen); break; case BasicOperation.IndirectLoad: - // FIXME IndirectLoad needs an operand (should not be BasicInstruction) - // TODO depending on type of operand instructionEncoder.OpCode(SRM.ILOpCode.Ldind_X); + // FIXME IndirectLoad needs an operand (should not be BasicInstruction). There's already a PR that fixes this // example is already generated for all variants break; case BasicOperation.IndirectStore: - // FIXME IndirectStore needs an operand (should not be BasicInstruction) - // instructionEncoder.OpCode(SRM.ILOpCode.Stobj); - // instructionEncoder.token(); + // FIXME IndirectStore needs an operand (should not be BasicInstruction). There's already a PR that fixes this break; case BasicOperation.Breakpoint: instructionEncoder.OpCode(SRM.ILOpCode.Break); @@ -415,6 +409,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case LoadArrayElementOperation.Address: + // TODO test. Example present but not supported in model instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); break; } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs index 8a8b1b8a..fec113d8 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs @@ -69,7 +69,6 @@ Quiza estan mal algunos de los valores de addLocalScope y por eso no anda // FIXME ?? var nextLocalConstantHandle = ECMA335.MetadataTokens.LocalConstantHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalConstant)); - metadataContainer.metadataBuilder.AddLocalScope( method: containingMethodHandle, importScope: default, // FIXME ?? diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index bfd4fc66..1dc5b417 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -142,6 +142,11 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para break; } + if (parameter.HasDefaultValue) + { + attributes |= ParameterAttributes.Optional | ParameterAttributes.HasDefault; + } + return attributes; } diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 9e1fda54..21ac21da 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -74,11 +74,11 @@ private SRM.EntityHandle ReferenceHandleOf(IType type) switch (type) { case IBasicType basicType: return ReferenceHandleOf(basicType); - case IType arrayOrPointerType when arrayOrPointerType is ArrayType || arrayOrPointerType is PointerType: + case IType iType when iType is ArrayType || iType is PointerType || iType is IGenericParameterReference: { var signature = new SRM.BlobBuilder(); var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); - Encode(arrayOrPointerType, encoder); + Encode(iType, encoder); // FIXME should be stored? or added every time? return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); } From 637c2e727b5ac77d9ef370fb8346ff4c2bb08769 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 22 Dec 2019 21:04:33 -0300 Subject: [PATCH 081/256] overflow and unsigned variants --- .../Methods/Body/MethodBodyGenerator.cs | 148 ++++++++++++++---- 1 file changed, 120 insertions(+), 28 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index b4ccccc3..afe35705 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -34,27 +34,47 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case BasicInstruction basicInstruction: switch (basicInstruction.Operation) { - // TODO - // check overflow for variants (ej: add, add_ovf, add_ovf_un) - // see all IlOpCode constants and ECMA - case BasicOperation.Nop: instructionEncoder.OpCode(SRM.ILOpCode.Nop); break; case BasicOperation.Add: - instructionEncoder.OpCode(SRM.ILOpCode.Add); + if (basicInstruction.OverflowCheck) + { + instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Add_ovf_un : SRM.ILOpCode.Add_ovf); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Add); + } + break; case BasicOperation.Sub: - instructionEncoder.OpCode(SRM.ILOpCode.Sub); + if (basicInstruction.OverflowCheck) + { + instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Sub_ovf_un : SRM.ILOpCode.Sub_ovf); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Sub); + } + break; case BasicOperation.Mul: - instructionEncoder.OpCode(SRM.ILOpCode.Mul); + if (basicInstruction.OverflowCheck) + { + instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Mul_ovf_un : SRM.ILOpCode.Mul_ovf); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Mul); + } + break; case BasicOperation.Div: - instructionEncoder.OpCode(SRM.ILOpCode.Div); + instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Div_un : SRM.ILOpCode.Div); break; case BasicOperation.Rem: - instructionEncoder.OpCode(SRM.ILOpCode.Rem); + instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Rem_un : SRM.ILOpCode.Rem); break; case BasicOperation.And: instructionEncoder.OpCode(SRM.ILOpCode.And); @@ -69,16 +89,16 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(SRM.ILOpCode.Shl); break; case BasicOperation.Shr: - instructionEncoder.OpCode(SRM.ILOpCode.Shr); + instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Shr_un : SRM.ILOpCode.Shr); break; case BasicOperation.Eq: instructionEncoder.OpCode(SRM.ILOpCode.Ceq); break; case BasicOperation.Lt: - instructionEncoder.OpCode(SRM.ILOpCode.Clt); + instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Clt_un : SRM.ILOpCode.Clt); break; case BasicOperation.Gt: - instructionEncoder.OpCode(SRM.ILOpCode.Cgt); + instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Cgt_un : SRM.ILOpCode.Cgt); break; case BasicOperation.Throw: instructionEncoder.OpCode(SRM.ILOpCode.Throw); @@ -143,7 +163,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var opCode = SRM.ILOpCode.Br_s; switch (branchInstruction.Operation) { - // TODO all short forms can also be not short form (ex: br and br.s) and there's "un" variants + // TODO all short forms can also be not short form (ex: br and br.s) case BranchOperation.False: opCode = SRM.ILOpCode.Brfalse_s; break; @@ -157,16 +177,16 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) opCode = SRM.ILOpCode.Bne_un_s; break; case BranchOperation.Lt: - opCode = SRM.ILOpCode.Blt_s; + opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Blt_un_s : SRM.ILOpCode.Blt_s; break; case BranchOperation.Le: - opCode = SRM.ILOpCode.Ble_s; + opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Ble_un_s : SRM.ILOpCode.Ble_s; break; case BranchOperation.Gt: - opCode = SRM.ILOpCode.Bgt_s; + opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Bgt_un_s : SRM.ILOpCode.Bgt_s; break; case BranchOperation.Ge: - opCode = SRM.ILOpCode.Bge_s; + opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Bge_un_s : SRM.ILOpCode.Bge_s; break; case BranchOperation.Branch: opCode = SRM.ILOpCode.Br_s; @@ -183,47 +203,119 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case ConvertInstruction convertInstruction: switch (convertInstruction.Operation) { - // TODO overflow variants and conv.i, conv.u, conv.r.un + // TODO conv.i, conv.u, case ConvertOperation.Conv: if (convertInstruction.ConversionType.Equals(PlatformTypes.Int8)) { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i1); + if (convertInstruction.OverflowCheck) + { + instructionEncoder.OpCode(convertInstruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_i1_un + : SRM.ILOpCode.Conv_ovf_i1); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i1); + } } else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt8)) { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u1); + if (convertInstruction.OverflowCheck) + { + instructionEncoder.OpCode(convertInstruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_u1_un + : SRM.ILOpCode.Conv_ovf_u1); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u1); + } } else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int16)) { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i2); + if (convertInstruction.OverflowCheck) + { + instructionEncoder.OpCode(convertInstruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_i2_un + : SRM.ILOpCode.Conv_ovf_i2); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i2); + } } else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt16)) { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u2); + if (convertInstruction.OverflowCheck) + { + instructionEncoder.OpCode(convertInstruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_u2_un + : SRM.ILOpCode.Conv_ovf_u2); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u2); + } } else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int32)) { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i4); + if (convertInstruction.OverflowCheck) + { + instructionEncoder.OpCode(convertInstruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_i4_un + : SRM.ILOpCode.Conv_ovf_i4); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i4); + } } else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt32)) { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u4); + if (convertInstruction.OverflowCheck) + { + instructionEncoder.OpCode(convertInstruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_u4_un + : SRM.ILOpCode.Conv_ovf_u4); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u4); + } } else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int64)) { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); + if (convertInstruction.OverflowCheck) + { + instructionEncoder.OpCode(convertInstruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_i8_un + : SRM.ILOpCode.Conv_ovf_i8); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); + } } else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt64)) { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u8); + if (convertInstruction.OverflowCheck) + { + instructionEncoder.OpCode(convertInstruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_u8_un + : SRM.ILOpCode.Conv_ovf_u8); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u8); + } } else if (convertInstruction.ConversionType.Equals(PlatformTypes.Float32)) { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_r4); + instructionEncoder.OpCode(convertInstruction.UnsignedOperands ? SRM.ILOpCode.Conv_r_un : SRM.ILOpCode.Conv_r4); } else if (convertInstruction.ConversionType.Equals(PlatformTypes.Float64)) { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_r8); + instructionEncoder.OpCode(convertInstruction.UnsignedOperands ? SRM.ILOpCode.Conv_r_un : SRM.ILOpCode.Conv_r8); } break; From 9c15d583cb2cc68fc372860c25cf1f4dba46683a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 26 Dec 2019 15:09:09 -0300 Subject: [PATCH 082/256] fix several body generation issues --- Examples/Examples.cs | 6 ++- MetadataGenerator/Extensions.cs | 2 + .../Methods/Body/MethodBodyGenerator.cs | 54 ++++++++++++++----- .../Generators/Methods/MethodGenerator.cs | 7 +-- .../Metadata/MetadataResolver.cs | 8 +-- 5 files changed, 55 insertions(+), 22 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index cfc2afe8..ad03ef12 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -140,8 +140,10 @@ public virtual void VirtualMethod() public class ClassWithMoreComplexFieldsAndParametersOrReturnTypes { public string[] stringArrayField; - public string[][] stringArrayArrayField; - public string[,,] stringJaggedArrayField; + public string[][] stringJaggedArrayField; + public string[,,] stringMultiDimensionalArrayField; + public Exception[][,] exceptionMultiDimensionalJaggedArray; + public int[,][] intMultiDimensionalJaggedArray; public Exception[] exceptionArrayField; public B b; diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index de37cf22..39f22059 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -17,6 +17,8 @@ public static T FirstOr(this IEnumerable enumerable, T defaultValue) public static bool IsOneOf(this MethodParameterKind kind, params MethodParameterKind[] kinds) => ImmutableList.Create(kinds).Contains(kind); + public static bool IsOneOf(this IType type, params IType[] types) => ImmutableList.Create(types).Contains(type); + public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.EntityHandle methodReference) { encoder.OpCode(SRM.ILOpCode.Callvirt); diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index afe35705..1a38b2d0 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -317,28 +317,58 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { instructionEncoder.OpCode(convertInstruction.UnsignedOperands ? SRM.ILOpCode.Conv_r_un : SRM.ILOpCode.Conv_r8); } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.IntPtr)) + { + if (convertInstruction.OverflowCheck) + { + instructionEncoder.OpCode(convertInstruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_i_un + : SRM.ILOpCode.Conv_ovf_i); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i); + } + } + else if (convertInstruction.ConversionType.Equals(PlatformTypes.UIntPtr)) + { + if (convertInstruction.OverflowCheck) + { + instructionEncoder.OpCode(convertInstruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_u_un + : SRM.ILOpCode.Conv_ovf_u); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u); + } + } break; case ConvertOperation.Cast: instructionEncoder.OpCode(SRM.ILOpCode.Castclass); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); break; /* FIXMEunccoment when isInst PR is merged case ConvertOperation.IsInst: instructionEncoder.OpCode(SRM.ILOpCode.Isinst); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); break; */ case ConvertOperation.Box: instructionEncoder.OpCode(SRM.ILOpCode.Box); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); break; case ConvertOperation.Unbox: instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); break; case ConvertOperation.UnboxPtr: instructionEncoder.OpCode(SRM.ILOpCode.Unbox); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); break; } - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); break; case MethodCallInstruction methodCallInstruction: switch (methodCallInstruction.Operation) @@ -392,24 +422,19 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.LoadString(metadataContainer.metadataBuilder.GetOrAddUserString(value)); } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Int8) || - loadInstruction.Operand.Type.Equals(PlatformTypes.UInt8)) + else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.UInt8)) { var value = (int) (loadInstruction.Operand as Constant).Value; instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); instructionEncoder.Token(value); } - else if ( - loadInstruction.Operand.Type.Equals(PlatformTypes.Int16) || - loadInstruction.Operand.Type.Equals(PlatformTypes.Int32) || - loadInstruction.Operand.Type.Equals(PlatformTypes.UInt16) || - loadInstruction.Operand.Type.Equals(PlatformTypes.UInt32)) + else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int16, PlatformTypes.Int32, PlatformTypes.UInt16, + PlatformTypes.UInt32)) { var value = (int) (loadInstruction.Operand as Constant).Value; instructionEncoder.LoadConstantI4(value); } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Int64) || - loadInstruction.Operand.Type.Equals(PlatformTypes.UInt64)) + else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) { var value = (long) (loadInstruction.Operand as Constant).Value; instructionEncoder.LoadConstantI8(value); @@ -477,8 +502,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u4); } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int64) || - loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt64)) + else if (loadArrayElementInstruction.Array.ElementsType.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i8); } @@ -497,16 +521,18 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) else { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); + instructionEncoder.Token( + metadataContainer.ResolveReferenceHandleFor(loadArrayElementInstruction.Array.ElementsType)); } break; case LoadArrayElementOperation.Address: // TODO test. Example present but not supported in model instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadArrayElementInstruction.Array.ElementsType)); break; } - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadArrayElementInstruction.Array.ElementsType)); break; case LoadMethodAddressInstruction loadMethodAddressInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); @@ -601,9 +627,9 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) else { instructionEncoder.OpCode(SRM.ILOpCode.Stelem); + instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeArrayElementInstruction.Array.ElementsType)); } - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeArrayElementInstruction.Array.ElementsType)); break; default: throw new Exception("instruction type not handled"); diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 7108b87d..3312711d 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -39,14 +39,15 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) } } + // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated // programatically then the maxStack is gonna be missing - var methodBody = method.HasBody + var methodBodyOffset = method.HasBody ? metadataContainer.methodBodyStream.AddMethodBody( instructionEncoder: methodBodyGenerator.Generate(method.Body), localVariablesSignature: methodLocalsGenerator.GenerateLocalVariablesSignatureFor(method.Body), maxStack: method.Body.MaxStack) - : default; + : -1; var nextParameterHandle = ECMA335.MetadataTokens.ParameterHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); var methodDefinitionHandle = metadataContainer.metadataBuilder.AddMethodDefinition( @@ -54,7 +55,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) implAttributes: SR.MethodImplAttributes.IL | SR.MethodImplAttributes.Managed, // FIXME what else? name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), signature: metadataContainer.metadataBuilder.GetOrAddBlob(methodSignature), - bodyOffset: methodBody, + bodyOffset: methodBodyOffset, parameterList: firstParameterHandle ?? nextParameterHandle); methodLocalsGenerator.GenerateLocalVariables(method.Body, methodDefinitionHandle); diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 21ac21da..3774a208 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -5,6 +5,7 @@ using MetadataGenerator.Generators.Methods; using Model; using Model.Types; +using static System.Linq.Enumerable; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -243,12 +244,13 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), arrayShapeEncoder => { - // FIXME real values for sizes and lowerBounds - // size cannot be known (example: int[]) + var lowerBounds = arrayType.Rank > 1 + ? Repeat(0, (int) arrayType.Rank).ToImmutableArray() // FIXME 0 because ArrayType does not know bounds + : ImmutableArray.Empty; arrayShapeEncoder.Shape( rank: (int) arrayType.Rank, sizes: ImmutableArray.Empty, - lowerBounds: ImmutableArray.Empty); + lowerBounds: lowerBounds); }); break; case PointerType pointerType: From cb6c4fad137e77c54afae94d859ba957a8c903f6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 26 Dec 2019 18:05:32 -0300 Subject: [PATCH 083/256] initialize method parameters (default values) --- Examples/Examples.cs | 2 +- .../Methods/Body/MethodLocalsGenerator.cs | 3 +- .../Generators/Methods/MethodGenerator.cs | 21 +++----- .../Methods/MethodParametersGenerator.cs | 51 +++++++++++++++++++ .../Metadata/MetadataResolver.cs | 5 +- MetadataGenerator/MetadataGenerator.csproj | 1 + 6 files changed, 64 insertions(+), 19 deletions(-) create mode 100644 MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs diff --git a/Examples/Examples.cs b/Examples/Examples.cs index ad03ef12..2ccb66f9 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -147,7 +147,7 @@ public class ClassWithMoreComplexFieldsAndParametersOrReturnTypes public Exception[] exceptionArrayField; public B b; - public void MethodWithOptionalParameters( + public void MethodWithOptionalParametersAndDefaultValues( string someParam, int optionalInt = 0, EmptyStruct optionalStruct = new EmptyStruct(), diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs index fec113d8..f72b90c7 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs @@ -1,4 +1,5 @@ -using MetadataGenerator.Metadata; +using System.Threading; +using MetadataGenerator.Metadata; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 3312711d..dcda8e81 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -14,6 +14,7 @@ internal class MethodGenerator private readonly MethodSignatureGenerator methodSignatureGenerator; private readonly MethodBodyGenerator methodBodyGenerator; private readonly MethodLocalsGenerator methodLocalsGenerator; + private readonly MethodParametersGenerator methodParametersGenerator; public MethodGenerator(MetadataContainer metadataContainer) { @@ -21,24 +22,14 @@ public MethodGenerator(MetadataContainer metadataContainer) methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); methodBodyGenerator = new MethodBodyGenerator(metadataContainer); methodLocalsGenerator = new MethodLocalsGenerator(metadataContainer); + methodParametersGenerator = new MethodParametersGenerator(metadataContainer); } public SRM.MethodDefinitionHandle Generate(MethodDefinition method) { + var parameters = methodParametersGenerator.Generate(method.Parameters) + ?? ECMA335.MetadataTokens.ParameterHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); var methodSignature = methodSignatureGenerator.GenerateSignatureOf(method); - SRM.ParameterHandle? firstParameterHandle = null; - foreach (var parameter in method.Parameters) - { - var parameterHandle = metadataContainer.metadataBuilder.AddParameter( - GetParameterAttributesFor(parameter), - metadataContainer.metadataBuilder.GetOrAddString(parameter.Name), - parameter.Index); - if (!firstParameterHandle.HasValue) - { - firstParameterHandle = parameterHandle; - } - } - // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated // programatically then the maxStack is gonna be missing @@ -49,14 +40,14 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) maxStack: method.Body.MaxStack) : -1; - var nextParameterHandle = ECMA335.MetadataTokens.ParameterHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); + var methodDefinitionHandle = metadataContainer.metadataBuilder.AddMethodDefinition( attributes: GetMethodAttributesFor(method), implAttributes: SR.MethodImplAttributes.IL | SR.MethodImplAttributes.Managed, // FIXME what else? name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), signature: metadataContainer.metadataBuilder.GetOrAddBlob(methodSignature), bodyOffset: methodBodyOffset, - parameterList: firstParameterHandle ?? nextParameterHandle); + parameterList: parameters); methodLocalsGenerator.GenerateLocalVariables(method.Body, methodDefinitionHandle); diff --git a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs b/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs new file mode 100644 index 00000000..f5f5366b --- /dev/null +++ b/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using MetadataGenerator.Metadata; +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SR = System.Reflection; +using SRM = System.Reflection.Metadata; +using static MetadataGenerator.Metadata.AttributesProvider; + +namespace MetadataGenerator.Generators.Methods +{ + internal class MethodParametersGenerator + { + private readonly MetadataContainer metadataContainer; + + internal MethodParametersGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public SRM.ParameterHandle? Generate(IList methodParameters) + { + SRM.ParameterHandle? firstParameterHandle = null; + foreach (var parameter in methodParameters) + { + var parameterHandle = metadataContainer.metadataBuilder.AddParameter( + GetParameterAttributesFor(parameter), + metadataContainer.metadataBuilder.GetOrAddString(parameter.Name), + parameter.Index); + if (parameter.HasDefaultValue) + { + metadataContainer.metadataBuilder.AddConstant(parameterHandle, parameter.DefaultValue.Value); + } + + if (!firstParameterHandle.HasValue) + { + firstParameterHandle = parameterHandle; + } + + /* TODO add custom attributes (ex: varargs), see ECMA under custom attributes + metadataContainer.metadataBuilder.AddCustomAttribute( + parameter handle, + some handle, + value + ) + */ + } + + return firstParameterHandle; + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 3774a208..c9ffe65c 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -221,12 +221,13 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { case IBasicType basicType: { + var isValueType = type.TypeKind == TypeKind.ValueType; if (basicType.IsGenericInstantiation()) { var genericInstantiation = encoder.GenericInstantiation( ReferenceHandleOf(basicType.GenericType), basicType.GenericParameterCount, - type.TypeKind == TypeKind.ValueType); + isValueType); foreach (var genericArg in basicType.GenericArguments) { Encode(genericArg, genericInstantiation.AddArgument()); @@ -234,7 +235,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) } else { - encoder.Type(ReferenceHandleOf(basicType), type.TypeKind == TypeKind.ValueType); + encoder.Type(ReferenceHandleOf(basicType), isValueType); } break; diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 7bd19bae..3170c2a7 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -30,6 +30,7 @@ + From 4a007d153912d2ed963c52cd0e19a3c475fb2e0f Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 28 Dec 2019 19:22:41 -0300 Subject: [PATCH 084/256] refactor --- Examples/Examples.cs | 4 + MetadataGenerator/Generator.cs | 9 +- .../Fields/FieldSignatureGenerator.cs | 2 +- .../Body/MethodBodyControlFlowGenerator.cs | 2 +- .../Methods/Body/MethodBodyGenerator.cs | 39 +++-- .../Methods/Body/MethodLocalsGenerator.cs | 17 +- .../Generators/Methods/MethodGenerator.cs | 3 +- .../Methods/MethodSignatureGenerator.cs | 8 +- MetadataGenerator/Generators/TypeGenerator.cs | 8 +- .../Metadata/AttributesProvider.cs | 6 +- .../Metadata/MetadataContainer.cs | 12 +- .../Metadata/MetadataResolver.cs | 147 ++++++++++-------- 12 files changed, 129 insertions(+), 128 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 2ccb66f9..375290f5 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -87,6 +87,10 @@ public static void DoNothing(int x) } } + public static class EmptyStaticClass + { + } + public class SimpleClass { diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 732a10c7..56954a23 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -11,8 +11,8 @@ public class Generator : IGenerator { public void Generate(Assembly assembly) { - using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) - // using (var peStream = File.OpenWrite($"./{assembly.Name}.exe")) + using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) + // using (var peStream = File.OpenWrite($"./{assembly.Name}.exe")) { var metadataContainer = AssemblyGenerator.Generate(assembly); var peHeaderBuilder = new SRPE.PEHeaderBuilder( @@ -25,9 +25,8 @@ public void Generate(Assembly assembly) header: peHeaderBuilder, metadataRootBuilder: new ECMA335.MetadataRootBuilder(metadataContainer.metadataBuilder), ilStream: metadataContainer.methodBodyStream.Builder, - entryPoint: metadataContainer.MainMethodHandle ?? default, - // FIXME CorFlags.Requires32Bit | CorFlags.StrongNameSigned depend on dll. Requires/prefers 32 bit? - flags: SRPE.CorFlags.ILOnly).Serialize(peBlob); + entryPoint: metadataContainer.MainMethodHandle ?? default + ).Serialize(peBlob); peBlob.WriteContentTo(peStream); } } diff --git a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs index 67a79032..c9215713 100644 --- a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs @@ -17,7 +17,7 @@ public FieldSignatureGenerator(MetadataContainer metadataContainer) public SRM.BlobBuilder GenerateSignatureOf(IFieldReference field) { var fieldSignature = new SRM.BlobBuilder(); - metadataContainer.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); + metadataContainer.metadataResolver.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); return fieldSignature; } } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index 1eb410f5..f22aeb57 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -67,7 +67,7 @@ public void ProcessExceptionInformation(IList exceptionInformati case ExceptionHandlerBlockKind.Catch: var catchType = ((CatchExceptionHandler) protectedBlock.Handler).ExceptionType; controlFlowBuilder.AddCatchRegion(tryStart, tryEnd, handlerStart, handlerEnd, - metadataContainer.ResolveReferenceHandleFor(catchType)); + metadataContainer.metadataResolver.HandleOf(catchType)); break; case ExceptionHandlerBlockKind.Fault: case ExceptionHandlerBlockKind.Finally: diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 1a38b2d0..1bf09a56 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -347,25 +347,25 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case ConvertOperation.Cast: instructionEncoder.OpCode(SRM.ILOpCode.Castclass); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); break; /* FIXMEunccoment when isInst PR is merged case ConvertOperation.IsInst: instructionEncoder.OpCode(SRM.ILOpCode.Isinst); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); break; */ case ConvertOperation.Box: instructionEncoder.OpCode(SRM.ILOpCode.Box); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); break; case ConvertOperation.Unbox: instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); break; case ConvertOperation.UnboxPtr: instructionEncoder.OpCode(SRM.ILOpCode.Unbox); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(convertInstruction.ConversionType)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); break; } @@ -374,11 +374,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) switch (methodCallInstruction.Operation) { case MethodCallOperation.Virtual: - instructionEncoder.CallVirtual(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method)); + instructionEncoder.CallVirtual(metadataContainer.metadataResolver.HandleOf(methodCallInstruction.Method)); break; case MethodCallOperation.Static: case MethodCallOperation.Jump: - instructionEncoder.Call(metadataContainer.ResolveReferenceHandleFor(methodCallInstruction.Method)); + instructionEncoder.Call(metadataContainer.metadataResolver.HandleOf(methodCallInstruction.Method)); break; } @@ -466,14 +466,13 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; } - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadFieldInstruction.Field)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadFieldInstruction.Field)); break; case LoadArrayElementInstruction loadArrayElementInstruction: switch (loadArrayElementInstruction.Operation) { // TODO not doing anything until LoadArrayElementInstruction PR is merged (because right now is treated as BasicOperation) case LoadArrayElementOperation.Content: - // TODO there are multiple instructions with this kind of ifs. Maybe extract method? if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i); @@ -522,27 +521,26 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); instructionEncoder.Token( - metadataContainer.ResolveReferenceHandleFor(loadArrayElementInstruction.Array.ElementsType)); + metadataContainer.metadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); } break; case LoadArrayElementOperation.Address: - // TODO test. Example present but not supported in model instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadArrayElementInstruction.Array.ElementsType)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); break; } break; case LoadMethodAddressInstruction loadMethodAddressInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadMethodAddressInstruction.Method)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadMethodAddressInstruction.Method)); break; case CreateArrayInstruction createArrayInstruction: if (createArrayInstruction.Type.IsVector) { instructionEncoder.OpCode(SRM.ILOpCode.Newarr); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(createArrayInstruction.Type.ElementsType)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(createArrayInstruction.Type.ElementsType)); } else { @@ -551,7 +549,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case CreateObjectInstruction createObjectInstruction: - var method = metadataContainer.ResolveReferenceHandleFor(createObjectInstruction.Constructor); + var method = metadataContainer.metadataResolver.HandleOf(createObjectInstruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); break; @@ -568,7 +566,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case StoreFieldInstruction storeFieldInstruction: instructionEncoder.OpCode(storeFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeFieldInstruction.Field)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(storeFieldInstruction.Field)); break; case SwitchInstruction switchInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Switch); @@ -580,15 +578,14 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case SizeofInstruction sizeofInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(sizeofInstruction.MeasuredType)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(sizeofInstruction.MeasuredType)); break; case LoadTokenInstruction loadTokenInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(loadTokenInstruction.Token)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadTokenInstruction.Token)); break; case IndirectMethodCallInstruction indirectMethodCallInstruction: - // TODO test - var methodSignature = metadataContainer.ResolveReferenceHandleFor(indirectMethodCallInstruction.Function); + var methodSignature = metadataContainer.metadataResolver.HandleOf(indirectMethodCallInstruction.Function); instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); break; case StoreArrayElementInstruction storeArrayElementInstruction: @@ -627,7 +624,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) else { instructionEncoder.OpCode(SRM.ILOpCode.Stelem); - instructionEncoder.Token(metadataContainer.ResolveReferenceHandleFor(storeArrayElementInstruction.Array.ElementsType)); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(storeArrayElementInstruction.Array.ElementsType)); } break; diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs index f72b90c7..841647b3 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs @@ -1,5 +1,4 @@ -using System.Threading; -using MetadataGenerator.Metadata; +using MetadataGenerator.Metadata; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -24,17 +23,11 @@ public SRM.StandaloneSignatureHandle GenerateLocalVariablesSignatureFor(MethodBo var encoder = new ECMA335.BlobEncoder(signature).LocalVariableSignature(body.LocalVariables.Count); foreach (var localVariable in body.LocalVariables) { - metadataContainer.Encode( - localVariable.Type, - encoder.AddVariable().Type(isPinned: false)); - // FIXME pinned is achieved by the fixed keyword and this is not in the modeled + // TODO pinned is achieved by the fixed keyword and this is not in the model + metadataContainer.metadataResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); } - // FIXME this adds ad signature everytime? getOrAddBlob though. Locals are most likely different for each method though - localVariablesSignature = - metadataContainer.metadataBuilder.AddStandaloneSignature(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); - - return localVariablesSignature; + localVariablesSignature = metadataContainer.metadataResolver.GetOrAddStandaloneSignature(signature); } return localVariablesSignature; @@ -67,9 +60,9 @@ Quiza estan mal algunos de los valores de addLocalScope y por eso no anda var nextLocalVariableHandle = ECMA335.MetadataTokens.LocalVariableHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalVariable)); - // FIXME ?? var nextLocalConstantHandle = ECMA335.MetadataTokens.LocalConstantHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalConstant)); + metadataContainer.metadataBuilder.AddLocalScope( method: containingMethodHandle, importScope: default, // FIXME ?? diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index dcda8e81..188aa6b5 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -40,10 +40,9 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) maxStack: method.Body.MaxStack) : -1; - var methodDefinitionHandle = metadataContainer.metadataBuilder.AddMethodDefinition( attributes: GetMethodAttributesFor(method), - implAttributes: SR.MethodImplAttributes.IL | SR.MethodImplAttributes.Managed, // FIXME what else? + implAttributes: SR.MethodImplAttributes.IL | SR.MethodImplAttributes.Managed, name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), signature: metadataContainer.metadataBuilder.GetOrAddBlob(methodSignature), bodyOffset: methodBodyOffset, diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 0d7fb06d..2ad92f05 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -23,7 +23,7 @@ public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) var encoder = new ECMA335.BlobEncoder(signature).MethodSpecificationSignature(method.GenericArguments.Count); foreach (var genericArg in method.GenericArguments) { - metadataContainer.Encode(genericArg, encoder.AddArgument()); + metadataContainer.metadataResolver.Encode(genericArg, encoder.AddArgument()); } return signature; @@ -34,7 +34,7 @@ public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) } } - // FIXME 0 because FunctionPointerType does not have that property (there's a fixme in that class) + // 0 because FunctionPointerType does not have that property (there's a comment in that class) public SRM.BlobBuilder GenerateSignatureOf(FunctionPointerType method) => GenerateMethodSignature(method.IsStatic, 0, method.Parameters, method.ReturnType); @@ -59,7 +59,7 @@ private SRM.BlobBuilder GenerateMethodSignature( { // TODO isByRef param. ref in return type is not in the model var encoder = returnTypeEncoder.Type(); - metadataContainer.Encode(returnType, encoder); + metadataContainer.metadataResolver.Encode(returnType, encoder); } }, parametersEncoder => @@ -69,7 +69,7 @@ private SRM.BlobBuilder GenerateMethodSignature( var isByRef = parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref); var type = isByRef ? (parameter.Type as PointerType).TargetType : parameter.Type; var encoder = parametersEncoder.AddParameter().Type(isByRef); - metadataContainer.Encode(type, encoder); + metadataContainer.metadataResolver.Encode(type, encoder); } }); return methodSignature; diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index 9626fca2..94b5fd50 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -30,8 +30,8 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) var metadataBuilder = metadataContainer.metadataBuilder; var fieldDefinitionHandles = type.Fields.Select(field => fieldGenerator.Generate(field)).ToList(); - /* TODO Properties: (works) but model is missing Property concept - * extract to PropertiesGenerator + /* TODO model is missing Property concept + * pseudocode var propertySignatureBlogBuilder = new BlobBuilder(); new BlobEncoder(propertySignatureBlogBuilder) @@ -70,7 +70,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) attributes: GetTypeAttributesFor(type), @namespace: metadataBuilder.GetOrAddString(type.ContainingNamespace.FullName), name: metadataBuilder.GetOrAddString(TypeNameOf(type)), - baseType: type.Base != null ? metadataContainer.ResolveReferenceHandleFor(type.Base) : default, + baseType: type.Base != null ? metadataContainer.metadataResolver.HandleOf(type.Base) : default, fieldList: fieldDefinitionHandles.FirstOr(nextFieldDefinitionHandle), methodList: methodDefinitionHandles.FirstOr(nextMethodDefinitionHandle)); @@ -78,7 +78,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) { metadataBuilder.AddInterfaceImplementation( type: typeDefinitionHandle, - implementedInterface: metadataContainer.ResolveReferenceHandleFor(interfaze)); + implementedInterface: metadataContainer.metadataResolver.HandleOf(interfaze)); } // generate class generic parameters (Class) diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index 1dc5b417..5bb1646b 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -101,7 +101,7 @@ public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) (method.IsVirtual ? MethodAttributes.Virtual : 0) | (method.ContainingType.Kind is TypeDefinitionKind.Interface ? MethodAttributes.NewSlot - : 0) | // FIXME not entirely correct. Model is missing the new keyword + : 0) | // FIXME not correct. Depends on the new keyword but model is missing it (constructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | (specialName ? MethodAttributes.SpecialName : 0); switch (method.Visibility) @@ -132,13 +132,13 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para { case MethodParameterKind.In: // attributes |= ParameterAttributes.In; - // FIXME this seems to be always true... and illspy of original is not + // FIXME this seems to be always true... and illspy of original is not. Unncoment when PR is merged break; case MethodParameterKind.Out: attributes |= ParameterAttributes.Out; break; case MethodParameterKind.Ref: - // TODO + // There is no ParameterAttributes.Ref and no Params.Flags related (see ECMA) break; } diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index e2d1776a..3bdc607d 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -12,7 +12,7 @@ namespace MetadataGenerator.Metadata internal class MetadataContainer { public readonly ECMA335.MetadataBuilder metadataBuilder; - private readonly MetadataResolver metadataResolver; + public readonly MetadataResolver metadataResolver; public readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; private SRM.MethodDefinitionHandle? mainMethodHandle; private readonly IDictionary> genericParameters = new Dictionary>(); @@ -37,11 +37,6 @@ public MetadataContainer(Assembly assembly) metadataResolver = new MetadataResolver(this, assembly); } - public SRM.EntityHandle ResolveReferenceHandleFor(IMetadataReference metadataReference) => - metadataResolver.ReferenceHandleOf(metadataReference); - - public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) => metadataResolver.Encode(type, encoder); - public void RegisterGenericParameter(SRM.TypeDefinitionHandle owner, GenericParameter genericParameter) => DoRegisterGenericParameter(owner, genericParameter); @@ -55,11 +50,12 @@ void GenerateGenericParameter() => metadataBuilder.AddGenericParameter( GenericParameterAttributes.None, metadataBuilder.GetOrAddString(genericParameter.Name), genericParameter.Index); - /* FIXME generic constraints not in the model + /* TODO generic constraints not in the model. Do when PR is merged + pseudocode: if(genericParameter.hasConstraint()){ metadataBuilder.AddGenericParameterConstraint( genericParameterHandle, - metadataContainer.ResolveReferenceHandleFor(genericParameter.contraint)); + metadataContainer.metadataResolver.HandleOf(genericParameter.contraint)); }*/ var key = ECMA335.CodedIndex.TypeOrMethodDef(owner); diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index c9ffe65c..72e0c2e7 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -11,6 +11,7 @@ namespace MetadataGenerator.Metadata { + // FIXME is there a way to unify all this dictionaries and logic of GetOrAdd? internal class MetadataResolver { private readonly Assembly assembly; @@ -18,6 +19,16 @@ internal class MetadataResolver private readonly IDictionary assemblyReferences = new Dictionary(); private readonly IDictionary typeReferences = new Dictionary(); private readonly IDictionary memberReferences = new Dictionary(); + + private readonly IDictionary typeSpecificationReferences = + new Dictionary(); + + private readonly IDictionary methodSpecificationReferences = + new Dictionary(); + + private readonly IDictionary standaloneSignatureReferences = + new Dictionary(); + private readonly FieldSignatureGenerator fieldSignatureGenerator; private readonly MethodSignatureGenerator methodSignatureGenerator; @@ -31,7 +42,7 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) // FIXME parameters assemblyReferences.Add(assemblyReference.Name, metadataContainer.metadataBuilder.AddAssemblyReference( name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), - version: new Version(4, 0, 0, 0), + version: new Version(4, 0, 0, 0), // version should be in the assemblyReference culture: metadataContainer.metadataBuilder.GetOrAddString("neutral"), publicKeyOrToken: metadataContainer.metadataBuilder.GetOrAddBlob( ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), @@ -44,76 +55,46 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); } - public SRM.EntityHandle ReferenceHandleOf(IMetadataReference metadataReference) + public SRM.EntityHandle HandleOf(IMetadataReference metadataReference) { switch (metadataReference) { case IFieldReference field: { var signature = fieldSignatureGenerator.GenerateSignatureOf(field); - return ReferenceHandleOf(field, signature); + return GetOrAddFieldReference(field, signature); } case IMethodReference method: { var signature = methodSignatureGenerator.GenerateSignatureOf(method); - return ReferenceHandleOf(method, signature); + return GetOrAddMethodReference(method, signature); } case FunctionPointerType functionPointer: { var signature = methodSignatureGenerator.GenerateSignatureOf(functionPointer); - return metadataContainer.metadataBuilder.AddStandaloneSignature(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + return GetOrAddStandaloneSignature(signature); } case IType type: - return ReferenceHandleOf(type); - default: - throw new Exception($"Metadata reference not supported"); - } - } - - private SRM.EntityHandle ReferenceHandleOf(IType type) - { - switch (type) - { - case IBasicType basicType: return ReferenceHandleOf(basicType); - case IType iType when iType is ArrayType || iType is PointerType || iType is IGenericParameterReference: - { - var signature = new SRM.BlobBuilder(); - var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); - Encode(iType, encoder); - // FIXME should be stored? or added every time? - return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); - } + switch (type) + { + case IBasicType basicType: + return GetOrAddTypeReference(basicType); + case IType iType when iType is ArrayType || iType is PointerType || iType is IGenericParameterReference: + return GetOrAddTypeSpecificationFor(iType); + default: + throw new Exception($"type {type} not yet supported"); + } default: - throw new Exception($"type ${type} not yet supported"); + throw new Exception($"Metadata {metadataReference} reference not supported"); } } - /* - * Returns a TypeReference for type. It stores references because metadata does not have a getOrAddTypeReference. - */ - private SRM.EntityHandle ReferenceHandleOf(IBasicType type) + private SRM.EntityHandle GetOrAddTypeReference(IBasicType type) { - // TODO rewrite this method better - // FIXME should be stored? or added every time? - if (type.IsGenericInstantiation()) - { - var signature = new SRM.BlobBuilder(); - var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); - Encode(type, encoder); - return metadataContainer.metadataBuilder.AddTypeSpecification(metadataContainer.metadataBuilder.GetOrAddBlob(signature)); - } + if (type.IsGenericInstantiation()) return GetOrAddTypeSpecificationFor(type); var typeName = type.Name; - /** - * CLS-compliant generic type names are encoded using the format “name[`arity]”, where […] indicates that the grave accent character “`” and - * arity together are optional. The encoded name shall follow these rules: - * - name shall be an ID that does not contain the “`” character. - * - arity is specified as an unsigned decimal number without leading zeros or spaces. - * - For a normal generic type, arity is the number of type parameters declared on the type. - * - For a nested generic type, arity is the number of newly introduced type parameters. - */ - // FIXME partial logic. See TypeGenerator.TypeNameOf. Needs to be unified with that if (type.IsGenericType()) { @@ -134,7 +115,7 @@ private SRM.EntityHandle ReferenceHandleOf(IBasicType type) else { // if not, recursively get a reference for the containing type and use that as the resolution scope - resolutionScope = ReferenceHandleOf(type.ContainingType); + resolutionScope = GetOrAddTypeReference(type.ContainingType); } typeReference = metadataContainer.metadataBuilder.AddTypeReference( @@ -142,25 +123,58 @@ private SRM.EntityHandle ReferenceHandleOf(IBasicType type) @namespace: metadataContainer.metadataBuilder.GetOrAddString(type.ContainingNamespace), name: metadataContainer.metadataBuilder.GetOrAddString(typeName)); typeReferences.Add(key, typeReference); - - return typeReference; } - // if not add the new type reference to metadata and store it return typeReference; } - private SRM.EntityHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuilder signature) + private SRM.TypeSpecificationHandle GetOrAddTypeSpecificationFor(IType type) { - if (method.IsGenericInstantiation()) + var signature = new SRM.BlobBuilder(); + var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); + Encode(type, encoder); + var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + if (!typeSpecificationReferences.TryGetValue(blobHandle, out var typeSpecification)) { - // FIXME should be stored and not add a new one each time (like the else branch). - // FIXME To do this, the key should have info related to the instantiation that unequivocally identifies that particular instantiation - var methodSpecificationHandle = metadataContainer.metadataBuilder.AddMethodSpecification( - ReferenceHandleOf(method.GenericMethod, methodSignatureGenerator.GenerateSignatureOf(method.GenericMethod)), - metadataContainer.metadataBuilder.GetOrAddBlob(signature) + typeSpecification = metadataContainer.metadataBuilder.AddTypeSpecification(blobHandle); + typeSpecificationReferences.Add(blobHandle, typeSpecification); + } + + return typeSpecification; + } + + private SRM.MethodSpecificationHandle GetOrAddMethodSpecificationFor(IMethodReference method, SRM.BlobBuilder signature) + { + var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + if (!methodSpecificationReferences.TryGetValue(blobHandle, out var methodSpecification)) + { + methodSpecification = metadataContainer.metadataBuilder.AddMethodSpecification( + GetOrAddMethodReference(method.GenericMethod, methodSignatureGenerator.GenerateSignatureOf(method.GenericMethod)), + blobHandle ); - return methodSpecificationHandle; + methodSpecificationReferences.Add(blobHandle, methodSpecification); + } + + return methodSpecification; + } + + public SRM.StandaloneSignatureHandle GetOrAddStandaloneSignature(SRM.BlobBuilder signature) + { + var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + if (!standaloneSignatureReferences.TryGetValue(blobHandle, out var standaloneSignature)) + { + standaloneSignature = metadataContainer.metadataBuilder.AddStandaloneSignature(blobHandle); + standaloneSignatureReferences.Add(blobHandle, standaloneSignature); + } + + return standaloneSignature; + } + + private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.BlobBuilder signature) + { + if (method.IsGenericInstantiation()) + { + return GetOrAddMethodSpecificationFor(method, signature); } else { @@ -169,7 +183,7 @@ private SRM.EntityHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuil if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) { methodReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( - parent: ReferenceHandleOf(method.ContainingType), + parent: GetOrAddTypeReference(method.ContainingType), name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); memberReferences.Add(key, methodReferenceHandle); @@ -179,14 +193,14 @@ private SRM.EntityHandle ReferenceHandleOf(IMethodReference method, SRM.BlobBuil } } - private SRM.MemberReferenceHandle ReferenceHandleOf(IFieldReference field, SRM.BlobBuilder signature) + private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field, SRM.BlobBuilder signature) { var key = $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.Name}.{field.Name}"; if (!memberReferences.TryGetValue(key, out var memberReferenceHandle)) { memberReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( - parent: ReferenceHandleOf(field.ContainingType), + parent: GetOrAddTypeReference(field.ContainingType), name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); memberReferences.Add(key, memberReferenceHandle); @@ -198,7 +212,7 @@ private SRM.MemberReferenceHandle ReferenceHandleOf(IFieldReference field, SRM.B } // SignatureTypeEncoder is a struct but it is not necessary to pass it by reference since - // it operates on its Builder (BlobBuilder) which is a class (tha means the builder reference is always the same) + // it operates on its Builder (BlobBuilder) which is a class (that means the builder reference is always the same) public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); @@ -225,7 +239,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) if (basicType.IsGenericInstantiation()) { var genericInstantiation = encoder.GenericInstantiation( - ReferenceHandleOf(basicType.GenericType), + GetOrAddTypeReference(basicType.GenericType), basicType.GenericParameterCount, isValueType); foreach (var genericArg in basicType.GenericArguments) @@ -235,7 +249,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) } else { - encoder.Type(ReferenceHandleOf(basicType), isValueType); + encoder.Type(GetOrAddTypeReference(basicType), isValueType); } break; @@ -246,7 +260,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) arrayShapeEncoder => { var lowerBounds = arrayType.Rank > 1 - ? Repeat(0, (int) arrayType.Rank).ToImmutableArray() // FIXME 0 because ArrayType does not know bounds + ? Repeat(0, (int) arrayType.Rank).ToImmutableArray() // 0 because ArrayType does not know bounds : ImmutableArray.Empty; arrayShapeEncoder.Shape( rank: (int) arrayType.Rank, @@ -256,7 +270,6 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) break; case PointerType pointerType: { - // TODO there's also signatureTypeEncode.FunctionPointer()/IntPtr()/UIntPtr var targetType = pointerType.TargetType; if (targetType.Equals(PlatformTypes.Void)) { From ca68664539edff08e4dda400391306f10ee90586 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 8 Jan 2020 19:36:33 -0300 Subject: [PATCH 085/256] ExamplesExe --- Examples/Examples.cs | 132 +++++++++++------- ExamplesEXE/ExamplesEXE.cs | 58 ++++++-- MetadataGenerator/Generator.cs | 9 +- .../Generators/AssemblyGenerator.cs | 4 +- .../Methods/Body/MethodBodyGenerator.cs | 1 - .../Methods/Body/MethodLocalsGenerator.cs | 7 +- .../Metadata/AttributesProvider.cs | 4 +- .../Metadata/MetadataResolver.cs | 7 +- 8 files changed, 149 insertions(+), 73 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 375290f5..2329d360 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -149,7 +149,7 @@ public class ClassWithMoreComplexFieldsAndParametersOrReturnTypes public Exception[][,] exceptionMultiDimensionalJaggedArray; public int[,][] intMultiDimensionalJaggedArray; public Exception[] exceptionArrayField; - public B b; + public B b = new B(); public void MethodWithOptionalParametersAndDefaultValues( string someParam, @@ -518,7 +518,7 @@ public class NestedGenericClass namespace MethodBody { - public abstract class ContainingClass + public /*FIXME unccoment abstract*/ class ContainingClass { public void HelloWorld() { @@ -546,35 +546,41 @@ public int Arithmetics(int x, int y) return z; } - public void Logic(bool x, bool y) + public bool Logic(bool x, bool y) { var z = x && y; z = x || y; z = !x; z = x ^ y; + + return z; } - public void BitwiseOperations(int x) + public int BitwiseOperations(int x) { var z = x & x; z = x | x; z = x ^ x; z = x >> 1; z = z << 1; + + return z; } - public abstract void NoBody(); + // FIXME unccoment public abstract void NoBody(); public void Alloc() { unsafe { var x = stackalloc int[3]; + Console.WriteLine(*x); } } - public void Nothing(T arg) + public Type Nothing(T arg) { + return arg.GetType(); } public void Nothing2() @@ -582,7 +588,7 @@ public void Nothing2() } // TODO more generic method calls examples - public void Calls(SimpleClass simpleClass, Action f) + public int Calls(SimpleClass simpleClass, Func func) { Console.WriteLine("A method call"); // static simpleClass.DoNothing(); // virtual @@ -590,27 +596,30 @@ public void Calls(SimpleClass simpleClass, Action f) var l = new List {"holas"}; - f(1); + var result = func(1); + result += l.Count; // TODO calli (indirect) - /* FIXME - not working when reading dll - var g = new Generics.Generic(); - g.PrintGeneric("hola"); - g.PrintGeneric(1); - */ + // FIXME + // not working when reading dll + //var g = new Generics.Generic(); + //g.PrintGeneric("hola"); + //g.PrintGeneric(1); + // Nothing(""); Nothing2(); - /* FIXME - not working when reading dll - Nothing2>(); - Nothing2.NestedClassThatAddsNewGenericParameters.NestedNestedClassThatDoesNotAddNewGenericParameters>(); - */ + // FIXME + //not working when reading dll + //Nothing2>(); + //Nothing2.NestedClassThatAddsNewGenericParameters.NestedNestedClassThatDoesNotAddNewGenericParameters>(); + // + + return result; } - public void Arrays(EmptyStruct[] structArray) + public double Arrays(EmptyStruct[] structArray) { byte y = 1; short s = 3; @@ -640,6 +649,8 @@ public void Arrays(EmptyStruct[] structArray) floatArray[1] = f; // stelem.r4 doubleArray[1] = d; // stelem.r8 structArray[0] = p; // stelem + + return y + d + byteArray.Length + structArray[0].GetHashCode() + structArray.Rank; } public void Empty() @@ -647,7 +658,7 @@ public void Empty() } // FIXME not generated correctly - public void Convert(object o) + public int Convert(object o) { long x1 = 1; double d = 1.0; @@ -676,9 +687,11 @@ public void Convert(object o) int i = (int) l; // unbox.any int // TODO unbox (unbox ptr) + + return i + x6 + s.Length + l.GetHashCode() + o.ToString().Length; } - public void LoadConstant() + public double LoadConstant() { string s = "hello world!"; // ldstr int zero = 0; // ldc.i4.0 @@ -698,9 +711,11 @@ public void LoadConstant() long l = long.MinValue; // ldc.i8 float f = float.MinValue; // ldc.r4 double d = double.MinValue; // ldc.r8 + + return s.Length + minusOne + k + f; } - public void LoadArgument(int arg1, string arg2, bool arg3, int arg4) + public string LoadArgument(int arg1, string arg2, bool arg3, int arg4) { var i0 = this; // ldarg.0 var i1 = arg1; // ldarg.1 @@ -708,9 +723,11 @@ public void LoadArgument(int arg1, string arg2, bool arg3, int arg4) var i3 = arg3; // ldarg.3 var i4 = arg4; // ldarg.s $value // TODO ldarg $value (see ecma) + + return arg2 + arg1 + i4 + i0; } - public void LoadLocal() + public int LoadLocal() { var x0 = 10; var x1 = 12; @@ -724,6 +741,8 @@ public void LoadLocal() var y3 = x3; // ldloc.3 var y4 = x4; // ldloc.s $index (=4) // TODO ldloc $index (see ecma) + + return x0 + x1 + y4 + y2; } public void LoadAddress(int x) @@ -734,6 +753,8 @@ public void LoadAddress(int x) // TODO ldloca $argNum var q = &x; // ldarga.s 0 // TODO ldarga $argNum + + Console.WriteLine(*q); } } @@ -743,7 +764,7 @@ public void LoadPointer() Action y = null; // ldnull } - public void LoadIndirect(ref object g) + public string LoadIndirect(ref object g) { unsafe { @@ -769,40 +790,43 @@ public void LoadIndirect(ref object g) var x9 = *&f; // ldind.r8 var x10 = *&h; // ldind.i var x11 = g; // ldind.ref + + return a_1 + c_2.ToString() + x4 + x11 + g.ToString().Length; } } - public void Compare(int b, int x) + public bool Compare(int b, int x) { var a = b == 2; // ceq a = b > 2; // cgt a = b < 2; // clt + + return a; } - public void Create() + public unsafe int**[] Create() { new SimpleClass(1, "a"); // newobj $methodCall var a = new int[] {1, 2, 3}; // newarr int var b = new Exception[] { }; // newarr Clases.SimpleClass - unsafe - { - var c = new int*[] { }; // newarr int* - var d = new int**[] { }; // newarr int** - } + var c = new int*[] { }; // newarr int* + var d = new int**[] { }; // newarr int** + + return d; } - public void LoadArray(Exception[] x, int[] q) + public int LoadArray(Exception[] x, int[] q) { var a = x[1]; // ldelem.ref - var b = (new sbyte[] { })[0]; // ldelem.i1 - var c = (new byte[] { })[0]; // ldelem.u1 - var d = (new short[] { })[0]; // ldelem.i2 - var e = (new ushort[] { })[0]; // ldelem.u2 - var f = (new int[] { })[0]; // ldelem.i4 - var g = (new uint[] { })[0]; // ldelem.u4 - var h = (new long[] { })[0]; // ldelem.i8 -- ldelem.u8 (alias) - var j = (new float[] { })[0]; // ldelem.r4 - var k = (new double[] { })[0]; // ldelem.r8 + var b = (new sbyte[] {1})[0]; // ldelem.i1 + var c = (new byte[] {2})[0]; // ldelem.u1 + var d = (new short[] {3})[0]; // ldelem.i2 + var e = (new ushort[] {4})[0]; // ldelem.u2 + var f = (new int[] {5})[0]; // ldelem.i4 + var g = (new uint[] {6})[0]; // ldelem.u4 + var h = (new long[] {7})[0]; // ldelem.i8 -- ldelem.u8 (alias) + var j = (new float[] {8})[0]; // ldelem.r4 + var k = (new double[] {9})[0]; // ldelem.r8 // TODO unccoment when LoadArrayElementInstruction PR is merged // var l = new EmptyStruct[] {new EmptyStruct() }[0]; // ldelem typeTok @@ -818,9 +842,11 @@ public void LoadArray(Exception[] x, int[] q) var m = (new int[] {1, 2, 3}).Length; // ldlen + + return m + k.GetHashCode() + c + a.Message.Length + q.Length; } - public void LoadField() + public string LoadField() { var a = new SimpleClass(1, "b").unassignedString; // ldfld string $field var b = new SimpleClass(1, "b").readOnlyIntField; // ldfld int $field @@ -832,16 +858,21 @@ public void LoadField() // fixed (int* d = &(new Classes.SimpleClass(1, "b")).readOnlyIntField) // ldflda int32 $field // { } // } + + + return c.GetType().ToString() + b; } - public void StoreField() + public Exception StoreField() { new SimpleClass(1, "b").unassignedString = ""; // stfld string $field StaticClass.i = 1; // stsfld int $field StaticClass.e = new Exception(); // stsfld Exception $field + + return StaticClass.e; } - public void StoreValue(int arg) + public int StoreValue(int arg) { int l0, l1, l2, l3, l4; l0 = 1; // stloc.0 @@ -853,9 +884,11 @@ public void StoreValue(int arg) arg = 1; // starg.s arg // TODO starg arg (not short form) + + return arg + l4; } - public void SizeOf() + public int SizeOf() { unsafe { @@ -863,14 +896,17 @@ public void SizeOf() // var x = sizeof(Structs.NonEmptyStruct); // sizeof $type var z = sizeof(NonEmptyStruct***); // sizeof $type*** var y = sizeof(int*); // sizeof int* + + return y + z; } } // TODO other cases // FIXME generation almost correct - public void LoadToken() + public Type LoadToken() { var x = typeof(T); + return x; } public void Branch(int a, int b, Exception e) @@ -935,6 +971,7 @@ public void ExceptionHandlingTryCatchSpecific(int x) } catch (Exception ex) { + Console.WriteLine(ex.Message); } } @@ -947,6 +984,7 @@ public void ExceptionHandlingTryCatchFilter(int x) } catch (Exception ex) when (ex.Message.Contains("by zero")) { + Console.WriteLine(ex.Message); } } diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index e229b79e..284476ee 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -1,24 +1,56 @@ -using System; -using Other; +using MethodBody; namespace ExamplesEXE { public static class MainClass { + // TODO run peverify /il /md /verbose Console/bin/Debug/ExamplesEXE.exe public static void Main(string[] args) { - new SomeClass().Print("hola"); - } - } -} + // FIXME hay algo con las abstract clases o la herencia. Porque MethodBody.ContainingClass es + // FIXME abstracta (porque tiene un metodo sin body) y al hacer una clase que herede esa aca y + // FIXME hacerle un new revienta con lo del vtable + var a = new ContainingClass(); -namespace Other -{ - public class SomeClass - { - public void Print(T arg) - { - Console.WriteLine(arg); + /* works [and returns the same as original (in isolation at least)] + Console.WriteLine(a.Arithmetics(1, 2)); + Console.WriteLine(a.Compare(6, 90)); + a.Branch(1, 2, new Exception()); + Console.WriteLine(a.Convert(new Exception())); + a.Empty(); + Console.WriteLine(a.Logic(true, false)); + a.Nothing2(); + Console.WriteLine(a.BitwiseOperations(235)); + a.HelloWorld(); + Console.WriteLine(a.LoadArgument(1, "2", true, 4)); + Console.WriteLine(a.LoadConstant()); + Console.WriteLine(a.LoadLocal()); + a.LoadPointer(); + Console.WriteLine(a.ReturnsArg(10)); + Console.WriteLine(a.ReturnsOne()); + Console.WriteLine(a.SizeOf()); + Console.WriteLine(a.StoreValue(100)); + a.ExceptionHandlingTryCatchSpecific(0); + a.ExceptionHandlingTryCatch(0); + a.ExceptionHandlingTryCatchFilter(0); + */ + + /* does not work + a.Alloc(); + Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); + a.Calls(new SimpleClass(3, "a"), e => 5); + Console.WriteLine(a.Nothing(new object())); + a.LoadAddress(4); + Console.WriteLine(a.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); + Console.WriteLine(a.LoadField()); + Console.WriteLine(a.LoadToken()); + Console.WriteLine(a.StoreField()); + */ + + // pending to try + // a.Create(); + // a.ExceptionHandlingTryCatchFinally(new Exception("asd")); + // a.LoadIndirect(); } } } \ No newline at end of file diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 56954a23..373f7484 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using MetadataGenerator.Generators; using Model; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -11,9 +12,11 @@ public class Generator : IGenerator { public void Generate(Assembly assembly) { - using (var peStream = File.OpenWrite($"./{assembly.Name}.dll")) - // using (var peStream = File.OpenWrite($"./{assembly.Name}.exe")) + var fileName = $"./{assembly.Name}.dll"; + // var fileName = $"./{assembly.Name}.exe"; + using (var peStream = File.OpenWrite(fileName)) { + Console.WriteLine($"Processing: {fileName.Substring(2)}"); var metadataContainer = AssemblyGenerator.Generate(assembly); var peHeaderBuilder = new SRPE.PEHeaderBuilder( imageCharacteristics: metadataContainer.Executable diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index b97aedef..eb3352cc 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -27,12 +27,14 @@ public static MetadataContainer Generate(Assembly assembly) flags: SR.AssemblyFlags.PublicKey, hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1); + var moduleName = $"{assembly.Name}.{(metadataContainer.Executable ? "exe" : "dll")}"; metadataBuilder.AddModule( generation: 0, - moduleName: metadataBuilder.GetOrAddString($"{assembly.Name}.{(metadataContainer.Executable ? "exe" : "dll")}"), + moduleName: metadataBuilder.GetOrAddString(moduleName), mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), encId: metadataBuilder.GetOrAddGuid(Guid.Empty), encBaseId: metadataBuilder.GetOrAddGuid(Guid.Empty)); + Console.WriteLine($"Generating: {moduleName}"); /* * Generic parameters table must be sorted by owner (TypeOrMethodDef that owns the generic parameter). Since the dll's methods and types don't follow a * particular order, the info needed to generate this parameters is stored during type/method generation but not added to the MetadataBuilder until now diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 1bf09a56..d8ed8ae7 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -203,7 +203,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case ConvertInstruction convertInstruction: switch (convertInstruction.Operation) { - // TODO conv.i, conv.u, case ConvertOperation.Conv: if (convertInstruction.ConversionType.Equals(PlatformTypes.Int8)) { diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs index 841647b3..b81cdbbc 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs @@ -63,11 +63,14 @@ Quiza estan mal algunos de los valores de addLocalScope y por eso no anda var nextLocalConstantHandle = ECMA335.MetadataTokens.LocalConstantHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalConstant)); + var nextImportScopeHandle = + ECMA335.MetadataTokens.ImportScopeHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.ImportScope)); + metadataContainer.metadataBuilder.AddLocalScope( method: containingMethodHandle, - importScope: default, // FIXME ?? + importScope: nextImportScopeHandle, // addImportScope() ? variableList: firstLocalVariableHandle ?? nextLocalVariableHandle, - constantList: nextLocalConstantHandle, // FIXME addLocalConstant() + constantList: nextLocalConstantHandle, // addLocalConstant() ? startOffset: default, // FIXME ?? length: default); // FIXME ?? } diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index 5bb1646b..f783f3e4 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -101,7 +101,7 @@ public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) (method.IsVirtual ? MethodAttributes.Virtual : 0) | (method.ContainingType.Kind is TypeDefinitionKind.Interface ? MethodAttributes.NewSlot - : 0) | // FIXME not correct. Depends on the new keyword but model is missing it + : 0) | // TODO not correct. Depends on the new keyword but model is missing it (constructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | (specialName ? MethodAttributes.SpecialName : 0); switch (method.Visibility) @@ -132,7 +132,7 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para { case MethodParameterKind.In: // attributes |= ParameterAttributes.In; - // FIXME this seems to be always true... and illspy of original is not. Unncoment when PR is merged + // TODO this seems to be always true... and illspy of original is not. Unncoment when PR is merged break; case MethodParameterKind.Out: attributes |= ParameterAttributes.Out; diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 72e0c2e7..9ad77ed5 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -42,10 +42,9 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) // FIXME parameters assemblyReferences.Add(assemblyReference.Name, metadataContainer.metadataBuilder.AddAssemblyReference( name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), - version: new Version(4, 0, 0, 0), // version should be in the assemblyReference - culture: metadataContainer.metadataBuilder.GetOrAddString("neutral"), - publicKeyOrToken: metadataContainer.metadataBuilder.GetOrAddBlob( - ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), + version: new Version(4, 0, 0, 0), // FIXME version should be in the assemblyReference? + culture: default, + publicKeyOrToken: default, flags: default, hashValue: default) ); From f8a57bf0d2c9dd27c92a31f0f5cf5f8472ef1fa0 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 8 Jan 2020 20:17:21 -0300 Subject: [PATCH 086/256] unccomment code base on PR merges --- Examples/Examples.cs | 8 ++------ .../Generators/Methods/Body/MethodBodyGenerator.cs | 3 --- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 2329d360..ffb97ec9 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -657,7 +657,6 @@ public void Empty() { } - // FIXME not generated correctly public int Convert(object o) { long x1 = 1; @@ -679,9 +678,7 @@ public int Convert(object o) string s = (string) (object) "asd"; // castclass $class var x = (int[]) (object) new int[] { }; - - // FIXME framework read not working (unccoment when isInst PR is merged) - // var b = o is Classes.SimpleClass; // isinst $class + var b = o is SimpleClass; // isinst $class object l = 1; // box int int i = (int) l; // unbox.any int @@ -827,8 +824,7 @@ public int LoadArray(Exception[] x, int[] q) var h = (new long[] {7})[0]; // ldelem.i8 -- ldelem.u8 (alias) var j = (new float[] {8})[0]; // ldelem.r4 var k = (new double[] {9})[0]; // ldelem.r8 - // TODO unccoment when LoadArrayElementInstruction PR is merged - // var l = new EmptyStruct[] {new EmptyStruct() }[0]; // ldelem typeTok + var l = new EmptyStruct[] {new EmptyStruct()}[0]; // ldelem typeTok // TODO ldelem.i ??? // diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index d8ed8ae7..664171c9 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -348,12 +348,10 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(SRM.ILOpCode.Castclass); instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); break; - /* FIXMEunccoment when isInst PR is merged case ConvertOperation.IsInst: instructionEncoder.OpCode(SRM.ILOpCode.Isinst); instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); break; - */ case ConvertOperation.Box: instructionEncoder.OpCode(SRM.ILOpCode.Box); instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); @@ -470,7 +468,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case LoadArrayElementInstruction loadArrayElementInstruction: switch (loadArrayElementInstruction.Operation) { - // TODO not doing anything until LoadArrayElementInstruction PR is merged (because right now is treated as BasicOperation) case LoadArrayElementOperation.Content: if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) { From af1552c712c0517fe6807a4e7af1f8a4bd4ad069 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 9 Jan 2020 22:38:07 -0300 Subject: [PATCH 087/256] minor fixes --- ExamplesEXE/ExamplesEXE.cs | 5 ++++- .../Generators/AssemblyGenerator.cs | 11 +++++----- .../Methods/Body/MethodLocalsGenerator.cs | 6 ++--- .../Generators/Methods/MethodGenerator.cs | 22 ++++++++++++------- .../Methods/MethodParametersGenerator.cs | 6 ++--- .../Metadata/MetadataResolver.cs | 6 ++--- 6 files changed, 33 insertions(+), 23 deletions(-) diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 284476ee..1f6bc3e5 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -35,6 +35,10 @@ public static void Main(string[] args) a.ExceptionHandlingTryCatchFilter(0); */ + /* works but differs form original + a.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); + */ + /* does not work a.Alloc(); Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); @@ -49,7 +53,6 @@ public static void Main(string[] args) // pending to try // a.Create(); - // a.ExceptionHandlingTryCatchFinally(new Exception("asd")); // a.LoadIndirect(); } } diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index eb3352cc..97211f8f 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -18,22 +18,23 @@ public static MetadataContainer Generate(Assembly assembly) namespaceGenerator.Generate(namezpace); } - // FIXME args metadataBuilder.AddAssembly( name: metadataBuilder.GetOrAddString(assembly.Name), - version: new Version(1, 0, 0, 0), + version: new Version(0, 0, 0, 1), culture: default, publicKey: default, flags: SR.AssemblyFlags.PublicKey, - hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1); + hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1 + ); var moduleName = $"{assembly.Name}.{(metadataContainer.Executable ? "exe" : "dll")}"; metadataBuilder.AddModule( generation: 0, moduleName: metadataBuilder.GetOrAddString(moduleName), mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), - encId: metadataBuilder.GetOrAddGuid(Guid.Empty), - encBaseId: metadataBuilder.GetOrAddGuid(Guid.Empty)); + encId: default, + encBaseId: default); + Console.WriteLine($"Generating: {moduleName}"); /* * Generic parameters table must be sorted by owner (TypeOrMethodDef that owns the generic parameter). Since the dll's methods and types don't follow a diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs index b81cdbbc..3e2167b3 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs @@ -33,7 +33,7 @@ public SRM.StandaloneSignatureHandle GenerateLocalVariablesSignatureFor(MethodBo return localVariablesSignature; } - public void GenerateLocalVariables(MethodBody body, SRM.MethodDefinitionHandle containingMethodHandle) + public void GenerateLocalVariables(MethodBody body, SRM.MethodDefinitionHandle containingMethodHandle, int bodyLengthInBytes) { /* FIXME GenerateLocalVariablesSignatureFor solo genera la firma (que se usa para hacer el addMethodBody) y no agrega las variables por lo que no deberia andar. Sin embargo parece que anda solo con eso. @@ -71,8 +71,8 @@ Quiza estan mal algunos de los valores de addLocalScope y por eso no anda importScope: nextImportScopeHandle, // addImportScope() ? variableList: firstLocalVariableHandle ?? nextLocalVariableHandle, constantList: nextLocalConstantHandle, // addLocalConstant() ? - startOffset: default, // FIXME ?? - length: default); // FIXME ?? + startOffset: 0, + length: bodyLengthInBytes); } } } diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 188aa6b5..a86b6329 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -31,14 +31,20 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) ?? ECMA335.MetadataTokens.ParameterHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); var methodSignature = methodSignatureGenerator.GenerateSignatureOf(method); - // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated - // programatically then the maxStack is gonna be missing - var methodBodyOffset = method.HasBody - ? metadataContainer.methodBodyStream.AddMethodBody( - instructionEncoder: methodBodyGenerator.Generate(method.Body), + var methodBodyOffset = -1; + var bodyLengthInBytes = 0; + if (method.HasBody) + { + // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated + // programatically then the maxStack is gonna be missing + var maxStack = method.Body.MaxStack; + var instructionEncoder = methodBodyGenerator.Generate(method.Body); + methodBodyOffset = metadataContainer.methodBodyStream.AddMethodBody( + instructionEncoder: instructionEncoder, localVariablesSignature: methodLocalsGenerator.GenerateLocalVariablesSignatureFor(method.Body), - maxStack: method.Body.MaxStack) - : -1; + maxStack: maxStack); + bodyLengthInBytes = instructionEncoder.Offset; + } var methodDefinitionHandle = metadataContainer.metadataBuilder.AddMethodDefinition( attributes: GetMethodAttributesFor(method), @@ -48,7 +54,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) bodyOffset: methodBodyOffset, parameterList: parameters); - methodLocalsGenerator.GenerateLocalVariables(method.Body, methodDefinitionHandle); + methodLocalsGenerator.GenerateLocalVariables(method.Body, methodDefinitionHandle, bodyLengthInBytes); return methodDefinitionHandle; } diff --git a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs b/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs index f5f5366b..8783cf25 100644 --- a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs @@ -23,9 +23,9 @@ internal MethodParametersGenerator(MetadataContainer metadataContainer) foreach (var parameter in methodParameters) { var parameterHandle = metadataContainer.metadataBuilder.AddParameter( - GetParameterAttributesFor(parameter), - metadataContainer.metadataBuilder.GetOrAddString(parameter.Name), - parameter.Index); + attributes: GetParameterAttributesFor(parameter), + name: metadataContainer.metadataBuilder.GetOrAddString(parameter.Name), + sequenceNumber: parameter.Index); if (parameter.HasDefaultValue) { metadataContainer.metadataBuilder.AddConstant(parameterHandle, parameter.DefaultValue.Value); diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 9ad77ed5..b791f9c6 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Reflection; using MetadataGenerator.Generators.Fields; using MetadataGenerator.Generators.Methods; -using Model; using Model.Types; using static System.Linq.Enumerable; +using Assembly = Model.Assembly; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -39,13 +40,12 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) foreach (var assemblyReference in assembly.References) { - // FIXME parameters assemblyReferences.Add(assemblyReference.Name, metadataContainer.metadataBuilder.AddAssemblyReference( name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), version: new Version(4, 0, 0, 0), // FIXME version should be in the assemblyReference? culture: default, publicKeyOrToken: default, - flags: default, + flags: AssemblyFlags.PublicKey, hashValue: default) ); } From 32abbbe08f22607546c2b286de7b907498297f7d Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 12 Jan 2020 11:56:40 -0300 Subject: [PATCH 088/256] Fix field and method reference collisions. Fix static field store --- Examples/Examples.cs | 12 ++++++---- ExamplesEXE/ExamplesEXE.cs | 24 +++++++++---------- ExamplesEXE/ExamplesEXE.csproj | 1 + MetadataGenerator/Extensions.cs | 5 ++-- MetadataGenerator/Generator.cs | 4 ++-- .../Methods/Body/MethodBodyGenerator.cs | 4 ++-- .../Metadata/MetadataResolver.cs | 22 +++++++++++------ 7 files changed, 41 insertions(+), 31 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index ffb97ec9..96f07f61 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -97,6 +97,7 @@ public class SimpleClass public readonly int readOnlyIntField = 212; public string unassignedString; public const string CONST_STRING = "const"; + public static long staticLongField = 2; public SimpleClass(int x, string y) { @@ -569,12 +570,12 @@ public int BitwiseOperations(int x) // FIXME unccoment public abstract void NoBody(); - public void Alloc() + public int Alloc() { unsafe { var x = stackalloc int[3]; - Console.WriteLine(*x); + return *x; } } @@ -592,7 +593,7 @@ public int Calls(SimpleClass simpleClass, Func func) { Console.WriteLine("A method call"); // static simpleClass.DoNothing(); // virtual - Alloc(); // normal + ReturnsOne(); // normal var l = new List {"holas"}; @@ -608,7 +609,6 @@ public int Calls(SimpleClass simpleClass, Func func) //g.PrintGeneric(1); // - Nothing(""); Nothing2(); // FIXME //not working when reading dll @@ -847,6 +847,7 @@ public string LoadField() var a = new SimpleClass(1, "b").unassignedString; // ldfld string $field var b = new SimpleClass(1, "b").readOnlyIntField; // ldfld int $field var c = new ClassWithMoreComplexFieldsAndParametersOrReturnTypes().b; // ldfld class $field + var d = SimpleClass.staticLongField; // ldsfld //FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? // unsafe @@ -854,9 +855,10 @@ public string LoadField() // fixed (int* d = &(new Classes.SimpleClass(1, "b")).readOnlyIntField) // ldflda int32 $field // { } // } + // TODO ldsflda - return c.GetType().ToString() + b; + return c.GetType().ToString() + b + d; } public Exception StoreField() diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 1f6bc3e5..74752e83 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -33,6 +33,9 @@ public static void Main(string[] args) a.ExceptionHandlingTryCatchSpecific(0); a.ExceptionHandlingTryCatch(0); a.ExceptionHandlingTryCatchFilter(0); + a.Calls(new SimpleClass(3, "a"), e => 5); + Console.WriteLine(a.LoadField()); + Console.WriteLine(a.StoreField()); */ /* works but differs form original @@ -40,20 +43,15 @@ public static void Main(string[] args) */ /* does not work - a.Alloc(); - Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); - a.Calls(new SimpleClass(3, "a"), e => 5); - Console.WriteLine(a.Nothing(new object())); - a.LoadAddress(4); - Console.WriteLine(a.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); - Console.WriteLine(a.LoadField()); - Console.WriteLine(a.LoadToken()); - Console.WriteLine(a.StoreField()); + a.Alloc(); Esta no anda por que faltan los load y store indirect + a.LoadAddress(4); no anda por que faltan los load y store indirect + a.LoadIndirect(); no anda por que faltan los load y store indirect + Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); a este le falta el contrained. en Arrays() + Console.WriteLine(a.Nothing(new object())); a no anda porque falt a "constrained." + Console.WriteLine(a.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); no anda porque pongo mal unos class y value type + Console.WriteLine(a.LoadToken()); no anda porque pongo mal unos class y value type + unsafe { Console.WriteLine(a.Create()); } no anda porque pongo mal unos class y value type */ - - // pending to try - // a.Create(); - // a.LoadIndirect(); } } } \ No newline at end of file diff --git a/ExamplesEXE/ExamplesEXE.csproj b/ExamplesEXE/ExamplesEXE.csproj index 5482406b..a07dfa89 100644 --- a/ExamplesEXE/ExamplesEXE.csproj +++ b/ExamplesEXE/ExamplesEXE.csproj @@ -8,6 +8,7 @@ ExamplesEXE ExamplesEXE v4.5 + true true diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index 39f22059..12185ca0 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Model.Types; @@ -15,7 +16,7 @@ public static T FirstOr(this IEnumerable enumerable, T defaultValue) return first.Equals(default(T)) ? defaultValue : first; } - public static bool IsOneOf(this MethodParameterKind kind, params MethodParameterKind[] kinds) => ImmutableList.Create(kinds).Contains(kind); + public static bool IsOneOf(this Enum value, params Enum[] values) => ImmutableList.Create(values).Contains(value); public static bool IsOneOf(this IType type, params IType[] types) => ImmutableList.Create(types).Contains(type); diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 373f7484..a466c833 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -12,8 +12,8 @@ public class Generator : IGenerator { public void Generate(Assembly assembly) { - var fileName = $"./{assembly.Name}.dll"; - // var fileName = $"./{assembly.Name}.exe"; + var fileName = $"./{assembly.Name}.dll"; + // var fileName = $"./{assembly.Name}.exe"; using (var peStream = File.OpenWrite(fileName)) { Console.WriteLine($"Processing: {fileName.Substring(2)}"); diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 664171c9..25242cc8 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -455,11 +455,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) switch (loadFieldInstruction.Operation) { case LoadFieldOperation.Content: - instructionEncoder.OpCode(SRM.ILOpCode.Ldfld); + instructionEncoder.OpCode(loadFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Ldsfld : SRM.ILOpCode.Ldfld); break; case LoadFieldOperation.Address: // TODO test. Example present but not supported in model - instructionEncoder.OpCode(SRM.ILOpCode.Ldflda); + instructionEncoder.OpCode(loadFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Ldsflda : SRM.ILOpCode.Ldflda); break; } diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index b791f9c6..df27e6b6 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -19,7 +19,9 @@ internal class MetadataResolver private readonly MetadataContainer metadataContainer; private readonly IDictionary assemblyReferences = new Dictionary(); private readonly IDictionary typeReferences = new Dictionary(); - private readonly IDictionary memberReferences = new Dictionary(); + + private readonly IDictionary, SRM.MemberReferenceHandle> memberReferences = + new Dictionary, SRM.MemberReferenceHandle>(); private readonly IDictionary typeSpecificationReferences = new Dictionary(); @@ -177,14 +179,17 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl } else { - var key = - $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType}.{method.Name}"; + var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + var key = new KeyValuePair( + $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType}.{method.Name}", + blobHandle + ); if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) { methodReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( parent: GetOrAddTypeReference(method.ContainingType), name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), - signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + signature: blobHandle); memberReferences.Add(key, methodReferenceHandle); } @@ -194,14 +199,17 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field, SRM.BlobBuilder signature) { - var key = - $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.Name}.{field.Name}"; + var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + var key = new KeyValuePair( + $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.Name}.{field.Name}", + blobHandle + ); if (!memberReferences.TryGetValue(key, out var memberReferenceHandle)) { memberReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( parent: GetOrAddTypeReference(field.ContainingType), name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), - signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + signature: blobHandle); memberReferences.Add(key, memberReferenceHandle); return memberReferenceHandle; From 11cd1a5e5cd98cba1ba45ffd6621eed42ed0aac8 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 12 Jan 2020 16:51:46 -0300 Subject: [PATCH 089/256] refactor --- Console/Program.cs | 6 +- Examples/Examples.cs | 2 +- ExamplesEXE/ExamplesEXE.cs | 58 +++++++------- MetadataGenerator/Generator.cs | 7 +- .../Generators/AssemblyGenerator.cs | 1 - .../Methods/Body/MethodLocalsGenerator.cs | 79 ------------------- .../Body/MethodLocalsSignatureGenerator.cs | 37 +++++++++ .../Generators/Methods/MethodGenerator.cs | 13 +-- .../Metadata/MetadataResolver.cs | 3 +- MetadataGenerator/MetadataGenerator.csproj | 2 +- 10 files changed, 83 insertions(+), 125 deletions(-) delete mode 100644 MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs create mode 100644 MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs diff --git a/Console/Program.cs b/Console/Program.cs index ff6ab82d..e6af0020 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -372,6 +372,7 @@ private static void DisassembleAndThenAssemble(string input) PlatformTypes.Resolve(host); + System.Console.WriteLine($"Reading {input}"); var loader = new MetadataProvider.Loader(host); loader.LoadAssembly(input); @@ -385,8 +386,9 @@ private static void DisassembleAndThenAssemble(string input) static void Main(string[] args) { - DisassembleAndThenAssemble(@"../../../Examples/bin/Debug/Examples.dll"); - // DisassembleAndThenAssemble(@"../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"); + var input = @"../../../Examples/bin/Debug/Examples.dll"; + // var input = @"../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"; + DisassembleAndThenAssemble(input); //RunSomeTests(); // RunGenericsTests(); diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 96f07f61..45b23ab0 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -865,7 +865,7 @@ public Exception StoreField() { new SimpleClass(1, "b").unassignedString = ""; // stfld string $field StaticClass.i = 1; // stsfld int $field - StaticClass.e = new Exception(); // stsfld Exception $field + StaticClass.e = new Exception("all good"); // stsfld Exception $field return StaticClass.e; } diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 74752e83..2bda5509 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -1,10 +1,13 @@ -using MethodBody; +using System; +using Classes; +using MethodBody; namespace ExamplesEXE { public static class MainClass { // TODO run peverify /il /md /verbose Console/bin/Debug/ExamplesEXE.exe + // IMPORTANT ExamplesEXE has Examples as reference so it's important to copy de latest Examples.dll to the Console/bin/debug directory public static void Main(string[] args) { // FIXME hay algo con las abstract clases o la herencia. Porque MethodBody.ContainingClass es @@ -12,37 +15,36 @@ public static void Main(string[] args) // FIXME hacerle un new revienta con lo del vtable var a = new ContainingClass(); - /* works [and returns the same as original (in isolation at least)] - Console.WriteLine(a.Arithmetics(1, 2)); - Console.WriteLine(a.Compare(6, 90)); - a.Branch(1, 2, new Exception()); - Console.WriteLine(a.Convert(new Exception())); - a.Empty(); - Console.WriteLine(a.Logic(true, false)); - a.Nothing2(); - Console.WriteLine(a.BitwiseOperations(235)); - a.HelloWorld(); - Console.WriteLine(a.LoadArgument(1, "2", true, 4)); - Console.WriteLine(a.LoadConstant()); - Console.WriteLine(a.LoadLocal()); - a.LoadPointer(); - Console.WriteLine(a.ReturnsArg(10)); - Console.WriteLine(a.ReturnsOne()); - Console.WriteLine(a.SizeOf()); - Console.WriteLine(a.StoreValue(100)); - a.ExceptionHandlingTryCatchSpecific(0); - a.ExceptionHandlingTryCatch(0); - a.ExceptionHandlingTryCatchFilter(0); - a.Calls(new SimpleClass(3, "a"), e => 5); - Console.WriteLine(a.LoadField()); - Console.WriteLine(a.StoreField()); - */ + // works and returns the same as original + Console.WriteLine(a.Arithmetics(1, 2)); + Console.WriteLine(a.Compare(6, 90)); + a.Branch(1, 2, new Exception()); + Console.WriteLine(a.Convert(new Exception())); + a.Empty(); + Console.WriteLine(a.Logic(true, false)); + a.Nothing2(); + Console.WriteLine(a.BitwiseOperations(235)); + a.HelloWorld(); + Console.WriteLine(a.LoadArgument(1, "2", true, 4)); + Console.WriteLine(a.LoadConstant()); + Console.WriteLine(a.LoadLocal()); + a.LoadPointer(); + Console.WriteLine(a.ReturnsArg(10)); + Console.WriteLine(a.ReturnsOne()); + Console.WriteLine(a.SizeOf()); + Console.WriteLine(a.StoreValue(100)); + a.ExceptionHandlingTryCatchSpecific(0); + a.ExceptionHandlingTryCatch(0); + a.ExceptionHandlingTryCatchFilter(0); + Console.WriteLine(a.LoadField()); + Console.WriteLine(a.StoreField()); + a.Calls(new SimpleClass(3, "a"), e => 5); - /* works but differs form original + /* FIXME works but differs form original a.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); */ - /* does not work + /* FIXME does not work a.Alloc(); Esta no anda por que faltan los load y store indirect a.LoadAddress(4); no anda por que faltan los load y store indirect a.LoadIndirect(); no anda por que faltan los load y store indirect diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index a466c833..e28f4167 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -10,13 +10,14 @@ namespace MetadataGenerator { public class Generator : IGenerator { + // TODO assembly should know if it is a dll or exe. With this i can make the generation more dynamic. Submit PR public void Generate(Assembly assembly) { - var fileName = $"./{assembly.Name}.dll"; - // var fileName = $"./{assembly.Name}.exe"; + var fileName = $"./{assembly.Name}(generated).dll"; + // var fileName = $"./{assembly.Name}(generated).exe"; + Console.WriteLine($"Generating Console/bin/debug/{fileName.Substring(2)}"); using (var peStream = File.OpenWrite(fileName)) { - Console.WriteLine($"Processing: {fileName.Substring(2)}"); var metadataContainer = AssemblyGenerator.Generate(assembly); var peHeaderBuilder = new SRPE.PEHeaderBuilder( imageCharacteristics: metadataContainer.Executable diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index 97211f8f..45b903f4 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -35,7 +35,6 @@ public static MetadataContainer Generate(Assembly assembly) encId: default, encBaseId: default); - Console.WriteLine($"Generating: {moduleName}"); /* * Generic parameters table must be sorted by owner (TypeOrMethodDef that owns the generic parameter). Since the dll's methods and types don't follow a * particular order, the info needed to generate this parameters is stored during type/method generation but not added to the MetadataBuilder until now diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs deleted file mode 100644 index 3e2167b3..00000000 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsGenerator.cs +++ /dev/null @@ -1,79 +0,0 @@ -using MetadataGenerator.Metadata; -using Model.Types; -using ECMA335 = System.Reflection.Metadata.Ecma335; -using SRM = System.Reflection.Metadata; - -namespace MetadataGenerator.Generators.Methods.Body -{ - internal class MethodLocalsGenerator - { - private readonly MetadataContainer metadataContainer; - - public MethodLocalsGenerator(MetadataContainer metadataContainer) - { - this.metadataContainer = metadataContainer; - } - - public SRM.StandaloneSignatureHandle GenerateLocalVariablesSignatureFor(MethodBody body) - { - SRM.StandaloneSignatureHandle localVariablesSignature = default; - if (body?.LocalVariables?.Count > 0) - { - var signature = new SRM.BlobBuilder(); - var encoder = new ECMA335.BlobEncoder(signature).LocalVariableSignature(body.LocalVariables.Count); - foreach (var localVariable in body.LocalVariables) - { - // TODO pinned is achieved by the fixed keyword and this is not in the model - metadataContainer.metadataResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); - } - - localVariablesSignature = metadataContainer.metadataResolver.GetOrAddStandaloneSignature(signature); - } - - return localVariablesSignature; - } - - public void GenerateLocalVariables(MethodBody body, SRM.MethodDefinitionHandle containingMethodHandle, int bodyLengthInBytes) - { - /* FIXME GenerateLocalVariablesSignatureFor solo genera la firma (que se usa para hacer el addMethodBody) - y no agrega las variables por lo que no deberia andar. Sin embargo parece que anda solo con eso. - Ver si es necesario este codigo de abajo o no - No aparecen los nombres de las variables locales (similar a lo que pasaba con los parameters cuadno solo ponia la firma) - Asi que tiene pinta a que es necesario hacer esto. Sin embargo al hacerlo no cambia nada. - Quiza estan mal algunos de los valores de addLocalScope y por eso no anda - */ - if (body?.LocalVariables?.Count > 0) - { - SRM.LocalVariableHandle? firstLocalVariableHandle = null; - foreach (var localVariable in body.LocalVariables) - { - var localVariableHandle = metadataContainer.metadataBuilder.AddLocalVariable( - attributes: SRM.LocalVariableAttributes.None, - index: body.LocalVariables.IndexOf(localVariable), - name: metadataContainer.metadataBuilder.GetOrAddString(localVariable.Name)); - if (!firstLocalVariableHandle.HasValue) - { - firstLocalVariableHandle = localVariableHandle; - } - } - - var nextLocalVariableHandle = - ECMA335.MetadataTokens.LocalVariableHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalVariable)); - - var nextLocalConstantHandle = - ECMA335.MetadataTokens.LocalConstantHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.LocalConstant)); - - var nextImportScopeHandle = - ECMA335.MetadataTokens.ImportScopeHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.ImportScope)); - - metadataContainer.metadataBuilder.AddLocalScope( - method: containingMethodHandle, - importScope: nextImportScopeHandle, // addImportScope() ? - variableList: firstLocalVariableHandle ?? nextLocalVariableHandle, - constantList: nextLocalConstantHandle, // addLocalConstant() ? - startOffset: 0, - length: bodyLengthInBytes); - } - } - } -} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs new file mode 100644 index 00000000..eccc6751 --- /dev/null +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using MetadataGenerator.Metadata; +using Model.ThreeAddressCode.Values; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generators.Methods.Body +{ + internal class MethodLocalsSignatureGenerator + { + private readonly MetadataContainer metadataContainer; + + public MethodLocalsSignatureGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public SRM.StandaloneSignatureHandle GenerateSignatureFor(IList localVariables) + { + SRM.StandaloneSignatureHandle localVariablesSignature = default; + if (localVariables.Count > 0) + { + var signature = new SRM.BlobBuilder(); + var encoder = new ECMA335.BlobEncoder(signature).LocalVariableSignature(localVariables.Count); + foreach (var localVariable in localVariables) + { + // TODO pinned is achieved by the fixed keyword and this is not in the model + metadataContainer.metadataResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); + } + + localVariablesSignature = metadataContainer.metadataResolver.GetOrAddStandaloneSignature(signature); + } + + return localVariablesSignature; + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index a86b6329..4fd94fa3 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -13,7 +13,7 @@ internal class MethodGenerator private readonly MetadataContainer metadataContainer; private readonly MethodSignatureGenerator methodSignatureGenerator; private readonly MethodBodyGenerator methodBodyGenerator; - private readonly MethodLocalsGenerator methodLocalsGenerator; + private readonly MethodLocalsSignatureGenerator methodLocalsSignatureGenerator; private readonly MethodParametersGenerator methodParametersGenerator; public MethodGenerator(MetadataContainer metadataContainer) @@ -21,7 +21,7 @@ public MethodGenerator(MetadataContainer metadataContainer) this.metadataContainer = metadataContainer; methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); methodBodyGenerator = new MethodBodyGenerator(metadataContainer); - methodLocalsGenerator = new MethodLocalsGenerator(metadataContainer); + methodLocalsSignatureGenerator = new MethodLocalsSignatureGenerator(metadataContainer); methodParametersGenerator = new MethodParametersGenerator(metadataContainer); } @@ -32,18 +32,15 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var methodSignature = methodSignatureGenerator.GenerateSignatureOf(method); var methodBodyOffset = -1; - var bodyLengthInBytes = 0; if (method.HasBody) { // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated // programatically then the maxStack is gonna be missing var maxStack = method.Body.MaxStack; - var instructionEncoder = methodBodyGenerator.Generate(method.Body); methodBodyOffset = metadataContainer.methodBodyStream.AddMethodBody( - instructionEncoder: instructionEncoder, - localVariablesSignature: methodLocalsGenerator.GenerateLocalVariablesSignatureFor(method.Body), + instructionEncoder: methodBodyGenerator.Generate(method.Body), + localVariablesSignature: methodLocalsSignatureGenerator.GenerateSignatureFor(method.Body.LocalVariables), maxStack: maxStack); - bodyLengthInBytes = instructionEncoder.Offset; } var methodDefinitionHandle = metadataContainer.metadataBuilder.AddMethodDefinition( @@ -54,8 +51,6 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) bodyOffset: methodBodyOffset, parameterList: parameters); - methodLocalsGenerator.GenerateLocalVariables(method.Body, methodDefinitionHandle, bodyLengthInBytes); - return methodDefinitionHandle; } } diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index df27e6b6..758b014b 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -42,9 +42,10 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) foreach (var assemblyReference in assembly.References) { + // TODO version,culture and others should be in the assemblyReference. Submit PR with this assemblyReferences.Add(assemblyReference.Name, metadataContainer.metadataBuilder.AddAssemblyReference( name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), - version: new Version(4, 0, 0, 0), // FIXME version should be in the assemblyReference? + version: new Version(4, 0, 0, 0), culture: default, publicKeyOrToken: default, flags: AssemblyFlags.PublicKey, diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 3170c2a7..32610009 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -40,7 +40,7 @@ - + From 4f6766302604c7ebd1daf3a69fe5a113e6a0ac7e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 12 Jan 2020 18:46:19 -0300 Subject: [PATCH 090/256] add assembly kind --- CCIProvider/AssemblyTraverser.cs | 13 ++++++++++++- MetadataProvider/AssemblyExtractor.cs | 10 +++++++++- Model/Assembly.cs | 10 +++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/CCIProvider/AssemblyTraverser.cs b/CCIProvider/AssemblyTraverser.cs index 65a4af0b..a83f6933 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/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..22502552 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -171,11 +171,19 @@ public FieldDefinition GetDefinedField(SRM.FieldDefinitionHandle handle) return result; } + + private AssemblyKind AssemblyKindFrom(SRPE.PEHeaders headers) + { + if (headers.IsDll) return AssemblyKind.DLL; + if (headers.IsExe || headers.IsConsoleApplication) return AssemblyKind.EXE; + else throw new Exception($"Assembly kind not supported"); + } + public Assembly Extract() { var assemblydef = metadata.GetAssemblyDefinition(); var name = metadata.GetString(assemblydef.Name); - assembly = new Assembly(name); + assembly = new Assembly(name, AssemblyKindFrom(reader.PEHeaders)); foreach (var handle in metadata.AssemblyReferences) { diff --git a/Model/Assembly.cs b/Model/Assembly.cs index 454bae9e..2258cb0c 100644 --- a/Model/Assembly.cs +++ b/Model/Assembly.cs @@ -44,16 +44,24 @@ public override bool Equals(object obj) } } + public enum AssemblyKind + { + EXE, + DLL + } + public class Assembly : IAssemblyReference { public string Name { get; private set; } + public AssemblyKind Kind { get; private set; } public IList References { get; private set; } public Namespace RootNamespace { get; set; } - public Assembly(string name) + public Assembly(string name, AssemblyKind kind) { this.Name = name; this.References = new List(); + this.Kind = kind; } public bool MatchReference(IAssemblyReference reference) From 2522112c9ab9281e04619bd4f81255df9fb39332 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 12 Jan 2020 18:53:39 -0300 Subject: [PATCH 091/256] equals and hashcode --- Model/Assembly.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Model/Assembly.cs b/Model/Assembly.cs index 2258cb0c..5cd23ac2 100644 --- a/Model/Assembly.cs +++ b/Model/Assembly.cs @@ -77,7 +77,7 @@ public override string ToString() public override int GetHashCode() { - return this.Name.GetHashCode(); + return this.Name.GetHashCode() ^ this.Kind.GetHashCode(); } public override bool Equals(object obj) @@ -85,7 +85,8 @@ public override bool Equals(object obj) var other = obj as Assembly; var result = other != null && - this.Name == other.Name; + this.Name == other.Name && + this.Kind == other.Kind; return result; } From 2f034d6428353eecc70630b7808c40c418de142b Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 12 Jan 2020 18:56:36 -0300 Subject: [PATCH 092/256] remove unnecessary $ --- MetadataProvider/AssemblyExtractor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 22502552..b145874d 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -176,7 +176,7 @@ private AssemblyKind AssemblyKindFrom(SRPE.PEHeaders headers) { if (headers.IsDll) return AssemblyKind.DLL; if (headers.IsExe || headers.IsConsoleApplication) return AssemblyKind.EXE; - else throw new Exception($"Assembly kind not supported"); + else throw new Exception("Assembly kind not supported"); } public Assembly Extract() From 87c778c73ff1966717af4f7736b1711b53af4e6c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 12 Jan 2020 19:12:05 -0300 Subject: [PATCH 093/256] use assembly kind --- Console/Program.cs | 3 +-- MetadataGenerator/Generator.cs | 7 +++---- MetadataGenerator/Generators/AssemblyGenerator.cs | 2 +- MetadataGenerator/Metadata/MetadataContainer.cs | 2 -- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index e6af0020..f2c2791b 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -386,8 +386,7 @@ private static void DisassembleAndThenAssemble(string input) static void Main(string[] args) { - var input = @"../../../Examples/bin/Debug/Examples.dll"; - // var input = @"../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"; + var input = args[0].Equals("dll") ? @"../../../Examples/bin/Debug/Examples.dll" : @"../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"; DisassembleAndThenAssemble(input); //RunSomeTests(); diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index e28f4167..d5c01fa0 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -10,17 +10,16 @@ namespace MetadataGenerator { public class Generator : IGenerator { - // TODO assembly should know if it is a dll or exe. With this i can make the generation more dynamic. Submit PR public void Generate(Assembly assembly) { - var fileName = $"./{assembly.Name}(generated).dll"; - // var fileName = $"./{assembly.Name}(generated).exe"; + var extension = assembly.Kind == AssemblyKind.EXE ? "exe" : "dll"; + var fileName = $"./{assembly.Name}(generated).{extension}"; Console.WriteLine($"Generating Console/bin/debug/{fileName.Substring(2)}"); using (var peStream = File.OpenWrite(fileName)) { var metadataContainer = AssemblyGenerator.Generate(assembly); var peHeaderBuilder = new SRPE.PEHeaderBuilder( - imageCharacteristics: metadataContainer.Executable + imageCharacteristics: assembly.Kind == AssemblyKind.EXE ? SRPE.Characteristics.ExecutableImage : SRPE.Characteristics.Dll ); diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index 45b903f4..3061e1a3 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -27,7 +27,7 @@ public static MetadataContainer Generate(Assembly assembly) hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1 ); - var moduleName = $"{assembly.Name}.{(metadataContainer.Executable ? "exe" : "dll")}"; + var moduleName = $"{assembly.Name}.{(assembly.Kind == AssemblyKind.EXE ? "exe" : "dll")}"; metadataBuilder.AddModule( generation: 0, moduleName: metadataBuilder.GetOrAddString(moduleName), diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 3bdc607d..4d4273dd 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -28,8 +28,6 @@ public SRM.MethodDefinitionHandle? MainMethodHandle } } - public bool Executable => mainMethodHandle != null; - public MetadataContainer(Assembly assembly) { metadataBuilder = new ECMA335.MetadataBuilder(); From 083a89463b34e2380ac7d9c3d74c8e09e12967f4 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 12 Jan 2020 22:24:53 -0300 Subject: [PATCH 094/256] generate initObj --- .../Generators/Methods/Body/MethodBodyGenerator.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 25242cc8..e32b1558 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -130,9 +130,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case BasicOperation.InitBlock: instructionEncoder.OpCode(SRM.ILOpCode.Initblk); break; - case BasicOperation.InitObject: - // FIXME InitObject needs an operand (should not be BasicInstruction). There's already a PR that fixes this - break; case BasicOperation.CopyObject: // FIXME CopyObject needs an operand (should not be BasicInstruction) break; @@ -623,6 +620,10 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(storeArrayElementInstruction.Array.ElementsType)); } + break; + case InitObjInstruction initObjInstruction: + instructionEncoder.OpCode(SRM.ILOpCode.Initobj); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(initObjInstruction.Type)); break; default: throw new Exception("instruction type not handled"); From 4a7d9ba2ea2b9a0749ea4e2d735a4faa4fd40e2c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 12 Jan 2020 23:21:30 -0300 Subject: [PATCH 095/256] generate constrained. instruction. Fix IN parameters --- Examples/Examples.cs | 1 - ExamplesEXE/ExamplesEXE.cs | 5 ++--- .../Generators/Methods/Body/MethodBodyGenerator.cs | 4 ++++ MetadataGenerator/Metadata/AttributesProvider.cs | 5 +++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 45b23ab0..79d65154 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -470,7 +470,6 @@ public IList GetExceptionsList(List _) return new List(); } - // TODO this generated a "constrained." instruction. But is not supported in the model (it puts a Nop instruction in its place) public void PrintGeneric(T t) { Console.WriteLine(t.ToString()); diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 2bda5509..6c135ce3 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -39,7 +39,7 @@ public static void Main(string[] args) Console.WriteLine(a.LoadField()); Console.WriteLine(a.StoreField()); a.Calls(new SimpleClass(3, "a"), e => 5); - + Console.WriteLine(a.Nothing(new object())); /* FIXME works but differs form original a.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); */ @@ -48,8 +48,7 @@ public static void Main(string[] args) a.Alloc(); Esta no anda por que faltan los load y store indirect a.LoadAddress(4); no anda por que faltan los load y store indirect a.LoadIndirect(); no anda por que faltan los load y store indirect - Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); a este le falta el contrained. en Arrays() - Console.WriteLine(a.Nothing(new object())); a no anda porque falt a "constrained." + Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); ????? Console.WriteLine(a.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); no anda porque pongo mal unos class y value type Console.WriteLine(a.LoadToken()); no anda porque pongo mal unos class y value type unsafe { Console.WriteLine(a.Create()); } no anda porque pongo mal unos class y value type diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index e32b1558..74394f43 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -625,6 +625,10 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(SRM.ILOpCode.Initobj); instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(initObjInstruction.Type)); break; + case ConstrainedInstruction constrainedInstruction: + instructionEncoder.OpCode(SRM.ILOpCode.Constrained); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(constrainedInstruction.ThisType)); + break; default: throw new Exception("instruction type not handled"); } diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index f783f3e4..3f066315 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -131,8 +131,7 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para switch (parameter.Kind) { case MethodParameterKind.In: - // attributes |= ParameterAttributes.In; - // TODO this seems to be always true... and illspy of original is not. Unncoment when PR is merged + attributes |= ParameterAttributes.In; break; case MethodParameterKind.Out: attributes |= ParameterAttributes.Out; @@ -140,6 +139,8 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para case MethodParameterKind.Ref: // There is no ParameterAttributes.Ref and no Params.Flags related (see ECMA) break; + case MethodParameterKind.Normal: + break; } if (parameter.HasDefaultValue) From 8a09ec80b2ffee46efb4c2832d4a7029d4c61f55 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 13 Jan 2020 22:54:06 -0300 Subject: [PATCH 096/256] revert LoadArrayElementInstruction and StoreArrayElementInstruction PRs --- Backend/Transformations/Disassembler.cs | 44 +++++++++++++++++++++++++ CCIProvider/CodeProvider.cs | 10 ++++-- CCIProvider/OperationHelper.cs | 22 +++++++++++++ MetadataProvider/AssemblyExtractor.cs | 44 ++----------------------- MetadataProvider/OperationHelper.cs | 22 +++++++++++++ Model/Bytecode/Instructions.cs | 5 ++- 6 files changed, 103 insertions(+), 44 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index cc11c7ac..f6ab12c9 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -191,6 +191,19 @@ public override void Visit(Bytecode.BasicInstruction op) ProcessIndirectLoad(op); break; + case Bytecode.BasicOperation.StoreArrayElement: + ProcessStoreArrayElement(op); + break; + + case Bytecode.BasicOperation.LoadArrayElement: + ProcessLoadArrayElement(op); + break; + + case Bytecode.BasicOperation.LoadArrayElementAddress: + ProcessLoadArrayElementAddress(op); + break; + + case Bytecode.BasicOperation.IndirectStore: ProcessIndirectStore(op); break; @@ -358,6 +371,27 @@ private void ProcessIndirectLoad(Bytecode.BasicInstruction op) 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) { @@ -368,6 +402,16 @@ private void ProcessIndirectStore(Bytecode.BasicInstruction op) 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); diff --git a/CCIProvider/CodeProvider.cs b/CCIProvider/CodeProvider.cs index 44d556ce..a095a7e7 100644 --- a/CCIProvider/CodeProvider.cs +++ b/CCIProvider/CodeProvider.cs @@ -169,6 +169,8 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) case Cci.OperationCode.Array_Get: case Cci.OperationCode.Array_Addr: + instruction = ProcessLoadArrayElement(operation); + break; case Cci.OperationCode.Ldelem: case Cci.OperationCode.Ldelem_I: case Cci.OperationCode.Ldelem_I1: @@ -181,8 +183,10 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) case Cci.OperationCode.Ldelem_U2: case Cci.OperationCode.Ldelem_U4: case Cci.OperationCode.Ldelem_Ref: + instruction = ProcessBasic(operation); + break; case Cci.OperationCode.Ldelema: - instruction = ProcessLoadArrayElement(operation); + instruction = ProcessBasic(operation); break; case Cci.OperationCode.Beq: @@ -455,6 +459,8 @@ 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: @@ -464,7 +470,7 @@ private IInstruction ExtractInstruction(Cci.IOperation operation) case Cci.OperationCode.Stelem_R4: case Cci.OperationCode.Stelem_R8: case Cci.OperationCode.Stelem_Ref: - instruction = ProcessStoreArrayElement(operation); + instruction = ProcessBasic(operation); break; case Cci.OperationCode.Stfld: diff --git a/CCIProvider/OperationHelper.cs b/CCIProvider/OperationHelper.cs index a636f089..ac743e35 100644 --- a/CCIProvider/OperationHelper.cs +++ b/CCIProvider/OperationHelper.cs @@ -68,6 +68,19 @@ public static BasicOperation ToBasicOperation(Cci.OperationCode opcode) 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: @@ -77,6 +90,15 @@ public static BasicOperation ToBasicOperation(Cci.OperationCode opcode) 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(); diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 9365ac3f..bff3d300 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -795,43 +795,21 @@ private IInstruction ExtractInstruction(ILInstruction operation) break; case SRM.ILOpCode.Ldelem: - instruction = ProcessLoadArrayElement(operation, new ArrayType(GetOperand(operation)), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_i: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.IntPtr), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_i1: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Int8), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_i2: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Int16), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_i4: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Int32), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_i8: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Int64), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_r4: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Float32), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_r8: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Float64), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_u1: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.UInt8), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_u2: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.UInt16), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_u4: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.UInt32), LoadArrayElementOperation.Content); - break; case SRM.ILOpCode.Ldelem_ref: - instruction = ProcessLoadArrayElement(operation, new ArrayType(PlatformTypes.Object), LoadArrayElementOperation.Content); + instruction = ProcessBasic(operation); break; case SRM.ILOpCode.Ldelema: - instruction = ProcessLoadArrayElement(operation, new ArrayType(GetOperand(operation)), LoadArrayElementOperation.Address); + instruction = ProcessBasic(operation); break; case SRM.ILOpCode.Beq: @@ -1104,31 +1082,15 @@ private IInstruction ExtractInstruction(ILInstruction operation) break; case SRM.ILOpCode.Stelem: - instruction = ProcessStoreArrayElement(operation, new ArrayType(GetOperand(operation))); - break; case SRM.ILOpCode.Stelem_i: - instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.IntPtr)); - break; case SRM.ILOpCode.Stelem_i1: - instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Int8)); - break; case SRM.ILOpCode.Stelem_i2: - instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Int16)); - break; case SRM.ILOpCode.Stelem_i4: - instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Int32)); - break; case SRM.ILOpCode.Stelem_i8: - instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Int64)); - break; case SRM.ILOpCode.Stelem_r4: - instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Float32)); - break; case SRM.ILOpCode.Stelem_r8: - instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Float64)); - break; case SRM.ILOpCode.Stelem_ref: - instruction = ProcessStoreArrayElement(operation, new ArrayType(PlatformTypes.Object)); + instruction = ProcessBasic(operation); break; case SRM.ILOpCode.Stfld: diff --git a/MetadataProvider/OperationHelper.cs b/MetadataProvider/OperationHelper.cs index c27de0d8..f14458a4 100644 --- a/MetadataProvider/OperationHelper.cs +++ b/MetadataProvider/OperationHelper.cs @@ -77,6 +77,28 @@ public static BasicOperation ToBasicOperation(SRM.ILOpCode opcode) case SRM.ILOpCode.Stind_r8: case SRM.ILOpCode.Stind_ref: case SRM.ILOpCode.Stobj: return BasicOperation.IndirectStore; + case SRM.ILOpCode.Ldelem: + case SRM.ILOpCode.Ldelem_i: + case SRM.ILOpCode.Ldelem_i1: + case SRM.ILOpCode.Ldelem_i2: + case SRM.ILOpCode.Ldelem_i4: + case SRM.ILOpCode.Ldelem_i8: + case SRM.ILOpCode.Ldelem_r4: + case SRM.ILOpCode.Ldelem_r8: + case SRM.ILOpCode.Ldelem_u1: + case SRM.ILOpCode.Ldelem_u2: + case SRM.ILOpCode.Ldelem_u4: + case SRM.ILOpCode.Ldelem_ref: return BasicOperation.LoadArrayElement; + case SRM.ILOpCode.Ldelema: return BasicOperation.LoadArrayElementAddress; + case SRM.ILOpCode.Stelem: + case SRM.ILOpCode.Stelem_i: + case SRM.ILOpCode.Stelem_i1: + case SRM.ILOpCode.Stelem_i2: + case SRM.ILOpCode.Stelem_i4: + case SRM.ILOpCode.Stelem_i8: + case SRM.ILOpCode.Stelem_r4: + case SRM.ILOpCode.Stelem_r8: + case SRM.ILOpCode.Stelem_ref: return BasicOperation.StoreArrayElement; case SRM.ILOpCode.Break: return BasicOperation.Breakpoint; default: throw opcode.ToUnknownValueException(); diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index 0590fd0c..3ddaddd9 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -40,7 +40,10 @@ public enum BasicOperation CopyBlock, LoadArrayLength, IndirectLoad, + LoadArrayElement, + LoadArrayElementAddress, IndirectStore, + StoreArrayElement, Breakpoint, Return } @@ -301,7 +304,7 @@ public override string ToString() return this.ToString("new {0}", this.Type); } } - + public class LoadArrayElementInstruction : Instruction { public LoadArrayElementOperation Operation { get; set; } From e3ba1435b065f6d4b2a136ed42c9ed28e280f303 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 2 Feb 2020 23:47:28 -0300 Subject: [PATCH 097/256] generate store/load indirect instructions --- Examples/Examples.cs | 25 ++++++ ExamplesEXE/ExamplesEXE.cs | 10 ++- .../Methods/Body/MethodBodyGenerator.cs | 80 ++++++++++++++++++- 3 files changed, 110 insertions(+), 5 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 79d65154..9554f9e7 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -791,6 +791,31 @@ public string LoadIndirect(ref object g) } } + public unsafe int StoreIndirect( + out sbyte outByte, + out short outShort, + out int outInt, + out long outLong, + out float outFloat, + out double outDouble, + out IntPtr outIntPtr, + out SimpleClass outClass + ) + { + IntPtr h = default; + + outByte = 1; // stind.i1 + outShort = 2; // stind.i2 + outInt = 3; // stind.i4 + outLong = 4; // stind.i8 (stind.u8 is alias for stind.i8) + outFloat = 5; // stind.r4 + outDouble = 6; // stind.r8 + outIntPtr = h; // stind.i + outClass = new SimpleClass(1, ""); // stind.ref + + return (int) (outByte + outDouble + outClass.GetHashCode()); + } + public bool Compare(int b, int x) { var a = b == 2; // ceq diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 6c135ce3..6dd48464 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -14,6 +14,7 @@ public static void Main(string[] args) // FIXME abstracta (porque tiene un metodo sin body) y al hacer una clase que herede esa aca y // FIXME hacerle un new revienta con lo del vtable var a = new ContainingClass(); + object g = new object(); // works and returns the same as original Console.WriteLine(a.Arithmetics(1, 2)); @@ -40,14 +41,17 @@ public static void Main(string[] args) Console.WriteLine(a.StoreField()); a.Calls(new SimpleClass(3, "a"), e => 5); Console.WriteLine(a.Nothing(new object())); + Console.WriteLine(a.Alloc()); + a.LoadAddress(4); + + /* FIXME works but differs form original a.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); */ /* FIXME does not work - a.Alloc(); Esta no anda por que faltan los load y store indirect - a.LoadAddress(4); no anda por que faltan los load y store indirect - a.LoadIndirect(); no anda por que faltan los load y store indirect + Console.WriteLine(a.LoadIndirect(ref g)); + a.StoreIndirect(out sbyte b, out short s, out int i, out long l, out float f, out double d, out IntPtr ip, out SimpleClass sc); Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); ????? Console.WriteLine(a.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); no anda porque pongo mal unos class y value type Console.WriteLine(a.LoadToken()); no anda porque pongo mal unos class y value type diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 90cfdd19..67b7f859 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -623,10 +623,86 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(constrainedInstruction.ThisType)); break; case LoadIndirectInstruction loadIndirectInstruction: - // TODO + if (loadIndirectInstruction.Type.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i1); + } + else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i2); + } + else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i4); + } + else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Int64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i8); + } + else if (loadIndirectInstruction.Type.Equals(PlatformTypes.UInt8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_u1); + } + else if (loadIndirectInstruction.Type.Equals(PlatformTypes.UInt16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_u2); + } + else if (loadIndirectInstruction.Type.Equals(PlatformTypes.UInt32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_u4); + } + else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_r4); + } + else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_r8); + } + else if (loadIndirectInstruction.Type.Equals(PlatformTypes.IntPtr)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i); + } + else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Object)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_ref); + } + break; case StoreIndirectInstruction storeIndirectInstruction: - // TODO + if (storeIndirectInstruction.Type.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_i1); + } + else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_i2); + } + else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_i4); + } + else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Int64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_i8); + } + else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_r4); + } + else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_r8); + } + else if (storeIndirectInstruction.Type.Equals(PlatformTypes.IntPtr)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_i); + } + else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Object)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_ref); + } + break; default: throw new Exception("instruction type not handled"); From fc37c948b155196e7b24f772d4663fa00ef5dc9c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 3 Feb 2020 00:18:21 -0300 Subject: [PATCH 098/256] remove unmarked labels logic --- Examples/Examples.cs | 4 ++- .../Body/MethodBodyControlFlowGenerator.cs | 25 +------------------ .../Methods/Body/MethodBodyGenerator.cs | 5 ---- 3 files changed, 4 insertions(+), 30 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 9554f9e7..c0930cdb 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1010,6 +1010,8 @@ public void ExceptionHandlingTryCatchFilter(int x) } } + /* FIXME finally end label is wrong in the model (one more that it should be, that label does not exist) so this results in an + FIXME unmarked label. Fix in the model. The IL though is generated correctly public void ExceptionHandlingTryCatchFinally(Exception e) { try @@ -1024,6 +1026,6 @@ public void ExceptionHandlingTryCatchFinally(Exception e) { Console.WriteLine("finally"); } - } + }*/ } } \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index f22aeb57..7a237350 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using MetadataGenerator.Metadata; using Model; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -25,11 +24,6 @@ public ECMA335.LabelHandle LabelHandleFor(string label) { labelHandle = instructionEncoder.DefineLabel(); labelHandles.Add(label, labelHandle); - - - // FIXME remove - unmarkedLabels.Add(labelHandle); - // } return labelHandle; @@ -41,10 +35,6 @@ public void MarkCurrentLabel() if (labelHandles.TryGetValue(instructionEncoder.CurrentLabelString(), out var labelHandle)) { instructionEncoder.MarkLabel(labelHandle); - - //FIXME remove - unmarkedLabels.Remove(labelHandle); - // } } @@ -76,18 +66,5 @@ public void ProcessExceptionInformation(IList exceptionInformati } } } - - // FIXME only to develop while all instructions are not generated correctly because if some label results unmarked then - // SRM throws an exception. - private readonly IList unmarkedLabels = new List(); - - [Obsolete("Use only to develop while there are still instructions not being generated correctly")] - public void MarkAllUnmarkedLabels() - { - foreach (var label in unmarkedLabels) - { - instructionEncoder.MarkLabel(label); - } - } } } \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 67b7f859..6a12eba8 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -130,9 +130,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case BasicOperation.InitBlock: instructionEncoder.OpCode(SRM.ILOpCode.Initblk); break; - case BasicOperation.CopyObject: - // FIXME CopyObject needs an operand (should not be BasicInstruction) - break; case BasicOperation.CopyBlock: instructionEncoder.OpCode(SRM.ILOpCode.Cpblk); break; @@ -709,8 +706,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } } - controlFlowGenerator.MarkAllUnmarkedLabels(); // FIXME remove - return instructionEncoder; } } From e7a11039518b4b65e87f1e19638c3d37f0bf7d90 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 8 Feb 2020 18:39:49 -0300 Subject: [PATCH 099/256] fix pointers and reference handle --- Examples/Examples.cs | 44 +++++------- ExamplesEXE/ExamplesEXE.cs | 71 +++++++++---------- .../Methods/MethodSignatureGenerator.cs | 10 ++- .../Metadata/MetadataResolver.cs | 7 ++ 4 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index c0930cdb..4791af81 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reflection; using System.Reflection.Metadata; using Accessibility; using Classes; @@ -414,34 +415,23 @@ public class NestedNestedB } } -// FIXME ref and out are beign generated like type*& instead of type&. That is because the type a & type in the model is represented as a pointer type. namespace PointersAndReferences { public class PointersAndReferenceClass { - private int number = 1; - private Exception exception = new Exception(); - - public void MethodWithRefAndOutParameters(ref string refString, ref Exception refException, out int outInt, out SimpleClass outClass) + public unsafe void* MethodWithRefOutAndPointerParameters( + ref string refString, + out string outString, + ref int refInt, + out int outInt, + ref EmptyStruct refStruct, + out EmptyStruct outStruct, + int* intPointer, + EmptyStruct* structPointer) { + outString = ""; outInt = 2; - outClass = new SimpleClass(1, ""); - } - - // FIXME not in the model - public ref int RefInt() - { - return ref number; - } - - // FIXME not in the model - public ref Exception RefException() - { - return ref exception; - } - - public unsafe void* UnsafeMethod(int* intPointer, EmptyStruct* structPointer, uint* uintPointer) - { + outStruct = new EmptyStruct(); return null; } } @@ -760,7 +750,7 @@ public void LoadPointer() Action y = null; // ldnull } - public string LoadIndirect(ref object g) + public string LoadIndirect(ref int g) { unsafe { @@ -791,7 +781,7 @@ public string LoadIndirect(ref object g) } } - public unsafe int StoreIndirect( + public double StoreIndirect( out sbyte outByte, out short outShort, out int outInt, @@ -813,7 +803,7 @@ out SimpleClass outClass outIntPtr = h; // stind.i outClass = new SimpleClass(1, ""); // stind.ref - return (int) (outByte + outDouble + outClass.GetHashCode()); + return outByte + outDouble + outClass.readOnlyIntField; } public bool Compare(int b, int x) @@ -1010,8 +1000,8 @@ public void ExceptionHandlingTryCatchFilter(int x) } } - /* FIXME finally end label is wrong in the model (one more that it should be, that label does not exist) so this results in an - FIXME unmarked label. Fix in the model. The IL though is generated correctly + /* FIXME finally end label is wrong in the model (one more that it should be, that label does not exist)? this example results in an + FIXME unmarked label. The IL though is generated correctly public void ExceptionHandlingTryCatchFinally(Exception e) { try diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 6dd48464..c1c6a975 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -1,6 +1,4 @@ -using System; -using Classes; -using MethodBody; +using MethodBody; namespace ExamplesEXE { @@ -14,47 +12,46 @@ public static void Main(string[] args) // FIXME abstracta (porque tiene un metodo sin body) y al hacer una clase que herede esa aca y // FIXME hacerle un new revienta con lo del vtable var a = new ContainingClass(); - object g = new object(); - - // works and returns the same as original - Console.WriteLine(a.Arithmetics(1, 2)); - Console.WriteLine(a.Compare(6, 90)); - a.Branch(1, 2, new Exception()); - Console.WriteLine(a.Convert(new Exception())); - a.Empty(); - Console.WriteLine(a.Logic(true, false)); - a.Nothing2(); - Console.WriteLine(a.BitwiseOperations(235)); - a.HelloWorld(); - Console.WriteLine(a.LoadArgument(1, "2", true, 4)); - Console.WriteLine(a.LoadConstant()); - Console.WriteLine(a.LoadLocal()); - a.LoadPointer(); - Console.WriteLine(a.ReturnsArg(10)); - Console.WriteLine(a.ReturnsOne()); - Console.WriteLine(a.SizeOf()); - Console.WriteLine(a.StoreValue(100)); - a.ExceptionHandlingTryCatchSpecific(0); - a.ExceptionHandlingTryCatch(0); - a.ExceptionHandlingTryCatchFilter(0); - Console.WriteLine(a.LoadField()); - Console.WriteLine(a.StoreField()); - a.Calls(new SimpleClass(3, "a"), e => 5); - Console.WriteLine(a.Nothing(new object())); - Console.WriteLine(a.Alloc()); - a.LoadAddress(4); - + var g = 5; + /* works and returns the same as original + Console.WriteLine(a.Arithmetics(1, 2)); + Console.WriteLine(a.Compare(6, 90)); + a.Branch(1, 2, new Exception()); + Console.WriteLine(a.Convert(new Exception())); + a.Empty(); + Console.WriteLine(a.Logic(true, false)); + a.Nothing2(); + Console.WriteLine(a.BitwiseOperations(235)); + a.HelloWorld(); + Console.WriteLine(a.LoadArgument(1, "2", true, 4)); + Console.WriteLine(a.LoadConstant()); + Console.WriteLine(a.LoadLocal()); + a.LoadPointer(); + Console.WriteLine(a.ReturnsArg(10)); + Console.WriteLine(a.ReturnsOne()); + Console.WriteLine(a.SizeOf()); + Console.WriteLine(a.StoreValue(100)); + a.ExceptionHandlingTryCatchSpecific(0); + a.ExceptionHandlingTryCatch(0); + a.ExceptionHandlingTryCatchFilter(0); + Console.WriteLine(a.LoadField()); + Console.WriteLine(a.StoreField()); + a.Calls(new SimpleClass(3, "a"), e => 5); + Console.WriteLine(a.Nothing(new object())); + Console.WriteLine(a.Alloc()); + a.LoadAddress(4); + Console.WriteLine(a.LoadIndirect(ref g)); + Console.WriteLine(a.StoreIndirect(out sbyte b, out short s, out int i, out long l, out float f, out double d, out IntPtr ip, out SimpleClass sc)); + Console.WriteLine(a.LoadToken()); + */ /* FIXME works but differs form original a.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); */ /* FIXME does not work - Console.WriteLine(a.LoadIndirect(ref g)); - a.StoreIndirect(out sbyte b, out short s, out int i, out long l, out float f, out double d, out IntPtr ip, out SimpleClass sc); - Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); ????? + Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); no anda porque pongo mal unos class y value type Console.WriteLine(a.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); no anda porque pongo mal unos class y value type - Console.WriteLine(a.LoadToken()); no anda porque pongo mal unos class y value type unsafe { Console.WriteLine(a.Create()); } no anda porque pongo mal unos class y value type */ } diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 2ad92f05..9d51b2ae 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -66,8 +66,14 @@ private SRM.BlobBuilder GenerateMethodSignature( { foreach (var parameter in parameters) { - var isByRef = parameter.Kind.IsOneOf(MethodParameterKind.Out, MethodParameterKind.Ref); - var type = isByRef ? (parameter.Type as PointerType).TargetType : parameter.Type; + var isByRef = false; + var type = parameter.Type; + if (parameter.Type is ManagedPointerType managedPointerType) + { + isByRef = true; + type = managedPointerType.TargetType; + } + var encoder = parametersEncoder.AddParameter().Type(isByRef); metadataContainer.metadataResolver.Encode(type, encoder); } diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 758b014b..f65e0348 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -237,6 +237,8 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) else if (type.Equals(PlatformTypes.String)) encoder.String(); else if (type.Equals(PlatformTypes.Single)) encoder.Single(); else if (type.Equals(PlatformTypes.Object)) encoder.Object(); + else if (type.Equals(PlatformTypes.IntPtr)) encoder.IntPtr(); + else if (type.Equals(PlatformTypes.UIntPtr)) encoder.UIntPtr(); else { switch (type) @@ -290,6 +292,11 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) break; } + case FunctionPointerType _: + { + encoder.FunctionPointer(); + break; + } case IGenericParameterReference genericParameter: switch (genericParameter.Kind) { From 6a684a8963a0d1f5e3251635da97122300302ee0 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 8 Feb 2020 18:41:20 -0300 Subject: [PATCH 100/256] Differenciate pointers and managed pointers --- MetadataProvider/SignatureTypeProvider.cs | 2 +- Model/Types/Types.cs | 37 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/MetadataProvider/SignatureTypeProvider.cs b/MetadataProvider/SignatureTypeProvider.cs index 9ce7a48e..59699882 100644 --- a/MetadataProvider/SignatureTypeProvider.cs +++ b/MetadataProvider/SignatureTypeProvider.cs @@ -149,7 +149,7 @@ public virtual IType GetPointerType(IType targetType) public virtual IType GetByReferenceType(IType targetType) { - var result = new PointerType(targetType); + var result = new ManagedPointerType(targetType); return result; } diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index 0d6934db..553a249a 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -650,6 +650,43 @@ public override bool Equals(object obj) return result; } } + + public class ManagedPointerType : IReferenceType + { + public ISet Attributes { get; private set; } + public IType TargetType { get; set; } + + public ManagedPointerType(IType targetType) + { + this.TargetType = targetType; + this.Attributes = new HashSet(); + } + + public TypeKind TypeKind + { + get { return TypeKind.ReferenceType; } + } + + public override string ToString() + { + return string.Format("{0}&", this.TargetType); + } + + public override int GetHashCode() + { + return this.TargetType.GetHashCode(); + } + + public override bool Equals(object obj) + { + var other = obj as ManagedPointerType; + + var result = other != null && + this.TargetType.Equals(other.TargetType); + + return result; + } + } public class PointerType : IReferenceType { From 0c5cccd16a1646c33167681508ba1efb70969bce Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 8 Feb 2020 20:40:35 -0300 Subject: [PATCH 101/256] Add some missing attributes for types, fields and methods --- MetadataProvider/AssemblyExtractor.cs | 28 ++++++++++++++++++++++++++- Model/Types/TypeDefinitions.cs | 12 ++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..0a1fb95d 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -246,6 +246,24 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) type.ContainingType = currentType; type.ContainingAssembly = assembly; type.ContainingNamespace = currentNamespace; + if (typedef.Attributes.HasFlag(SR.TypeAttributes.Abstract)) + { + if (typedef.Attributes.HasFlag(SR.TypeAttributes.Sealed)) + { + type.IsStatic = true; + } + else + { + type.IsAbstract = true; + } + } + else if (typedef.Attributes.HasFlag(SR.TypeAttributes.Sealed)) + { + type.IsSealed = true; + } + + type.BeforeFieldInit = typedef.Attributes.HasFlag(SR.TypeAttributes.BeforeFieldInit); + currentType = type; foreach (var handle in typedef.GetGenericParameters()) @@ -471,6 +489,10 @@ private void ExtractField(SRM.FieldDefinitionHandle handle) field.IsStatic = fielddef.Attributes.HasFlag(SR.FieldAttributes.Static); field.Visibility = GetVisibilityKind(fielddef.Attributes); field.Value = ExtractFieldDefaultValue(fielddef); + field.IsReadonly = fielddef.Attributes.HasFlag(SR.FieldAttributes.InitOnly); + field.IsLiteral = fielddef.Attributes.HasFlag(SR.FieldAttributes.Literal); + field.SpecialName = fielddef.Attributes.HasFlag(SR.FieldAttributes.SpecialName); + field.RuntimeSpecialName = fielddef.Attributes.HasFlag(SR.FieldAttributes.RTSpecialName); currentType.Fields.Add(field); } @@ -508,7 +530,11 @@ private void ExtractMethod(SRM.MethodDefinitionHandle methoddefHandle) method.IsVirtual = methoddef.Attributes.HasFlag(SR.MethodAttributes.Virtual); method.IsExternal = methoddef.Attributes.HasFlag(SR.MethodAttributes.PinvokeImpl); method.IsConstructor = method.Name.EndsWith(".ctor"); - + method.HidesMember = methoddef.Attributes.HasFlag(SR.MethodAttributes.NewSlot); + method.IsSealed = methoddef.Attributes.HasFlag(SR.MethodAttributes.Final); + method.SpecialName = methoddef.Attributes.HasFlag(SR.MethodAttributes.SpecialName); + method.RuntimeSpecialName = methoddef.Attributes.HasFlag(SR.MethodAttributes.RTSpecialName); + currentType.Methods.Add(method); currentMethod = method; diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 27062ea7..f968f129 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -112,6 +112,10 @@ public class FieldDefinition : ITypeMemberDefinition, IFieldReference public Constant Value { get; set; } public bool IsStatic { get; set; } + public bool IsReadonly { get; set; } + public bool IsLiteral { get; set; } + public bool SpecialName { get; set; } + public bool RuntimeSpecialName { get; set; } public FieldDefinition(string name, IType type) { @@ -412,6 +416,10 @@ public class MethodDefinition : ITypeMemberDefinition, IMethodReference, IGeneri public bool IsVirtual { get; set; } public bool IsConstructor { get; set; } public bool IsExternal { get; set; } + public bool HidesMember { get; set; } + public bool IsSealed { get; set; } + public bool SpecialName { get; set; } + public bool RuntimeSpecialName { get; set; } public MethodBody Body { get; set; } public MethodDefinition(string name, IType returnType) @@ -623,6 +631,10 @@ public class TypeDefinition : IBasicType, IGenericDefinition, ITypeMemberDefinit public IList Methods { get; private set; } public IList Types { get; private set; } public IBasicType UnderlayingType { get; set; } + public bool IsStatic { get; set; } + public bool IsAbstract { get; set; } + public bool IsSealed { get; set; } + public bool BeforeFieldInit { get; set; } public TypeDefinition(string name, TypeKind typeKind = TypeKind.Unknown, TypeDefinitionKind kind = TypeDefinitionKind.Unknown) { From 1e050e5decc573a5e9f1f9cebf0f4874d9767934 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 8 Feb 2020 20:54:26 -0300 Subject: [PATCH 102/256] Correct attributes for types, fields and methods --- Examples/Examples.cs | 6 +++- .../Metadata/AttributesProvider.cs | 34 ++++++++----------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 4791af81..84808e05 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -88,6 +88,10 @@ public static void DoNothing(int x) } } + public sealed class SealedClass + { + } + public static class EmptyStaticClass { } @@ -337,7 +341,7 @@ protected void NotVisibileToDerivedClass() public class DerivedClass : BaseClass { - public override void CanImplement() + public sealed override void CanImplement() { } } diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index 3f066315..8c7cec3c 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -33,7 +33,7 @@ private static TypeAttributes StructTypeAttributes(TypeDefinition typeDefinition VisibilityAttributesFor(typeDefinition) | TypeAttributes.SequentialLayout | TypeAttributes.Sealed | - TypeAttributes.BeforeFieldInit; //FIXME: when? + (typeDefinition.BeforeFieldInit ? TypeAttributes.BeforeFieldInit : 0); } private static TypeAttributes EnumTypeAttributes(TypeDefinition typeDefinition) @@ -46,7 +46,10 @@ private static TypeAttributes EnumTypeAttributes(TypeDefinition typeDefinition) private static TypeAttributes ClassTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Class | - TypeAttributes.BeforeFieldInit | //FIXME: when? + (typeDefinition.BeforeFieldInit ? TypeAttributes.BeforeFieldInit : 0) | + (typeDefinition.IsAbstract ? TypeAttributes.Abstract : 0) | + (typeDefinition.IsSealed ? TypeAttributes.Sealed : 0) | + (typeDefinition.IsStatic ? TypeAttributes.Abstract | TypeAttributes.Sealed : 0) | VisibilityAttributesFor(typeDefinition); } @@ -59,13 +62,10 @@ public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) { var fieldAttributes = (field.IsStatic ? FieldAttributes.Static : 0) | - (field.ContainingType.Kind is TypeDefinitionKind.Enum && field.Type.Equals(field.ContainingType) - ? FieldAttributes.Literal - : 0) | - (field.ContainingType.Kind is TypeDefinitionKind.Enum && - field.Name.Equals("value__", StringComparison.InvariantCultureIgnoreCase) - ? FieldAttributes.RTSpecialName | FieldAttributes.SpecialName - : 0); + (field.IsLiteral ? FieldAttributes.Literal : 0) | + (field.IsReadonly ? FieldAttributes.InitOnly : 0) | + (field.SpecialName ? FieldAttributes.SpecialName : 0) | + (field.RuntimeSpecialName ? FieldAttributes.RTSpecialName : 0); switch (field.Visibility) { case VisibilityKind.Public: @@ -89,21 +89,15 @@ public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) { - var constructor = method.IsConstructor || method.Name.Equals(".cctor"); - var specialName = - method.Name.StartsWith("get_", StringComparison.Ordinal) || - method.Name.StartsWith("set_", StringComparison.Ordinal) || - method.Name.StartsWith("op_", StringComparison.Ordinal); var methodAttributes = - MethodAttributes.HideBySig | // FIXME when? + MethodAttributes.HideBySig | (method.IsAbstract ? MethodAttributes.Abstract : 0) | (method.IsStatic ? MethodAttributes.Static : 0) | (method.IsVirtual ? MethodAttributes.Virtual : 0) | - (method.ContainingType.Kind is TypeDefinitionKind.Interface - ? MethodAttributes.NewSlot - : 0) | // TODO not correct. Depends on the new keyword but model is missing it - (constructor ? MethodAttributes.SpecialName | MethodAttributes.RTSpecialName : 0) | - (specialName ? MethodAttributes.SpecialName : 0); + (method.HidesMember ? MethodAttributes.NewSlot : 0) | + (method.IsSealed ? MethodAttributes.Final : 0) | + (method.SpecialName ? MethodAttributes.SpecialName : 0) | + (method.RuntimeSpecialName ? MethodAttributes.RTSpecialName : 0); switch (method.Visibility) { case VisibilityKind.Public: From 7e280ff7980568eafa12383a5194ccf10ceb1695 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 8 Feb 2020 21:08:39 -0300 Subject: [PATCH 103/256] examples --- Examples/Examples.cs | 4 ++-- ExamplesEXE/ExamplesEXE.cs | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 84808e05..363aa136 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -512,7 +512,7 @@ public class NestedGenericClass namespace MethodBody { - public /*FIXME unccoment abstract*/ class ContainingClass + public abstract class ContainingClass { public void HelloWorld() { @@ -561,7 +561,7 @@ public int BitwiseOperations(int x) return z; } - // FIXME unccoment public abstract void NoBody(); + public abstract void NoBody(); public int Alloc() { diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index c1c6a975..6f284bed 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -4,14 +4,12 @@ namespace ExamplesEXE { public static class MainClass { - // TODO run peverify /il /md /verbose Console/bin/Debug/ExamplesEXE.exe + // TODO pedump --verify all Console/bin/Debug/ExamplesEXE\(generated\).exe + // TODO pedump --verify all Console/bin/Debug/Examples\(generated\).dll // IMPORTANT ExamplesEXE has Examples as reference so it's important to copy de latest Examples.dll to the Console/bin/debug directory public static void Main(string[] args) { - // FIXME hay algo con las abstract clases o la herencia. Porque MethodBody.ContainingClass es - // FIXME abstracta (porque tiene un metodo sin body) y al hacer una clase que herede esa aca y - // FIXME hacerle un new revienta con lo del vtable - var a = new ContainingClass(); + var a = new ConcreteContainingClass(); var g = 5; /* works and returns the same as original Console.WriteLine(a.Arithmetics(1, 2)); @@ -50,10 +48,17 @@ public static void Main(string[] args) */ /* FIXME does not work - Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); no anda porque pongo mal unos class y value type - Console.WriteLine(a.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); no anda porque pongo mal unos class y value type - unsafe { Console.WriteLine(a.Create()); } no anda porque pongo mal unos class y value type + Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); + Console.WriteLine(a.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); + unsafe { Console.WriteLine(a.Create()); } */ } } + + public class ConcreteContainingClass : ContainingClass + { + public override void NoBody() + { + } + } } \ No newline at end of file From 9a1d4686246ee60a3a4a0bbe0bf5363b88615b5a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 9 Feb 2020 17:40:20 -0300 Subject: [PATCH 104/256] fix array encoding --- Examples/Examples.cs | 28 +++--- ExamplesEXE/ExamplesEXE.cs | 92 ++++++++++--------- .../Methods/MethodSignatureGenerator.cs | 1 + .../Metadata/MetadataResolver.cs | 37 +++++--- 4 files changed, 92 insertions(+), 66 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 363aa136..cac944bc 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Reflection; +using System.Globalization; using System.Reflection.Metadata; using Accessibility; using Classes; @@ -122,7 +122,12 @@ protected string ReturnStringArg(string arg) return arg; } - internal double ReturnADobule(double arg) + public int[] ReceivesArraysAndReturnsIntArray(string[] s, Exception[] e) + { + return new[] {1}; + } + + internal double ReturnADouble(double arg) { return arg; } @@ -450,7 +455,7 @@ public class Generic where D : Exception // FIXME generic constraint not i public IList> listOfListField; - // FIXME the assigment is done in the .ctor with a stfld instruction but i'm generating a stsfld instruction. That's because somehow the field that i recieve is static + // FIXME the assigment is done in the .ctor with a stfld instruction but i'm generating a stsfld instruction. That's because somehow the field that i Receives is static // FIXME when in reality it is not. Maybe a fault in the model? public readonly List stringList = new List {"holas"}; @@ -473,12 +478,12 @@ public void MethodWithGenericConstraint(T t) where T : Enum // FIXME generic { } - public E RecievesAndReturnsGenericType(T t, E e) + public E ReceivesAndReturnsGenericType(T t, E e) { return e; } - public IList RecievesAndReturnsGenericTypeList(IList listT) + public IList ReceivesAndReturnsGenericTypeList(IList listT) { return listT; } @@ -512,7 +517,7 @@ public class NestedGenericClass namespace MethodBody { - public abstract class ContainingClass + public abstract class ContainingClass { public void HelloWorld() { @@ -643,7 +648,7 @@ public double Arrays(EmptyStruct[] structArray) doubleArray[1] = d; // stelem.r8 structArray[0] = p; // stelem - return y + d + byteArray.Length + structArray[0].GetHashCode() + structArray.Rank; + return y + d + byteArray.Length + structArray[0].ToString().Length + structArray.Rank; } public void Empty() @@ -678,7 +683,7 @@ public int Convert(object o) // TODO unbox (unbox ptr) - return i + x6 + s.Length + l.GetHashCode() + o.ToString().Length; + return i + x6 + s.Length + l.ToString().Length + o.ToString().Length; } public double LoadConstant() @@ -819,15 +824,14 @@ public bool Compare(int b, int x) return a; } - public unsafe int**[] Create() + public unsafe int*[] Create() { new SimpleClass(1, "a"); // newobj $methodCall var a = new int[] {1, 2, 3}; // newarr int var b = new Exception[] { }; // newarr Clases.SimpleClass var c = new int*[] { }; // newarr int* - var d = new int**[] { }; // newarr int** - return d; + return c; } public int LoadArray(Exception[] x, int[] q) @@ -857,7 +861,7 @@ public int LoadArray(Exception[] x, int[] q) var m = (new int[] {1, 2, 3}).Length; // ldlen - return m + k.GetHashCode() + c + a.Message.Length + q.Length; + return m + k.ToString(CultureInfo.InvariantCulture).Length + c + a.Message.Length + q.Length; } public string LoadField() diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 6f284bed..04d7834e 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -1,4 +1,7 @@ -using MethodBody; +using System; +using Classes; +using MethodBody; +using Structs; namespace ExamplesEXE { @@ -9,53 +12,58 @@ public static class MainClass // IMPORTANT ExamplesEXE has Examples as reference so it's important to copy de latest Examples.dll to the Console/bin/debug directory public static void Main(string[] args) { - var a = new ConcreteContainingClass(); - var g = 5; - /* works and returns the same as original - Console.WriteLine(a.Arithmetics(1, 2)); - Console.WriteLine(a.Compare(6, 90)); - a.Branch(1, 2, new Exception()); - Console.WriteLine(a.Convert(new Exception())); - a.Empty(); - Console.WriteLine(a.Logic(true, false)); - a.Nothing2(); - Console.WriteLine(a.BitwiseOperations(235)); - a.HelloWorld(); - Console.WriteLine(a.LoadArgument(1, "2", true, 4)); - Console.WriteLine(a.LoadConstant()); - Console.WriteLine(a.LoadLocal()); - a.LoadPointer(); - Console.WriteLine(a.ReturnsArg(10)); - Console.WriteLine(a.ReturnsOne()); - Console.WriteLine(a.SizeOf()); - Console.WriteLine(a.StoreValue(100)); - a.ExceptionHandlingTryCatchSpecific(0); - a.ExceptionHandlingTryCatch(0); - a.ExceptionHandlingTryCatchFilter(0); - Console.WriteLine(a.LoadField()); - Console.WriteLine(a.StoreField()); - a.Calls(new SimpleClass(3, "a"), e => 5); - Console.WriteLine(a.Nothing(new object())); - Console.WriteLine(a.Alloc()); - a.LoadAddress(4); - Console.WriteLine(a.LoadIndirect(ref g)); - Console.WriteLine(a.StoreIndirect(out sbyte b, out short s, out int i, out long l, out float f, out double d, out IntPtr ip, out SimpleClass sc)); - Console.WriteLine(a.LoadToken()); - */ + var methodBodyExamples = new MethodBodyExamples(); + var g = 5;qq + var sc = new SimpleClass(3, "a"); - /* FIXME works but differs form original - a.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); - */ + // FIXME some fail due to the ValueType/ReferenceType problem. + Console.WriteLine(methodBodyExamples.Arithmetics(1, 2)); + Console.WriteLine(methodBodyExamples.Compare(6, 90)); + methodBodyExamples.Branch(1, 2, new Exception()); + Console.WriteLine(methodBodyExamples.Convert(new Exception())); + methodBodyExamples.Empty(); + Console.WriteLine(methodBodyExamples.Logic(true, false)); + methodBodyExamples.Nothing2(); + Console.WriteLine(methodBodyExamples.BitwiseOperations(235)); + methodBodyExamples.HelloWorld(); + Console.WriteLine(methodBodyExamples.LoadArgument(1, "2", true, 4)); + Console.WriteLine(methodBodyExamples.LoadConstant()); + Console.WriteLine(methodBodyExamples.LoadLocal()); + methodBodyExamples.LoadPointer(); + Console.WriteLine(methodBodyExamples.ReturnsArg(10)); + Console.WriteLine(methodBodyExamples.ReturnsOne()); + Console.WriteLine(methodBodyExamples.SizeOf()); + Console.WriteLine(methodBodyExamples.StoreValue(100)); + methodBodyExamples.ExceptionHandlingTryCatchSpecific(0); + methodBodyExamples.ExceptionHandlingTryCatch(0); + methodBodyExamples.ExceptionHandlingTryCatchFilter(0); + Console.WriteLine(methodBodyExamples.LoadField()); + Console.WriteLine(methodBodyExamples.StoreField()); + methodBodyExamples.Calls(sc, e => 5); + Console.WriteLine(methodBodyExamples.Nothing(new object())); + Console.WriteLine(methodBodyExamples.Alloc()); + methodBodyExamples.LoadAddress(4); + Console.WriteLine(methodBodyExamples.LoadIndirect(ref g)); + Console.WriteLine(methodBodyExamples.StoreIndirect(out sbyte b, out short q, out int i, out long l, out float f, out double d, + out IntPtr ip, + out SimpleClass s)); + Console.WriteLine(methodBodyExamples.LoadToken()); + Console.WriteLine(sc.ReceivesArraysAndReturnsIntArray(new[] {""}, new[] {new Exception()})); + unsafe + { + Console.WriteLine(methodBodyExamples.Create()); + } + + Console.WriteLine(methodBodyExamples.Arrays(new[] {new EmptyStruct()})); + Console.WriteLine(methodBodyExamples.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); - /* FIXME does not work - Console.WriteLine(a.Arrays(new[] {new EmptyStruct()})); - Console.WriteLine(a.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); - unsafe { Console.WriteLine(a.Create()); } + /* FIXME Try when that example is fixed + methodBodyExamples.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); */ } } - public class ConcreteContainingClass : ContainingClass + public class MethodBodyExamples : ContainingClass { public override void NoBody() { diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 9d51b2ae..8433400a 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Collections.Immutable; using MetadataGenerator.Metadata; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index f65e0348..a9ef7e1a 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -265,19 +265,30 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) break; } case ArrayType arrayType: - encoder.Array( - elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), - arrayShapeEncoder => - { - var lowerBounds = arrayType.Rank > 1 - ? Repeat(0, (int) arrayType.Rank).ToImmutableArray() // 0 because ArrayType does not know bounds - : ImmutableArray.Empty; - arrayShapeEncoder.Shape( - rank: (int) arrayType.Rank, - sizes: ImmutableArray.Empty, - lowerBounds: lowerBounds); - }); + { + if (arrayType.IsVector) + { + Encode(arrayType.ElementsType, encoder.SZArray()); + } + else + { + encoder.Array( + elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), + arrayShapeEncoder => + { + /** + * This assumes that all dimensions have 0 as lower bound and none declare sizes. + * Lower bounds and sizes are not modelled. + */ + var lowerBounds = Repeat(0, (int) arrayType.Rank).ToImmutableArray(); + var sizes = ImmutableArray.Empty; + arrayShapeEncoder.Shape((int) arrayType.Rank, sizes, lowerBounds); + }); + } + + break; + } case PointerType pointerType: { var targetType = pointerType.TargetType; @@ -298,6 +309,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) break; } case IGenericParameterReference genericParameter: + { switch (genericParameter.Kind) { case GenericParameterKind.Type: @@ -309,6 +321,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) } break; + } default: throw new Exception($"Type {type} not supported"); } From 0a08ade45dc2eb373c81dd1507af88601fa71cd6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 9 Feb 2020 17:41:32 -0300 Subject: [PATCH 105/256] fix --- ExamplesEXE/ExamplesEXE.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 04d7834e..c7fa9759 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -13,7 +13,7 @@ public static class MainClass public static void Main(string[] args) { var methodBodyExamples = new MethodBodyExamples(); - var g = 5;qq + var g = 5; var sc = new SimpleClass(3, "a"); // FIXME some fail due to the ValueType/ReferenceType problem. From ff9d77a89768e2783c04028aa7d704777411aac7 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 13 Feb 2020 21:46:20 -0300 Subject: [PATCH 106/256] comments --- Examples/Examples.cs | 7 +------ ExamplesEXE/ExamplesEXE.cs | 12 ++++++------ MetadataGenerator/Generators/AssemblyGenerator.cs | 10 +++++----- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index cac944bc..7c921cc7 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -302,8 +302,6 @@ public int CompareTo(object obj) } } -// FIXME is generating [Examples.dll]Delegates.ClassThatUsesDelegate/Del ReturnsADelegate instead of Delegates.ClassThatUsesDelegate/Del ReturnsADelegate -// (same assembly) namespace Delegates { public class SampleClass @@ -912,8 +910,7 @@ public int SizeOf() { unsafe { - // FIXME unccomment when on of the instructiosn PRs is merged (needs the TypeDefinitionHandle case that is missing) - // var x = sizeof(Structs.NonEmptyStruct); // sizeof $type + var x = sizeof(NonEmptyStruct); // sizeof $type var z = sizeof(NonEmptyStruct***); // sizeof $type*** var y = sizeof(int*); // sizeof int* @@ -921,8 +918,6 @@ public int SizeOf() } } - // TODO other cases - // FIXME generation almost correct public Type LoadToken() { var x = typeof(T); diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index c7fa9759..b474f48b 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -1,7 +1,5 @@ -using System; -using Classes; +using Classes; using MethodBody; -using Structs; namespace ExamplesEXE { @@ -15,7 +13,7 @@ public static void Main(string[] args) var methodBodyExamples = new MethodBodyExamples(); var g = 5; var sc = new SimpleClass(3, "a"); - + /* // FIXME some fail due to the ValueType/ReferenceType problem. Console.WriteLine(methodBodyExamples.Arithmetics(1, 2)); Console.WriteLine(methodBodyExamples.Compare(6, 90)); @@ -54,8 +52,10 @@ public static void Main(string[] args) Console.WriteLine(methodBodyExamples.Create()); } - Console.WriteLine(methodBodyExamples.Arrays(new[] {new EmptyStruct()})); - Console.WriteLine(methodBodyExamples.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); + Console.WriteLine(methodBodyExamples.Arrays(new[] {new EmptyStruct()})); + Console.WriteLine(methodBodyExamples.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); + methodBodyExamples.Calls(sc, e => 5); + */ /* FIXME Try when that example is fixed methodBodyExamples.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index 3061e1a3..90cf756f 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -13,11 +13,6 @@ public static MetadataContainer Generate(Assembly assembly) var namespaceGenerator = new NamespaceGenerator(metadataContainer); var metadataBuilder = metadataContainer.metadataBuilder; - foreach (var namezpace in assembly.RootNamespace.Namespaces) - { - namespaceGenerator.Generate(namezpace); - } - metadataBuilder.AddAssembly( name: metadataBuilder.GetOrAddString(assembly.Name), version: new Version(0, 0, 0, 1), @@ -35,6 +30,11 @@ public static MetadataContainer Generate(Assembly assembly) encId: default, encBaseId: default); + foreach (var namezpace in assembly.RootNamespace.Namespaces) + { + namespaceGenerator.Generate(namezpace); + } + /* * Generic parameters table must be sorted by owner (TypeOrMethodDef that owns the generic parameter). Since the dll's methods and types don't follow a * particular order, the info needed to generate this parameters is stored during type/method generation but not added to the MetadataBuilder until now From d7f975e49433ba656107aa33c04e2183f84c9542 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 18 Feb 2020 22:42:44 -0300 Subject: [PATCH 107/256] comments --- .../Generators/Methods/Body/MethodBodyGenerator.cs | 1 - MetadataGenerator/Generators/TypeGenerator.cs | 2 +- MetadataGenerator/Metadata/AttributesProvider.cs | 1 - MetadataGenerator/Metadata/MetadataResolver.cs | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 6a12eba8..2ffe49c6 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -445,7 +445,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(loadFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Ldsfld : SRM.ILOpCode.Ldfld); break; case LoadFieldOperation.Address: - // TODO test. Example present but not supported in model instructionEncoder.OpCode(loadFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Ldsflda : SRM.ILOpCode.Ldflda); break; } diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index 94b5fd50..295c63fd 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -38,7 +38,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) .PropertySignature(isInstanceProperty: true?) .Parameters( 0, - returnType => returnType.Type().Int32() (algun type), + returnType => returnType.Type().Int32() (some type), parameters => { }); var propertyDefinitionHandle = metadata.AddProperty( diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index 8c7cec3c..35b5a787 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -145,7 +145,6 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para return attributes; } - // TODO other visibilities? private static TypeAttributes VisibilityAttributesFor(TypeDefinition typeDefinition) { if (typeDefinition.ContainingType != null) diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index a9ef7e1a..7572e11a 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -12,7 +12,6 @@ namespace MetadataGenerator.Metadata { - // FIXME is there a way to unify all this dictionaries and logic of GetOrAdd? internal class MetadataResolver { private readonly Assembly assembly; From d49b678b262f38b3be22528e3c833532c05853e1 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Feb 2020 13:43:02 -0300 Subject: [PATCH 108/256] resolve type kind --- MetadataProvider/SignatureTypeProvider.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/MetadataProvider/SignatureTypeProvider.cs b/MetadataProvider/SignatureTypeProvider.cs index 9ce7a48e..e35663c0 100644 --- a/MetadataProvider/SignatureTypeProvider.cs +++ b/MetadataProvider/SignatureTypeProvider.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Reflection.Metadata.Ecma335; using System.Text; using SRM = System.Reflection.Metadata; @@ -50,6 +51,7 @@ public virtual IType GetPrimitiveType(SRM.PrimitiveTypeCode typeCode) public virtual IType GetTypeFromDefinition(SRM.MetadataReader reader, SRM.TypeDefinitionHandle handle, byte rawTypeKind = 0) { var result = extractor.GetDefinedType(handle); + result.TypeKind = ResolveTypeKind(reader, handle, rawTypeKind); return result; } @@ -63,7 +65,8 @@ public virtual IType GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeRef var type = new BasicType(name) { ContainingNamespace = namespaze, - GenericParameterCount = genericParameterCount + GenericParameterCount = genericParameterCount, + TypeKind = ResolveTypeKind(reader, handle, rawTypeKind) }; type.Resolve(extractor.Host); @@ -232,5 +235,20 @@ public virtual IType GetFunctionPointerType(SRM.MethodSignature signature return result; } + + private TypeKind ResolveTypeKind(SRM.MetadataReader reader, SRM.EntityHandle typeHandle, byte rawTypeKind) + { + var typeKind = reader.ResolveSignatureTypeKind(typeHandle, rawTypeKind); + switch (typeKind) + { + case SRM.SignatureTypeKind.Class: + return TypeKind.ReferenceType; + case SRM.SignatureTypeKind.ValueType: + return TypeKind.ValueType; + default: + return TypeKind.Unknown; + } + + } } } \ No newline at end of file From cd63e6b092c7ef3486b6d9d12658db8bd7684257 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Feb 2020 13:48:24 -0300 Subject: [PATCH 109/256] examples working --- ExamplesEXE/ExamplesEXE.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index b474f48b..9892dc6b 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -1,5 +1,7 @@ -using Classes; +using System; +using Classes; using MethodBody; +using Structs; namespace ExamplesEXE { @@ -13,8 +15,7 @@ public static void Main(string[] args) var methodBodyExamples = new MethodBodyExamples(); var g = 5; var sc = new SimpleClass(3, "a"); - /* - // FIXME some fail due to the ValueType/ReferenceType problem. + Console.WriteLine(methodBodyExamples.Arithmetics(1, 2)); Console.WriteLine(methodBodyExamples.Compare(6, 90)); methodBodyExamples.Branch(1, 2, new Exception()); @@ -52,10 +53,9 @@ public static void Main(string[] args) Console.WriteLine(methodBodyExamples.Create()); } - Console.WriteLine(methodBodyExamples.Arrays(new[] {new EmptyStruct()})); - Console.WriteLine(methodBodyExamples.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); - methodBodyExamples.Calls(sc, e => 5); - */ + Console.WriteLine(methodBodyExamples.Arrays(new[] {new EmptyStruct()})); + Console.WriteLine(methodBodyExamples.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); + methodBodyExamples.Calls(sc, e => 5); /* FIXME Try when that example is fixed methodBodyExamples.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); From 4bce69cca4b2d6d97759d1162e6f894d6fb87509 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Feb 2020 14:43:02 -0300 Subject: [PATCH 110/256] more properties examples --- Examples/Examples.cs | 44 ++++++++++++++++++++++++-------------- ExamplesEXE/ExamplesEXE.cs | 23 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 7c921cc7..e6749037 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -35,34 +35,46 @@ public enum EnumOfUShorts : ushort } } -// TODO not yet supported in the framework model -// TODO interface with properties -// TODO struct with properties -namespace PropertiesGettersAndSetters +namespace Properties { public class ClassWithProperties { - public double AutoImplementedProperty { get; set; } - public char AnotherAutoImplementedProperty { get; } + public double DoublePropertyWithAutoImplementedGetSet { get; set; } + public byte BytePropertyWithAutoImplementedGetAndDefaultValue { get; } = 1; + public Exception ExceptionPropertyWithAutoImplementedGetSetAndDefaultValue { get; set; } = new Exception("all good"); + public DerivedClass DerivedClassPropertyWithAutoImplementedGetSet { get; set; } - public int PropertyWithBackingField + public int IntPropertyWithBackingField { - get => backingField; - set => backingField = value; + get => intBackingField + 1; + set => intBackingField = value - 1; } - private int backingField; + private int intBackingField; - public string AnotherPropertyWithBackingField - { - get => otherBackingField; - } + public string StringPropertyWithBackingField => " " + stringBackingField + " "; - private string otherBackingField; + private readonly string stringBackingField = "some.value"; + } + + public struct StructWithProperties : IInterfaceWithProperties + { + public double DoublePropertyWithAutoImplementedGetSet { get; set; } + public DerivedClass DerivedClassPropertyWithAutoImplementedGetSet { get; set; } - public void get_ShouldNotHaveSpecialname() + public int IntPropertyWithBackingField { + get => intBackingField + 1; + set => intBackingField = value - 1; } + + private int intBackingField; + } + + public interface IInterfaceWithProperties + { + double DoublePropertyWithAutoImplementedGetSet { get; set; } + DerivedClass DerivedClassPropertyWithAutoImplementedGetSet { get; set; } } } diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 9892dc6b..8206bf30 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -56,6 +56,29 @@ public static void Main(string[] args) Console.WriteLine(methodBodyExamples.Arrays(new[] {new EmptyStruct()})); Console.WriteLine(methodBodyExamples.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); methodBodyExamples.Calls(sc, e => 5); +/* + waiting on properties implementation + var classWithProperties = new ClassWithProperties(); + classWithProperties.IntPropertyWithBackingField = 2; + Console.WriteLine(classWithProperties.IntPropertyWithBackingField); + Console.WriteLine(classWithProperties.StringPropertyWithBackingField); + classWithProperties.DoublePropertyWithAutoImplementedGetSet = 1.4; + Console.WriteLine(classWithProperties.DoublePropertyWithAutoImplementedGetSet); + Console.WriteLine(classWithProperties.BytePropertyWithAutoImplementedGetAndDefaultValue); + Console.WriteLine(classWithProperties.ExceptionPropertyWithAutoImplementedGetSetAndDefaultValue); + classWithProperties.ExceptionPropertyWithAutoImplementedGetSetAndDefaultValue = null; + Console.WriteLine(classWithProperties.ExceptionPropertyWithAutoImplementedGetSetAndDefaultValue); + classWithProperties.DerivedClassPropertyWithAutoImplementedGetSet = new DerivedClass(); + Console.WriteLine(classWithProperties.DerivedClassPropertyWithAutoImplementedGetSet); + + var structWithProperties = new StructWithProperties(); + structWithProperties.IntPropertyWithBackingField = 2; + Console.WriteLine(structWithProperties.IntPropertyWithBackingField); + structWithProperties.DoublePropertyWithAutoImplementedGetSet = 1.4; + Console.WriteLine(structWithProperties.DoublePropertyWithAutoImplementedGetSet); + structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet = new DerivedClass(); + Console.WriteLine(structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet); +*/ /* FIXME Try when that example is fixed methodBodyExamples.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); From a39243bf49640c4d343cd18f77c687c9699721ab Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 25 Feb 2020 16:37:27 -0300 Subject: [PATCH 111/256] extract properties --- MetadataProvider/AssemblyExtractor.cs | 20 ++++++++++++++++++++ Model/Types/TypeDefinitions.cs | 1 + 2 files changed, 21 insertions(+) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..934ca112 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -281,6 +281,11 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) } defGenericContext.TypeParameters.Clear(); + + foreach (var handle in typedef.GetProperties()) + { + ExtractProperty(handle); + } foreach (var handle in typedef.GetNestedTypes()) { @@ -495,6 +500,21 @@ private Constant ExtractFieldDefaultValue(SRM.FieldDefinition fielddef) return result; } + + private void ExtractProperty(SRM.PropertyDefinitionHandle handle) + { + var propertyDef = metadata.GetPropertyDefinition(handle); + var name = metadata.GetString(propertyDef.Name); + var signature = propertyDef.DecodeSignature(signatureTypeProvider, defGenericContext); + var property = new PropertyDefinition(name, signature.ReturnType) + { + Getter = !propertyDef.GetAccessors().Getter.IsNil ? GetDefinedMethod(propertyDef.GetAccessors().Getter) : default, + Setter = !propertyDef.GetAccessors().Setter.IsNil ? GetDefinedMethod(propertyDef.GetAccessors().Setter) : default, + ContainingType = currentType, + IsInstanceProperty = signature.Header.IsInstance + }; + currentType.PropertyDefinitions.Add(property); + } private void ExtractMethod(SRM.MethodDefinitionHandle methoddefHandle) { diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 637db38d..343e4932 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -423,6 +423,7 @@ public bool MatchReference(ITypeMemberReference member) return false; } + public bool IsInstanceProperty { get; set; } public override bool Equals(object obj) { if (obj is PropertyDefinition propertyDef) From 406da635c331484b7b8c2f3e6d5d34ccea9836bf Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 25 Feb 2020 16:42:50 -0300 Subject: [PATCH 112/256] refactor --- MetadataProvider/AssemblyExtractor.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 934ca112..483338b0 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -506,10 +506,12 @@ private void ExtractProperty(SRM.PropertyDefinitionHandle handle) var propertyDef = metadata.GetPropertyDefinition(handle); var name = metadata.GetString(propertyDef.Name); var signature = propertyDef.DecodeSignature(signatureTypeProvider, defGenericContext); + var getter = propertyDef.GetAccessors().Getter; + var setter = propertyDef.GetAccessors().Setter; var property = new PropertyDefinition(name, signature.ReturnType) { - Getter = !propertyDef.GetAccessors().Getter.IsNil ? GetDefinedMethod(propertyDef.GetAccessors().Getter) : default, - Setter = !propertyDef.GetAccessors().Setter.IsNil ? GetDefinedMethod(propertyDef.GetAccessors().Setter) : default, + Getter = !getter.IsNil ? GetDefinedMethod(getter) : default, + Setter = !setter.IsNil ? GetDefinedMethod(setter) : default, ContainingType = currentType, IsInstanceProperty = signature.Header.IsInstance }; From 87be0af238fdb64f881a4445289ce07da12f6488 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 25 Feb 2020 16:45:57 -0300 Subject: [PATCH 113/256] styling --- Model/Types/TypeDefinitions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 343e4932..4d706aae 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -416,6 +416,7 @@ IBasicType ITypeMemberReference.ContainingType { get { return this.ContainingType; } } + public bool IsInstanceProperty { get; set; } public bool MatchReference(ITypeMemberReference member) { if (member is PropertyDefinition) @@ -423,7 +424,6 @@ public bool MatchReference(ITypeMemberReference member) return false; } - public bool IsInstanceProperty { get; set; } public override bool Equals(object obj) { if (obj is PropertyDefinition propertyDef) From 278bd4fd3bc0953bfb30c57d0e48b59885a4ed4a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 25 Feb 2020 17:00:20 -0300 Subject: [PATCH 114/256] property generation --- ExamplesEXE/ExamplesEXE.cs | 6 +- .../Generators/PropertyGenerator.cs | 55 +++++++++++++++++++ MetadataGenerator/Generators/TypeGenerator.cs | 37 +++++-------- MetadataGenerator/MetadataGenerator.csproj | 2 + 4 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 MetadataGenerator/Generators/PropertyGenerator.cs diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 8206bf30..f969fbff 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -1,6 +1,8 @@ using System; using Classes; +using Hierarchy; using MethodBody; +using Properties; using Structs; namespace ExamplesEXE @@ -56,8 +58,7 @@ public static void Main(string[] args) Console.WriteLine(methodBodyExamples.Arrays(new[] {new EmptyStruct()})); Console.WriteLine(methodBodyExamples.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); methodBodyExamples.Calls(sc, e => 5); -/* - waiting on properties implementation + var classWithProperties = new ClassWithProperties(); classWithProperties.IntPropertyWithBackingField = 2; Console.WriteLine(classWithProperties.IntPropertyWithBackingField); @@ -78,7 +79,6 @@ waiting on properties implementation Console.WriteLine(structWithProperties.DoublePropertyWithAutoImplementedGetSet); structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet = new DerivedClass(); Console.WriteLine(structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet); -*/ /* FIXME Try when that example is fixed methodBodyExamples.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); diff --git a/MetadataGenerator/Generators/PropertyGenerator.cs b/MetadataGenerator/Generators/PropertyGenerator.cs new file mode 100644 index 00000000..535388ef --- /dev/null +++ b/MetadataGenerator/Generators/PropertyGenerator.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using MetadataGenerator.Metadata; +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SR = System.Reflection; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generators +{ + internal class PropertyGenerator + { + private readonly MetadataContainer metadataContainer; + + public PropertyGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public SRM.PropertyDefinitionHandle Generate( + PropertyDefinition property, + IDictionary methodDefHandleOf) + { + var signature = new SRM.BlobBuilder(); + new ECMA335.BlobEncoder(signature) + .PropertySignature(isInstanceProperty: property.IsInstanceProperty) + .Parameters( + parameterCount: 0, + returnType: returnTypeEncoder => metadataContainer.metadataResolver.Encode(property.PropertyType, returnTypeEncoder.Type()), + parameters: parametersEncoder => { }); + + var propertyDefinitionHandle = metadataContainer.metadataBuilder.AddProperty( + attributes: SR.PropertyAttributes.None, + name: metadataContainer.metadataBuilder.GetOrAddString(property.Name), + signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + + if (property.Getter != null) + { + metadataContainer.metadataBuilder.AddMethodSemantics( + propertyDefinitionHandle, + SR.MethodSemanticsAttributes.Getter, + methodDefHandleOf[property.Getter]); + } + + if (property.Setter != null) + { + metadataContainer.metadataBuilder.AddMethodSemantics( + propertyDefinitionHandle, + SR.MethodSemanticsAttributes.Setter, + methodDefHandleOf[property.Setter]); + } + + return propertyDefinitionHandle; + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index 295c63fd..c8ee716e 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -16,12 +16,14 @@ internal class TypeGenerator private readonly MetadataContainer metadataContainer; private readonly MethodGenerator methodGenerator; private readonly FieldGenerator fieldGenerator; + private readonly PropertyGenerator propertyGenerator; public TypeGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; methodGenerator = new MethodGenerator(metadataContainer); fieldGenerator = new FieldGenerator(metadataContainer); + propertyGenerator = new PropertyGenerator(metadataContainer); } public SRM.TypeDefinitionHandle Generate(TypeDefinition type) @@ -29,30 +31,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) var methodDefinitionHandles = new List(); var metadataBuilder = metadataContainer.metadataBuilder; var fieldDefinitionHandles = type.Fields.Select(field => fieldGenerator.Generate(field)).ToList(); - - /* TODO model is missing Property concept - * pseudocode - - var propertySignatureBlogBuilder = new BlobBuilder(); - new BlobEncoder(propertySignatureBlogBuilder) - .PropertySignature(isInstanceProperty: true?) - .Parameters( - 0, - returnType => returnType.Type().Int32() (some type), - parameters => { }); - - var propertyDefinitionHandle = metadata.AddProperty( - attributes: PropertyAttributes.None, - name: metadata.GetOrAddString(""), - signature: metadata.GetOrAddBlob(propertySignatureBlogBuilder)); - - // associate methods (get, set) to property - metadata.AddMethodSemantics( - propertyDefinitionHandle, - method.Name.StartsWith("get_") ? MethodSemanticsAttributes.Getter : MethodSemanticsAttributes.Setter, - methodHandle); //getter/setter - metadata.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandle); - */ + var methodDefToHandle = new Dictionary(); foreach (var method in type.Methods) { @@ -62,10 +41,18 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) { metadataContainer.MainMethodHandle = methodHandle; } + + methodDefToHandle.Add(method, methodHandle); } + var propertyDefinitionHandles = type.PropertyDefinitions + .Select(property => propertyGenerator.Generate(property, methodDefToHandle)) + .ToList(); + var nextFieldDefinitionHandle = ECMA335.MetadataTokens.FieldDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.Field)); var nextMethodDefinitionHandle = ECMA335.MetadataTokens.MethodDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.MethodDef)); + var nextPropertyDefinitionHandle = + ECMA335.MetadataTokens.PropertyDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.Property)); var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( attributes: GetTypeAttributesFor(type), @namespace: metadataBuilder.GetOrAddString(type.ContainingNamespace.FullName), @@ -74,6 +61,8 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) fieldList: fieldDefinitionHandles.FirstOr(nextFieldDefinitionHandle), methodList: methodDefinitionHandles.FirstOr(nextMethodDefinitionHandle)); + metadataContainer.metadataBuilder.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandles.FirstOr(nextPropertyDefinitionHandle)); + foreach (var interfaze in type.Interfaces) { metadataBuilder.AddInterfaceImplementation( diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 32610009..e193b583 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -33,6 +33,7 @@ + @@ -50,6 +51,7 @@ + ..\packages\System.Collections.Immutable.1.5.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll From 277b9cb36379be4b0a3457df41abad47a7f93976 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 5 Mar 2020 22:49:59 -0300 Subject: [PATCH 115/256] fix some instruction generation --- .../Body/MethodBodyControlFlowGenerator.cs | 12 +++ .../Methods/Body/MethodBodyGenerator.cs | 97 ++++++++++++++++--- .../Metadata/MetadataResolver.cs | 2 +- 3 files changed, 95 insertions(+), 16 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index 7a237350..2e702bc0 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using MetadataGenerator.Metadata; using Model; +using Model.Bytecode; using ECMA335 = System.Reflection.Metadata.Ecma335; namespace MetadataGenerator.Generators.Methods.Body @@ -29,6 +30,17 @@ public ECMA335.LabelHandle LabelHandleFor(string label) return labelHandle; } + // FIXME name, quiza hacer tmb con las exception information asi es mas prolijo? y despues en el labelHandle solo levantarla y nunca crearla + public void DefineNeededBranchLabels(IList instructions) + { + foreach (var instruction in instructions) + { + if (instruction is BranchInstruction branchInstruction) + { + LabelHandleFor(branchInstruction.Target); + } + } + } public void MarkCurrentLabel() { diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 2ffe49c6..e2053486 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -24,11 +24,14 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), new ECMA335.ControlFlowBuilder()); var controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); + controlFlowGenerator.DefineNeededBranchLabels(body.Instructions); foreach (var instruction in body.Instructions) { controlFlowGenerator.MarkCurrentLabel(); + if (instruction.Offset != instructionEncoder.Offset) throw new Exception(); + switch (instruction) { case BasicInstruction basicInstruction: @@ -142,48 +145,86 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case BasicOperation.Return: instructionEncoder.OpCode(SRM.ILOpCode.Ret); break; + default: + throw new UnhandledCase(); } break; case BranchInstruction branchInstruction: { - var opCode = SRM.ILOpCode.Br_s; + SRM.ILOpCode opCode; + var isShortForm = Convert.ToInt32(branchInstruction.Target.Substring(2), 16) < 256; switch (branchInstruction.Operation) { - // TODO all short forms can also be not short form (ex: br and br.s) case BranchOperation.False: - opCode = SRM.ILOpCode.Brfalse_s; + opCode = isShortForm ? SRM.ILOpCode.Brfalse_s : SRM.ILOpCode.Brfalse; break; case BranchOperation.True: - opCode = SRM.ILOpCode.Brtrue_s; + opCode = isShortForm ? SRM.ILOpCode.Brtrue_s : SRM.ILOpCode.Brtrue; break; case BranchOperation.Eq: - opCode = SRM.ILOpCode.Beq_s; + opCode = isShortForm ? SRM.ILOpCode.Beq_s : SRM.ILOpCode.Beq; break; case BranchOperation.Neq: - opCode = SRM.ILOpCode.Bne_un_s; + opCode = isShortForm ? SRM.ILOpCode.Bne_un_s : SRM.ILOpCode.Bne_un; break; case BranchOperation.Lt: - opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Blt_un_s : SRM.ILOpCode.Blt_s; + if (branchInstruction.UnsignedOperands) + { + opCode = isShortForm ? SRM.ILOpCode.Blt_un_s : SRM.ILOpCode.Blt_un; + } + else + { + opCode = isShortForm ? SRM.ILOpCode.Blt_s : SRM.ILOpCode.Blt; + } + break; case BranchOperation.Le: - opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Ble_un_s : SRM.ILOpCode.Ble_s; + if (branchInstruction.UnsignedOperands) + { + opCode = isShortForm ? SRM.ILOpCode.Ble_un_s : SRM.ILOpCode.Ble_un; + } + else + { + opCode = isShortForm ? SRM.ILOpCode.Ble_s : SRM.ILOpCode.Ble; + } + break; case BranchOperation.Gt: - opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Bgt_un_s : SRM.ILOpCode.Bgt_s; + if (branchInstruction.UnsignedOperands) + { + opCode = isShortForm ? SRM.ILOpCode.Bgt_un_s : SRM.ILOpCode.Bgt_un; + } + else + { + opCode = isShortForm ? SRM.ILOpCode.Bgt_s : SRM.ILOpCode.Bgt; + } + break; case BranchOperation.Ge: - opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Bge_un_s : SRM.ILOpCode.Bge_s; + if (branchInstruction.UnsignedOperands) + { + opCode = isShortForm ? SRM.ILOpCode.Bge_un_s : SRM.ILOpCode.Bge_un; + } + else + { + opCode = isShortForm ? SRM.ILOpCode.Bge_s : SRM.ILOpCode.Bge; + } + break; case BranchOperation.Branch: - opCode = SRM.ILOpCode.Br_s; + opCode = isShortForm ? SRM.ILOpCode.Br_s : SRM.ILOpCode.Br; break; case BranchOperation.Leave: - opCode = SRM.ILOpCode.Leave_s; + opCode = isShortForm ? SRM.ILOpCode.Leave_s : SRM.ILOpCode.Leave; break; + default: + throw new UnhandledCase(); } + instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(branchInstruction.Target)); + break; } @@ -329,6 +370,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(SRM.ILOpCode.Conv_u); } } + else throw new UnhandledCase(); break; case ConvertOperation.Cast: @@ -351,6 +393,8 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(SRM.ILOpCode.Unbox); instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); break; + default: + throw new UnhandledCase(); } break; @@ -364,6 +408,8 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case MethodCallOperation.Jump: instructionEncoder.Call(metadataContainer.metadataResolver.HandleOf(methodCallInstruction.Method)); break; + default: + throw new UnhandledCase(); } break; @@ -399,8 +445,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); } - - if (loadInstruction.Operand.Type.Equals(PlatformTypes.String)) + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.String)) { var value = (string) (loadInstruction.Operand as Constant).Value; instructionEncoder.LoadString(metadataContainer.metadataBuilder.GetOrAddUserString(value)); @@ -433,8 +478,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var value = (double) (loadInstruction.Operand as Constant).Value; instructionEncoder.LoadConstantR8(value); } + else throw new UnhandledCase(); break; + default: + throw new UnhandledCase(); } break; @@ -447,6 +495,8 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case LoadFieldOperation.Address: instructionEncoder.OpCode(loadFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Ldsflda : SRM.ILOpCode.Ldflda); break; + default: + throw new UnhandledCase(); } instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadFieldInstruction.Field)); @@ -511,6 +561,9 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); break; + + default: + throw new UnhandledCase(); } break; @@ -663,6 +716,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { instructionEncoder.OpCode(SRM.ILOpCode.Ldind_ref); } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldobj); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadIndirectInstruction.Type)); + } break; case StoreIndirectInstruction storeIndirectInstruction: @@ -698,14 +756,23 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { instructionEncoder.OpCode(SRM.ILOpCode.Stind_ref); } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Stobj); + instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(storeIndirectInstruction.Type)); + } break; default: - throw new Exception("instruction type not handled"); + throw new UnhandledCase(); } } return instructionEncoder; } } + + internal class UnhandledCase : Exception + { + } } \ No newline at end of file diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 7572e11a..4348d973 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -249,7 +249,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { var genericInstantiation = encoder.GenericInstantiation( GetOrAddTypeReference(basicType.GenericType), - basicType.GenericParameterCount, + basicType.GenericArguments.Count, isValueType); foreach (var genericArg in basicType.GenericArguments) { From 853d63fb87eaad6dd30cbc0577f8c0f6166c54bd Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 19 Mar 2020 19:51:14 -0300 Subject: [PATCH 116/256] fixes --- MetadataProvider/AssemblyExtractor.cs | 165 ++++++++++------------ MetadataProvider/SignatureTypeProvider.cs | 15 +- Model/Assembly.cs | 4 +- Model/Bytecode/Instructions.cs | 6 + Model/ThreeAddressCode/Operands.cs | 3 + Model/Types/TypeDefinitions.cs | 69 ++++++++- Model/Types/Types.cs | 72 ++++++++++ 7 files changed, 235 insertions(+), 99 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..feaa58fd 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -13,75 +13,6 @@ namespace MetadataProvider { internal class AssemblyExtractor { - #region FakeArrayType - - private struct FakeArrayType : IBasicType - { - public ArrayType Type { get; private set; } - - public FakeArrayType(ArrayType type) - { - this.Type = type; - } - - public IAssemblyReference ContainingAssembly - { - get { return null; } - } - - public string ContainingNamespace - { - get { return string.Empty; } - } - - public string Name - { - get { return "FakeArray"; } - } - - public string GenericName - { - get { return this.Name; } - } - - public IList GenericArguments - { - get { return null; } - } - - public IBasicType GenericType - { - get { return null; } - } - - public TypeDefinition ResolvedType - { - get { return null; } - } - - public TypeKind TypeKind - { - get { return TypeKind.ReferenceType; } - } - - public ISet Attributes - { - get { return null; } - } - - public int GenericParameterCount - { - get { return 0; } - } - - public IBasicType ContainingType - { - get { return null; } - } - } - - #endregion - private IDictionary definedTypes; private IDictionary definedMethods; private IDictionary definedFields; @@ -127,9 +58,14 @@ public TypeDefinition GetDefinedType(SRM.TypeDefinitionHandle handle) { var typedef = metadata.GetTypeDefinition(handle); var name = metadata.GetString(typedef.Name); - name = GetGenericName(name); + name = GetGenericName(name, out var genericParameterCount); - result = new TypeDefinition(name); + result = new TypeDefinition(name) + { + GenericParameterCount = genericParameterCount, + ContainingAssembly = assembly, + ContainingNamespace = currentNamespace + }; definedTypes.Add(handle, result); } @@ -145,9 +81,13 @@ public MethodDefinition GetDefinedMethod(SRM.MethodDefinitionHandle handle) { var methoddef = metadata.GetMethodDefinition(handle); var name = metadata.GetString(methoddef.Name); - name = GetGenericName(name); + name = GetGenericName(name, out _); result = new MethodDefinition(name, null); + foreach (var genericParameterHandle in methoddef.GetGenericParameters()) + { + ExtractGenericParameter(GenericParameterKind.Method, result, genericParameterHandle); + } definedMethods.Add(handle, result); } @@ -175,13 +115,19 @@ public Assembly Extract() { var assemblydef = metadata.GetAssemblyDefinition(); var name = metadata.GetString(assemblydef.Name); - assembly = new Assembly(name); + assembly = new Assembly(name) + { + Version = assemblydef.Version + }; foreach (var handle in metadata.AssemblyReferences) { var referencedef = metadata.GetAssemblyReference(handle); name = metadata.GetString(referencedef.Name); - var reference = new AssemblyReference(name); + var reference = new AssemblyReference(name) + { + Version = referencedef.Version + }; assembly.References.Add(reference); } @@ -281,6 +227,11 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) } defGenericContext.TypeParameters.Clear(); + + foreach (var handle in typedef.GetProperties()) + { + ExtractProperty(handle); + } foreach (var handle in typedef.GetNestedTypes()) { @@ -495,6 +446,25 @@ private Constant ExtractFieldDefaultValue(SRM.FieldDefinition fielddef) return result; } + + private void ExtractProperty(SRM.PropertyDefinitionHandle handle) + { + var propertyDef = metadata.GetPropertyDefinition(handle); + var name = metadata.GetString(propertyDef.Name); + CreateGenericParameterReferences(GenericParameterKind.Type, currentType.GenericParameters.Count); + var signature = propertyDef.DecodeSignature(signatureTypeProvider, refGenericContext); + var getter = propertyDef.GetAccessors().Getter; + var setter = propertyDef.GetAccessors().Setter; + var property = new PropertyDefinition(name, signature.ReturnType) + { + Getter = !getter.IsNil ? GetDefinedMethod(getter) : default, + Setter = !setter.IsNil ? GetDefinedMethod(setter) : default, + ContainingType = currentType, + IsInstanceProperty = signature.Header.IsInstance + }; + currentType.PropertyDefinitions.Add(property); + BindGenericParameterReferences(GenericParameterKind.Type, currentType); + } private void ExtractMethod(SRM.MethodDefinitionHandle methoddefHandle) { @@ -632,7 +602,11 @@ private void ExtractParameters(IList parameters) type = signatureTypeProvider.GetByReferenceType(type); } - var v = new LocalVariable("this", true) { Type = type }; + var v = new LocalVariable("this", true) + { + Type = type, + Index = parameters.Count + }; parameters.Add(v); } @@ -640,7 +614,8 @@ private void ExtractParameters(IList parameters) { var v = new LocalVariable(parameter.Name, true) { - Type = parameter.Type + Type = parameter.Type, + Index = parameters.Count }; parameters.Add(v); @@ -659,7 +634,8 @@ private void ExtractLocalVariables(SRM.MethodBodyBlock bodyBlock, IList(op); IInstruction instruction; - if (method.ContainingType is FakeArrayType) + if (method.ContainingType is ArrayTypeWrapper) { - var arrayType = (FakeArrayType)method.ContainingType; + var arrayType = (ArrayTypeWrapper)method.ContainingType; var withLowerBounds = method.Parameters.Count > arrayType.Type.Rank; - - instruction = ProcessCreateArray(op, arrayType.Type, withLowerBounds); + var createArrayInstruction = ProcessCreateArray(op, arrayType.Type, withLowerBounds); + createArrayInstruction.Constructor = method; + instruction = createArrayInstruction; } else { @@ -1450,19 +1427,22 @@ private IInstruction ProcessMethodCall(ILInstruction op) var method = GetOperand(op); IInstruction instruction; - if (method.ContainingType is FakeArrayType) + if (method.ContainingType is ArrayTypeWrapper) { - var arrayType = (FakeArrayType)method.ContainingType; + var arrayType = (ArrayTypeWrapper)method.ContainingType; if (method.Name == "Set") { - instruction = ProcessStoreArrayElement(op, arrayType.Type); + var storeArrayElementInstruction = ProcessStoreArrayElement(op, arrayType.Type); + storeArrayElementInstruction.Method = method; + instruction = storeArrayElementInstruction; } else { var operation = OperationHelper.ToLoadArrayElementOperation(method.Name); - - instruction = ProcessLoadArrayElement(op, arrayType.Type, operation); + var loadArrayElementInstruction = ProcessLoadArrayElement(op, operation, arrayType.Type); + loadArrayElementInstruction.Method = method; + instruction = loadArrayElementInstruction; } } else @@ -1652,12 +1632,15 @@ private IInstruction ProcessConversion(ILInstruction op) #endregion - private static string GetGenericName(string name) + private static string GetGenericName(string name, out int genericParameterCount) { var start = name.LastIndexOf('`'); + genericParameterCount = 0; if (start > -1) { + var count = name.Substring(start + 1); + genericParameterCount = Convert.ToInt32(count); name = name.Remove(start); } diff --git a/MetadataProvider/SignatureTypeProvider.cs b/MetadataProvider/SignatureTypeProvider.cs index 9ce7a48e..e6e921db 100644 --- a/MetadataProvider/SignatureTypeProvider.cs +++ b/MetadataProvider/SignatureTypeProvider.cs @@ -75,7 +75,10 @@ public virtual IType GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeRef var assemblyHandle = (SRM.AssemblyReferenceHandle)typeref.ResolutionScope; var assembly = reader.GetAssemblyReference(assemblyHandle); name = reader.GetString(assembly.Name); - type.ContainingAssembly = new AssemblyReference(name); + type.ContainingAssembly = new AssemblyReference(name) + { + Version = assembly.Version + }; break; } @@ -171,6 +174,16 @@ public virtual IType GetPinnedType(IType targetType) public virtual IType GetGenericInstantiation(IType genericType, ImmutableArray genericArguments) { var result = genericType as IBasicType; + switch (result) + { + case BasicType basicType: + basicType.GenericParameterCount = genericArguments.Length; + break; + case TypeDefinition typeDefinition: + typeDefinition.GenericParameterCount = genericArguments.Length; + break; + } + result = result.Instantiate(genericArguments); return result; } diff --git a/Model/Assembly.cs b/Model/Assembly.cs index 454bae9e..2d2994a3 100644 --- a/Model/Assembly.cs +++ b/Model/Assembly.cs @@ -12,11 +12,13 @@ namespace Model public interface IAssemblyReference { string Name { get; } + Version Version { get; } } public class AssemblyReference : IAssemblyReference { public string Name { get; private set; } + public Version Version { get; set; } public AssemblyReference(string name) { @@ -49,7 +51,7 @@ public class Assembly : IAssemblyReference public string Name { get; private set; } public IList References { get; private set; } public Namespace RootNamespace { get; set; } - + public Version Version { get; set; } public Assembly(string name) { this.Name = name; diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index bb12534e..8cf7d27a 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -245,6 +245,8 @@ public class CreateArrayInstruction : Instruction public ArrayType Type { get; set; } public bool WithLowerBound { get; set; } + public IMethodReference Constructor { get; set; } + public CreateArrayInstruction(uint label, ArrayType type) : base(label) { @@ -266,6 +268,8 @@ public override string ToString() public class LoadArrayElementInstruction : Instruction { public LoadArrayElementOperation Operation { get; set; } + + public IMethodReference Method { get; set; } public ArrayType Array { get; set; } public LoadArrayElementInstruction(uint label, LoadArrayElementOperation operation, ArrayType array) @@ -290,6 +294,8 @@ public override string ToString() public class StoreArrayElementInstruction : Instruction { public ArrayType Array { get; set; } + + public IMethodReference Method { get; set; } public StoreArrayElementInstruction(uint label, ArrayType array) : base(label) diff --git a/Model/ThreeAddressCode/Operands.cs b/Model/ThreeAddressCode/Operands.cs index 7d658fe9..39ab1072 100644 --- a/Model/ThreeAddressCode/Operands.cs +++ b/Model/ThreeAddressCode/Operands.cs @@ -292,6 +292,9 @@ public class LocalVariable : IVariable public string Name { get; set; } public IType Type { get; set; } public bool IsParameter { get; set; } + + // int? because int defaults to 0 if not present + public int? Index { get; set; } public LocalVariable(string name, bool isParameter = false) { diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 27062ea7..7f4b1475 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -397,7 +397,66 @@ public override bool Equals(object obj) return result; } } + public class PropertyDefinition : ITypeMemberDefinition + { + public PropertyDefinition(string name, IType propType) + { + PropertyType = propType; + Name = name; + Attributes = new HashSet(); + } + + public ISet Attributes { get; private set; } + public IType PropertyType { get; set; } + public string Name { get; set; } + public MethodDefinition Getter { get; set; } + public MethodDefinition Setter { get; set; } + public TypeDefinition ContainingType { get; set; } + IBasicType ITypeMemberReference.ContainingType + { + get { return this.ContainingType; } + } + public bool IsInstanceProperty { get; set; } + public bool MatchReference(ITypeMemberReference member) + { + if (member is PropertyDefinition) + return member.Equals(this); + return false; + } + public override bool Equals(object obj) + { + if (obj is PropertyDefinition propertyDef) + { + bool hasSetter = (propertyDef.Setter != null) == (this.Setter != null); + bool hasGetter = (propertyDef.Getter != null) == (this.Getter != null); + return propertyDef.Name.Equals(this.Name) && + propertyDef.PropertyType.Equals(this.PropertyType) && + hasSetter && hasGetter && + (propertyDef.Getter == null || propertyDef.Getter.Equals(this.Getter)) && + (propertyDef.Setter == null || propertyDef.Setter.Equals(this.Setter)) && + (propertyDef.ContainingType.Equals(this.ContainingType)); + } + return false; + } + public override string ToString() + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("Property definition"); + stringBuilder.AppendLine(String.Format("Name: {0}", Name)); + stringBuilder.AppendLine(String.Format("Property type: {0}", PropertyType)); + stringBuilder.AppendLine(String.Format("Containing type: {0}", ContainingType)); + if (Getter != null) + stringBuilder.AppendLine(String.Format("Getter: {0}", Getter.ToSignatureString())); + if (Setter != null) + stringBuilder.AppendLine(String.Format("Setter: {0}", Setter.ToSignatureString())); + return stringBuilder.ToString(); + } + public override int GetHashCode() + { + return this.Name.GetHashCode(); + } + } public class MethodDefinition : ITypeMemberDefinition, IMethodReference, IGenericDefinition { public VisibilityKind Visibility { get; set; } @@ -623,7 +682,9 @@ public class TypeDefinition : IBasicType, IGenericDefinition, ITypeMemberDefinit public IList Methods { get; private set; } public IList Types { get; private set; } public IBasicType UnderlayingType { get; set; } - + public ISet PropertyDefinitions { get; private set; } + + public int GenericParameterCount { get; set; } public TypeDefinition(string name, TypeKind typeKind = TypeKind.Unknown, TypeDefinitionKind kind = TypeDefinitionKind.Unknown) { this.Name = name; @@ -635,6 +696,7 @@ public TypeDefinition(string name, TypeKind typeKind = TypeKind.Unknown, TypeDef this.Fields = new List(); this.Methods = new List(); this.Types = new List(); + this.PropertyDefinitions = new HashSet(); } public string GenericName @@ -676,11 +738,6 @@ IBasicType ITypeMemberReference.ContainingType #region IGenericReference members - int IGenericReference.GenericParameterCount - { - get { return this.GenericParameters.Count; } - } - #endregion #region IBasicType members diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index 0d6934db..e26edc8b 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -37,6 +37,9 @@ public interface IReferenceType : IType public static class PlatformTypes { + public static Boolean Includes(IType type) => platformTypes.FirstOrDefault(type.Equals) != null; + + private static readonly ICollection platformTypes = new List(); public static readonly UnknownType Unknown = UnknownType.Value; @@ -732,4 +735,73 @@ public override bool Equals(object obj) return result; } } + + #region ArrayTypeWrapper + + public struct ArrayTypeWrapper : IBasicType + { + public ArrayType Type { get; } + + public ArrayTypeWrapper(ArrayType type) + { + this.Type = type; + } + + public IAssemblyReference ContainingAssembly + { + get { return null; } + } + + public string ContainingNamespace + { + get { return string.Empty; } + } + + public string Name + { + get { return "ArrayTypeWrapper"; } + } + + public string GenericName + { + get { return this.Name; } + } + + public IList GenericArguments + { + get { return null; } + } + + public IBasicType GenericType + { + get { return null; } + } + + public TypeDefinition ResolvedType + { + get { return null; } + } + + public TypeKind TypeKind + { + get { return TypeKind.ReferenceType; } + } + + public ISet Attributes + { + get { return null; } + } + + public int GenericParameterCount + { + get { return 0; } + } + + public IBasicType ContainingType + { + get { return null; } + } + } + + #endregion } From cb1eea599cb40a98101a6c01508eb5558993d934 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 19 Mar 2020 20:34:44 -0300 Subject: [PATCH 117/256] fixes derived from processing some libraries --- Console/Program.cs | 5 +- .../Generators/AssemblyGenerator.cs | 10 +- .../Methods/Body/MethodBodyGenerator.cs | 176 +++++++++------- MetadataGenerator/Generators/TypeGenerator.cs | 4 +- .../Metadata/MetadataContainer.cs | 193 ++++++++++++++---- .../Metadata/MetadataResolver.cs | 52 ++++- 6 files changed, 309 insertions(+), 131 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index f2c2791b..271026e9 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -386,7 +386,10 @@ private static void DisassembleAndThenAssemble(string input) static void Main(string[] args) { - var input = args[0].Equals("dll") ? @"../../../Examples/bin/Debug/Examples.dll" : @"../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"; + // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/netcoreapp2.1/TinyCsvParser.Test.dll"; + // var input = "../../../../../../Desktop/netcoreapp2.1/TinyCsvParser.Test.dll"; + // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/netcoreapp2.1/TinyCsvParser.dll"; + var input = "../../../../C-Sharp-Algorithms/Algorithms/bin/Debug/netcoreapp2.0/Algorithms.dll"; DisassembleAndThenAssemble(input); //RunSomeTests(); diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index 90cf756f..b543ecb0 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -15,7 +15,7 @@ public static MetadataContainer Generate(Assembly assembly) metadataBuilder.AddAssembly( name: metadataBuilder.GetOrAddString(assembly.Name), - version: new Version(0, 0, 0, 1), + version: assembly.Version, culture: default, publicKey: default, flags: SR.AssemblyFlags.PublicKey, @@ -36,12 +36,12 @@ public static MetadataContainer Generate(Assembly assembly) } /* - * Generic parameters table must be sorted by owner (TypeOrMethodDef that owns the generic parameter). Since the dll's methods and types don't follow a - * particular order, the info needed to generate this parameters is stored during type/method generation but not added to the MetadataBuilder until now + * Some tables must be sorted by one or more of their columns. Since the dll's methods and types don't follow a + * particular order, the info needed to load this tables is stored during type/method generation but not added to the MetadataBuilder until now + * where they can be previously sorted */ + metadataContainer.GenerateInterfaceImplementations(); metadataContainer.GenerateGenericParameters(); - - // nested types table also needs to be sorted metadataContainer.GenerateNestedTypes(); return metadataContainer; diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index e2053486..87d88dc7 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -29,7 +29,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) foreach (var instruction in body.Instructions) { controlFlowGenerator.MarkCurrentLabel(); - if (instruction.Offset != instructionEncoder.Offset) throw new Exception(); switch (instruction) @@ -153,7 +152,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case BranchInstruction branchInstruction: { SRM.ILOpCode opCode; - var isShortForm = Convert.ToInt32(branchInstruction.Target.Substring(2), 16) < 256; + var nextInstructionOffset = + Convert.ToInt32(body.Instructions[body.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); + var currentInstructionOffset = Convert.ToInt32(branchInstruction.Label.Substring(2), 16); + // short forms are 1 byte opcode + 1 byte target. normal forms are 1 byte opcode + 4 byte target + var isShortForm = nextInstructionOffset - currentInstructionOffset == 2; switch (branchInstruction.Operation) { case BranchOperation.False: @@ -417,30 +420,37 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) switch (loadInstruction.Operation) { case LoadOperation.Address: - var operandVariable = (IVariable) loadInstruction.Operand; - if (operandVariable.IsParameter) + { + var variable = (LocalVariable) loadInstruction.Operand; + var index = variable.Index.Value; + if (variable.IsParameter) { - instructionEncoder.LoadArgumentAddress(body.Parameters.IndexOf(operandVariable)); + instructionEncoder.LoadArgumentAddress(index); } else { - instructionEncoder.LoadLocalAddress(body.LocalVariables.IndexOf(operandVariable)); + instructionEncoder.LoadLocalAddress(index); } break; + } case LoadOperation.Content: - operandVariable = (IVariable) loadInstruction.Operand; - if (operandVariable.IsParameter) + { + var variable = (LocalVariable) loadInstruction.Operand; + var index = variable.Index.Value; + if (variable.IsParameter) { - instructionEncoder.LoadArgument(body.Parameters.IndexOf(operandVariable)); + instructionEncoder.LoadArgument(index); } else { - instructionEncoder.LoadLocal(body.LocalVariables.IndexOf(operandVariable)); + instructionEncoder.LoadLocal(index); } break; + } case LoadOperation.Value: + { if (((Constant) loadInstruction.Operand).Value == null) { instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); @@ -481,6 +491,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) else throw new UnhandledCase(); break; + } default: throw new UnhandledCase(); } @@ -502,71 +513,81 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadFieldInstruction.Field)); break; case LoadArrayElementInstruction loadArrayElementInstruction: - switch (loadArrayElementInstruction.Operation) + { + if (loadArrayElementInstruction.Method != null) { - case LoadArrayElementOperation.Content: - if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i1); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt8)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u1); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int16)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i2); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt16)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u2); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i4); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u4); - } - else if (loadArrayElementInstruction.Array.ElementsType.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i8); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_r4); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float64)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_r8); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Object)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_ref); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); + instructionEncoder.Call(metadataContainer.metadataResolver.HandleOf(loadArrayElementInstruction.Method)); + } + else + { + switch (loadArrayElementInstruction.Operation) + { + case LoadArrayElementOperation.Content: + if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i1); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u1); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i2); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u2); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i4); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u4); + } + else if (loadArrayElementInstruction.Array.ElementsType.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i8); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_r4); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_r8); + } + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Object)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_ref); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); + instructionEncoder.Token( + metadataContainer.metadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); + } + + break; + case LoadArrayElementOperation.Address: + instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); instructionEncoder.Token( metadataContainer.metadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); - } + break; - break; - case LoadArrayElementOperation.Address: - instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); - break; - - default: - throw new UnhandledCase(); + default: + throw new UnhandledCase(); + } } break; + } case LoadMethodAddressInstruction loadMethodAddressInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadMethodAddressInstruction.Method)); @@ -579,26 +600,33 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } else { - throw new Exception("newarr only handles one dimension and zero based arrays"); + var method = metadataContainer.metadataResolver.HandleOf(createArrayInstruction.Constructor); + instructionEncoder.OpCode(SRM.ILOpCode.Newobj); + instructionEncoder.Token(method); } break; case CreateObjectInstruction createObjectInstruction: + { var method = metadataContainer.metadataResolver.HandleOf(createObjectInstruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); break; + } case StoreInstruction storeInstruction: + { + var index = ((LocalVariable) storeInstruction.Target).Index.Value; if (storeInstruction.Target.IsParameter) { - instructionEncoder.StoreArgument(body.Parameters.IndexOf(storeInstruction.Target)); + instructionEncoder.StoreArgument(index); } else { - instructionEncoder.StoreLocal(body.LocalVariables.IndexOf(storeInstruction.Target)); + instructionEncoder.StoreLocal(index); } break; + } case StoreFieldInstruction storeFieldInstruction: instructionEncoder.OpCode(storeFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(storeFieldInstruction.Field)); @@ -624,7 +652,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); break; case StoreArrayElementInstruction storeArrayElementInstruction: - if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) + if (storeArrayElementInstruction.Method != null) + { + instructionEncoder.Call(metadataContainer.metadataResolver.HandleOf(storeArrayElementInstruction.Method)); + } + else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) { instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i1); } diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index c8ee716e..c7805f96 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -65,9 +65,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) foreach (var interfaze in type.Interfaces) { - metadataBuilder.AddInterfaceImplementation( - type: typeDefinitionHandle, - implementedInterface: metadataContainer.metadataResolver.HandleOf(interfaze)); + metadataContainer.RegisterInterfaceImplementation(typeDefinitionHandle, metadataContainer.metadataResolver.HandleOf(interfaze)); } // generate class generic parameters (Class) diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 4d4273dd..6b23464e 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; +using System.Linq; using System.Reflection; using Model.Types; using Assembly = Model.Assembly; @@ -15,8 +15,9 @@ internal class MetadataContainer public readonly MetadataResolver metadataResolver; public readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; private SRM.MethodDefinitionHandle? mainMethodHandle; - private readonly IDictionary> genericParameters = new Dictionary>(); - private readonly IDictionary nestedTypes = new Dictionary(); + private readonly ISet genericParameterRows = new HashSet(); + private readonly ISet nestedTypeRows = new HashSet(); + private readonly ISet interfaceImplementationRows = new HashSet(); public SRM.MethodDefinitionHandle? MainMethodHandle { @@ -35,65 +36,177 @@ public MetadataContainer(Assembly assembly) metadataResolver = new MetadataResolver(this, assembly); } - public void RegisterGenericParameter(SRM.TypeDefinitionHandle owner, GenericParameter genericParameter) => - DoRegisterGenericParameter(owner, genericParameter); + public void RegisterGenericParameter(SRM.TypeDefinitionHandle parent, GenericParameter genericParameter) => + DoRegisterGenericParameter(parent, genericParameter); - public void RegisterGenericParameter(SRM.MethodDefinitionHandle owner, GenericParameter genericParameter) => - DoRegisterGenericParameter(owner, genericParameter); + public void RegisterGenericParameter(SRM.MethodDefinitionHandle parent, GenericParameter genericParameter) => + DoRegisterGenericParameter(parent, genericParameter); - private void DoRegisterGenericParameter(SRM.EntityHandle owner, GenericParameter genericParameter) - { - void GenerateGenericParameter() => metadataBuilder.AddGenericParameter( - owner, + private void DoRegisterGenericParameter(SRM.EntityHandle parent, GenericParameter genericParameter) => + genericParameterRows.Add(new GenericParamRow( + parent, GenericParameterAttributes.None, - metadataBuilder.GetOrAddString(genericParameter.Name), genericParameter.Index); + metadataBuilder.GetOrAddString(genericParameter.Name), + genericParameter.Index)); + + public void GenerateGenericParameters() => + genericParameterRows + .OrderBy(row => ECMA335.CodedIndex.TypeOrMethodDef(row.parent)) + .ThenBy(row => row.index) + .ToList() + .ForEach(row => metadataBuilder.AddGenericParameter( + row.parent, + row.attributes, + row.name, + row.index + )); + + public void RegisterNestedType(SRM.TypeDefinitionHandle type, SRM.TypeDefinitionHandle enclosingType) => + nestedTypeRows.Add(new NestedTypeRow(type, enclosingType)); + + public void GenerateNestedTypes() => + nestedTypeRows + .OrderBy(row => ECMA335.CodedIndex.TypeDefOrRef(row.type)) + .ToList() + .ForEach(row => metadataBuilder.AddNestedType(row.type, row.enclosingType)); - /* TODO generic constraints not in the model. Do when PR is merged - pseudocode: - if(genericParameter.hasConstraint()){ - metadataBuilder.AddGenericParameterConstraint( - genericParameterHandle, - metadataContainer.metadataResolver.HandleOf(genericParameter.contraint)); - }*/ + public void RegisterInterfaceImplementation(SRM.TypeDefinitionHandle type, SRM.EntityHandle implementedInterface) => + interfaceImplementationRows.Add(new InterfaceImplementationRow(type, implementedInterface)); - var key = ECMA335.CodedIndex.TypeOrMethodDef(owner); - if (genericParameters.TryGetValue(key, out var actions)) + public void GenerateInterfaceImplementations() => + interfaceImplementationRows + .OrderBy(row => ECMA335.CodedIndex.TypeDefOrRef(row.type)) + .ThenBy(row => ECMA335.CodedIndex.TypeDefOrRefOrSpec(row.implementedInterface)) + .ToList() + .ForEach(row => metadataBuilder.AddInterfaceImplementation(row.type, row.implementedInterface)); + + #region Rows + + private class InterfaceImplementationRow + { + public readonly SRM.TypeDefinitionHandle type; + public readonly SRM.EntityHandle implementedInterface; + + public InterfaceImplementationRow(SRM.TypeDefinitionHandle type, SRM.EntityHandle implementedInterface) { - actions.Add(GenerateGenericParameter); + this.type = type; + this.implementedInterface = implementedInterface; } - else + + public override bool Equals(object obj) { - genericParameters.Add(key, new List {GenerateGenericParameter}); + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + var other = (InterfaceImplementationRow) obj; + return type.Equals(other.type) && implementedInterface.Equals(other.implementedInterface); } - } - public void GenerateGenericParameters() - { - var sortedOwners = genericParameters.Keys.ToImmutableSortedSet(); - foreach (var owner in sortedOwners) + public override int GetHashCode() { - genericParameters.TryGetValue(owner, out var generateGenericParameterOperations); - foreach (var generateGenericParameter in generateGenericParameterOperations) + unchecked { - generateGenericParameter(); + return (type.GetHashCode() * 397) ^ implementedInterface.GetHashCode(); } } + + public static bool operator ==(InterfaceImplementationRow left, InterfaceImplementationRow right) + { + return Equals(left, right); + } + + public static bool operator !=(InterfaceImplementationRow left, InterfaceImplementationRow right) + { + return !Equals(left, right); + } } - public void RegisterNestedType(SRM.TypeDefinitionHandle nestedType, SRM.TypeDefinitionHandle enclosingType) + private class GenericParamRow { - var key = ECMA335.CodedIndex.TypeOrMethodDef(nestedType); - nestedTypes.Add(key, () => metadataBuilder.AddNestedType(nestedType, enclosingType)); + public readonly SRM.EntityHandle parent; + public readonly GenericParameterAttributes attributes; + public readonly SRM.StringHandle name; + public readonly ushort index; + + public GenericParamRow(SRM.EntityHandle parent, GenericParameterAttributes attributes, SRM.StringHandle name, ushort index) + { + this.parent = parent; + this.attributes = attributes; + this.name = name; + this.index = index; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + var other = (GenericParamRow) obj; + return parent.Equals(other.parent) && attributes == other.attributes && name.Equals(other.name) && index == other.index; + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = parent.GetHashCode(); + hashCode = (hashCode * 397) ^ (int) attributes; + hashCode = (hashCode * 397) ^ name.GetHashCode(); + hashCode = (hashCode * 397) ^ index.GetHashCode(); + return hashCode; + } + } + + public static bool operator ==(GenericParamRow left, GenericParamRow right) + { + return Equals(left, right); + } + + public static bool operator !=(GenericParamRow left, GenericParamRow right) + { + return !Equals(left, right); + } } - public void GenerateNestedTypes() + private class NestedTypeRow { - var sortedOwners = nestedTypes.Keys.ToImmutableSortedSet(); - foreach (var owner in sortedOwners) + public readonly SRM.TypeDefinitionHandle type; + public readonly SRM.TypeDefinitionHandle enclosingType; + + public NestedTypeRow(SRM.TypeDefinitionHandle type, SRM.TypeDefinitionHandle enclosingType) + { + this.type = type; + this.enclosingType = enclosingType; + } + + public override bool Equals(object obj) { - nestedTypes.TryGetValue(owner, out var addNestedType); - addNestedType(); + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + var other = (NestedTypeRow) obj; + return type.Equals(other.type) && enclosingType.Equals(other.enclosingType); + } + + public override int GetHashCode() + { + unchecked + { + return (type.GetHashCode() * 397) ^ enclosingType.GetHashCode(); + } + } + + public static bool operator ==(NestedTypeRow left, NestedTypeRow right) + { + return Equals(left, right); + } + + public static bool operator !=(NestedTypeRow left, NestedTypeRow right) + { + return !Equals(left, right); } } + + #endregion } } \ No newline at end of file diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 4348d973..70e741c3 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -4,6 +4,7 @@ using System.Reflection; using MetadataGenerator.Generators.Fields; using MetadataGenerator.Generators.Methods; +using MetadataGenerator.Generators.Methods.Body; using Model.Types; using static System.Linq.Enumerable; using Assembly = Model.Assembly; @@ -19,8 +20,8 @@ internal class MetadataResolver private readonly IDictionary assemblyReferences = new Dictionary(); private readonly IDictionary typeReferences = new Dictionary(); - private readonly IDictionary, SRM.MemberReferenceHandle> memberReferences = - new Dictionary, SRM.MemberReferenceHandle>(); + private readonly IDictionary, SRM.MemberReferenceHandle> memberReferences = + new Dictionary, SRM.MemberReferenceHandle>(); private readonly IDictionary typeSpecificationReferences = new Dictionary(); @@ -44,7 +45,7 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) // TODO version,culture and others should be in the assemblyReference. Submit PR with this assemblyReferences.Add(assemblyReference.Name, metadataContainer.metadataBuilder.AddAssemblyReference( name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), - version: new Version(4, 0, 0, 0), + version: assemblyReference.Version, culture: default, publicKeyOrToken: default, flags: AssemblyFlags.PublicKey, @@ -109,9 +110,21 @@ private SRM.EntityHandle GetOrAddTypeReference(IBasicType type) SRM.EntityHandle resolutionScope; if (type.ContainingType == null) // if defined in the namespace then search there { - resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) - ? default - : assemblyReferences[type.ContainingAssembly.Name]; + try + { + resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) + ? default + : assemblyReferences[type.ContainingAssembly.Name]; + } + // FIXME mmmmmm + catch (KeyNotFoundException) + { + if (PlatformTypes.Includes(type)) + { + resolutionScope = assemblyReferences["System.Runtime"]; + } + else throw; + } } else { @@ -177,11 +190,28 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl { return GetOrAddMethodSpecificationFor(method, signature); } + else if (method.ContainingType is ArrayTypeWrapper arrayTypeWrapper) + { + var parentHandle = GetOrAddTypeSpecificationFor(arrayTypeWrapper.Type); + var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + // FIXME sera suficiente? Hay que revisar todas las keys que uso en estos metodos a ver si tienen sentido + var key = new KeyValuePair(parentHandle, blobHandle); + if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) + { + methodReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( + parent: parentHandle, + name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), + signature: blobHandle); + memberReferences.Add(key, methodReferenceHandle); + } + + return methodReferenceHandle; + } else { var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); - var key = new KeyValuePair( - $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType}.{method.Name}", + var key = new KeyValuePair( + $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.GenericName}.{method.Name}", blobHandle ); if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) @@ -200,8 +230,8 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field, SRM.BlobBuilder signature) { var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); - var key = new KeyValuePair( - $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.Name}.{field.Name}", + var key = new KeyValuePair( + $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.GenericName}.{field.Name}", blobHandle ); if (!memberReferences.TryGetValue(key, out var memberReferenceHandle)) @@ -317,6 +347,8 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) case GenericParameterKind.Method: encoder.GenericMethodTypeParameter(genericParameter.Index); break; + default: + throw new UnhandledCase(); } break; From 55f1e18f95578a6f28688a63e14569aba7ca31f8 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 10 Apr 2020 09:53:08 -0300 Subject: [PATCH 118/256] a lot of changes --- .gitignore | 1 + Console/Program.cs | 10 +- Examples/Examples.cs | 55 ++++++++++- Examples/Examples.csproj | 13 +++ Examples/packages.config | 2 + MetadataGenerator/Generator.cs | 2 +- .../Generators/AssemblyGenerator.cs | 16 +++- .../Generators/Methods/MethodGenerator.cs | 8 +- .../Methods/MethodParametersGenerator.cs | 8 -- MetadataGenerator/Generators/TypeGenerator.cs | 20 +++- .../Metadata/MetadataContainer.cs | 15 ++- .../Metadata/MetadataResolver.cs | 91 ++++++++----------- Model/Extensions.cs | 4 + 13 files changed, 168 insertions(+), 77 deletions(-) diff --git a/.gitignore b/.gitignore index 21853cf1..59200b96 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ obj /packages .DS_Store .idea +TestResult.xml diff --git a/Console/Program.cs b/Console/Program.cs index 271026e9..628d15e5 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -386,10 +386,12 @@ private static void DisassembleAndThenAssemble(string input) static void Main(string[] args) { - // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/netcoreapp2.1/TinyCsvParser.Test.dll"; - // var input = "../../../../../../Desktop/netcoreapp2.1/TinyCsvParser.Test.dll"; - // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/netcoreapp2.1/TinyCsvParser.dll"; - var input = "../../../../C-Sharp-Algorithms/Algorithms/bin/Debug/netcoreapp2.0/Algorithms.dll"; + var input = "../../../Examples/bin/Debug/Examples.dll"; + // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll"; + // var input = "../../../../TinyCsvParser/TinyCsvParser/SelectedTests/bin/Debug/net45/SelectedTests.dll"; + // var input = "../../../../DSA/DSA/DSA-Selected-Tests/bin/Debug/net45/DSA-Selected-Tests.dll"; + // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll"; + // var input = "../../../../C-Sharp-Algorithms/Algorithms/bin/Debug/netcoreapp2.0/Algorithms.dll"; DisassembleAndThenAssemble(input); //RunSomeTests(); diff --git a/Examples/Examples.cs b/Examples/Examples.cs index e6749037..c62133ed 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection.Metadata; -using Accessibility; using Classes; using Hierarchy; using Nested.NestedNamespace.NestedNestedNamesace; +using NUnit.Framework; using Structs; namespace Enums @@ -364,10 +365,6 @@ public sealed override void CanImplement() public class ClassDerivedFromSystemClass : Exception { } - - public class ClassDerivedFromAccessibilityClass : CAccPropServicesClass - { - } } namespace Nested @@ -1033,4 +1030,52 @@ public void ExceptionHandlingTryCatchFinally(Exception e) } }*/ } +} + +namespace Attributes +{ + [Flags] + public enum ColoursFlags + { + Red = 1, + Blue = 2, + Pink = 4, + Green = 8 + } + + [ExcludeFromCodeCoverage, Obsolete("no use")] + public class AnnotatedClass + { + [Obsolete] public int ObsoleteProperty { get; set; } + [Obsolete] public int obsoleteField; + + [Obsolete("Method is obsolete", true)] + public void Method() + { + } + } +} + +namespace Tests +{ + [TestFixture] + public class TestSuite + { + [SetUp] + public void SetUp() + { + } + + [Test] + public void Test() + { + Assert.AreEqual(1, 1); + } + + [Test] + public void AnotherTest() + { + Assert.AreEqual(1, 1); + } + } } \ No newline at end of file diff --git a/Examples/Examples.csproj b/Examples/Examples.csproj index f25abb3f..d84fa2e3 100644 --- a/Examples/Examples.csproj +++ b/Examples/Examples.csproj @@ -1,5 +1,7 @@ + + Debug AnyCPU @@ -29,6 +31,10 @@ true + + ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll + True + @@ -46,4 +52,11 @@ + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. + + + + \ No newline at end of file diff --git a/Examples/packages.config b/Examples/packages.config index 3b5ff6d1..2f05e2f2 100644 --- a/Examples/packages.config +++ b/Examples/packages.config @@ -1,5 +1,7 @@  + + \ No newline at end of file diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index d5c01fa0..c80cb8bc 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -28,7 +28,7 @@ public void Generate(Assembly assembly) header: peHeaderBuilder, metadataRootBuilder: new ECMA335.MetadataRootBuilder(metadataContainer.metadataBuilder), ilStream: metadataContainer.methodBodyStream.Builder, - entryPoint: metadataContainer.MainMethodHandle ?? default + entryPoint: assembly.Kind.Equals(AssemblyKind.EXE) ? metadataContainer.MainMethodHandle : default ).Serialize(peBlob); peBlob.WriteContentTo(peStream); } diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index b543ecb0..7a93e810 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection.Metadata.Ecma335; using MetadataGenerator.Metadata; using Model; using SR = System.Reflection; @@ -23,12 +24,25 @@ public static MetadataContainer Generate(Assembly assembly) ); var moduleName = $"{assembly.Name}.{(assembly.Kind == AssemblyKind.EXE ? "exe" : "dll")}"; - metadataBuilder.AddModule( + metadataContainer.ModuleHandle = metadataBuilder.AddModule( generation: 0, moduleName: metadataBuilder.GetOrAddString(moduleName), mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), encId: default, encBaseId: default); + + /* + * CLI defines a special class, named , that does not have a base type and does not implement any interfaces. + * (This class is a toplevel class; i.e., it is not nested.). Used as owner of global members (methods, fields). + */ + metadataBuilder.AddTypeDefinition( + attributes: default, + @namespace: default, + name: metadataBuilder.GetOrAddString(""), + baseType: default, + fieldList: MetadataTokens.FieldDefinitionHandle(1), + methodList: MetadataTokens.MethodDefinitionHandle(1)); + foreach (var namezpace in assembly.RootNamespace.Namespaces) { diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 4fd94fa3..10334512 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -43,9 +43,15 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) maxStack: maxStack); } + var methodImplementationAttributes = + SR.MethodImplAttributes.IL | + (!method.HasBody && !method.IsAbstract // FIXME Could also be PinvokeImpl or InternalCall in some special cases + ? SR.MethodImplAttributes.Runtime + : SR.MethodImplAttributes.Managed); + var methodDefinitionHandle = metadataContainer.metadataBuilder.AddMethodDefinition( attributes: GetMethodAttributesFor(method), - implAttributes: SR.MethodImplAttributes.IL | SR.MethodImplAttributes.Managed, + implAttributes: methodImplementationAttributes, name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), signature: metadataContainer.metadataBuilder.GetOrAddBlob(methodSignature), bodyOffset: methodBodyOffset, diff --git a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs b/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs index 8783cf25..4a7b027a 100644 --- a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs @@ -35,14 +35,6 @@ internal MethodParametersGenerator(MetadataContainer metadataContainer) { firstParameterHandle = parameterHandle; } - - /* TODO add custom attributes (ex: varargs), see ECMA under custom attributes - metadataContainer.metadataBuilder.AddCustomAttribute( - parameter handle, - some handle, - value - ) - */ } return firstParameterHandle; diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index c7805f96..e63d4451 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -2,6 +2,7 @@ using System.Linq; using MetadataGenerator.Generators.Fields; using MetadataGenerator.Generators.Methods; +using MetadataGenerator.Generators.Methods.Body; using MetadataGenerator.Metadata; using Model.Types; using static MetadataGenerator.Metadata.AttributesProvider; @@ -95,16 +96,27 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) * - For a normal generic type, arity is the number of type parameters declared on the type. * - For a nested generic type, arity is the number of newly introduced type parameters. */ - private static string TypeNameOf(TypeDefinition type) + public static string TypeNameOf(IBasicType type) { var typeName = type.Name; if (type.IsGenericType()) { if (type.ContainingType != null) { - var containingTypeGenericParameters = type.ContainingType.GenericParameters.Select(p => p.Name).ToList(); + IList GenericParametersNamesOf(IBasicType iBasicType) + { + switch (iBasicType) + { + case BasicType bt: return bt.GenericArguments.Select(elem => ((IBasicType) elem).Name).ToList(); + case TypeDefinition td: return td.GenericParameters.Select(elem => elem.Name).ToList(); + default: throw new UnhandledCase(); + } + } + + var containingTypeGenericParameters = GenericParametersNamesOf(type.ContainingType); var newlyIntroducedGenericParametersCount = - type.GenericParameters.Count(parameter => !containingTypeGenericParameters.Contains(parameter.Name)); + GenericParametersNamesOf(type).Count(parameter => !containingTypeGenericParameters.Contains(parameter)); + if (newlyIntroducedGenericParametersCount > 0) { typeName = $"{typeName}`{newlyIntroducedGenericParametersCount}"; @@ -112,7 +124,7 @@ private static string TypeNameOf(TypeDefinition type) } else { - typeName = $"{typeName}`{type.GenericParameters.Count}"; + typeName = $"{typeName}`{type.GenericParameterCount}"; } } diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 6b23464e..7bcc49b7 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -15,13 +15,14 @@ internal class MetadataContainer public readonly MetadataResolver metadataResolver; public readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; private SRM.MethodDefinitionHandle? mainMethodHandle; + private SRM.ModuleDefinitionHandle? moduleHandle; private readonly ISet genericParameterRows = new HashSet(); private readonly ISet nestedTypeRows = new HashSet(); private readonly ISet interfaceImplementationRows = new HashSet(); - public SRM.MethodDefinitionHandle? MainMethodHandle + public SRM.MethodDefinitionHandle MainMethodHandle { - get => mainMethodHandle; + get => mainMethodHandle ?? throw new Exception("Main method handle was not set"); set { if (mainMethodHandle != null) throw new Exception("Assembly has more than one main method"); @@ -29,6 +30,16 @@ public SRM.MethodDefinitionHandle? MainMethodHandle } } + public SRM.ModuleDefinitionHandle ModuleHandle + { + get => moduleHandle ?? throw new Exception("Module handle was not set"); + set + { + if (moduleHandle != null) throw new Exception("Multiple modules not supported"); + moduleHandle = value; + } + } + public MetadataContainer(Assembly assembly) { metadataBuilder = new ECMA335.MetadataBuilder(); diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 70e741c3..70d42293 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -5,12 +5,17 @@ using MetadataGenerator.Generators.Fields; using MetadataGenerator.Generators.Methods; using MetadataGenerator.Generators.Methods.Body; +using Model; using Model.Types; using static System.Linq.Enumerable; +using static MetadataGenerator.Generators.TypeGenerator; using Assembly = Model.Assembly; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; +// TODO revisar si esas keys que pongo en los getOrAdd (al ser mas precisas) estan funcionando o hacen que siempre se agregue uno nuevo +// TODO para esto comparar sin guardar ninguna cuanto da el conteo de las tablas y guardando despues. +// TODO ver si conviene usar blobhandle, byteArray de la signature u otro. Evaluarlo tabla por tabla, quiza algunas andan bien y otras no namespace MetadataGenerator.Metadata { internal class MetadataResolver @@ -20,14 +25,14 @@ internal class MetadataResolver private readonly IDictionary assemblyReferences = new Dictionary(); private readonly IDictionary typeReferences = new Dictionary(); - private readonly IDictionary, SRM.MemberReferenceHandle> memberReferences = - new Dictionary, SRM.MemberReferenceHandle>(); + private readonly IDictionary, SRM.MemberReferenceHandle> memberReferences = + new Dictionary, SRM.MemberReferenceHandle>(); - private readonly IDictionary typeSpecificationReferences = - new Dictionary(); + private readonly IDictionary, SRM.TypeSpecificationHandle> typeSpecificationReferences = + new Dictionary, SRM.TypeSpecificationHandle>(); - private readonly IDictionary methodSpecificationReferences = - new Dictionary(); + private readonly IDictionary, SRM.MethodSpecificationHandle> methodSpecificationReferences = + new Dictionary, SRM.MethodSpecificationHandle>(); private readonly IDictionary standaloneSignatureReferences = new Dictionary(); @@ -42,7 +47,7 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) foreach (var assemblyReference in assembly.References) { - // TODO version,culture and others should be in the assemblyReference. Submit PR with this + // TODO culture and others should be in the assemblyReference. Submit PR with this assemblyReferences.Add(assemblyReference.Name, metadataContainer.metadataBuilder.AddAssemblyReference( name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), version: assemblyReference.Version, @@ -95,36 +100,16 @@ private SRM.EntityHandle GetOrAddTypeReference(IBasicType type) { if (type.IsGenericInstantiation()) return GetOrAddTypeSpecificationFor(type); - var typeName = type.Name; - - // FIXME partial logic. See TypeGenerator.TypeNameOf. Needs to be unified with that - if (type.IsGenericType()) - { - typeName = $"{type.Name}`{type.GenericParameterCount}"; - } - - var key = - $"{type.ContainingAssembly.Name}.{type.ContainingNamespace}.{(type.ContainingType != null ? (type.ContainingType.Name + ".") : "")}{typeName}"; + var typeName = TypeNameOf(type); + var key = type.GetFullName(); if (!typeReferences.TryGetValue(key, out var typeReference)) { SRM.EntityHandle resolutionScope; if (type.ContainingType == null) // if defined in the namespace then search there { - try - { - resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) - ? default - : assemblyReferences[type.ContainingAssembly.Name]; - } - // FIXME mmmmmm - catch (KeyNotFoundException) - { - if (PlatformTypes.Includes(type)) - { - resolutionScope = assemblyReferences["System.Runtime"]; - } - else throw; - } + resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) + ? metadataContainer.ModuleHandle + : (SRM.EntityHandle) assemblyReferences[type.ContainingAssembly.Name]; } else { @@ -148,10 +133,11 @@ private SRM.TypeSpecificationHandle GetOrAddTypeSpecificationFor(IType type) var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); Encode(type, encoder); var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); - if (!typeSpecificationReferences.TryGetValue(blobHandle, out var typeSpecification)) + var key = new Tuple(type.GetFullName(), blobHandle); + if (!typeSpecificationReferences.TryGetValue(key, out var typeSpecification)) { typeSpecification = metadataContainer.metadataBuilder.AddTypeSpecification(blobHandle); - typeSpecificationReferences.Add(blobHandle, typeSpecification); + typeSpecificationReferences.Add(key, typeSpecification); } return typeSpecification; @@ -159,14 +145,18 @@ private SRM.TypeSpecificationHandle GetOrAddTypeSpecificationFor(IType type) private SRM.MethodSpecificationHandle GetOrAddMethodSpecificationFor(IMethodReference method, SRM.BlobBuilder signature) { - var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); - if (!methodSpecificationReferences.TryGetValue(blobHandle, out var methodSpecification)) + var genericMethodSignature = methodSignatureGenerator.GenerateSignatureOf(method.GenericMethod); + var key = new Tuple( + $"{method.GenericMethod.ContainingType.GetFullName()}.{method.GenericName}", + genericMethodSignature.ToArray() + ); + if (!methodSpecificationReferences.TryGetValue(key, out var methodSpecification)) { methodSpecification = metadataContainer.metadataBuilder.AddMethodSpecification( - GetOrAddMethodReference(method.GenericMethod, methodSignatureGenerator.GenerateSignatureOf(method.GenericMethod)), - blobHandle + GetOrAddMethodReference(method.GenericMethod, genericMethodSignature), + metadataContainer.metadataBuilder.GetOrAddBlob(signature) ); - methodSpecificationReferences.Add(blobHandle, methodSpecification); + methodSpecificationReferences.Add(key, methodSpecification); } return methodSpecification; @@ -194,8 +184,7 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl { var parentHandle = GetOrAddTypeSpecificationFor(arrayTypeWrapper.Type); var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); - // FIXME sera suficiente? Hay que revisar todas las keys que uso en estos metodos a ver si tienen sentido - var key = new KeyValuePair(parentHandle, blobHandle); + var key = new Tuple(parentHandle, blobHandle); if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) { methodReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( @@ -210,8 +199,8 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl else { var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); - var key = new KeyValuePair( - $"{method.ContainingType.ContainingAssembly.Name}.{method.ContainingType.ContainingNamespace}.{method.ContainingType.GenericName}.{method.Name}", + var key = new Tuple( + $"{method.ContainingType.GetFullName()}.{method.GenericName}", blobHandle ); if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) @@ -230,8 +219,8 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field, SRM.BlobBuilder signature) { var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); - var key = new KeyValuePair( - $"{field.ContainingType.ContainingAssembly.Name}.{field.ContainingType.ContainingNamespace}.{field.ContainingType.GenericName}.{field.Name}", + var key = new Tuple( + $"{field.ContainingType.GetFullName()}.{field.Name}", blobHandle ); if (!memberReferences.TryGetValue(key, out var memberReferenceHandle)) @@ -272,23 +261,23 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { switch (type) { - case IBasicType basicType: + case IBasicType iBasicType: { var isValueType = type.TypeKind == TypeKind.ValueType; - if (basicType.IsGenericInstantiation()) + if (iBasicType.IsGenericInstantiation()) { var genericInstantiation = encoder.GenericInstantiation( - GetOrAddTypeReference(basicType.GenericType), - basicType.GenericArguments.Count, + GetOrAddTypeReference(iBasicType.GenericType), + iBasicType.GenericArguments.Count, isValueType); - foreach (var genericArg in basicType.GenericArguments) + foreach (var genericArg in iBasicType.GenericArguments) { Encode(genericArg, genericInstantiation.AddArgument()); } } else { - encoder.Type(GetOrAddTypeReference(basicType), isValueType); + encoder.Type(GetOrAddTypeReference(iBasicType), isValueType); } break; diff --git a/Model/Extensions.cs b/Model/Extensions.cs index 8ba54658..4c9e79c3 100644 --- a/Model/Extensions.cs +++ b/Model/Extensions.cs @@ -160,6 +160,10 @@ public static string GetFullName(this IType type) var pointerType = type as PointerType; var targetType = GetFullName(pointerType.TargetType); result = string.Format("{0}*", targetType); + } + else if (type is IGenericParameterReference genericParameterReference) + { + result = genericParameterReference.Name; } return result; From c9adf8119c6ca60d0478760730ff18d5df8347d9 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 10 Apr 2020 10:25:22 -0300 Subject: [PATCH 119/256] fix property map --- MetadataGenerator/Generators/TypeGenerator.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index e63d4451..35607978 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -46,10 +46,6 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) methodDefToHandle.Add(method, methodHandle); } - var propertyDefinitionHandles = type.PropertyDefinitions - .Select(property => propertyGenerator.Generate(property, methodDefToHandle)) - .ToList(); - var nextFieldDefinitionHandle = ECMA335.MetadataTokens.FieldDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.Field)); var nextMethodDefinitionHandle = ECMA335.MetadataTokens.MethodDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.MethodDef)); var nextPropertyDefinitionHandle = @@ -62,7 +58,14 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) fieldList: fieldDefinitionHandles.FirstOr(nextFieldDefinitionHandle), methodList: methodDefinitionHandles.FirstOr(nextMethodDefinitionHandle)); - metadataContainer.metadataBuilder.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandles.FirstOr(nextPropertyDefinitionHandle)); + var firstPropertyDefinitionHandle = type.PropertyDefinitions + .Select(property => propertyGenerator.Generate(property, methodDefToHandle)) + .FirstOrDefault(); + + if (!firstPropertyDefinitionHandle.IsNil) + { + metadataContainer.metadataBuilder.AddPropertyMap(typeDefinitionHandle, firstPropertyDefinitionHandle); + } foreach (var interfaze in type.Interfaces) { From d633147ed1b8e6f8f074b710afbdbdda25bf6887 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 10 Apr 2020 10:50:02 -0300 Subject: [PATCH 120/256] more fixes --- MetadataProvider/AssemblyExtractor.cs | 92 +++++++++++++---------- MetadataProvider/SignatureTypeProvider.cs | 10 --- Model/Types/TypeDefinitions.cs | 7 +- 3 files changed, 58 insertions(+), 51 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index feaa58fd..ff6f7e46 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -58,14 +58,19 @@ public TypeDefinition GetDefinedType(SRM.TypeDefinitionHandle handle) { var typedef = metadata.GetTypeDefinition(handle); var name = metadata.GetString(typedef.Name); - name = GetGenericName(name, out var genericParameterCount); + name = GetGenericName(name); result = new TypeDefinition(name) { - GenericParameterCount = genericParameterCount, ContainingAssembly = assembly, ContainingNamespace = currentNamespace }; + + foreach (var genericParameterHandle in typedef.GetGenericParameters()) + { + ExtractGenericParameter(GenericParameterKind.Type, result, genericParameterHandle); + } + definedTypes.Add(handle, result); } @@ -81,13 +86,14 @@ public MethodDefinition GetDefinedMethod(SRM.MethodDefinitionHandle handle) { var methoddef = metadata.GetMethodDefinition(handle); var name = metadata.GetString(methoddef.Name); - name = GetGenericName(name, out _); + name = GetGenericName(name); result = new MethodDefinition(name, null); foreach (var genericParameterHandle in methoddef.GetGenericParameters()) { ExtractGenericParameter(GenericParameterKind.Method, result, genericParameterHandle); } + definedMethods.Add(handle, result); } @@ -190,13 +196,11 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) } type.ContainingType = currentType; - type.ContainingAssembly = assembly; - type.ContainingNamespace = currentNamespace; currentType = type; - foreach (var handle in typedef.GetGenericParameters()) + foreach (var genericParameter in type.GenericParameters) { - ExtractGenericParameter(GenericParameterKind.Type, type, handle); + defGenericContext.TypeParameters.Add(genericParameter); } ExtractBaseType(typedef.BaseType); @@ -396,19 +400,6 @@ private void ExtractGenericParameter(GenericParameterKind parameterKind, IGeneri GenericContainer = genericContainer }; - if (parameterKind == GenericParameterKind.Type) - { - defGenericContext.TypeParameters.Add(genericParameter); - } - else if (parameterKind == GenericParameterKind.Method) - { - defGenericContext.MethodParameters.Add(genericParameter); - } - else - { - throw parameterKind.ToUnknownValueException(); - } - genericContainer.GenericParameters.Add(genericParameter); } @@ -460,7 +451,7 @@ private void ExtractProperty(SRM.PropertyDefinitionHandle handle) Getter = !getter.IsNil ? GetDefinedMethod(getter) : default, Setter = !setter.IsNil ? GetDefinedMethod(setter) : default, ContainingType = currentType, - IsInstanceProperty = signature.Header.IsInstance + IsStatic = !signature.Header.IsInstance }; currentType.PropertyDefinitions.Add(property); BindGenericParameterReferences(GenericParameterKind.Type, currentType); @@ -482,9 +473,9 @@ private void ExtractMethod(SRM.MethodDefinitionHandle methoddefHandle) currentType.Methods.Add(method); currentMethod = method; - foreach (var handle in methoddef.GetGenericParameters()) + foreach (var genericParameter in method.GenericParameters) { - ExtractGenericParameter(GenericParameterKind.Method, method, handle); + defGenericContext.MethodParameters.Add(genericParameter); } var signature = methoddef.DecodeSignature(signatureTypeProvider, defGenericContext); @@ -940,10 +931,16 @@ private IInstruction ExtractInstruction(ILInstruction operation) break; case SRM.ILOpCode.Ldfld: + instruction = ProcessLoadField(operation, false); + break; case SRM.ILOpCode.Ldsfld: + instruction = ProcessLoadField(operation, true); + break; case SRM.ILOpCode.Ldflda: + instruction = ProcessLoadField(operation, false); + break; case SRM.ILOpCode.Ldsflda: - instruction = ProcessLoadField(operation); + instruction = ProcessLoadField(operation, true); break; case SRM.ILOpCode.Ldftn: @@ -1058,8 +1055,10 @@ private IInstruction ExtractInstruction(ILInstruction operation) break; case SRM.ILOpCode.Stfld: + instruction = ProcessStoreField(operation, false); + break; case SRM.ILOpCode.Stsfld: - instruction = ProcessStoreField(operation); + instruction = ProcessStoreField(operation, true); break; case SRM.ILOpCode.Stind_i: @@ -1544,11 +1543,12 @@ private IInstruction ProcessLoadIndirect(ILInstruction op) return instruction; } - private IInstruction ProcessLoadField(ILInstruction op) + private IInstruction ProcessLoadField(ILInstruction op, bool isStatic) { var operation = OperationHelper.ToLoadFieldOperation(op.Opcode); var field = GetOperand(op); + SetFieldStaticProperty(field, isStatic); var instruction = new LoadFieldInstruction(op.Offset, operation, field); return instruction; } @@ -1588,10 +1588,11 @@ private IInstruction ProcessStoreLocal(ILInstruction op) return instruction; } - private IInstruction ProcessStoreField(ILInstruction op) + private IInstruction ProcessStoreField(ILInstruction op, bool isStatic) { var field = GetOperand(op); - + + SetFieldStaticProperty(field, isStatic); var instruction = new StoreFieldInstruction(op.Offset, field); return instruction; } @@ -1615,11 +1616,7 @@ private IInstruction ProcessConversion(ILInstruction op) var unsigned = OperationHelper.OperandsAreUnsigned(op.Opcode); var type = GetOperand(op); - if (operation == ConvertOperation.Box && type.TypeKind == TypeKind.ValueType) - { - type = PlatformTypes.Object; - } - else if (operation == ConvertOperation.Conv) + if (operation == ConvertOperation.Conv) { type = OperationHelper.GetOperationType(op.Opcode); } @@ -1632,19 +1629,38 @@ private IInstruction ProcessConversion(ILInstruction op) #endregion - private static string GetGenericName(string name, out int genericParameterCount) + private static string GetGenericName(string name) { var start = name.LastIndexOf('`'); - genericParameterCount = 0; - + if (start > -1) { - var count = name.Substring(start + 1); - genericParameterCount = Convert.ToInt32(count); name = name.Remove(start); } return name; } + + // FIXME + // Metadata static indicator for FieldReferences (!signatureHeader.IsInstance) appears to be incorrect when read. Maybe it is updated when + // it can resolve the reference. So field isStatic is ensured with the field operation kind (ex: stsfld => static, ldfld => not static) + private static void SetFieldStaticProperty(IFieldReference field, bool isStatic) + { + switch (field) + { + case FieldReference fieldReference: + { + fieldReference.IsStatic = isStatic; + break; + } + case FieldDefinition fieldDefinition: + { + fieldDefinition.IsStatic = isStatic; + break; + } + default: throw new Exception("case not handled"); + + } + } } } \ No newline at end of file diff --git a/MetadataProvider/SignatureTypeProvider.cs b/MetadataProvider/SignatureTypeProvider.cs index e6e921db..a17fdc13 100644 --- a/MetadataProvider/SignatureTypeProvider.cs +++ b/MetadataProvider/SignatureTypeProvider.cs @@ -174,16 +174,6 @@ public virtual IType GetPinnedType(IType targetType) public virtual IType GetGenericInstantiation(IType genericType, ImmutableArray genericArguments) { var result = genericType as IBasicType; - switch (result) - { - case BasicType basicType: - basicType.GenericParameterCount = genericArguments.Length; - break; - case TypeDefinition typeDefinition: - typeDefinition.GenericParameterCount = genericArguments.Length; - break; - } - result = result.Instantiate(genericArguments); return result; } diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 7f4b1475..4271ec11 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -397,7 +397,7 @@ public override bool Equals(object obj) return result; } } - public class PropertyDefinition : ITypeMemberDefinition + public class PropertyDefinition : ITypeMemberDefinition, IMetadataReference { public PropertyDefinition(string name, IType propType) { @@ -416,7 +416,7 @@ IBasicType ITypeMemberReference.ContainingType { get { return this.ContainingType; } } - public bool IsInstanceProperty { get; set; } + public bool IsStatic { get; set; } public bool MatchReference(ITypeMemberReference member) { if (member is PropertyDefinition) @@ -684,7 +684,8 @@ public class TypeDefinition : IBasicType, IGenericDefinition, ITypeMemberDefinit public IBasicType UnderlayingType { get; set; } public ISet PropertyDefinitions { get; private set; } - public int GenericParameterCount { get; set; } + public int GenericParameterCount => GenericParameters.Count; + public TypeDefinition(string name, TypeKind typeKind = TypeKind.Unknown, TypeDefinitionKind kind = TypeDefinitionKind.Unknown) { this.Name = name; From fe5f16b8b8876cb8cad19ba0602867574b0191a8 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 10 Apr 2020 11:10:02 -0300 Subject: [PATCH 121/256] missing merge --- MetadataProvider/AssemblyExtractor.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 40c1d5b1..9bd2526e 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -204,8 +204,6 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) } type.ContainingType = currentType; - type.ContainingAssembly = assembly; - type.ContainingNamespace = currentNamespace; if (typedef.Attributes.HasFlag(SR.TypeAttributes.Abstract)) { if (typedef.Attributes.HasFlag(SR.TypeAttributes.Sealed)) From c23b1e61f87b5f5d873432a5d183d065ffdd627b Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 10 Apr 2020 11:12:45 -0300 Subject: [PATCH 122/256] fix merge --- MetadataGenerator/Generators/PropertyGenerator.cs | 2 +- MetadataGenerator/Metadata/MetadataResolver.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/MetadataGenerator/Generators/PropertyGenerator.cs b/MetadataGenerator/Generators/PropertyGenerator.cs index 535388ef..1ef60a15 100644 --- a/MetadataGenerator/Generators/PropertyGenerator.cs +++ b/MetadataGenerator/Generators/PropertyGenerator.cs @@ -22,7 +22,7 @@ public SRM.PropertyDefinitionHandle Generate( { var signature = new SRM.BlobBuilder(); new ECMA335.BlobEncoder(signature) - .PropertySignature(isInstanceProperty: property.IsInstanceProperty) + .PropertySignature(isInstanceProperty: !property.IsStatic) .Parameters( parameterCount: 0, returnType: returnTypeEncoder => metadataContainer.metadataResolver.Encode(property.PropertyType, returnTypeEncoder.Type()), diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 70d42293..02858f2c 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -230,8 +230,6 @@ private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field, name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), signature: blobHandle); memberReferences.Add(key, memberReferenceHandle); - - return memberReferenceHandle; } return memberReferenceHandle; From 14b1be0ea1a9fc35fc98b4f545caa45b27409431 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 10 Apr 2020 13:44:28 -0300 Subject: [PATCH 123/256] fix namespace in GetDefinedType --- MetadataProvider/AssemblyExtractor.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index ff6f7e46..8253533a 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -63,7 +63,7 @@ public TypeDefinition GetDefinedType(SRM.TypeDefinitionHandle handle) result = new TypeDefinition(name) { ContainingAssembly = assembly, - ContainingNamespace = currentNamespace + ContainingNamespace = new Namespace(metadata.GetString(typedef.Namespace)) }; foreach (var genericParameterHandle in typedef.GetGenericParameters()) @@ -196,6 +196,8 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) } type.ContainingType = currentType; + type.ContainingAssembly = assembly; + type.ContainingNamespace = currentNamespace; currentType = type; foreach (var genericParameter in type.GenericParameters) From a0a2934f4fdb415dd7531c4b6519dd4c0aa1f953 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 13 Apr 2020 07:42:49 -0300 Subject: [PATCH 124/256] generate missing types at rootnamespace level --- .../Generators/AssemblyGenerator.cs | 25 +++---------------- .../Generators/NamespaceGenerator.cs | 8 +++--- MetadataGenerator/Generators/TypeGenerator.cs | 2 -- .../Metadata/MetadataResolver.cs | 3 +-- 4 files changed, 9 insertions(+), 29 deletions(-) diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index 7a93e810..2c18c9ea 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection.Metadata.Ecma335; using MetadataGenerator.Metadata; using Model; using SR = System.Reflection; @@ -30,29 +29,13 @@ public static MetadataContainer Generate(Assembly assembly) mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), encId: default, encBaseId: default); - - /* - * CLI defines a special class, named , that does not have a base type and does not implement any interfaces. - * (This class is a toplevel class; i.e., it is not nested.). Used as owner of global members (methods, fields). - */ - metadataBuilder.AddTypeDefinition( - attributes: default, - @namespace: default, - name: metadataBuilder.GetOrAddString(""), - baseType: default, - fieldList: MetadataTokens.FieldDefinitionHandle(1), - methodList: MetadataTokens.MethodDefinitionHandle(1)); - - foreach (var namezpace in assembly.RootNamespace.Namespaces) - { - namespaceGenerator.Generate(namezpace); - } + namespaceGenerator.Generate(assembly.RootNamespace); /* - * Some tables must be sorted by one or more of their columns. Since the dll's methods and types don't follow a - * particular order, the info needed to load this tables is stored during type/method generation but not added to the MetadataBuilder until now - * where they can be previously sorted + * Some tables must be sorted by one or more of their columns. Since the dll's methods and types don't follow a + * particular order, the info needed to load this tables is stored during type/method generation but not added to the MetadataBuilder + * until now where they can be previously sorted */ metadataContainer.GenerateInterfaceImplementations(); metadataContainer.GenerateGenericParameters(); diff --git a/MetadataGenerator/Generators/NamespaceGenerator.cs b/MetadataGenerator/Generators/NamespaceGenerator.cs index ac6e787e..a475184f 100644 --- a/MetadataGenerator/Generators/NamespaceGenerator.cs +++ b/MetadataGenerator/Generators/NamespaceGenerator.cs @@ -19,14 +19,14 @@ public NamespaceGenerator(MetadataContainer metadataContainer) public void Generate(Namespace namezpace) { - foreach (var nestedNamespace in namezpace.Namespaces) + foreach (var type in namezpace.Types) { - Generate(nestedNamespace); + GenerateTypes(type); } - foreach (var type in namezpace.Types) + foreach (var nestedNamespace in namezpace.Namespaces) { - GenerateTypes(type); + Generate(nestedNamespace); } } diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index 35607978..fb0fd379 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -48,8 +48,6 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) var nextFieldDefinitionHandle = ECMA335.MetadataTokens.FieldDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.Field)); var nextMethodDefinitionHandle = ECMA335.MetadataTokens.MethodDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.MethodDef)); - var nextPropertyDefinitionHandle = - ECMA335.MetadataTokens.PropertyDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.Property)); var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( attributes: GetTypeAttributesFor(type), @namespace: metadataBuilder.GetOrAddString(type.ContainingNamespace.FullName), diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 02858f2c..ad2bf562 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -100,7 +100,6 @@ private SRM.EntityHandle GetOrAddTypeReference(IBasicType type) { if (type.IsGenericInstantiation()) return GetOrAddTypeSpecificationFor(type); - var typeName = TypeNameOf(type); var key = type.GetFullName(); if (!typeReferences.TryGetValue(key, out var typeReference)) { @@ -120,7 +119,7 @@ private SRM.EntityHandle GetOrAddTypeReference(IBasicType type) typeReference = metadataContainer.metadataBuilder.AddTypeReference( resolutionScope: resolutionScope, @namespace: metadataContainer.metadataBuilder.GetOrAddString(type.ContainingNamespace), - name: metadataContainer.metadataBuilder.GetOrAddString(typeName)); + name: metadataContainer.metadataBuilder.GetOrAddString(TypeNameOf(type))); typeReferences.Add(key, typeReference); } From affb9d5bcbd0449f1d16ffdd7067877c76623487 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 14 Apr 2020 19:21:12 -0300 Subject: [PATCH 125/256] add culture and public key --- MetadataProvider/AssemblyExtractor.cs | 8 ++++++-- Model/Assembly.cs | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 8253533a..092df7f2 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -123,7 +123,9 @@ public Assembly Extract() var name = metadata.GetString(assemblydef.Name); assembly = new Assembly(name) { - Version = assemblydef.Version + Version = assemblydef.Version, + Culture = metadata.GetString(assemblydef.Culture), + PublicKey = metadata.GetBlobBytes(assemblydef.PublicKey) }; foreach (var handle in metadata.AssemblyReferences) @@ -132,7 +134,9 @@ public Assembly Extract() name = metadata.GetString(referencedef.Name); var reference = new AssemblyReference(name) { - Version = referencedef.Version + Version = referencedef.Version, + Culture = metadata.GetString(referencedef.Culture), + PublicKey = metadata.GetBlobBytes(referencedef.PublicKeyOrToken) }; assembly.References.Add(reference); diff --git a/Model/Assembly.cs b/Model/Assembly.cs index 2d2994a3..c3fc6b29 100644 --- a/Model/Assembly.cs +++ b/Model/Assembly.cs @@ -13,12 +13,16 @@ public interface IAssemblyReference { string Name { get; } Version Version { get; } + string Culture { get; } + byte[] PublicKey { get; } } public class AssemblyReference : IAssemblyReference { public string Name { get; private set; } public Version Version { get; set; } + public string Culture { get; set; } + public byte[] PublicKey { get; set; } public AssemblyReference(string name) { @@ -52,6 +56,8 @@ public class Assembly : IAssemblyReference public IList References { get; private set; } public Namespace RootNamespace { get; set; } public Version Version { get; set; } + public string Culture { get; set; } + public byte[] PublicKey { get; set; } public Assembly(string name) { this.Name = name; From dfa503e71ced12af396d9315c0a13b7c52337bea Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 14 Apr 2020 19:39:18 -0300 Subject: [PATCH 126/256] culture and public key on assembly and assemblyreferences --- Console/Program.cs | 6 +++--- MetadataGenerator/Generator.cs | 3 ++- MetadataGenerator/Generators/AssemblyGenerator.cs | 4 ++-- MetadataGenerator/Metadata/MetadataResolver.cs | 9 +++------ 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index 628d15e5..ae3349ad 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -1,4 +1,4 @@ -// Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. +// Copyright (c) Edgardo Zoppi. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. using System; using System.Collections.Generic; @@ -386,11 +386,11 @@ private static void DisassembleAndThenAssemble(string input) static void Main(string[] args) { - var input = "../../../Examples/bin/Debug/Examples.dll"; + // var input = "../../../Examples/bin/Debug/Examples.dll"; // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll"; // var input = "../../../../TinyCsvParser/TinyCsvParser/SelectedTests/bin/Debug/net45/SelectedTests.dll"; // var input = "../../../../DSA/DSA/DSA-Selected-Tests/bin/Debug/net45/DSA-Selected-Tests.dll"; - // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll"; + var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll"; // var input = "../../../../C-Sharp-Algorithms/Algorithms/bin/Debug/netcoreapp2.0/Algorithms.dll"; DisassembleAndThenAssemble(input); diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index c80cb8bc..f175e534 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -28,7 +28,8 @@ public void Generate(Assembly assembly) header: peHeaderBuilder, metadataRootBuilder: new ECMA335.MetadataRootBuilder(metadataContainer.metadataBuilder), ilStream: metadataContainer.methodBodyStream.Builder, - entryPoint: assembly.Kind.Equals(AssemblyKind.EXE) ? metadataContainer.MainMethodHandle : default + entryPoint: assembly.Kind.Equals(AssemblyKind.EXE) ? metadataContainer.MainMethodHandle : default, + flags: SRPE.CorFlags.ILOnly | SRPE.CorFlags.StrongNameSigned ).Serialize(peBlob); peBlob.WriteContentTo(peStream); } diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index 2c18c9ea..5d015aaa 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -16,8 +16,8 @@ public static MetadataContainer Generate(Assembly assembly) metadataBuilder.AddAssembly( name: metadataBuilder.GetOrAddString(assembly.Name), version: assembly.Version, - culture: default, - publicKey: default, + culture: metadataContainer.metadataBuilder.GetOrAddString(assembly.Culture), + publicKey: metadataContainer.metadataBuilder.GetOrAddBlob(assembly.PublicKey), flags: SR.AssemblyFlags.PublicKey, hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1 ); diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index ad2bf562..36024c82 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Reflection; using MetadataGenerator.Generators.Fields; using MetadataGenerator.Generators.Methods; using MetadataGenerator.Generators.Methods.Body; @@ -9,7 +8,6 @@ using Model.Types; using static System.Linq.Enumerable; using static MetadataGenerator.Generators.TypeGenerator; -using Assembly = Model.Assembly; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -47,13 +45,12 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) foreach (var assemblyReference in assembly.References) { - // TODO culture and others should be in the assemblyReference. Submit PR with this assemblyReferences.Add(assemblyReference.Name, metadataContainer.metadataBuilder.AddAssemblyReference( name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), version: assemblyReference.Version, - culture: default, - publicKeyOrToken: default, - flags: AssemblyFlags.PublicKey, + culture: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Culture), + publicKeyOrToken: metadataContainer.metadataBuilder.GetOrAddBlob(assemblyReference.PublicKey), + flags: default, hashValue: default) ); } From b3fc58ba33a5dd21541c568ddb695cd192058e1f Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 14 Apr 2020 20:06:06 -0300 Subject: [PATCH 127/256] generic parameter constraints --- Examples/Examples.cs | 6 +-- .../Metadata/MetadataContainer.cs | 41 ++++++++++++++----- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index c62133ed..bdf5571a 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -455,15 +455,13 @@ public class PointersAndReferenceClass namespace Generics { - public class Generic where D : Exception // FIXME generic constraint not in the model + public class Generic where D : Exception where E : EmptyClass { public C genericClassTypeField; public Dictionary genericField; public IList> listOfListField; - // FIXME the assigment is done in the .ctor with a stfld instruction but i'm generating a stsfld instruction. That's because somehow the field that i Receives is static - // FIXME when in reality it is not. Maybe a fault in the model? public readonly List stringList = new List {"holas"}; public IList GetExceptionsList(List _) @@ -481,7 +479,7 @@ public void PrintGeneric(T t) Console.WriteLine(t.ToString()); } - public void MethodWithGenericConstraint(T t) where T : Enum // FIXME generic constraint not in the model + public void MethodWithGenericConstraint(T t) where T : Enum { } diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 7bcc49b7..81fa1679 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using Model; using Model.Types; using Assembly = Model.Assembly; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -58,19 +59,28 @@ private void DoRegisterGenericParameter(SRM.EntityHandle parent, GenericParamete parent, GenericParameterAttributes.None, metadataBuilder.GetOrAddString(genericParameter.Name), - genericParameter.Index)); + genericParameter.Index, + genericParameter.Constraints.Select(type => metadataResolver.HandleOf(type)).ToSet() + )); public void GenerateGenericParameters() => genericParameterRows .OrderBy(row => ECMA335.CodedIndex.TypeOrMethodDef(row.parent)) .ThenBy(row => row.index) .ToList() - .ForEach(row => metadataBuilder.AddGenericParameter( - row.parent, - row.attributes, - row.name, - row.index - )); + .ForEach(row => + { + var genericParameterHandle = metadataBuilder.AddGenericParameter( + row.parent, + row.attributes, + row.name, + row.index + ); + foreach (var constraint in row.constraints) + { + metadataBuilder.AddGenericParameterConstraint(genericParameterHandle, constraint); + } + }); public void RegisterNestedType(SRM.TypeDefinitionHandle type, SRM.TypeDefinitionHandle enclosingType) => nestedTypeRows.Add(new NestedTypeRow(type, enclosingType)); @@ -93,6 +103,8 @@ public void GenerateInterfaceImplementations() => #region Rows + // FIXME hacen falta los equality members? Deberian mirar todos los campos? + private class InterfaceImplementationRow { public readonly SRM.TypeDefinitionHandle type; @@ -138,13 +150,20 @@ private class GenericParamRow public readonly GenericParameterAttributes attributes; public readonly SRM.StringHandle name; public readonly ushort index; + public readonly ISet constraints; - public GenericParamRow(SRM.EntityHandle parent, GenericParameterAttributes attributes, SRM.StringHandle name, ushort index) + public GenericParamRow( + SRM.EntityHandle parent, + GenericParameterAttributes attributes, + SRM.StringHandle name, + ushort index, + ISet constraints) { this.parent = parent; this.attributes = attributes; this.name = name; this.index = index; + this.constraints = constraints; } public override bool Equals(object obj) @@ -152,8 +171,9 @@ public override bool Equals(object obj) if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; - var other = (GenericParamRow) obj; - return parent.Equals(other.parent) && attributes == other.attributes && name.Equals(other.name) && index == other.index; + GenericParamRow other = (GenericParamRow) obj; + return parent.Equals(other.parent) && attributes == other.attributes && name.Equals(other.name) && index == other.index && + Equals(constraints, other.constraints); } public override int GetHashCode() @@ -164,6 +184,7 @@ public override int GetHashCode() hashCode = (hashCode * 397) ^ (int) attributes; hashCode = (hashCode * 397) ^ name.GetHashCode(); hashCode = (hashCode * 397) ^ index.GetHashCode(); + hashCode = (hashCode * 397) ^ (constraints != null ? constraints.GetHashCode() : 0); return hashCode; } } From 696f034b70cbac3fe5e99c36214348c808836b96 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 15 Apr 2020 23:11:44 -0300 Subject: [PATCH 128/256] better constraints --- Examples/Examples.cs | 10 +++++- .../Metadata/AttributesProvider.cs | 33 +++++++++++++++++++ .../Metadata/MetadataContainer.cs | 3 +- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index bdf5571a..5761f0c7 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -5,6 +5,7 @@ using System.Reflection.Metadata; using Classes; using Hierarchy; +using Interfaces; using Nested.NestedNamespace.NestedNestedNamesace; using NUnit.Framework; using Structs; @@ -455,7 +456,14 @@ public class PointersAndReferenceClass namespace Generics { - public class Generic where D : Exception where E : EmptyClass + public class Generic + where D : class + where E : Exception + where F : struct + where G : struct, ISampleInterface + where H : class, new() + // where I : unmanaged FIXME framework read not implemented + // where J : D FIXME framework read is not working { public C genericClassTypeField; public Dictionary genericField; diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index 35b5a787..e9e4f814 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -145,6 +145,39 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para return attributes; } + public static GenericParameterAttributes GetGenericParameterAttributesFor(GenericParameter genericParameter) + { + /* GenericParameterAttributes attributes = GenericParameterAttributes.None; + if (genericParameter.RequiresDefaultConstructor) + { + attributes |= GenericParameterAttributes.DefaultConstructorConstraint; + } + + switch (genericParameter.Variance) + { + case GenericParameterVariance.COVARIANT: + attributes |= GenericParameterAttributes.Covariant; + break; + case GenericParameterVariance.CONTRAVARIANT: + attributes |= GenericParameterAttributes.Contravariant; + break; + } + + switch (genericParameter.TypeKind) + { + case TypeKind.ValueType: + attributes |= GenericParameterAttributes.NotNullableValueTypeConstraint; + break; + case TypeKind.ReferenceType: + attributes |= GenericParameterAttributes.ReferenceTypeConstraint; + break; + } + + return attributes; + */ + return GenericParameterAttributes.None; + } + private static TypeAttributes VisibilityAttributesFor(TypeDefinition typeDefinition) { if (typeDefinition.ContainingType != null) diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 81fa1679..2e52d60f 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -7,6 +7,7 @@ using Assembly = Model.Assembly; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; +using static MetadataGenerator.Metadata.AttributesProvider; namespace MetadataGenerator.Metadata { @@ -57,7 +58,7 @@ public void RegisterGenericParameter(SRM.MethodDefinitionHandle parent, GenericP private void DoRegisterGenericParameter(SRM.EntityHandle parent, GenericParameter genericParameter) => genericParameterRows.Add(new GenericParamRow( parent, - GenericParameterAttributes.None, + GetGenericParameterAttributesFor(genericParameter), metadataBuilder.GetOrAddString(genericParameter.Name), genericParameter.Index, genericParameter.Constraints.Select(type => metadataResolver.HandleOf(type)).ToSet() From 143630d633f913ec97e4c9c1af8129c8a4df193a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 15 Apr 2020 23:25:08 -0300 Subject: [PATCH 129/256] generic parameter constraints --- CCIProvider/TypeExtractor.cs | 26 +++++++++++++++++++++++++- MetadataProvider/AssemblyExtractor.cs | 15 ++++++++++++++- Model/Types/Types.cs | 9 +++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/CCIProvider/TypeExtractor.cs b/CCIProvider/TypeExtractor.cs index 39e813c8..b00bf07b 100644 --- a/CCIProvider/TypeExtractor.cs +++ b/CCIProvider/TypeExtractor.cs @@ -7,7 +7,16 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Microsoft.Cci.MutableCodeModel; +using AssemblyReference = Model.AssemblyReference; using Cci = Microsoft.Cci; +using CustomAttribute = Model.Types.CustomAttribute; +using FieldDefinition = Model.Types.FieldDefinition; +using FieldReference = Model.Types.FieldReference; +using GenericParameter = Model.Types.GenericParameter; +using MethodBody = Model.Types.MethodBody; +using MethodDefinition = Model.Types.MethodDefinition; +using MethodReference = Model.Types.MethodReference; namespace CCIProvider { @@ -810,7 +819,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); diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 91923e0e..e08294a5 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -400,10 +400,23 @@ private void ExtractGenericParameter(GenericParameterKind parameterKind, IGeneri typeKind = TypeKind.ValueType; } + var variance = GenericParameterVariance.NONE; + if (genericParameterdef.Attributes.HasFlag(SR.GenericParameterAttributes.Contravariant)) + { + variance = GenericParameterVariance.CONTRAVARIANT; + } + + if (genericParameterdef.Attributes.HasFlag(SR.GenericParameterAttributes.Covariant)) + { + variance = GenericParameterVariance.COVARIANT; + } + var name = metadata.GetString(genericParameterdef.Name); var genericParameter = new GenericParameter(parameterKind, (ushort)genericParameterdef.Index, name, typeKind) { - GenericContainer = genericContainer + GenericContainer = genericContainer, + Variance = variance, + DefaultConstructorConstraint = genericParameterdef.Attributes.HasFlag(SR.GenericParameterAttributes.DefaultConstructorConstraint) }; genericContainer.GenericParameters.Add(genericParameter); diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index a15346f2..a1c73ecd 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -538,11 +538,20 @@ private static string GetName(GenericParameterKind kind, ushort index) return string.Format("{0}{1}", prefix, index); } } + + public enum GenericParameterVariance + { + COVARIANT, + CONTRAVARIANT, + NONE + } public class GenericParameter : IGenericParameterReference { public ISet Attributes { get; private set; } public ISet Constraints { get; private set; } + public bool DefaultConstructorConstraint { get; set; } + public GenericParameterVariance Variance { get; set; } public TypeKind TypeKind { get; set; } public IGenericDefinition GenericContainer { get; set; } public GenericParameterKind Kind { get; set; } From 905a56619eaf2a5a5659d140f81319905046238a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 15 Apr 2020 23:33:41 -0300 Subject: [PATCH 130/256] fix --- CCIProvider/TypeExtractor.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/CCIProvider/TypeExtractor.cs b/CCIProvider/TypeExtractor.cs index b00bf07b..b0b31929 100644 --- a/CCIProvider/TypeExtractor.cs +++ b/CCIProvider/TypeExtractor.cs @@ -7,16 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Microsoft.Cci.MutableCodeModel; -using AssemblyReference = Model.AssemblyReference; using Cci = Microsoft.Cci; -using CustomAttribute = Model.Types.CustomAttribute; -using FieldDefinition = Model.Types.FieldDefinition; -using FieldReference = Model.Types.FieldReference; -using GenericParameter = Model.Types.GenericParameter; -using MethodBody = Model.Types.MethodBody; -using MethodDefinition = Model.Types.MethodDefinition; -using MethodReference = Model.Types.MethodReference; namespace CCIProvider { From fa78c9533f31e67dd48392c8231137ef1f211e4c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 15 Apr 2020 23:37:24 -0300 Subject: [PATCH 131/256] remove unused method --- Model/Types/Types.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index a1c73ecd..88e701e1 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -37,9 +37,6 @@ public interface IReferenceType : IType public static class PlatformTypes { - public static Boolean Includes(IType type) => platformTypes.FirstOrDefault(type.Equals) != null; - - private static readonly ICollection platformTypes = new List(); public static readonly UnknownType Unknown = UnknownType.Value; From a06da309311f98bf4a8074219b260be9dd610da1 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 15 Apr 2020 23:40:20 -0300 Subject: [PATCH 132/256] uncomment --- .../Metadata/AttributesProvider.cs | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index e9e4f814..e520216d 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -147,35 +147,33 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para public static GenericParameterAttributes GetGenericParameterAttributesFor(GenericParameter genericParameter) { - /* GenericParameterAttributes attributes = GenericParameterAttributes.None; - if (genericParameter.RequiresDefaultConstructor) - { - attributes |= GenericParameterAttributes.DefaultConstructorConstraint; - } - - switch (genericParameter.Variance) - { - case GenericParameterVariance.COVARIANT: - attributes |= GenericParameterAttributes.Covariant; - break; - case GenericParameterVariance.CONTRAVARIANT: - attributes |= GenericParameterAttributes.Contravariant; - break; - } - - switch (genericParameter.TypeKind) - { - case TypeKind.ValueType: - attributes |= GenericParameterAttributes.NotNullableValueTypeConstraint; - break; - case TypeKind.ReferenceType: - attributes |= GenericParameterAttributes.ReferenceTypeConstraint; - break; - } - - return attributes; - */ - return GenericParameterAttributes.None; + GenericParameterAttributes attributes = GenericParameterAttributes.None; + if (genericParameter.DefaultConstructorConstraint) + { + attributes |= GenericParameterAttributes.DefaultConstructorConstraint; + } + + switch (genericParameter.Variance) + { + case GenericParameterVariance.COVARIANT: + attributes |= GenericParameterAttributes.Covariant; + break; + case GenericParameterVariance.CONTRAVARIANT: + attributes |= GenericParameterAttributes.Contravariant; + break; + } + + switch (genericParameter.TypeKind) + { + case TypeKind.ValueType: + attributes |= GenericParameterAttributes.NotNullableValueTypeConstraint; + break; + case TypeKind.ReferenceType: + attributes |= GenericParameterAttributes.ReferenceTypeConstraint; + break; + } + + return attributes; } private static TypeAttributes VisibilityAttributesFor(TypeDefinition typeDefinition) From feb5c8232585f1d6ea34d86e56b73886a23718f9 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 1 May 2020 15:40:40 -0300 Subject: [PATCH 133/256] fix switch instruction & resolver conflicts --- Examples/Examples.cs | 33 ++++++++++++++++--- .../Methods/Body/MethodBodyGenerator.cs | 7 +++- .../Metadata/MetadataResolver.cs | 15 +++++---- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 5761f0c7..6d7e22a5 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -314,6 +314,27 @@ public int CompareTo(object obj) return 0; } } + + public interface InterfaceWithMethodM1 + { + void M1(); + } + + public interface AnotherInterfaceWithMethodM1 + { + void M1(); + } + + public class ClassWithMultipleMethodsWithSameName : InterfaceWithMethodM1, AnotherInterfaceWithMethodM1 + { + void InterfaceWithMethodM1.M1() + { + } + + void AnotherInterfaceWithMethodM1.M1() + { + } + } } namespace Delegates @@ -358,7 +379,7 @@ protected void NotVisibileToDerivedClass() public class DerivedClass : BaseClass { - public sealed override void CanImplement() + public override void CanImplement() { } } @@ -456,14 +477,16 @@ public class PointersAndReferenceClass namespace Generics { - public class Generic + public class Generic where D : class where E : Exception where F : struct where G : struct, ISampleInterface where H : class, new() - // where I : unmanaged FIXME framework read not implemented - // where J : D FIXME framework read is not working + where I : List + where J : List + // where K : unmanaged FIXME framework read not implemented + // where L : D FIXME framework read is not working { public C genericClassTypeField; public Dictionary genericField; @@ -491,7 +514,7 @@ public void MethodWithGenericConstraint(T t) where T : Enum { } - public E ReceivesAndReturnsGenericType(T t, E e) + public E ReceivesAndReturnsGenericType(T t, E e) where E : List { return e; } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 87d88dc7..589c7ef7 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -632,13 +632,18 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(storeFieldInstruction.Field)); break; case SwitchInstruction switchInstruction: + { + var nextInstructionOffset = + Convert.ToInt32(body.Instructions[body.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); instructionEncoder.OpCode(SRM.ILOpCode.Switch); instructionEncoder.Token(switchInstruction.Targets.Count); switchInstruction.Targets - .Select(label => int.Parse(label.Substring(2), NumberStyles.HexNumber)) + .Select(label => Convert.ToInt32(label.Substring(2), 16)) + .Select(targetOffset => targetOffset - nextInstructionOffset) .ToList() .ForEach(instructionEncoder.Token); break; + } case SizeofInstruction sizeofInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(sizeofInstruction.MeasuredType)); diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 36024c82..ec285835 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -14,6 +14,7 @@ // TODO revisar si esas keys que pongo en los getOrAdd (al ser mas precisas) estan funcionando o hacen que siempre se agregue uno nuevo // TODO para esto comparar sin guardar ninguna cuanto da el conteo de las tablas y guardando despues. // TODO ver si conviene usar blobhandle, byteArray de la signature u otro. Evaluarlo tabla por tabla, quiza algunas andan bien y otras no +// TODO mas alla de la eficiencia, algunas tablas no admiten duplicados por lo que si no rompe por eso es que algunas esta usando. namespace MetadataGenerator.Metadata { internal class MetadataResolver @@ -23,8 +24,8 @@ internal class MetadataResolver private readonly IDictionary assemblyReferences = new Dictionary(); private readonly IDictionary typeReferences = new Dictionary(); - private readonly IDictionary, SRM.MemberReferenceHandle> memberReferences = - new Dictionary, SRM.MemberReferenceHandle>(); + private readonly IDictionary, SRM.MemberReferenceHandle> memberReferences = + new Dictionary, SRM.MemberReferenceHandle>(); private readonly IDictionary, SRM.TypeSpecificationHandle> typeSpecificationReferences = new Dictionary, SRM.TypeSpecificationHandle>(); @@ -180,7 +181,7 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl { var parentHandle = GetOrAddTypeSpecificationFor(arrayTypeWrapper.Type); var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); - var key = new Tuple(parentHandle, blobHandle); + var key = new Tuple(parentHandle, signature.ToArray()); if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) { methodReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( @@ -195,9 +196,9 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl else { var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); - var key = new Tuple( + var key = new Tuple( $"{method.ContainingType.GetFullName()}.{method.GenericName}", - blobHandle + signature.ToArray() ); if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) { @@ -215,9 +216,9 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field, SRM.BlobBuilder signature) { var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); - var key = new Tuple( + var key = new Tuple( $"{field.ContainingType.GetFullName()}.{field.Name}", - blobHandle + signature.ToArray() ); if (!memberReferences.TryGetValue(key, out var memberReferenceHandle)) { From 57598d86834c955510b2cbd07215c2fadf238f17 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 1 May 2020 16:48:01 -0300 Subject: [PATCH 134/256] method overrides, generic constraints --- MetadataProvider/AssemblyExtractor.cs | 107 ++++++++++++++++++++++---- Model/Extensions.cs | 49 +++++++++++- Model/Types/TypeDefinitions.cs | 50 +----------- Model/Types/Types.cs | 17 +++- 4 files changed, 160 insertions(+), 63 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index e08294a5..140f1d74 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -231,9 +231,10 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) type.UnderlayingType = valueField.Type as IBasicType; } + var methodOverrides = MethodOverridesOf(typedef); foreach (var handle in typedef.GetMethods()) { - ExtractMethod(handle); + ExtractMethod(handle, methodOverrides); } defGenericContext.TypeParameters.Clear(); @@ -420,10 +421,18 @@ private void ExtractGenericParameter(GenericParameterKind parameterKind, IGeneri }; genericContainer.GenericParameters.Add(genericParameter); - var constraints = genericParameterdef.GetConstraints().Select( - constraint => signatureTypeProvider.GetTypeFromHandle(metadata, defGenericContext, metadata.GetGenericParameterConstraint(constraint).Type - )); - genericParameter.Constraints.AddRange(constraints); + var typeConstraints = genericParameterdef.GetConstraints().Select( + constraint => + { + refGenericContext.MethodParameters.Clear(); + refGenericContext.TypeParameters.Clear(); + CreateGenericParameterReferences(parameterKind, genericContainer.GenericParameterCount); + var constraints = signatureTypeProvider.GetTypeFromHandle(metadata, refGenericContext, + metadata.GetGenericParameterConstraint(constraint).Type); + BindGenericParameterReferences(parameterKind, genericContainer); + return constraints; + }); + genericParameter.Constraints.AddRange(typeConstraints); } private void ExtractField(SRM.FieldDefinitionHandle handle) @@ -480,7 +489,7 @@ private void ExtractProperty(SRM.PropertyDefinitionHandle handle) BindGenericParameterReferences(GenericParameterKind.Type, currentType); } - private void ExtractMethod(SRM.MethodDefinitionHandle methoddefHandle) + private void ExtractMethod(SRM.MethodDefinitionHandle methoddefHandle, IList methodOverrides) { var methoddef = metadata.GetMethodDefinition(methoddefHandle); var method = GetDefinedMethod(methoddefHandle); @@ -511,6 +520,12 @@ private void ExtractMethod(SRM.MethodDefinitionHandle methoddefHandle) ExtractLocalVariablesNames(methoddefHandle); ExtractMethodBody(methoddef.RelativeVirtualAddress); + + var methodOverride = methodOverrides.FirstOrDefault(m => method.MatchSignature(m.newMethodImplementation)); + if (methodOverride != null) + { + method.OverridenMethod = methodOverride.overridenMethod; + } defGenericContext.MethodParameters.Clear(); currentMethod = null; @@ -1258,11 +1273,20 @@ private IFieldReference GetFieldReference(SRM.MemberReference member) BindGenericParameterReferences(GenericParameterKind.Type, containingType); return field; } + + private IMethodReference GetMethodReference(SRM.MemberReference member) => + GetMethodReference(member.Name, member.Parent, member.DecodeMethodSignature); + + private IMethodReference GetMethodReference(SRM.MethodDefinition methodDefinition) => + GetMethodReference(methodDefinition.Name, methodDefinition.GetDeclaringType(), methodDefinition.DecodeSignature); - private IMethodReference GetMethodReference(SRM.MemberReference member) + private IMethodReference GetMethodReference( + SRM.StringHandle methodName, + SRM.EntityHandle parent, + Func> decodeSignature) { - var name = metadata.GetString(member.Name); - var type = signatureTypeProvider.GetTypeFromHandle(metadata, defGenericContext, member.Parent); + var name = metadata.GetString(methodName); + var type = signatureTypeProvider.GetTypeFromHandle(metadata, defGenericContext, parent); if (type is ArrayType) { @@ -1272,7 +1296,7 @@ private IMethodReference GetMethodReference(SRM.MemberReference member) var containingType = (IBasicType)type; CreateGenericParameterReferences(GenericParameterKind.Type, containingType.GenericParameterCount); - var signature = member.DecodeMethodSignature(signatureTypeProvider, refGenericContext); + var signature = decodeSignature(signatureTypeProvider, refGenericContext); var method = new MethodReference(name, signature.ReturnType) { @@ -1664,9 +1688,8 @@ private static string GetGenericName(string name) return name; } - // FIXME - // Metadata static indicator for FieldReferences (!signatureHeader.IsInstance) appears to be incorrect when read. Maybe it is updated when - // it can resolve the reference. So field isStatic is ensured with the field operation kind (ex: stsfld => static, ldfld => not static) + // Metadata static indicator for FieldReferences (!signatureHeader.IsInstance) appears to be incorrect when read. + // So field isStatic is ensured with the field operation kind (ex: stsfld => static, ldfld => not static) private static void SetFieldStaticProperty(IFieldReference field, bool isStatic) { switch (field) @@ -1685,5 +1708,63 @@ private static void SetFieldStaticProperty(IFieldReference field, bool isStatic) } } + + private IList MethodOverridesOf(SRM.TypeDefinition typedef) => + typedef + .GetMethodImplementations() + .Select(handle => metadata.GetMethodImplementation(handle)) + .Select(methodImplementation => + { + IMethodReference newMethodImplementation; + switch (methodImplementation.MethodBody.Kind) + { + case SRM.HandleKind.MethodDefinition: + { + newMethodImplementation = GetMethodReference((SRM.MethodDefinitionHandle) methodImplementation.MethodBody); + break; + } + case SRM.HandleKind.MemberReference: + { + newMethodImplementation = GetMethodReference((SRM.MemberReferenceHandle) methodImplementation.MethodBody); + break; + } + default: + throw new Exception("Unexpected handle kind"); + } + + IMethodReference overridenMethod; + switch (methodImplementation.MethodDeclaration.Kind) + { + case SRM.HandleKind.MethodDefinition: + { + overridenMethod = GetMethodReference( + metadata.GetMethodDefinition((SRM.MethodDefinitionHandle) methodImplementation.MethodDeclaration)); + break; + } + case SRM.HandleKind.MemberReference: + { + overridenMethod = GetMethodReference( + metadata.GetMemberReference((SRM.MemberReferenceHandle) methodImplementation.MethodDeclaration)); + break; + } + default: + throw new Exception("Unexpected handle kind"); + } + + return new MethodOverride(newMethodImplementation, overridenMethod); + }) + .ToList(); + } + + internal class MethodOverride + { + public readonly IMethodReference newMethodImplementation; + public readonly IMethodReference overridenMethod; + + public MethodOverride(IMethodReference newMethodImplementation, IMethodReference overridenMethod) + { + this.newMethodImplementation = newMethodImplementation; + this.overridenMethod = overridenMethod; + } } } \ No newline at end of file diff --git a/Model/Extensions.cs b/Model/Extensions.cs index 8ba54658..ad6be5c7 100644 --- a/Model/Extensions.cs +++ b/Model/Extensions.cs @@ -246,7 +246,7 @@ public static BasicType Instantiate(this IBasicType type, IEnumerable gen ContainingAssembly = type.ContainingAssembly, ContainingNamespace = type.ContainingNamespace, ContainingType = type.ContainingType, - GenericParameterCount = type.GenericParameterCount, + GenericParameterCount = genericArguments.Count(), GenericType = type }; @@ -361,6 +361,53 @@ public static bool IsDelegate(this IType type) return result; } + public static bool MatchSignature(this IMethodReference method, IMethodReference anotherMethod) + { + var result = method.Name == anotherMethod.Name && + method.IsStatic == anotherMethod.IsStatic && + method.GenericParameterCount == anotherMethod.GenericParameterCount && + method.ReturnType.Equals(anotherMethod.ReturnType) && + method.MatchParameters(anotherMethod); + return result; + } + + public static bool MatchParameters(this IMethodReference method, IMethodReference anotherMethod) + { + var result = false; + + if (method.Parameters.Count == anotherMethod.Parameters.Count) + { + result = true; + + for (var i = 0; i < method.Parameters.Count && result; ++i) + { + var parameterdef = method.Parameters[i]; + var parameterref = anotherMethod.Parameters[i]; + + result = parameterdef.MatchReference(parameterref); + } + } + + return result; + } + + public static bool MatchReference(this IMethodParameterReference parameter, IMethodParameterReference anotherParameter) + { + var result = false; + + if (anotherParameter is MethodParameter) + { + result = parameter.Equals(anotherParameter); + } + else + { + result = parameter.Kind == anotherParameter.Kind && + parameter.Type.Equals(anotherParameter.Type); + } + + return result; + } + #region Control-flow helper methods public static bool IsBranch(this IInstruction instruction, out IList targets) diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 4271ec11..5678eb23 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -242,23 +242,6 @@ public bool HasDefaultValue get { return this.DefaultValue != null; } } - public bool MatchReference(IMethodParameterReference parameter) - { - var result = false; - - if (parameter is MethodParameter) - { - result = this.Equals(parameter); - } - else - { - result = this.Kind == parameter.Kind && - this.Type.Equals(parameter.Type); - } - - return result; - } - public override string ToString() { string kind; @@ -472,7 +455,8 @@ public class MethodDefinition : ITypeMemberDefinition, IMethodReference, IGeneri public bool IsConstructor { get; set; } public bool IsExternal { get; set; } public MethodBody Body { get; set; } - + public IMethodReference OverridenMethod { get; set; } + public MethodDefinition(string name, IType returnType) { this.Name = name; @@ -569,36 +553,6 @@ public bool MatchReference(ITypeMemberReference member) return result; } - public bool MatchSignature(IMethodReference method) - { - var result = this.Name == method.Name && - this.IsStatic == method.IsStatic && - this.GenericParameters.Count == method.GenericParameterCount && - this.ReturnType.Equals(method.ReturnType) && - this.MatchParameters(method); - return result; - } - - public bool MatchParameters(IMethodReference method) - { - var result = false; - - if (this.Parameters.Count == method.Parameters.Count) - { - result = true; - - for (var i = 0; i < this.Parameters.Count && result; ++i) - { - var parameterdef = this.Parameters[i]; - var parameterref = method.Parameters[i]; - - result = parameterdef.MatchReference(parameterref); - } - } - - return result; - } - public string ToSignatureString() { var result = new StringBuilder(); diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index 88e701e1..4a6f83f6 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -802,13 +802,28 @@ public ISet Attributes public int GenericParameterCount { - get { return 0; } + get { return GenericParameterCountOf(Type); } } public IBasicType ContainingType { get { return null; } } + + private int GenericParameterCountOf(IType type) + { + switch (Type.ElementsType) + { + case IGenericParameterReference genericParameterReference: + return genericParameterReference.GenericContainer.GenericParameterCount; + case ArrayType arrayType: + return GenericParameterCountOf(arrayType.ElementsType); + case PointerType pointerType: + return GenericParameterCountOf(pointerType.TargetType); + default: + return 0; + } + } } #endregion From dcf4f70a79e77b84255d917b7c4adaab70a7a7f6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 1 May 2020 16:58:14 -0300 Subject: [PATCH 135/256] missing import --- Backend/Utils/Helper.cs | 1 + 1 file changed, 1 insertion(+) 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 { From 0d0a6d0fbd01ca9705480bb58aec05d307247f9c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 1 May 2020 17:05:02 -0300 Subject: [PATCH 136/256] method overrides generation --- Console/Program.cs | 9 +++--- MetadataGenerator/Generators/TypeGenerator.cs | 29 +++++++++++++++++++ Model/Types/Types.cs | 2 ++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index ae3349ad..d164fb27 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -386,12 +386,11 @@ private static void DisassembleAndThenAssemble(string input) static void Main(string[] args) { - // var input = "../../../Examples/bin/Debug/Examples.dll"; + //var input = "../../../Examples/bin/Debug/Examples.dll"; + // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll"; // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll"; - // var input = "../../../../TinyCsvParser/TinyCsvParser/SelectedTests/bin/Debug/net45/SelectedTests.dll"; - // var input = "../../../../DSA/DSA/DSA-Selected-Tests/bin/Debug/net45/DSA-Selected-Tests.dll"; - var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll"; - // var input = "../../../../C-Sharp-Algorithms/Algorithms/bin/Debug/netcoreapp2.0/Algorithms.dll"; + var input = "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll"; + //var input = "../../../../C-Sharp-Algorithms/Algorithms/bin/Debug/netcoreapp2.0/Algorithms.dll"; DisassembleAndThenAssemble(input); //RunSomeTests(); diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index fb0fd379..a9d9fbe7 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -33,11 +33,19 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) var metadataBuilder = metadataContainer.metadataBuilder; var fieldDefinitionHandles = type.Fields.Select(field => fieldGenerator.Generate(field)).ToList(); var methodDefToHandle = new Dictionary(); + var methodOverrides = new List(); foreach (var method in type.Methods) { var methodHandle = methodGenerator.Generate(method); methodDefinitionHandles.Add(methodHandle); + if (method.OverridenMethod != null) + { + methodOverrides.Add(new MethodOverride( + methodHandle, + metadataContainer.metadataResolver.HandleOf(method.OverridenMethod))); + } + if (method.Name.Equals("Main")) { metadataContainer.MainMethodHandle = methodHandle; @@ -86,6 +94,15 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) } } + foreach (var methodOverride in methodOverrides) + { + metadataContainer.metadataBuilder.AddMethodImplementation( + typeDefinitionHandle, + methodOverride.methodImplementation, + methodOverride.overridenMethod + ); + } + return typeDefinitionHandle; } @@ -132,4 +149,16 @@ IList GenericParametersNamesOf(IBasicType iBasicType) return typeName; } } + + internal class MethodOverride + { + public readonly SRM.MethodDefinitionHandle methodImplementation; + public readonly SRM.EntityHandle overridenMethod; + + public MethodOverride(SRM.MethodDefinitionHandle methodImplementation, SRM.EntityHandle overridenMethod) + { + this.methodImplementation = methodImplementation; + this.overridenMethod = overridenMethod; + } + } } \ No newline at end of file diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index b7bb3c9e..f3f77148 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -855,6 +855,8 @@ private int GenericParameterCountOf(IType type) return genericParameterReference.GenericContainer.GenericParameterCount; case ArrayType arrayType: return GenericParameterCountOf(arrayType.ElementsType); + case ManagedPointerType managedPointerType: + return GenericParameterCountOf(managedPointerType.TargetType); case PointerType pointerType: return GenericParameterCountOf(pointerType.TargetType); default: From c7a117f1eff8c70ca079f05767bd18c83c18323c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 1 May 2020 19:47:20 -0300 Subject: [PATCH 137/256] remove generated in file name --- Console/Program.cs | 3 ++- MetadataGenerator/Generator.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index d164fb27..46c925e0 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -390,7 +390,8 @@ static void Main(string[] args) // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll"; // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll"; var input = "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll"; - //var input = "../../../../C-Sharp-Algorithms/Algorithms/bin/Debug/netcoreapp2.0/Algorithms.dll"; + // var input = "../../../../DSA/DSA/DSAUnitTests/bin/Debug/net45/DSAUnitTests.dll"; + DisassembleAndThenAssemble(input); //RunSomeTests(); diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index f175e534..d46739ae 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -13,7 +13,7 @@ public class Generator : IGenerator public void Generate(Assembly assembly) { var extension = assembly.Kind == AssemblyKind.EXE ? "exe" : "dll"; - var fileName = $"./{assembly.Name}(generated).{extension}"; + var fileName = $"./{assembly.Name}.{extension}"; Console.WriteLine($"Generating Console/bin/debug/{fileName.Substring(2)}"); using (var peStream = File.OpenWrite(fileName)) { From 367c4a43195f1791ca0d7bb0af5df7ea41c88e94 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 1 May 2020 22:52:56 -0300 Subject: [PATCH 138/256] Fix property generation (lazy FirstOrDefault) --- MetadataGenerator/Generators/TypeGenerator.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index a9d9fbe7..6abd94d7 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -66,6 +66,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) var firstPropertyDefinitionHandle = type.PropertyDefinitions .Select(property => propertyGenerator.Generate(property, methodDefToHandle)) + .ToList() .FirstOrDefault(); if (!firstPropertyDefinitionHandle.IsNil) From fb29027f9b266ffbf2bc58e63cbe31a1be66587a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 10 May 2020 17:04:44 -0300 Subject: [PATCH 139/256] layout information --- MetadataProvider/AssemblyExtractor.cs | 13 +++++++++++++ Model/Types/TypeDefinitions.cs | 14 ++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..24aa5179 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -287,6 +287,19 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) ExtractType(handle); } + var layout = typedef.GetLayout(); + if (!layout.IsDefault) + { + var kind = typedef.Attributes.HasFlag(SR.TypeAttributes.SequentialLayout) + ? LayoutKind.SequentialLayout + : LayoutKind.ExplicitLayout; + type.LayoutInformation = new LayoutInformation(kind) + { + PackingSize = layout.PackingSize, + ClassSize = layout.Size + }; + } + currentType = currentType.ContainingType; } diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 6a2d1bde..1b29ed7b 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -605,19 +605,21 @@ public enum VisibilityKind Internal = 4, Public = 8 } + public enum LayoutKind { - Unknown, - AutoLayout, // Class fields are auto-laid out - SequentialLayout, // Class fields are laid out sequentially - ExplicitLayout, // Layout is supplied explicitly + AutoLayout, + SequentialLayout, + ExplicitLayout } + public class LayoutInformation { public LayoutKind Kind { get; set; } - public short PackingSize { get; set; } + public int PackingSize { get; set; } public int ClassSize { get; set; } - public LayoutInformation(LayoutKind kind = LayoutKind.Unknown) + + public LayoutInformation(LayoutKind kind = LayoutKind.AutoLayout) { Kind = kind; PackingSize = -1; From 23db1b2ad2f7d8ec47957f90e6f59b03060c9ad7 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 10 May 2020 17:52:08 -0300 Subject: [PATCH 140/256] fix logic --- MetadataProvider/AssemblyExtractor.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 24aa5179..c403c504 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -288,18 +288,24 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) } var layout = typedef.GetLayout(); - if (!layout.IsDefault) + LayoutInformation layoutInformation; + if (layout.IsDefault) { - var kind = typedef.Attributes.HasFlag(SR.TypeAttributes.SequentialLayout) - ? LayoutKind.SequentialLayout - : LayoutKind.ExplicitLayout; - type.LayoutInformation = new LayoutInformation(kind) + var layoutKind = typedef.Attributes.HasFlag(SR.TypeAttributes.SequentialLayout) ? LayoutKind.SequentialLayout : LayoutKind.AutoLayout; + layoutInformation = new LayoutInformation(layoutKind); + } + else + { + var kind = typedef.Attributes.HasFlag(SR.TypeAttributes.SequentialLayout) ? LayoutKind.SequentialLayout : LayoutKind.ExplicitLayout; + layoutInformation = new LayoutInformation(kind) { PackingSize = layout.PackingSize, ClassSize = layout.Size }; } - + + type.LayoutInformation = layoutInformation; + currentType = currentType.ContainingType; } From 6bbe48d5088f1ab6ed3f8e61bb703d44493f5188 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 11 May 2020 08:14:41 -0300 Subject: [PATCH 141/256] add layout default check --- Model/Types/TypeDefinitions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 1b29ed7b..830c51bf 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -625,6 +625,8 @@ public LayoutInformation(LayoutKind kind = LayoutKind.AutoLayout) PackingSize = -1; ClassSize = -1; } + + public bool SpecifiesSizes() => PackingSize != -1 && ClassSize != -1; } public class TypeDefinition : IBasicType, IGenericDefinition, ITypeMemberDefinition, ITypeDefinitionContainer { From 454df95bb5dc057c1b7a05100cd71fae1c514581 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 11 May 2020 08:52:45 -0300 Subject: [PATCH 142/256] field rva --- MetadataProvider/AssemblyExtractor.cs | 11 +++++++++++ Model/Types/TypeDefinitions.cs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..cf8eb4d2 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -472,6 +472,17 @@ private void ExtractField(SRM.FieldDefinitionHandle handle) field.Visibility = GetVisibilityKind(fielddef.Attributes); field.Value = ExtractFieldDefaultValue(fielddef); + field.SpecifiesRelativeVirtualAddress = fielddef.Attributes.HasFlag(SR.FieldAttributes.HasFieldRVA); + if (field.SpecifiesRelativeVirtualAddress) + { + var fieldDataReader = reader.GetSectionData(fielddef.GetRelativeVirtualAddress()).GetReader(); + var fieldData = fieldDataReader.ReadBytes(fieldDataReader.Length); + field.Value = new Constant(fieldData) + { + Type = new ArrayType(PlatformTypes.Byte) + }; + } + currentType.Fields.Add(field); } diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 27062ea7..ab1f8da4 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -112,7 +112,7 @@ public class FieldDefinition : ITypeMemberDefinition, IFieldReference public Constant Value { get; set; } public bool IsStatic { get; set; } - + public bool SpecifiesRelativeVirtualAddress { get; set; } public FieldDefinition(string name, IType type) { this.Name = name; From 4485be4e572bcc73e73f1e7bb808e6cc761ce5a4 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 11 May 2020 08:55:09 -0300 Subject: [PATCH 143/256] whitespace --- Model/Types/TypeDefinitions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index ab1f8da4..d8579869 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -112,6 +112,7 @@ public class FieldDefinition : ITypeMemberDefinition, IFieldReference public Constant Value { get; set; } public bool IsStatic { get; set; } + public bool SpecifiesRelativeVirtualAddress { get; set; } public FieldDefinition(string name, IType type) { From 389bb920f792c70c09247ae464636bbafd0c6332 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 11 May 2020 08:55:42 -0300 Subject: [PATCH 144/256] whitespace --- Model/Types/TypeDefinitions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index d8579869..ab1f8da4 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -112,7 +112,6 @@ public class FieldDefinition : ITypeMemberDefinition, IFieldReference public Constant Value { get; set; } public bool IsStatic { get; set; } - public bool SpecifiesRelativeVirtualAddress { get; set; } public FieldDefinition(string name, IType type) { From 59e4ec63f9414b04189c14593fe62f6ba4f717fa Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 11 May 2020 18:58:35 -0300 Subject: [PATCH 145/256] generate field rva --- MetadataGenerator/Generator.cs | 1 + .../Generators/Fields/FieldGenerator.cs | 12 ++++++++++-- MetadataGenerator/Metadata/AttributesProvider.cs | 7 ++++++- MetadataGenerator/Metadata/MetadataContainer.cs | 2 ++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index d46739ae..53ebc640 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -28,6 +28,7 @@ public void Generate(Assembly assembly) header: peHeaderBuilder, metadataRootBuilder: new ECMA335.MetadataRootBuilder(metadataContainer.metadataBuilder), ilStream: metadataContainer.methodBodyStream.Builder, + mappedFieldData: metadataContainer.mappedFieldData, entryPoint: assembly.Kind.Equals(AssemblyKind.EXE) ? metadataContainer.MainMethodHandle : default, flags: SRPE.CorFlags.ILOnly | SRPE.CorFlags.StrongNameSigned ).Serialize(peBlob); diff --git a/MetadataGenerator/Generators/Fields/FieldGenerator.cs b/MetadataGenerator/Generators/Fields/FieldGenerator.cs index 82b04d83..87982aed 100644 --- a/MetadataGenerator/Generators/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldGenerator.cs @@ -1,4 +1,5 @@ -using MetadataGenerator.Metadata; +using System.Reflection.PortableExecutable; +using MetadataGenerator.Metadata; using Model.Types; using static MetadataGenerator.Metadata.AttributesProvider; using SRM = System.Reflection.Metadata; @@ -24,7 +25,14 @@ public SRM.FieldDefinitionHandle Generate(FieldDefinition field) name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), signature: metadataContainer.metadataBuilder.GetOrAddBlob(fieldSignature)); - if (field.Value != null) + if (field.SpecifiesRelativeVirtualAddress) + { + var offset = metadataContainer.mappedFieldData.Count; + metadataContainer.mappedFieldData.WriteBytes((byte[]) field.Value.Value); + metadataContainer.mappedFieldData.Align(ManagedPEBuilder.MappedFieldDataAlignment); + metadataContainer.metadataBuilder.AddFieldRelativeVirtualAddress(fieldDefinitionHandle, offset); + } + else if (field.Value != null) { metadataContainer.metadataBuilder.AddConstant(fieldDefinitionHandle, field.Value.Value); } diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index f3cce4a9..259186e8 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -66,7 +66,12 @@ public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) (field.IsLiteral ? FieldAttributes.Literal : 0) | (field.IsReadonly ? FieldAttributes.InitOnly : 0) | (field.SpecialName ? FieldAttributes.SpecialName : 0) | - (field.RuntimeSpecialName ? FieldAttributes.RTSpecialName : 0); + (field.RuntimeSpecialName ? FieldAttributes.RTSpecialName : 0) | + (field.SpecifiesRelativeVirtualAddress + ? FieldAttributes.HasFieldRVA + : field.Value != null + ? FieldAttributes.HasDefault + : 0); switch (field.Visibility) { case VisibilityKind.Public: diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 2e52d60f..111d12fe 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -16,6 +16,7 @@ internal class MetadataContainer public readonly ECMA335.MetadataBuilder metadataBuilder; public readonly MetadataResolver metadataResolver; public readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; + public readonly SRM.BlobBuilder mappedFieldData; private SRM.MethodDefinitionHandle? mainMethodHandle; private SRM.ModuleDefinitionHandle? moduleHandle; private readonly ISet genericParameterRows = new HashSet(); @@ -47,6 +48,7 @@ public MetadataContainer(Assembly assembly) metadataBuilder = new ECMA335.MetadataBuilder(); methodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); metadataResolver = new MetadataResolver(this, assembly); + mappedFieldData = new SRM.BlobBuilder(); } public void RegisterGenericParameter(SRM.TypeDefinitionHandle parent, GenericParameter genericParameter) => From ffc7cb2fec9296aca486ae7eac05c42e3c045b94 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 13 May 2020 19:26:39 -0300 Subject: [PATCH 146/256] generate fault region --- .../Generators/Methods/Body/MethodBodyControlFlowGenerator.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index 2e702bc0..f0f96f61 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -72,6 +72,8 @@ public void ProcessExceptionInformation(IList exceptionInformati metadataContainer.metadataResolver.HandleOf(catchType)); break; case ExceptionHandlerBlockKind.Fault: + controlFlowBuilder.AddFaultRegion(tryStart, tryEnd, handlerStart, handlerEnd); + break; case ExceptionHandlerBlockKind.Finally: controlFlowBuilder.AddFinallyRegion(tryStart, tryEnd, handlerStart, handlerEnd); break; From 50686097fbbe4520fe6022fb10d6c4ba04d364e1 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 16 May 2020 11:30:17 -0300 Subject: [PATCH 147/256] add IsVirtual property to IMethodReference --- MetadataProvider/AssemblyExtractor.cs | 20 ++++++++++++++++++-- Model/Types/TypeDefinitions.cs | 2 ++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..f058f90f 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -971,8 +971,10 @@ private IInstruction ExtractInstruction(ILInstruction operation) break; case SRM.ILOpCode.Ldftn: + instruction = ProcessLoadMethodAddress(operation, false); + break; case SRM.ILOpCode.Ldvirtftn: - instruction = ProcessLoadMethodAddress(operation); + instruction = ProcessLoadMethodAddress(operation, true); break; case SRM.ILOpCode.Ldc_i4: @@ -1573,10 +1575,24 @@ private IInstruction ProcessLoadField(ILInstruction op) return instruction; } - private IInstruction ProcessLoadMethodAddress(ILInstruction op) + private IInstruction ProcessLoadMethodAddress(ILInstruction op, bool isVirtual) { var operation = OperationHelper.ToLoadMethodAddressOperation(op.Opcode); var method = GetOperand(op); + switch (method) + { + case MethodDefinition methodDefinition: + { + methodDefinition.IsVirtual = isVirtual; + break; + } + case MethodReference methodReference: + { + methodReference.IsVirtual = isVirtual; + break; + } + default: throw new Exception("case not handled"); + } var instruction = new LoadMethodAddressInstruction(op.Offset, operation, method); return instruction; diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 27062ea7..752a3540 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -286,6 +286,7 @@ public interface IMethodReference : ITypeMemberReference, IMetadataReference, IG IMethodReference GenericMethod { get; } MethodDefinition ResolvedMethod { get; } bool IsStatic { get; } + bool IsVirtual { get; } } public class MethodReference : IMethodReference @@ -302,6 +303,7 @@ public class MethodReference : IMethodReference public IList Parameters { get; private set; } public IMethodReference GenericMethod { get; set; } public bool IsStatic { get; set; } + public bool IsVirtual { get; set; } public MethodReference(string name, IType returnType) { From bc197d77c0b3a3b2419edd51f8e98b8555201bdf Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 16 May 2020 11:37:48 -0300 Subject: [PATCH 148/256] ldvirtftn --- Console/Program.cs | 4 +++- .../Generators/Methods/Body/MethodBodyGenerator.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index ca6c53f8..91c1d4d9 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -389,8 +389,10 @@ static void Main(string[] args) // var input = "../../../Examples/bin/Debug/Examples.dll"; // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll"; // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll"; - var input = "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll"; + // var input = "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll"; // var input = "../../../../DSA/DSA/DSAUnitTests/bin/Debug/net45/DSAUnitTests.dll"; + //var input = "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.dll"; + var input = "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.Tests.dll"; DisassembleAndThenAssemble(input); diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 589c7ef7..1a98ac02 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -589,7 +589,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; } case LoadMethodAddressInstruction loadMethodAddressInstruction: - instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); + instructionEncoder.OpCode(loadMethodAddressInstruction.Method.IsVirtual ? SRM.ILOpCode.Ldvirtftn : SRM.ILOpCode.Ldftn); instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadMethodAddressInstruction.Method)); break; case CreateArrayInstruction createArrayInstruction: From 2f7af734375491a62f455333c5169bac4a39c8f9 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 17 May 2020 13:51:43 -0300 Subject: [PATCH 149/256] serializable --- MetadataProvider/AssemblyExtractor.cs | 1 + Model/Types/TypeDefinitions.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 0a1fb95d..8868ae6a 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -263,6 +263,7 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) } type.BeforeFieldInit = typedef.Attributes.HasFlag(SR.TypeAttributes.BeforeFieldInit); + type.Serializable = typedef.Attributes.HasFlag(SR.TypeAttributes.Serializable); currentType = type; diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index f968f129..8bf35d25 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -635,6 +635,7 @@ public class TypeDefinition : IBasicType, IGenericDefinition, ITypeMemberDefinit public bool IsAbstract { get; set; } public bool IsSealed { get; set; } public bool BeforeFieldInit { get; set; } + public bool Serializable { get; set; } public TypeDefinition(string name, TypeKind typeKind = TypeKind.Unknown, TypeDefinitionKind kind = TypeDefinitionKind.Unknown) { From 5a35c92f665a64bc754de2cf20ca3b8a708f4987 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 17 May 2020 13:54:49 -0300 Subject: [PATCH 150/256] serializable --- Console/Program.cs | 6 +++++- MetadataGenerator/Metadata/AttributesProvider.cs | 10 +++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index 91c1d4d9..dfe4057e 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -392,7 +392,11 @@ static void Main(string[] args) // var input = "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll"; // var input = "../../../../DSA/DSA/DSAUnitTests/bin/Debug/net45/DSAUnitTests.dll"; //var input = "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.dll"; - var input = "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.Tests.dll"; + // var input = "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.Tests.dll"; + // var input = "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Async.dll"; + // var input = "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll"; + // var input = "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll"; + var input = "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll"; DisassembleAndThenAssemble(input); diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/Metadata/AttributesProvider.cs index 259186e8..2c0582d6 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/Metadata/AttributesProvider.cs @@ -22,9 +22,10 @@ public static TypeAttributes GetTypeAttributesFor(TypeDefinition typeDefinition) private static TypeAttributes DelegateTypeAttributes(TypeDefinition typeDefinition) { - return TypeAttributes.Class - | TypeAttributes.Sealed - | VisibilityAttributesFor(typeDefinition); + return TypeAttributes.Class | + TypeAttributes.Sealed | + (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | + VisibilityAttributesFor(typeDefinition); } private static TypeAttributes StructTypeAttributes(TypeDefinition typeDefinition) @@ -32,6 +33,7 @@ private static TypeAttributes StructTypeAttributes(TypeDefinition typeDefinition return TypeAttributes.Class | VisibilityAttributesFor(typeDefinition) | LayoutAttributesFor(typeDefinition.LayoutInformation) | + (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | TypeAttributes.Sealed | (typeDefinition.BeforeFieldInit ? TypeAttributes.BeforeFieldInit : 0); } @@ -40,6 +42,7 @@ private static TypeAttributes EnumTypeAttributes(TypeDefinition typeDefinition) { return TypeAttributes.Class | VisibilityAttributesFor(typeDefinition) | + (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | TypeAttributes.Sealed; } @@ -50,6 +53,7 @@ private static TypeAttributes ClassTypeAttributes(TypeDefinition typeDefinition) (typeDefinition.IsAbstract ? TypeAttributes.Abstract : 0) | (typeDefinition.IsSealed ? TypeAttributes.Sealed : 0) | (typeDefinition.IsStatic ? TypeAttributes.Abstract | TypeAttributes.Sealed : 0) | + (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | LayoutAttributesFor(typeDefinition.LayoutInformation) | VisibilityAttributesFor(typeDefinition); } From e44329c983bcb6e33f30e60e14f2be82f336f4f6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 25 May 2020 15:39:51 -0300 Subject: [PATCH 151/256] more attributes cases --- Console/Program.cs | 49 +++++++++++++++++++++++++++++++------------ Examples/Examples.cs | 50 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index dfe4057e..b271b193 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -386,19 +386,42 @@ private static void DisassembleAndThenAssemble(string input) static void Main(string[] args) { - // var input = "../../../Examples/bin/Debug/Examples.dll"; - // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll"; - // var input = "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll"; - // var input = "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll"; - // var input = "../../../../DSA/DSA/DSAUnitTests/bin/Debug/net45/DSAUnitTests.dll"; - //var input = "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.dll"; - // var input = "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.Tests.dll"; - // var input = "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Async.dll"; - // var input = "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll"; - // var input = "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll"; - var input = "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll"; - - DisassembleAndThenAssemble(input); + var inputs = new[] + { + new[] {"../../../Examples/bin/Debug/Examples.dll"}, + new[] + { + "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll", + "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll" + }, + + new[] + { + "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll", + "../../../../DSA/DSA/DSAUnitTests/bin/Debug/net45/DSAUnitTests.dll" + }, + + new[] + { + "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.dll", + "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.Tests.dll" + }, + new[] + { + "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Async.dll", + "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll", + "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll", + "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll" + } + }; + + foreach (var input in inputs) + { + foreach (var file in input) + { + DisassembleAndThenAssemble(file); + } + } //RunSomeTests(); // RunGenericsTests(); diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 6d7e22a5..7c0de659 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Reflection.Metadata; using Classes; +using Enums; using Hierarchy; using Interfaces; using Nested.NestedNamespace.NestedNestedNamesace; @@ -1064,6 +1065,7 @@ public void ExceptionHandlingTryCatchFinally(Exception e) namespace Attributes { [Flags] + [AnnotatedClass.AttributeWithObjectParam(DefaultEnum.CONSTANT1)] public enum ColoursFlags { Red = 1, @@ -1072,16 +1074,56 @@ public enum ColoursFlags Green = 8 } - [ExcludeFromCodeCoverage, Obsolete("no use")] + [AttributeWithStringAndArrayParam("some.string", new[] {1, 2, 3, 4})] + [AttributeWithObjectArrayParam(new object[] {1, "some.string", DefaultEnum.CONSTANT1})] + [AttributeWithObjectParam(new[] {1, 2, 3})] + [AttributeWithTypeParam(typeof(EmptyClass))] public class AnnotatedClass { - [Obsolete] public int ObsoleteProperty { get; set; } - [Obsolete] public int obsoleteField; + [AttributeWithObjectParam(typeof(EmptyClass))] + public int property { get; set; } - [Obsolete("Method is obsolete", true)] + [Obsolete("field"), AttributeWithObjectParam(new[] {DefaultEnum.CONSTANT1, DefaultEnum.CONSTANT2})] + public int field; + + [AttributeWithObjectParam(new object[] {1, "some.string", DefaultEnum.CONSTANT1})] + public string anotherFIeld; + + [ExcludeFromCodeCoverage, Obsolete("Method is obsolete", true)] + [AttributeWithObjectParam("something")] + [AttributeWithTypeParam(typeof(Nested.ClassContainingNestedTypes.NestedClass))] public void Method() { } + + [AttributeUsage(AttributeTargets.All)] + public class AttributeWithObjectParam : Attribute + { + public AttributeWithObjectParam(object o) + { + } + } + + public class AttributeWithStringAndArrayParam : Attribute + { + public AttributeWithStringAndArrayParam(string s, int[] values) + { + } + } + + public class AttributeWithObjectArrayParam : Attribute + { + public AttributeWithObjectArrayParam(object[] args) + { + } + } + + public class AttributeWithTypeParam : Attribute + { + public AttributeWithTypeParam(Type t) + { + } + } } } From 14e0ac0969481fc43ff5fd88c9407623450b8ccf Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 25 May 2020 15:44:27 -0300 Subject: [PATCH 152/256] refactor --- Examples/Examples.cs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 7c0de659..f6f342d1 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1065,7 +1065,7 @@ public void ExceptionHandlingTryCatchFinally(Exception e) namespace Attributes { [Flags] - [AnnotatedClass.AttributeWithObjectParam(DefaultEnum.CONSTANT1)] + [AttributeWithObjectParam(DefaultEnum.CONSTANT1)] public enum ColoursFlags { Red = 1, @@ -1095,34 +1095,34 @@ public class AnnotatedClass public void Method() { } + } - [AttributeUsage(AttributeTargets.All)] - public class AttributeWithObjectParam : Attribute + [AttributeUsage(AttributeTargets.All)] + public class AttributeWithObjectParam : Attribute + { + public AttributeWithObjectParam(object o) { - public AttributeWithObjectParam(object o) - { - } } + } - public class AttributeWithStringAndArrayParam : Attribute + public class AttributeWithStringAndArrayParam : Attribute + { + public AttributeWithStringAndArrayParam(string s, int[] values) { - public AttributeWithStringAndArrayParam(string s, int[] values) - { - } } + } - public class AttributeWithObjectArrayParam : Attribute + public class AttributeWithObjectArrayParam : Attribute + { + public AttributeWithObjectArrayParam(object[] args) { - public AttributeWithObjectArrayParam(object[] args) - { - } } + } - public class AttributeWithTypeParam : Attribute + public class AttributeWithTypeParam : Attribute + { + public AttributeWithTypeParam(Type t) { - public AttributeWithTypeParam(Type t) - { - } } } } From 4f5d8e060fc5cf04cdf329dce7a42755afe0f79b Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 25 May 2020 16:11:25 -0300 Subject: [PATCH 153/256] custom attributes --- MetadataProvider/AssemblyExtractor.cs | 34 +++++++++++++++++++ .../CustomAttributeTypeProvider.cs | 33 ++++++++++++++++++ MetadataProvider/MetadataProvider.csproj | 1 + Model/Types/Types.cs | 2 ++ 4 files changed, 70 insertions(+) create mode 100644 MetadataProvider/CustomAttributeTypeProvider.cs diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 140f1d74..74fab308 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -28,6 +28,7 @@ internal class AssemblyExtractor private TypeDefinition currentType; private MethodDefinition currentMethod; private IDictionary currentMethodLocalVariablesNames; + private readonly CustomAttributeTypeProvider customAttributeTypeProvider; public AssemblyExtractor(Host host, SRPE.PEReader reader, SRM.MetadataReaderProvider pdbProvider = null) { @@ -40,6 +41,7 @@ public AssemblyExtractor(Host host, SRPE.PEReader reader, SRM.MetadataReaderProv this.defGenericContext = new GenericContext(); this.refGenericContext = new GenericContext(); this.signatureTypeProvider = new SignatureTypeProvider(this); + this.customAttributeTypeProvider = new CustomAttributeTypeProvider(signatureTypeProvider); if (pdbProvider != null) { @@ -248,6 +250,8 @@ private void ExtractType(SRM.TypeDefinitionHandle typedefHandle) { ExtractType(handle); } + + ExtractAttributes(type, typedef.GetCustomAttributes()); currentType = currentType.ContainingType; } @@ -445,6 +449,8 @@ private void ExtractField(SRM.FieldDefinitionHandle handle) field.IsStatic = fielddef.Attributes.HasFlag(SR.FieldAttributes.Static); field.Visibility = GetVisibilityKind(fielddef.Attributes); field.Value = ExtractFieldDefaultValue(fielddef); + + ExtractAttributes(field, fielddef.GetCustomAttributes()); currentType.Fields.Add(field); } @@ -487,6 +493,7 @@ private void ExtractProperty(SRM.PropertyDefinitionHandle handle) }; currentType.PropertyDefinitions.Add(property); BindGenericParameterReferences(GenericParameterKind.Type, currentType); + ExtractAttributes(property, propertyDef.GetCustomAttributes()); } private void ExtractMethod(SRM.MethodDefinitionHandle methoddefHandle, IList methodOverrides) @@ -526,6 +533,8 @@ private void ExtractMethod(SRM.MethodDefinitionHandle methoddefHandle, IList static, ldfld => not static) diff --git a/MetadataProvider/CustomAttributeTypeProvider.cs b/MetadataProvider/CustomAttributeTypeProvider.cs new file mode 100644 index 00000000..f196ad56 --- /dev/null +++ b/MetadataProvider/CustomAttributeTypeProvider.cs @@ -0,0 +1,33 @@ +using System.Reflection.Metadata; +using Model.Types; + +namespace MetadataProvider +{ + internal class CustomAttributeTypeProvider : ICustomAttributeTypeProvider + { + private readonly SignatureTypeProvider signatureTypeProvider; + + public CustomAttributeTypeProvider(SignatureTypeProvider signatureTypeProvider) + { + this.signatureTypeProvider = signatureTypeProvider; + } + + public IType GetPrimitiveType(PrimitiveTypeCode typeCode) => signatureTypeProvider.GetPrimitiveType(typeCode); + + public IType GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) => + signatureTypeProvider.GetTypeFromDefinition(reader, handle, rawTypeKind); + + public IType GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) => + signatureTypeProvider.GetTypeFromReference(reader, handle, rawTypeKind); + + public IType GetSZArrayType(IType elementType) => signatureTypeProvider.GetSZArrayType(elementType); + + public IType GetSystemType() => PlatformTypes.Type; + + public bool IsSystemType(IType type) => PlatformTypes.Type.Equals(type); + + public IType GetTypeFromSerializedName(string name) => new BasicType(name); + + public PrimitiveTypeCode GetUnderlyingEnumType(IType type) => PrimitiveTypeCode.Int32; + } +} \ No newline at end of file diff --git a/MetadataProvider/MetadataProvider.csproj b/MetadataProvider/MetadataProvider.csproj index 18c1c3a2..2f6ca308 100644 --- a/MetadataProvider/MetadataProvider.csproj +++ b/MetadataProvider/MetadataProvider.csproj @@ -49,6 +49,7 @@ + diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index 4a6f83f6..bfcf835a 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -81,6 +81,8 @@ public static class PlatformTypes public static readonly BasicType Task = New("mscorlib", "System.Threading.Tasks", "Task", TypeKind.ReferenceType); public static readonly BasicType GenericTask = New("mscorlib", "System.Threading.Tasks", "Task", TypeKind.ReferenceType, 1); + + public static readonly BasicType Type = New("mscorlib", "System", "Type", TypeKind.ReferenceType); public static void Resolve(Host host) { From c798ba7ad6e3f8f81d08e7593501c90b7c433630 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 25 May 2020 16:27:16 -0300 Subject: [PATCH 154/256] generate custom attributes --- .../Generators/CustomAttributeGenerator.cs | 180 ++++++++++++++++++ .../Generators/Fields/FieldGenerator.cs | 7 + .../Generators/Methods/MethodGenerator.cs | 7 + .../Generators/PropertyGenerator.cs | 7 + MetadataGenerator/Generators/TypeGenerator.cs | 7 + MetadataGenerator/MetadataGenerator.csproj | 1 + 6 files changed, 209 insertions(+) create mode 100644 MetadataGenerator/Generators/CustomAttributeGenerator.cs diff --git a/MetadataGenerator/Generators/CustomAttributeGenerator.cs b/MetadataGenerator/Generators/CustomAttributeGenerator.cs new file mode 100644 index 00000000..33495938 --- /dev/null +++ b/MetadataGenerator/Generators/CustomAttributeGenerator.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Immutable; +using MetadataGenerator.Metadata; +using Model; +using Model.ThreeAddressCode.Values; +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SR = System.Reflection; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generators +{ + internal class CustomAttributeGenerator + { + private readonly MetadataContainer metadataContainer; + + public CustomAttributeGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public void Generate(SRM.EntityHandle owner, CustomAttribute customAttribute) + { + var customAttributeEncodedValue = new SRM.BlobBuilder(); + new ECMA335.BlobEncoder(customAttributeEncodedValue) + .CustomAttributeSignature( + fixedArgumentsEncoder => + { + foreach (var argument in customAttribute.Arguments) + { + if (argument.Type is ArrayType) + { + EncodeVector(customAttribute, argument, fixedArgumentsEncoder.AddArgument()); + } + else if (argument.Type.Equals(PlatformTypes.Type)) + { + EncodeComplexValue(customAttribute, argument, fixedArgumentsEncoder.AddArgument()); + } + else + { + EncodeSimpleValue(customAttribute, argument, fixedArgumentsEncoder.AddArgument()); + } + } + }, + namedArgumentsEncoder => + { + // TODO named arguments are not read in AssemblyExtractor + namedArgumentsEncoder.Count(0); + }); + + metadataContainer.metadataBuilder.AddCustomAttribute( + owner, + metadataContainer.metadataResolver.HandleOf(customAttribute.Constructor), + metadataContainer.metadataBuilder.GetOrAddBlob(customAttributeEncodedValue)); + } + + /* + * Encodes vector (only SZArray are permitted as arguments of a custom attribute constructor) + * The constructor can have this value as an object, object[] or type[]. In the first two cases, the type needs to be encoded as well. + */ + private static void EncodeVector(CustomAttribute customAttribute, Constant argument, ECMA335.LiteralEncoder encoder) + { + var type = ((ArrayType) argument.Type).ElementsType; + var elements = (ImmutableArray>) argument.Value; + if (TypeOfMatchedParameterInConstructorIsObject(customAttribute, argument)) + { + if (type.Equals(PlatformTypes.Object)) + { + encoder.TaggedVector( + arrayTypeEncoder => arrayTypeEncoder.ObjectArray(), + vectorEncoder => + { + var literalsEncoder = vectorEncoder.Count(elements.Length); + foreach (var element in elements) + { + literalsEncoder.AddLiteral().TaggedScalar( + typeEncoder => EncodeType(element.Type, typeEncoder), + scalarEncoder => scalarEncoder.Constant(element.Value)); + } + }); + } + else + { + encoder.TaggedVector( + vectorTypeEncoder => EncodeType(type, vectorTypeEncoder.ElementType()), + vectorElementsEncoder => + { + var literalsEncoder = vectorElementsEncoder.Count(elements.Length); + foreach (var element in elements) + { + literalsEncoder.AddLiteral().Scalar().Constant(element.Value); + } + }); + } + } + else + { + if (type.Equals(PlatformTypes.Object)) + { + var literalsEncoder = encoder.Vector().Count(elements.Length); + foreach (var element in elements) + { + literalsEncoder.AddLiteral().TaggedScalar( + typeEncoder => EncodeType(element.Type, typeEncoder), + scalarEncoder => scalarEncoder.Constant(element.Value)); + } + } + else + { + var literalsEncoder = encoder.Vector().Count(elements.Length); + foreach (var element in elements) + { + literalsEncoder.AddLiteral().Scalar().Constant(element.Value); + } + } + } + } + + /* + * Encode types. Types are represented by their serialized name (namespace.type or namespace.type+anotherType if nested) + * If this parameter has type object in the customAttribute constructor, then its real type also needs to be encoded. + */ + private static void EncodeComplexValue(CustomAttribute customAttribute, Constant argument, ECMA335.LiteralEncoder encoder) + { + var serializedTypeName = ((IBasicType) argument.Value).Name; + if (TypeOfMatchedParameterInConstructorIsObject(customAttribute, argument)) + { + encoder.TaggedScalar( + typeEncoder => EncodeType(argument.Type, typeEncoder), + scalarEncoder => scalarEncoder.SystemType(serializedTypeName)); + } + else + { + encoder.Scalar().SystemType(serializedTypeName); + } + } + + /* + * Simple values: bool (as byte), char, float32, float64, int8, int16, int32, int64, unsigned int8, unsigned int16, unsigned int32,unsigned int64, enums (integer value) + * If this parameter has type object in the customAttribute constructor, then its real type also needs to be encoded. + */ + private static void EncodeSimpleValue(CustomAttribute customAttribute, Constant argument, ECMA335.LiteralEncoder encoder) + { + var type = argument.Type; + var value = type.Equals(PlatformTypes.Boolean) ? Convert.ToByte(argument.Value) : argument.Value; + if (TypeOfMatchedParameterInConstructorIsObject(customAttribute, argument)) + { + encoder.TaggedScalar( + typeEncoder => EncodeType(type, typeEncoder), + scalarEncoder => scalarEncoder.Constant(value)); + } + else + { + encoder.Scalar().Constant(value); + } + } + + private static bool TypeOfMatchedParameterInConstructorIsObject(CustomAttribute customAttribute, Constant argument) => + customAttribute.Constructor.Parameters[customAttribute.Arguments.IndexOf(argument)].Type.Equals(PlatformTypes.Object); + + private static void EncodeType(IType type, ECMA335.CustomAttributeElementTypeEncoder encoder) + { + if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); + else if (type.Equals(PlatformTypes.Byte)) encoder.Byte(); + else if (type.Equals(PlatformTypes.SByte)) encoder.SByte(); + else if (type.Equals(PlatformTypes.Char)) encoder.Char(); + else if (type.Equals(PlatformTypes.Double)) encoder.Double(); + else if (type.Equals(PlatformTypes.Int16)) encoder.Int16(); + else if (type.Equals(PlatformTypes.UInt16)) encoder.UInt16(); + else if (type.Equals(PlatformTypes.Int32)) encoder.Int32(); + else if (type.Equals(PlatformTypes.UInt32)) encoder.UInt32(); + else if (type.Equals(PlatformTypes.Int64)) encoder.Int64(); + else if (type.Equals(PlatformTypes.UInt64)) encoder.UInt64(); + else if (type.Equals(PlatformTypes.String)) encoder.String(); + else if (type.Equals(PlatformTypes.Single)) encoder.Single(); + else if (type.Equals(PlatformTypes.Type)) encoder.SystemType(); + else encoder.Enum(type.GetFullName()); + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Fields/FieldGenerator.cs b/MetadataGenerator/Generators/Fields/FieldGenerator.cs index 87982aed..4f2c3bdf 100644 --- a/MetadataGenerator/Generators/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldGenerator.cs @@ -10,11 +10,13 @@ internal class FieldGenerator { private readonly MetadataContainer metadataContainer; private readonly FieldSignatureGenerator fieldSignatureGenerator; + private readonly CustomAttributeGenerator customAttributeGenerator; public FieldGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; fieldSignatureGenerator = new FieldSignatureGenerator(metadataContainer); + customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } public SRM.FieldDefinitionHandle Generate(FieldDefinition field) @@ -37,6 +39,11 @@ public SRM.FieldDefinitionHandle Generate(FieldDefinition field) metadataContainer.metadataBuilder.AddConstant(fieldDefinitionHandle, field.Value.Value); } + foreach (var customAttribute in field.Attributes) + { + customAttributeGenerator.Generate(fieldDefinitionHandle, customAttribute); + } + return fieldDefinitionHandle; } } diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 10334512..a015bce4 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -15,6 +15,7 @@ internal class MethodGenerator private readonly MethodBodyGenerator methodBodyGenerator; private readonly MethodLocalsSignatureGenerator methodLocalsSignatureGenerator; private readonly MethodParametersGenerator methodParametersGenerator; + private readonly CustomAttributeGenerator customAttributeGenerator; public MethodGenerator(MetadataContainer metadataContainer) { @@ -23,6 +24,7 @@ public MethodGenerator(MetadataContainer metadataContainer) methodBodyGenerator = new MethodBodyGenerator(metadataContainer); methodLocalsSignatureGenerator = new MethodLocalsSignatureGenerator(metadataContainer); methodParametersGenerator = new MethodParametersGenerator(metadataContainer); + customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } public SRM.MethodDefinitionHandle Generate(MethodDefinition method) @@ -57,6 +59,11 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) bodyOffset: methodBodyOffset, parameterList: parameters); + foreach (var customAttribute in method.Attributes) + { + customAttributeGenerator.Generate(methodDefinitionHandle, customAttribute); + } + return methodDefinitionHandle; } } diff --git a/MetadataGenerator/Generators/PropertyGenerator.cs b/MetadataGenerator/Generators/PropertyGenerator.cs index 1ef60a15..49c8381e 100644 --- a/MetadataGenerator/Generators/PropertyGenerator.cs +++ b/MetadataGenerator/Generators/PropertyGenerator.cs @@ -10,10 +10,12 @@ namespace MetadataGenerator.Generators internal class PropertyGenerator { private readonly MetadataContainer metadataContainer; + private readonly CustomAttributeGenerator customAttributeGenerator; public PropertyGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; + customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } public SRM.PropertyDefinitionHandle Generate( @@ -49,6 +51,11 @@ public SRM.PropertyDefinitionHandle Generate( methodDefHandleOf[property.Setter]); } + foreach (var customAttribute in property.Attributes) + { + customAttributeGenerator.Generate(propertyDefinitionHandle, customAttribute); + } + return propertyDefinitionHandle; } } diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index a4abb407..30d85334 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -18,6 +18,7 @@ internal class TypeGenerator private readonly MethodGenerator methodGenerator; private readonly FieldGenerator fieldGenerator; private readonly PropertyGenerator propertyGenerator; + private readonly CustomAttributeGenerator customAttributeGenerator; public TypeGenerator(MetadataContainer metadataContainer) { @@ -25,6 +26,7 @@ public TypeGenerator(MetadataContainer metadataContainer) methodGenerator = new MethodGenerator(metadataContainer); fieldGenerator = new FieldGenerator(metadataContainer); propertyGenerator = new PropertyGenerator(metadataContainer); + customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } public SRM.TypeDefinitionHandle Generate(TypeDefinition type) @@ -112,6 +114,11 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) (uint) type.LayoutInformation.ClassSize); } + foreach (var customAttribute in type.Attributes) + { + customAttributeGenerator.Generate(typeDefinitionHandle, customAttribute); + } + return typeDefinitionHandle; } diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index e193b583..b0f0c9ff 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -29,6 +29,7 @@ + From e28f6bf61b11387dd8b9583cabba6e0838b21ad3 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 25 May 2020 16:30:48 -0300 Subject: [PATCH 155/256] refactor --- MetadataGenerator/Generator.cs | 6 +- .../Generators/AssemblyGenerator.cs | 6 +- .../Generators/CustomAttributeGenerator.cs | 6 +- .../Generators/Fields/FieldGenerator.cs | 16 +-- .../Fields/FieldSignatureGenerator.cs | 2 +- .../Body/MethodBodyControlFlowGenerator.cs | 2 +- .../Methods/Body/MethodBodyGenerator.cs | 52 ++++----- .../Body/MethodLocalsSignatureGenerator.cs | 4 +- .../Generators/Methods/MethodGenerator.cs | 10 +- .../Methods/MethodParametersGenerator.cs | 6 +- .../Methods/MethodSignatureGenerator.cs | 6 +- .../Generators/PropertyGenerator.cs | 12 +- MetadataGenerator/Generators/TypeGenerator.cs | 14 +-- .../Metadata/MetadataContainer.cs | 108 +++++++++--------- .../Metadata/MetadataResolver.cs | 44 +++---- 15 files changed, 147 insertions(+), 147 deletions(-) diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 53ebc640..a722d1f8 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -26,9 +26,9 @@ public void Generate(Assembly assembly) var peBlob = new SRM.BlobBuilder(); new SRPE.ManagedPEBuilder( header: peHeaderBuilder, - metadataRootBuilder: new ECMA335.MetadataRootBuilder(metadataContainer.metadataBuilder), - ilStream: metadataContainer.methodBodyStream.Builder, - mappedFieldData: metadataContainer.mappedFieldData, + metadataRootBuilder: new ECMA335.MetadataRootBuilder(metadataContainer.MetadataBuilder), + ilStream: metadataContainer.MethodBodyStream.Builder, + mappedFieldData: metadataContainer.MappedFieldData, entryPoint: assembly.Kind.Equals(AssemblyKind.EXE) ? metadataContainer.MainMethodHandle : default, flags: SRPE.CorFlags.ILOnly | SRPE.CorFlags.StrongNameSigned ).Serialize(peBlob); diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index 5d015aaa..0d9dcd54 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -11,13 +11,13 @@ public static MetadataContainer Generate(Assembly assembly) { var metadataContainer = new MetadataContainer(assembly); var namespaceGenerator = new NamespaceGenerator(metadataContainer); - var metadataBuilder = metadataContainer.metadataBuilder; + var metadataBuilder = metadataContainer.MetadataBuilder; metadataBuilder.AddAssembly( name: metadataBuilder.GetOrAddString(assembly.Name), version: assembly.Version, - culture: metadataContainer.metadataBuilder.GetOrAddString(assembly.Culture), - publicKey: metadataContainer.metadataBuilder.GetOrAddBlob(assembly.PublicKey), + culture: metadataContainer.MetadataBuilder.GetOrAddString(assembly.Culture), + publicKey: metadataContainer.MetadataBuilder.GetOrAddBlob(assembly.PublicKey), flags: SR.AssemblyFlags.PublicKey, hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1 ); diff --git a/MetadataGenerator/Generators/CustomAttributeGenerator.cs b/MetadataGenerator/Generators/CustomAttributeGenerator.cs index 33495938..ef6597e7 100644 --- a/MetadataGenerator/Generators/CustomAttributeGenerator.cs +++ b/MetadataGenerator/Generators/CustomAttributeGenerator.cs @@ -48,10 +48,10 @@ public void Generate(SRM.EntityHandle owner, CustomAttribute customAttribute) namedArgumentsEncoder.Count(0); }); - metadataContainer.metadataBuilder.AddCustomAttribute( + metadataContainer.MetadataBuilder.AddCustomAttribute( owner, - metadataContainer.metadataResolver.HandleOf(customAttribute.Constructor), - metadataContainer.metadataBuilder.GetOrAddBlob(customAttributeEncodedValue)); + metadataContainer.MetadataResolver.HandleOf(customAttribute.Constructor), + metadataContainer.MetadataBuilder.GetOrAddBlob(customAttributeEncodedValue)); } /* diff --git a/MetadataGenerator/Generators/Fields/FieldGenerator.cs b/MetadataGenerator/Generators/Fields/FieldGenerator.cs index 4f2c3bdf..49207087 100644 --- a/MetadataGenerator/Generators/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldGenerator.cs @@ -22,21 +22,21 @@ public FieldGenerator(MetadataContainer metadataContainer) public SRM.FieldDefinitionHandle Generate(FieldDefinition field) { var fieldSignature = fieldSignatureGenerator.GenerateSignatureOf(field); - var fieldDefinitionHandle = metadataContainer.metadataBuilder.AddFieldDefinition( + var fieldDefinitionHandle = metadataContainer.MetadataBuilder.AddFieldDefinition( attributes: GetFieldAttributesFor(field), - name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), - signature: metadataContainer.metadataBuilder.GetOrAddBlob(fieldSignature)); + name: metadataContainer.MetadataBuilder.GetOrAddString(field.Name), + signature: metadataContainer.MetadataBuilder.GetOrAddBlob(fieldSignature)); if (field.SpecifiesRelativeVirtualAddress) { - var offset = metadataContainer.mappedFieldData.Count; - metadataContainer.mappedFieldData.WriteBytes((byte[]) field.Value.Value); - metadataContainer.mappedFieldData.Align(ManagedPEBuilder.MappedFieldDataAlignment); - metadataContainer.metadataBuilder.AddFieldRelativeVirtualAddress(fieldDefinitionHandle, offset); + var offset = metadataContainer.MappedFieldData.Count; + metadataContainer.MappedFieldData.WriteBytes((byte[]) field.Value.Value); + metadataContainer.MappedFieldData.Align(ManagedPEBuilder.MappedFieldDataAlignment); + metadataContainer.MetadataBuilder.AddFieldRelativeVirtualAddress(fieldDefinitionHandle, offset); } else if (field.Value != null) { - metadataContainer.metadataBuilder.AddConstant(fieldDefinitionHandle, field.Value.Value); + metadataContainer.MetadataBuilder.AddConstant(fieldDefinitionHandle, field.Value.Value); } foreach (var customAttribute in field.Attributes) diff --git a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs index c9215713..b2bf7c03 100644 --- a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs @@ -17,7 +17,7 @@ public FieldSignatureGenerator(MetadataContainer metadataContainer) public SRM.BlobBuilder GenerateSignatureOf(IFieldReference field) { var fieldSignature = new SRM.BlobBuilder(); - metadataContainer.metadataResolver.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); + metadataContainer.MetadataResolver.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); return fieldSignature; } } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index f0f96f61..c8ea2495 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -69,7 +69,7 @@ public void ProcessExceptionInformation(IList exceptionInformati case ExceptionHandlerBlockKind.Catch: var catchType = ((CatchExceptionHandler) protectedBlock.Handler).ExceptionType; controlFlowBuilder.AddCatchRegion(tryStart, tryEnd, handlerStart, handlerEnd, - metadataContainer.metadataResolver.HandleOf(catchType)); + metadataContainer.MetadataResolver.HandleOf(catchType)); break; case ExceptionHandlerBlockKind.Fault: controlFlowBuilder.AddFaultRegion(tryStart, tryEnd, handlerStart, handlerEnd); diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 1a98ac02..e0b34c90 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -378,23 +378,23 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case ConvertOperation.Cast: instructionEncoder.OpCode(SRM.ILOpCode.Castclass); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(convertInstruction.ConversionType)); break; case ConvertOperation.IsInst: instructionEncoder.OpCode(SRM.ILOpCode.Isinst); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(convertInstruction.ConversionType)); break; case ConvertOperation.Box: instructionEncoder.OpCode(SRM.ILOpCode.Box); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(convertInstruction.ConversionType)); break; case ConvertOperation.Unbox: instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(convertInstruction.ConversionType)); break; case ConvertOperation.UnboxPtr: instructionEncoder.OpCode(SRM.ILOpCode.Unbox); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(convertInstruction.ConversionType)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(convertInstruction.ConversionType)); break; default: throw new UnhandledCase(); @@ -405,11 +405,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) switch (methodCallInstruction.Operation) { case MethodCallOperation.Virtual: - instructionEncoder.CallVirtual(metadataContainer.metadataResolver.HandleOf(methodCallInstruction.Method)); + instructionEncoder.CallVirtual(metadataContainer.MetadataResolver.HandleOf(methodCallInstruction.Method)); break; case MethodCallOperation.Static: case MethodCallOperation.Jump: - instructionEncoder.Call(metadataContainer.metadataResolver.HandleOf(methodCallInstruction.Method)); + instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(methodCallInstruction.Method)); break; default: throw new UnhandledCase(); @@ -458,7 +458,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) else if (loadInstruction.Operand.Type.Equals(PlatformTypes.String)) { var value = (string) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadString(metadataContainer.metadataBuilder.GetOrAddUserString(value)); + instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); } else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.UInt8)) @@ -510,13 +510,13 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) throw new UnhandledCase(); } - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadFieldInstruction.Field)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(loadFieldInstruction.Field)); break; case LoadArrayElementInstruction loadArrayElementInstruction: { if (loadArrayElementInstruction.Method != null) { - instructionEncoder.Call(metadataContainer.metadataResolver.HandleOf(loadArrayElementInstruction.Method)); + instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(loadArrayElementInstruction.Method)); } else { @@ -571,14 +571,14 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); instructionEncoder.Token( - metadataContainer.metadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); + metadataContainer.MetadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); } break; case LoadArrayElementOperation.Address: instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); instructionEncoder.Token( - metadataContainer.metadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); + metadataContainer.MetadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); break; default: @@ -590,17 +590,17 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } case LoadMethodAddressInstruction loadMethodAddressInstruction: instructionEncoder.OpCode(loadMethodAddressInstruction.Method.IsVirtual ? SRM.ILOpCode.Ldvirtftn : SRM.ILOpCode.Ldftn); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadMethodAddressInstruction.Method)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(loadMethodAddressInstruction.Method)); break; case CreateArrayInstruction createArrayInstruction: if (createArrayInstruction.Type.IsVector) { instructionEncoder.OpCode(SRM.ILOpCode.Newarr); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(createArrayInstruction.Type.ElementsType)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(createArrayInstruction.Type.ElementsType)); } else { - var method = metadataContainer.metadataResolver.HandleOf(createArrayInstruction.Constructor); + var method = metadataContainer.MetadataResolver.HandleOf(createArrayInstruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); } @@ -608,7 +608,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case CreateObjectInstruction createObjectInstruction: { - var method = metadataContainer.metadataResolver.HandleOf(createObjectInstruction.Constructor); + var method = metadataContainer.MetadataResolver.HandleOf(createObjectInstruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); break; @@ -629,7 +629,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } case StoreFieldInstruction storeFieldInstruction: instructionEncoder.OpCode(storeFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(storeFieldInstruction.Field)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(storeFieldInstruction.Field)); break; case SwitchInstruction switchInstruction: { @@ -646,20 +646,20 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } case SizeofInstruction sizeofInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(sizeofInstruction.MeasuredType)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(sizeofInstruction.MeasuredType)); break; case LoadTokenInstruction loadTokenInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadTokenInstruction.Token)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(loadTokenInstruction.Token)); break; case IndirectMethodCallInstruction indirectMethodCallInstruction: - var methodSignature = metadataContainer.metadataResolver.HandleOf(indirectMethodCallInstruction.Function); + var methodSignature = metadataContainer.MetadataResolver.HandleOf(indirectMethodCallInstruction.Function); instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); break; case StoreArrayElementInstruction storeArrayElementInstruction: if (storeArrayElementInstruction.Method != null) { - instructionEncoder.Call(metadataContainer.metadataResolver.HandleOf(storeArrayElementInstruction.Method)); + instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(storeArrayElementInstruction.Method)); } else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) { @@ -696,17 +696,17 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) else { instructionEncoder.OpCode(SRM.ILOpCode.Stelem); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(storeArrayElementInstruction.Array.ElementsType)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(storeArrayElementInstruction.Array.ElementsType)); } break; case InitObjInstruction initObjInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Initobj); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(initObjInstruction.Type)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(initObjInstruction.Type)); break; case ConstrainedInstruction constrainedInstruction: instructionEncoder.OpCode(SRM.ILOpCode.Constrained); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(constrainedInstruction.ThisType)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(constrainedInstruction.ThisType)); break; case LoadIndirectInstruction loadIndirectInstruction: if (loadIndirectInstruction.Type.Equals(PlatformTypes.Int8)) @@ -756,7 +756,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) else { instructionEncoder.OpCode(SRM.ILOpCode.Ldobj); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(loadIndirectInstruction.Type)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(loadIndirectInstruction.Type)); } break; @@ -796,7 +796,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) else { instructionEncoder.OpCode(SRM.ILOpCode.Stobj); - instructionEncoder.Token(metadataContainer.metadataResolver.HandleOf(storeIndirectInstruction.Type)); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(storeIndirectInstruction.Type)); } break; diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs index eccc6751..988921bb 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs @@ -25,10 +25,10 @@ public SRM.StandaloneSignatureHandle GenerateSignatureFor(IList local foreach (var localVariable in localVariables) { // TODO pinned is achieved by the fixed keyword and this is not in the model - metadataContainer.metadataResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); + metadataContainer.MetadataResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); } - localVariablesSignature = metadataContainer.metadataResolver.GetOrAddStandaloneSignature(signature); + localVariablesSignature = metadataContainer.MetadataResolver.GetOrAddStandaloneSignature(signature); } return localVariablesSignature; diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index a015bce4..5d1b8d94 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -30,7 +30,7 @@ public MethodGenerator(MetadataContainer metadataContainer) public SRM.MethodDefinitionHandle Generate(MethodDefinition method) { var parameters = methodParametersGenerator.Generate(method.Parameters) - ?? ECMA335.MetadataTokens.ParameterHandle(metadataContainer.metadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); + ?? ECMA335.MetadataTokens.ParameterHandle(metadataContainer.MetadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); var methodSignature = methodSignatureGenerator.GenerateSignatureOf(method); var methodBodyOffset = -1; @@ -39,7 +39,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated // programatically then the maxStack is gonna be missing var maxStack = method.Body.MaxStack; - methodBodyOffset = metadataContainer.methodBodyStream.AddMethodBody( + methodBodyOffset = metadataContainer.MethodBodyStream.AddMethodBody( instructionEncoder: methodBodyGenerator.Generate(method.Body), localVariablesSignature: methodLocalsSignatureGenerator.GenerateSignatureFor(method.Body.LocalVariables), maxStack: maxStack); @@ -51,11 +51,11 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) ? SR.MethodImplAttributes.Runtime : SR.MethodImplAttributes.Managed); - var methodDefinitionHandle = metadataContainer.metadataBuilder.AddMethodDefinition( + var methodDefinitionHandle = metadataContainer.MetadataBuilder.AddMethodDefinition( attributes: GetMethodAttributesFor(method), implAttributes: methodImplementationAttributes, - name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), - signature: metadataContainer.metadataBuilder.GetOrAddBlob(methodSignature), + name: metadataContainer.MetadataBuilder.GetOrAddString(method.Name), + signature: metadataContainer.MetadataBuilder.GetOrAddBlob(methodSignature), bodyOffset: methodBodyOffset, parameterList: parameters); diff --git a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs b/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs index 4a7b027a..dfd7e296 100644 --- a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs @@ -22,13 +22,13 @@ internal MethodParametersGenerator(MetadataContainer metadataContainer) SRM.ParameterHandle? firstParameterHandle = null; foreach (var parameter in methodParameters) { - var parameterHandle = metadataContainer.metadataBuilder.AddParameter( + var parameterHandle = metadataContainer.MetadataBuilder.AddParameter( attributes: GetParameterAttributesFor(parameter), - name: metadataContainer.metadataBuilder.GetOrAddString(parameter.Name), + name: metadataContainer.MetadataBuilder.GetOrAddString(parameter.Name), sequenceNumber: parameter.Index); if (parameter.HasDefaultValue) { - metadataContainer.metadataBuilder.AddConstant(parameterHandle, parameter.DefaultValue.Value); + metadataContainer.MetadataBuilder.AddConstant(parameterHandle, parameter.DefaultValue.Value); } if (!firstParameterHandle.HasValue) diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 8433400a..b19cab73 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -24,7 +24,7 @@ public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) var encoder = new ECMA335.BlobEncoder(signature).MethodSpecificationSignature(method.GenericArguments.Count); foreach (var genericArg in method.GenericArguments) { - metadataContainer.metadataResolver.Encode(genericArg, encoder.AddArgument()); + metadataContainer.MetadataResolver.Encode(genericArg, encoder.AddArgument()); } return signature; @@ -60,7 +60,7 @@ private SRM.BlobBuilder GenerateMethodSignature( { // TODO isByRef param. ref in return type is not in the model var encoder = returnTypeEncoder.Type(); - metadataContainer.metadataResolver.Encode(returnType, encoder); + metadataContainer.MetadataResolver.Encode(returnType, encoder); } }, parametersEncoder => @@ -76,7 +76,7 @@ private SRM.BlobBuilder GenerateMethodSignature( } var encoder = parametersEncoder.AddParameter().Type(isByRef); - metadataContainer.metadataResolver.Encode(type, encoder); + metadataContainer.MetadataResolver.Encode(type, encoder); } }); return methodSignature; diff --git a/MetadataGenerator/Generators/PropertyGenerator.cs b/MetadataGenerator/Generators/PropertyGenerator.cs index 49c8381e..58cf8425 100644 --- a/MetadataGenerator/Generators/PropertyGenerator.cs +++ b/MetadataGenerator/Generators/PropertyGenerator.cs @@ -27,17 +27,17 @@ public SRM.PropertyDefinitionHandle Generate( .PropertySignature(isInstanceProperty: !property.IsStatic) .Parameters( parameterCount: 0, - returnType: returnTypeEncoder => metadataContainer.metadataResolver.Encode(property.PropertyType, returnTypeEncoder.Type()), + returnType: returnTypeEncoder => metadataContainer.MetadataResolver.Encode(property.PropertyType, returnTypeEncoder.Type()), parameters: parametersEncoder => { }); - var propertyDefinitionHandle = metadataContainer.metadataBuilder.AddProperty( + var propertyDefinitionHandle = metadataContainer.MetadataBuilder.AddProperty( attributes: SR.PropertyAttributes.None, - name: metadataContainer.metadataBuilder.GetOrAddString(property.Name), - signature: metadataContainer.metadataBuilder.GetOrAddBlob(signature)); + name: metadataContainer.MetadataBuilder.GetOrAddString(property.Name), + signature: metadataContainer.MetadataBuilder.GetOrAddBlob(signature)); if (property.Getter != null) { - metadataContainer.metadataBuilder.AddMethodSemantics( + metadataContainer.MetadataBuilder.AddMethodSemantics( propertyDefinitionHandle, SR.MethodSemanticsAttributes.Getter, methodDefHandleOf[property.Getter]); @@ -45,7 +45,7 @@ public SRM.PropertyDefinitionHandle Generate( if (property.Setter != null) { - metadataContainer.metadataBuilder.AddMethodSemantics( + metadataContainer.MetadataBuilder.AddMethodSemantics( propertyDefinitionHandle, SR.MethodSemanticsAttributes.Setter, methodDefHandleOf[property.Setter]); diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index 30d85334..730bec1d 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -32,7 +32,7 @@ public TypeGenerator(MetadataContainer metadataContainer) public SRM.TypeDefinitionHandle Generate(TypeDefinition type) { var methodDefinitionHandles = new List(); - var metadataBuilder = metadataContainer.metadataBuilder; + var metadataBuilder = metadataContainer.MetadataBuilder; var fieldDefinitionHandles = type.Fields.Select(field => fieldGenerator.Generate(field)).ToList(); var methodDefToHandle = new Dictionary(); var methodOverrides = new List(); @@ -45,7 +45,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) { methodOverrides.Add(new MethodOverride( methodHandle, - metadataContainer.metadataResolver.HandleOf(method.OverridenMethod))); + metadataContainer.MetadataResolver.HandleOf(method.OverridenMethod))); } if (method.Name.Equals("Main")) @@ -62,7 +62,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) attributes: GetTypeAttributesFor(type), @namespace: metadataBuilder.GetOrAddString(type.ContainingNamespace.FullName), name: metadataBuilder.GetOrAddString(TypeNameOf(type)), - baseType: type.Base != null ? metadataContainer.metadataResolver.HandleOf(type.Base) : default, + baseType: type.Base != null ? metadataContainer.MetadataResolver.HandleOf(type.Base) : default, fieldList: fieldDefinitionHandles.FirstOr(nextFieldDefinitionHandle), methodList: methodDefinitionHandles.FirstOr(nextMethodDefinitionHandle)); @@ -73,12 +73,12 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) if (!firstPropertyDefinitionHandle.IsNil) { - metadataContainer.metadataBuilder.AddPropertyMap(typeDefinitionHandle, firstPropertyDefinitionHandle); + metadataContainer.MetadataBuilder.AddPropertyMap(typeDefinitionHandle, firstPropertyDefinitionHandle); } foreach (var interfaze in type.Interfaces) { - metadataContainer.RegisterInterfaceImplementation(typeDefinitionHandle, metadataContainer.metadataResolver.HandleOf(interfaze)); + metadataContainer.RegisterInterfaceImplementation(typeDefinitionHandle, metadataContainer.MetadataResolver.HandleOf(interfaze)); } // generate class generic parameters (Class) @@ -99,7 +99,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) foreach (var methodOverride in methodOverrides) { - metadataContainer.metadataBuilder.AddMethodImplementation( + metadataContainer.MetadataBuilder.AddMethodImplementation( typeDefinitionHandle, methodOverride.methodImplementation, methodOverride.overridenMethod @@ -108,7 +108,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) if (type.LayoutInformation.SpecifiesSizes()) { - metadataContainer.metadataBuilder.AddTypeLayout( + metadataContainer.MetadataBuilder.AddTypeLayout( typeDefinitionHandle, (ushort) type.LayoutInformation.PackingSize, (uint) type.LayoutInformation.ClassSize); diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 111d12fe..1d7612c6 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -4,19 +4,19 @@ using System.Reflection; using Model; using Model.Types; -using Assembly = Model.Assembly; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; using static MetadataGenerator.Metadata.AttributesProvider; +using Assembly = Model.Assembly; namespace MetadataGenerator.Metadata { internal class MetadataContainer { - public readonly ECMA335.MetadataBuilder metadataBuilder; - public readonly MetadataResolver metadataResolver; - public readonly ECMA335.MethodBodyStreamEncoder methodBodyStream; - public readonly SRM.BlobBuilder mappedFieldData; + public readonly ECMA335.MetadataBuilder MetadataBuilder; + public readonly MetadataResolver MetadataResolver; + public readonly ECMA335.MethodBodyStreamEncoder MethodBodyStream; + public readonly SRM.BlobBuilder MappedFieldData; private SRM.MethodDefinitionHandle? mainMethodHandle; private SRM.ModuleDefinitionHandle? moduleHandle; private readonly ISet genericParameterRows = new HashSet(); @@ -45,10 +45,10 @@ public SRM.ModuleDefinitionHandle ModuleHandle public MetadataContainer(Assembly assembly) { - metadataBuilder = new ECMA335.MetadataBuilder(); - methodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); - metadataResolver = new MetadataResolver(this, assembly); - mappedFieldData = new SRM.BlobBuilder(); + MetadataBuilder = new ECMA335.MetadataBuilder(); + MethodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); + MetadataResolver = new MetadataResolver(this, assembly); + MappedFieldData = new SRM.BlobBuilder(); } public void RegisterGenericParameter(SRM.TypeDefinitionHandle parent, GenericParameter genericParameter) => @@ -61,27 +61,27 @@ private void DoRegisterGenericParameter(SRM.EntityHandle parent, GenericParamete genericParameterRows.Add(new GenericParamRow( parent, GetGenericParameterAttributesFor(genericParameter), - metadataBuilder.GetOrAddString(genericParameter.Name), + MetadataBuilder.GetOrAddString(genericParameter.Name), genericParameter.Index, - genericParameter.Constraints.Select(type => metadataResolver.HandleOf(type)).ToSet() + genericParameter.Constraints.Select(type => MetadataResolver.HandleOf(type)).ToSet() )); public void GenerateGenericParameters() => genericParameterRows - .OrderBy(row => ECMA335.CodedIndex.TypeOrMethodDef(row.parent)) - .ThenBy(row => row.index) + .OrderBy(row => ECMA335.CodedIndex.TypeOrMethodDef(row.Parent)) + .ThenBy(row => row.Index) .ToList() .ForEach(row => { - var genericParameterHandle = metadataBuilder.AddGenericParameter( - row.parent, - row.attributes, - row.name, - row.index + var genericParameterHandle = MetadataBuilder.AddGenericParameter( + row.Parent, + row.Attributes, + row.Name, + row.Index ); - foreach (var constraint in row.constraints) + foreach (var constraint in row.Constraints) { - metadataBuilder.AddGenericParameterConstraint(genericParameterHandle, constraint); + MetadataBuilder.AddGenericParameterConstraint(genericParameterHandle, constraint); } }); @@ -90,19 +90,19 @@ public void RegisterNestedType(SRM.TypeDefinitionHandle type, SRM.TypeDefinition public void GenerateNestedTypes() => nestedTypeRows - .OrderBy(row => ECMA335.CodedIndex.TypeDefOrRef(row.type)) + .OrderBy(row => ECMA335.CodedIndex.TypeDefOrRef(row.Type)) .ToList() - .ForEach(row => metadataBuilder.AddNestedType(row.type, row.enclosingType)); + .ForEach(row => MetadataBuilder.AddNestedType(row.Type, row.EnclosingType)); public void RegisterInterfaceImplementation(SRM.TypeDefinitionHandle type, SRM.EntityHandle implementedInterface) => interfaceImplementationRows.Add(new InterfaceImplementationRow(type, implementedInterface)); public void GenerateInterfaceImplementations() => interfaceImplementationRows - .OrderBy(row => ECMA335.CodedIndex.TypeDefOrRef(row.type)) - .ThenBy(row => ECMA335.CodedIndex.TypeDefOrRefOrSpec(row.implementedInterface)) + .OrderBy(row => ECMA335.CodedIndex.TypeDefOrRef(row.Type)) + .ThenBy(row => ECMA335.CodedIndex.TypeDefOrRefOrSpec(row.ImplementedInterface)) .ToList() - .ForEach(row => metadataBuilder.AddInterfaceImplementation(row.type, row.implementedInterface)); + .ForEach(row => MetadataBuilder.AddInterfaceImplementation(row.Type, row.ImplementedInterface)); #region Rows @@ -110,13 +110,13 @@ public void GenerateInterfaceImplementations() => private class InterfaceImplementationRow { - public readonly SRM.TypeDefinitionHandle type; - public readonly SRM.EntityHandle implementedInterface; + public readonly SRM.TypeDefinitionHandle Type; + public readonly SRM.EntityHandle ImplementedInterface; public InterfaceImplementationRow(SRM.TypeDefinitionHandle type, SRM.EntityHandle implementedInterface) { - this.type = type; - this.implementedInterface = implementedInterface; + Type = type; + ImplementedInterface = implementedInterface; } public override bool Equals(object obj) @@ -125,14 +125,14 @@ public override bool Equals(object obj) if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; var other = (InterfaceImplementationRow) obj; - return type.Equals(other.type) && implementedInterface.Equals(other.implementedInterface); + return Type.Equals(other.Type) && ImplementedInterface.Equals(other.ImplementedInterface); } public override int GetHashCode() { unchecked { - return (type.GetHashCode() * 397) ^ implementedInterface.GetHashCode(); + return (Type.GetHashCode() * 397) ^ ImplementedInterface.GetHashCode(); } } @@ -149,11 +149,11 @@ public override int GetHashCode() private class GenericParamRow { - public readonly SRM.EntityHandle parent; - public readonly GenericParameterAttributes attributes; - public readonly SRM.StringHandle name; - public readonly ushort index; - public readonly ISet constraints; + public readonly SRM.EntityHandle Parent; + public readonly GenericParameterAttributes Attributes; + public readonly SRM.StringHandle Name; + public readonly ushort Index; + public readonly ISet Constraints; public GenericParamRow( SRM.EntityHandle parent, @@ -162,11 +162,11 @@ public GenericParamRow( ushort index, ISet constraints) { - this.parent = parent; - this.attributes = attributes; - this.name = name; - this.index = index; - this.constraints = constraints; + Parent = parent; + Attributes = attributes; + Name = name; + Index = index; + Constraints = constraints; } public override bool Equals(object obj) @@ -175,19 +175,19 @@ public override bool Equals(object obj) if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; GenericParamRow other = (GenericParamRow) obj; - return parent.Equals(other.parent) && attributes == other.attributes && name.Equals(other.name) && index == other.index && - Equals(constraints, other.constraints); + return Parent.Equals(other.Parent) && Attributes == other.Attributes && Name.Equals(other.Name) && Index == other.Index && + Equals(Constraints, other.Constraints); } public override int GetHashCode() { unchecked { - var hashCode = parent.GetHashCode(); - hashCode = (hashCode * 397) ^ (int) attributes; - hashCode = (hashCode * 397) ^ name.GetHashCode(); - hashCode = (hashCode * 397) ^ index.GetHashCode(); - hashCode = (hashCode * 397) ^ (constraints != null ? constraints.GetHashCode() : 0); + var hashCode = Parent.GetHashCode(); + hashCode = (hashCode * 397) ^ (int) Attributes; + hashCode = (hashCode * 397) ^ Name.GetHashCode(); + hashCode = (hashCode * 397) ^ Index.GetHashCode(); + hashCode = (hashCode * 397) ^ (Constraints != null ? Constraints.GetHashCode() : 0); return hashCode; } } @@ -205,13 +205,13 @@ public override int GetHashCode() private class NestedTypeRow { - public readonly SRM.TypeDefinitionHandle type; - public readonly SRM.TypeDefinitionHandle enclosingType; + public readonly SRM.TypeDefinitionHandle Type; + public readonly SRM.TypeDefinitionHandle EnclosingType; public NestedTypeRow(SRM.TypeDefinitionHandle type, SRM.TypeDefinitionHandle enclosingType) { - this.type = type; - this.enclosingType = enclosingType; + Type = type; + EnclosingType = enclosingType; } public override bool Equals(object obj) @@ -220,14 +220,14 @@ public override bool Equals(object obj) if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; var other = (NestedTypeRow) obj; - return type.Equals(other.type) && enclosingType.Equals(other.enclosingType); + return Type.Equals(other.Type) && EnclosingType.Equals(other.EnclosingType); } public override int GetHashCode() { unchecked { - return (type.GetHashCode() * 397) ^ enclosingType.GetHashCode(); + return (Type.GetHashCode() * 397) ^ EnclosingType.GetHashCode(); } } diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index ec285835..9d6e363f 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -46,11 +46,11 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) foreach (var assemblyReference in assembly.References) { - assemblyReferences.Add(assemblyReference.Name, metadataContainer.metadataBuilder.AddAssemblyReference( - name: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Name), + assemblyReferences.Add(assemblyReference.Name, metadataContainer.MetadataBuilder.AddAssemblyReference( + name: metadataContainer.MetadataBuilder.GetOrAddString(assemblyReference.Name), version: assemblyReference.Version, - culture: metadataContainer.metadataBuilder.GetOrAddString(assemblyReference.Culture), - publicKeyOrToken: metadataContainer.metadataBuilder.GetOrAddBlob(assemblyReference.PublicKey), + culture: metadataContainer.MetadataBuilder.GetOrAddString(assemblyReference.Culture), + publicKeyOrToken: metadataContainer.MetadataBuilder.GetOrAddBlob(assemblyReference.PublicKey), flags: default, hashValue: default) ); @@ -114,10 +114,10 @@ private SRM.EntityHandle GetOrAddTypeReference(IBasicType type) resolutionScope = GetOrAddTypeReference(type.ContainingType); } - typeReference = metadataContainer.metadataBuilder.AddTypeReference( + typeReference = metadataContainer.MetadataBuilder.AddTypeReference( resolutionScope: resolutionScope, - @namespace: metadataContainer.metadataBuilder.GetOrAddString(type.ContainingNamespace), - name: metadataContainer.metadataBuilder.GetOrAddString(TypeNameOf(type))); + @namespace: metadataContainer.MetadataBuilder.GetOrAddString(type.ContainingNamespace), + name: metadataContainer.MetadataBuilder.GetOrAddString(TypeNameOf(type))); typeReferences.Add(key, typeReference); } @@ -129,11 +129,11 @@ private SRM.TypeSpecificationHandle GetOrAddTypeSpecificationFor(IType type) var signature = new SRM.BlobBuilder(); var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); Encode(type, encoder); - var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var key = new Tuple(type.GetFullName(), blobHandle); if (!typeSpecificationReferences.TryGetValue(key, out var typeSpecification)) { - typeSpecification = metadataContainer.metadataBuilder.AddTypeSpecification(blobHandle); + typeSpecification = metadataContainer.MetadataBuilder.AddTypeSpecification(blobHandle); typeSpecificationReferences.Add(key, typeSpecification); } @@ -149,9 +149,9 @@ private SRM.MethodSpecificationHandle GetOrAddMethodSpecificationFor(IMethodRefe ); if (!methodSpecificationReferences.TryGetValue(key, out var methodSpecification)) { - methodSpecification = metadataContainer.metadataBuilder.AddMethodSpecification( + methodSpecification = metadataContainer.MetadataBuilder.AddMethodSpecification( GetOrAddMethodReference(method.GenericMethod, genericMethodSignature), - metadataContainer.metadataBuilder.GetOrAddBlob(signature) + metadataContainer.MetadataBuilder.GetOrAddBlob(signature) ); methodSpecificationReferences.Add(key, methodSpecification); } @@ -161,10 +161,10 @@ private SRM.MethodSpecificationHandle GetOrAddMethodSpecificationFor(IMethodRefe public SRM.StandaloneSignatureHandle GetOrAddStandaloneSignature(SRM.BlobBuilder signature) { - var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); if (!standaloneSignatureReferences.TryGetValue(blobHandle, out var standaloneSignature)) { - standaloneSignature = metadataContainer.metadataBuilder.AddStandaloneSignature(blobHandle); + standaloneSignature = metadataContainer.MetadataBuilder.AddStandaloneSignature(blobHandle); standaloneSignatureReferences.Add(blobHandle, standaloneSignature); } @@ -180,13 +180,13 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl else if (method.ContainingType is ArrayTypeWrapper arrayTypeWrapper) { var parentHandle = GetOrAddTypeSpecificationFor(arrayTypeWrapper.Type); - var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var key = new Tuple(parentHandle, signature.ToArray()); if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) { - methodReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( + methodReferenceHandle = metadataContainer.MetadataBuilder.AddMemberReference( parent: parentHandle, - name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), + name: metadataContainer.MetadataBuilder.GetOrAddString(method.Name), signature: blobHandle); memberReferences.Add(key, methodReferenceHandle); } @@ -195,16 +195,16 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl } else { - var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var key = new Tuple( $"{method.ContainingType.GetFullName()}.{method.GenericName}", signature.ToArray() ); if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) { - methodReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( + methodReferenceHandle = metadataContainer.MetadataBuilder.AddMemberReference( parent: GetOrAddTypeReference(method.ContainingType), - name: metadataContainer.metadataBuilder.GetOrAddString(method.Name), + name: metadataContainer.MetadataBuilder.GetOrAddString(method.Name), signature: blobHandle); memberReferences.Add(key, methodReferenceHandle); } @@ -215,16 +215,16 @@ private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.Bl private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field, SRM.BlobBuilder signature) { - var blobHandle = metadataContainer.metadataBuilder.GetOrAddBlob(signature); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var key = new Tuple( $"{field.ContainingType.GetFullName()}.{field.Name}", signature.ToArray() ); if (!memberReferences.TryGetValue(key, out var memberReferenceHandle)) { - memberReferenceHandle = metadataContainer.metadataBuilder.AddMemberReference( + memberReferenceHandle = metadataContainer.MetadataBuilder.AddMemberReference( parent: GetOrAddTypeReference(field.ContainingType), - name: metadataContainer.metadataBuilder.GetOrAddString(field.Name), + name: metadataContainer.MetadataBuilder.GetOrAddString(field.Name), signature: blobHandle); memberReferences.Add(key, memberReferenceHandle); } From 2535a6ae59458cbb68996f7ec51c95dc9b9318fb Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 25 May 2020 20:28:48 -0300 Subject: [PATCH 156/256] remove assembler class --- Backend/Backend.csproj | 1 - Backend/Transformations/Assembler.cs | 17 ----------------- 2 files changed, 18 deletions(-) delete mode 100644 Backend/Transformations/Assembler.cs diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj index a96e42d4..4cf55d5c 100644 --- a/Backend/Backend.csproj +++ b/Backend/Backend.csproj @@ -79,7 +79,6 @@ - diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs deleted file mode 100644 index 29c9e9c7..00000000 --- a/Backend/Transformations/Assembler.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Model.Types; -namespace Backend.Transformations -{ - // Responsible for converting three address code to simplified bytecode - public class Assembler - { - public Assembler() - { - } - // TODO extract interface for assembler and disassembler?? SSA? - public MethodBody Execute() - { - throw new NotImplementedException(); - } - } -} From d2157c2820366f87c33f06e4b2135a7521d1ab56 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 26 May 2020 08:56:41 -0300 Subject: [PATCH 157/256] Translate simple instructions --- Backend/Backend.csproj | 1 + Backend/Transformations/Assembler.cs | 244 +++++++++++++++++++++++++++ Backend/Utils/OperationHelper.cs | 58 +++++++ Console/Program.cs | 17 +- Model/Types/TypeDefinitions.cs | 2 +- 5 files changed, 319 insertions(+), 3 deletions(-) create mode 100644 Backend/Transformations/Assembler.cs diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj index 4cf55d5c..cec0f167 100644 --- a/Backend/Backend.csproj +++ b/Backend/Backend.csproj @@ -62,6 +62,7 @@ + diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs new file mode 100644 index 00000000..50482476 --- /dev/null +++ b/Backend/Transformations/Assembler.cs @@ -0,0 +1,244 @@ +using System; +using System.Linq; +using Backend.Utils; +using Model; +using Model.ThreeAddressCode.Instructions; +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; + +// FIXME parti desde code-generator por las cosas que arregle en el metadata-provider. Esta en branch aparte. Estaria bueno hacer el PR de esto +// FIXME sobre el branch de metadata-provider sin los cambios del code-generator. +namespace Backend.Transformations +{ + public class Assembler + { + private readonly MethodDefinition method; + + public Assembler(MethodDefinition method) + { + if (!method.Body.Kind.Equals(MethodBodyKind.ThreeAddressCode)) + { + throw new Exception("MethodBody must be in Three Address Code"); + } + + this.method = method; + } + + public MethodBody Execute() + { + var body = new MethodBody(MethodBodyKind.Bytecode); + + 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) + { + new InstructionTranslator(body).Visit(method.Body); + } + + return body; + } + + + //FIXME Revisar las operaciones que agregue (ej isinst, castClass, etc). Porque esas tampoco estan en las equivalentes del TAC y entonces no las puedo generar. + // FIXME va a haber que agregarlas al TAC no solo a los enums sino distinguirlas al momento de crearlas (al traducir de bytecode que ahora las tiene a tac). + + // FIXME De la misma forma, hay algunas Instrucciones nuevas que habia metido creo. Y esas seguramente no esten en el Visitor por lo que tambien + // FIXME va a haber que crearlas al traucir de bytecode a tac. (Ej indirectLoad/Store, Constrained, etc). + + // FIXME hay un par de metodos que no implemente porque son instrucciones de las que heredan otras por lo que entiendo que no hay que implementarlas. + // FIXME pero tenerlo en cuenta por si despues falta algo, quiza habia alguna que si. + private class InstructionTranslator : InstructionVisitor + { + private readonly MethodBody body; + + public InstructionTranslator(MethodBody body) + { + this.body = body; + } + + public override void Visit(BinaryInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, OperationHelper.ToBasicOperation(instruction.Operation)) + { + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands + }; + body.Instructions.Add(basicInstruction); + } + + public override void Visit(UnaryInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, OperationHelper.ToBasicOperation(instruction.Operation)); + body.Instructions.Add(basicInstruction); + } + + public override void Visit(LoadInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(StoreInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(NopInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop); + body.Instructions.Add(basicInstruction); + } + + public override void Visit(BreakpointInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Breakpoint); + body.Instructions.Add(basicInstruction); + } + + public override void Visit(TryInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(FaultInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(FinallyInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(CatchInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(ConvertInstruction instruction) + { + var convertInstruction = new Bytecode.ConvertInstruction( + instruction.Offset, + OperationHelper.ToConvertOperation(instruction.Operation), + instruction.ConversionType) + { + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands, + }; + body.Instructions.Add(convertInstruction); + } + + public override void Visit(ReturnInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Return); + body.Instructions.Add(basicInstruction); + } + + public override void Visit(ThrowInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Throw); + body.Instructions.Add(basicInstruction); + } + + public override void Visit(UnconditionalBranchInstruction instruction) + { + var unconditionalBranchInstruction = new Bytecode.BranchInstruction( + instruction.Offset, + Bytecode.BranchOperation.Branch, + Convert.ToUInt32(instruction.Target.Substring(2), 16)); + body.Instructions.Add(unconditionalBranchInstruction); + } + + public override void Visit(ConditionalBranchInstruction instruction) + { + var conditionalBranchInstruction = new Bytecode.BranchInstruction( + instruction.Offset, + OperationHelper.ToBranchOperation(instruction.Operation), + Convert.ToUInt32(instruction.Target.Substring(2), 16)); + body.Instructions.Add(conditionalBranchInstruction); + } + + public override void Visit(SwitchInstruction instruction) + { + var targets = instruction.Targets.Select(target => Convert.ToUInt32(target.Substring(2), 16)).ToList(); + var switchInstruction = new Bytecode.SwitchInstruction(instruction.Offset, targets); + body.Instructions.Add(switchInstruction); + } + + public override void Visit(SizeofInstruction instruction) + { + var sizeofInstruction = new Bytecode.SizeofInstruction(instruction.Offset, instruction.MeasuredType); + body.Instructions.Add(sizeofInstruction); + } + + public override void Visit(LoadTokenInstruction instruction) + { + var loadTokenInstruction = new Bytecode.LoadTokenInstruction(instruction.Offset, instruction.Token); + body.Instructions.Add(loadTokenInstruction); + } + + public override void Visit(MethodCallInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(IndirectMethodCallInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(CreateObjectInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(CopyMemoryInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(LocalAllocationInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(InitializeMemoryInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(InitializeObjectInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(CopyObjectInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(CreateArrayInstruction instruction) + { + throw new Exception(); + } + + public override void Visit(PhiInstruction instruction) + { + throw new Exception(); + } + } + } +} \ No newline at end of file diff --git a/Backend/Utils/OperationHelper.cs b/Backend/Utils/OperationHelper.cs index bdd4cb89..285dd455 100644 --- a/Backend/Utils/OperationHelper.cs +++ b/Backend/Utils/OperationHelper.cs @@ -137,5 +137,63 @@ 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.Unbox; + 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(); + } + } } } diff --git a/Console/Program.cs b/Console/Program.cs index b271b193..44752f4f 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -415,15 +415,28 @@ static void Main(string[] args) } }; - foreach (var input in inputs) + /* foreach (var input in inputs) { foreach (var file in input) { DisassembleAndThenAssemble(file); } } +*/ + var host = new Host(); - //RunSomeTests(); + PlatformTypes.Resolve(host); + + var loader = new MetadataProvider.Loader(host); + var assembly = loader.LoadAssembly("../../../Examples/bin/Debug/Examples.dll"); + var methods = assembly.RootNamespace.Namespaces[4].Types[0].Methods; + + var method = methods[1]; + method.Body = new Disassembler(method).Execute(); // to tac + var assembler = new Assembler(method); + var newBody = assembler.Execute(); + + //RunSomeTests(); // RunGenericsTests(); //RunInterPointsToTests(); diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 42fc0bd6..8a6c92b2 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -820,7 +820,7 @@ public class MethodBody : IInstructionContainer { public IList Parameters { get; private set; } public IList LocalVariables { get; private set; } - public IList Instructions { get; private set; } + public IList Instructions { get; set; } // fixme undo, just for testing public IList ExceptionInformation { get; private set; } public ushort MaxStack { get; set; } public MethodBodyKind Kind { get; set; } From f5c38da7116f5f820dc6eb1fea12f2f23f71757c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 27 May 2020 08:49:23 -0300 Subject: [PATCH 158/256] Add isInst TAC ConvertOperation. Remove unused methods, visit InitObjInstruction --- Backend/Transformations/Disassembler.cs | 32 +------------------------ Backend/Utils/OperationHelper.cs | 2 +- Model/ThreeAddressCode/Instructions.cs | 1 + 3 files changed, 3 insertions(+), 32 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 11f53028..122b826d 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -303,7 +303,7 @@ private void ProcessInitializeMemory(Bytecode.BasicInstruction op) body.Instructions.Add(instruction); } - private void ProcessInitializeObject(Bytecode.InitObjInstruction op) + public override void Visit(Bytecode.InitObjInstruction op) { var targetAddress = stack.Pop(); var instruction = new Tac.InitializeObjectInstruction(op.Offset, targetAddress); @@ -337,36 +337,6 @@ private void ProcessLoadArrayLength(Bytecode.BasicInstruction op) var instruction = new Tac.LoadInstruction(op.Offset, dest, length); 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 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) { diff --git a/Backend/Utils/OperationHelper.cs b/Backend/Utils/OperationHelper.cs index 285dd455..d2e6e98f 100644 --- a/Backend/Utils/OperationHelper.cs +++ b/Backend/Utils/OperationHelper.cs @@ -33,7 +33,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(); } } diff --git a/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index d38675a3..a0a4fff1 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -50,6 +50,7 @@ public enum BranchOperation public enum ConvertOperation { Conv, + IsInst, Cast, Box, Unbox, From a3a53d85f003258b7c378ec0f22a9f81fbbf43ed Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 27 May 2020 08:56:15 -0300 Subject: [PATCH 159/256] remove comments. Process Assemble CreateArrayInstruction --- Backend/Transformations/Assembler.cs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 50482476..d4d77e07 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -17,8 +17,7 @@ using SwitchInstruction = Model.ThreeAddressCode.Instructions.SwitchInstruction; using Bytecode = Model.Bytecode; -// FIXME parti desde code-generator por las cosas que arregle en el metadata-provider. Esta en branch aparte. Estaria bueno hacer el PR de esto -// FIXME sobre el branch de metadata-provider sin los cambios del code-generator. + namespace Backend.Transformations { public class Assembler @@ -52,15 +51,6 @@ public MethodBody Execute() return body; } - - //FIXME Revisar las operaciones que agregue (ej isinst, castClass, etc). Porque esas tampoco estan en las equivalentes del TAC y entonces no las puedo generar. - // FIXME va a haber que agregarlas al TAC no solo a los enums sino distinguirlas al momento de crearlas (al traducir de bytecode que ahora las tiene a tac). - - // FIXME De la misma forma, hay algunas Instrucciones nuevas que habia metido creo. Y esas seguramente no esten en el Visitor por lo que tambien - // FIXME va a haber que crearlas al traucir de bytecode a tac. (Ej indirectLoad/Store, Constrained, etc). - - // FIXME hay un par de metodos que no implemente porque son instrucciones de las que heredan otras por lo que entiendo que no hay que implementarlas. - // FIXME pero tenerlo en cuenta por si despues falta algo, quiza habia alguna que si. private class InstructionTranslator : InstructionVisitor { private readonly MethodBody body; @@ -232,7 +222,12 @@ public override void Visit(CopyObjectInstruction instruction) public override void Visit(CreateArrayInstruction instruction) { - throw new Exception(); + var createArrayInstruction = + new Bytecode.CreateArrayInstruction(instruction.Offset, new ArrayType(instruction.ElementType, instruction.Rank)) + { + WithLowerBound = instruction.LowerBounds.Any() + }; + body.Instructions.Add(createArrayInstruction); } public override void Visit(PhiInstruction instruction) From ac28f4299970edd613ecf1b51b78fa3bb9ad10a6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 28 May 2020 08:44:53 -0300 Subject: [PATCH 160/256] translate more instructions --- Backend/Transformations/Assembler.cs | 32 ++++++++++++++++++------- Backend/Transformations/Disassembler.cs | 5 +++- Backend/Utils/OperationHelper.cs | 11 +++++++++ Model/ThreeAddressCode/Instructions.cs | 4 +++- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index d4d77e07..17676629 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -15,7 +15,7 @@ using SizeofInstruction = Model.ThreeAddressCode.Instructions.SizeofInstruction; using StoreInstruction = Model.ThreeAddressCode.Instructions.StoreInstruction; using SwitchInstruction = Model.ThreeAddressCode.Instructions.SwitchInstruction; -using Bytecode = Model.Bytecode; +using Bytecode = Model.Bytecode;q namespace Backend.Transformations @@ -78,11 +78,16 @@ public override void Visit(UnaryInstruction instruction) public override void Visit(LoadInstruction instruction) { + // translate to dup, loadArrayLength, loadArrayElement, loadArrayElementAddress, loadStaticField, loadInstanceField, + // loadStaticFieldAddress, loadInnstanceFieldAddress, loadIndirect, loadConstant, loadVariable, loadVariableAddress, + // loadStaticMethodAddress, loadVirtualMethodAddress, + // StoreInstruction? CreateObjectInstruction? (se genera una en el visit de ambos) throw new Exception(); } public override void Visit(StoreInstruction instruction) { + // translate to store array element, store field, store indirect throw new Exception(); } @@ -182,32 +187,42 @@ public override void Visit(LoadTokenInstruction instruction) public override void Visit(MethodCallInstruction instruction) { - throw new Exception(); + var methodCallInstruction = new Bytecode.MethodCallInstruction( + instruction.Offset, + OperationHelper.ToMethodCallOperation(instruction.Operation), + instruction.Method + ); + body.Instructions.Add(methodCallInstruction); } public override void Visit(IndirectMethodCallInstruction instruction) { - throw new Exception(); + var indirectMethodCallInstruction = new Bytecode.IndirectMethodCallInstruction(instruction.Offset, instruction.Function); + body.Instructions.Add(indirectMethodCallInstruction); } public override void Visit(CreateObjectInstruction instruction) { - throw new Exception(); + var createObjectInstruction = new Bytecode.CreateObjectInstruction(instruction.Offset, instruction.Constructor); + body.Instructions.Add(createObjectInstruction); } public override void Visit(CopyMemoryInstruction instruction) { - throw new Exception(); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyBlock); + body.Instructions.Add(basicInstruction); } public override void Visit(LocalAllocationInstruction instruction) { - throw new Exception(); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LocalAllocation); + body.Instructions.Add(basicInstruction); } public override void Visit(InitializeMemoryInstruction instruction) { - throw new Exception(); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.InitBlock); + body.Instructions.Add(basicInstruction); } public override void Visit(InitializeObjectInstruction instruction) @@ -217,7 +232,8 @@ public override void Visit(InitializeObjectInstruction instruction) public override void Visit(CopyObjectInstruction instruction) { - throw new Exception(); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyObject); + body.Instructions.Add(basicInstruction); } public override void Visit(CreateArrayInstruction instruction) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 122b826d..5f3d776d 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -611,7 +611,10 @@ public override void Visit(Bytecode.CreateObjectInstruction op) arguments.Add(allocationResult); arguments.Reverse(); - IInstruction instruction = new Tac.CreateObjectInstruction(op.Offset, allocationResult, op.Constructor.ContainingType); + IInstruction instruction = new Tac.CreateObjectInstruction(op.Offset, allocationResult, op.Constructor.ContainingType) + { + Constructor = op.Constructor + }; body.Instructions.Add(instruction); instruction = new Tac.MethodCallInstruction(op.Offset, null, Tac.MethodCallOperation.Static, op.Constructor, arguments); diff --git a/Backend/Utils/OperationHelper.cs b/Backend/Utils/OperationHelper.cs index d2e6e98f..f4b2c58a 100644 --- a/Backend/Utils/OperationHelper.cs +++ b/Backend/Utils/OperationHelper.cs @@ -195,5 +195,16 @@ public static Bytecode.BasicOperation ToBasicOperation(Tac.BinaryOperation opera 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/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index a0a4fff1..14400747 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -1077,7 +1077,9 @@ public override string ToString() public class CreateObjectInstruction : DefinitionInstruction { public IType AllocationType { get; set; } - + + public IMethodReference Constructor { get; set; } + public CreateObjectInstruction(uint offset, IVariable result, IType allocationType) : base(offset, result) { From 9d52be5877a980232e25c3e97ef8f864f1d9e08d Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 28 May 2020 08:45:54 -0300 Subject: [PATCH 161/256] remove unwanted char --- Backend/Transformations/Assembler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 17676629..a2ea0a46 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -15,7 +15,7 @@ using SizeofInstruction = Model.ThreeAddressCode.Instructions.SizeofInstruction; using StoreInstruction = Model.ThreeAddressCode.Instructions.StoreInstruction; using SwitchInstruction = Model.ThreeAddressCode.Instructions.SwitchInstruction; -using Bytecode = Model.Bytecode;q +using Bytecode = Model.Bytecode; namespace Backend.Transformations From 4899c05186059eedf2d9e0e9528d79774e601b55 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 31 May 2020 16:10:04 -0300 Subject: [PATCH 162/256] fixes and translate more instructions --- Backend/Transformations/Assembler.cs | 37 +++++++++++++++++++------ Backend/Transformations/Disassembler.cs | 5 ++-- Backend/Utils/OperationHelper.cs | 3 +- Console/Program.cs | 19 ++++++------- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index a2ea0a46..491b1b8d 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -3,6 +3,7 @@ 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; @@ -41,7 +42,7 @@ 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); + body.ExceptionInformation.AddRange(method.Body.ExceptionInformation); // FIXME this needs to be generated if (method.Body.Instructions.Count > 0) { @@ -87,8 +88,26 @@ public override void Visit(LoadInstruction instruction) public override void Visit(StoreInstruction instruction) { - // translate to store array element, store field, store indirect - throw new Exception(); + Bytecode.Instruction storeInstruction; + switch (instruction.Result) + { + case ArrayElementAccess arrayElementAccess: + storeInstruction = new Bytecode.StoreArrayElementInstruction(instruction.Offset, (ArrayType) arrayElementAccess.Array.Type); + 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 Exception(); // TODO msg + } + + body.Instructions.Add(storeInstruction); } public override void Visit(NopInstruction instruction) @@ -105,22 +124,22 @@ public override void Visit(BreakpointInstruction instruction) public override void Visit(TryInstruction instruction) { - throw new Exception(); + // TODO } public override void Visit(FaultInstruction instruction) { - throw new Exception(); + // TODO } public override void Visit(FinallyInstruction instruction) { - throw new Exception(); + // TODO } public override void Visit(CatchInstruction instruction) { - throw new Exception(); + // TODO } public override void Visit(ConvertInstruction instruction) @@ -148,6 +167,7 @@ public override void Visit(ThrowInstruction instruction) body.Instructions.Add(basicInstruction); } + // TODO branch, leave, false, true public override void Visit(UnconditionalBranchInstruction instruction) { var unconditionalBranchInstruction = new Bytecode.BranchInstruction( @@ -227,7 +247,8 @@ public override void Visit(InitializeMemoryInstruction instruction) public override void Visit(InitializeObjectInstruction instruction) { - throw new Exception(); + var initObjInstruction = new Bytecode.InitObjInstruction(instruction.Offset, instruction.TargetAddress.Type); + body.Instructions.Add(initObjInstruction); } public override void Visit(CopyObjectInstruction instruction) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 5f3d776d..0e859a23 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -306,6 +306,7 @@ private void ProcessInitializeMemory(Bytecode.BasicInstruction op) public override void Visit(Bytecode.InitObjInstruction op) { var targetAddress = stack.Pop(); + targetAddress = new TemporalVariable(targetAddress.Prefix, targetAddress.Index) { Type = op.Type}; var instruction = new Tac.InitializeObjectInstruction(op.Offset, targetAddress); body.Instructions.Add(instruction); } @@ -578,9 +579,8 @@ public override void Visit(Bytecode.StoreArrayElementInstruction op) } var array = stack.Pop(); - + array = new TemporalVariable(array.Prefix, array.Index) { Type = op.Array }; indices.Reverse(); - var dest = new ArrayElementAccess(array, indices); var instruction = new Tac.StoreInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); @@ -900,6 +900,7 @@ public override void Visit(Bytecode.StoreIndirectInstruction op) { var source = stack.Pop(); var address = stack.Pop(); + address = new TemporalVariable(address.Prefix, address.Index) { Type = new PointerType(op.Type) }; var dest = new Dereference(address); var instruction = new Tac.StoreInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); diff --git a/Backend/Utils/OperationHelper.cs b/Backend/Utils/OperationHelper.cs index f4b2c58a..f3975e98 100644 --- a/Backend/Utils/OperationHelper.cs +++ b/Backend/Utils/OperationHelper.cs @@ -137,7 +137,7 @@ public static bool IsBranch(Bytecode.Instruction instruction) return result; } - + public static Bytecode.BranchOperation ToBranchOperation(Tac.BranchOperation operation) { switch (operation) @@ -161,6 +161,7 @@ public static Bytecode.ConvertOperation ToConvertOperation(Tac.ConvertOperation case Tac.ConvertOperation.Box: return Bytecode.ConvertOperation.Box; case Tac.ConvertOperation.Unbox: return Bytecode.ConvertOperation.Unbox; case Tac.ConvertOperation.UnboxPtr: return Bytecode.ConvertOperation.Unbox; + case Tac.ConvertOperation.IsInst: return Bytecode.ConvertOperation.IsInst; default: throw operation.ToUnknownValueException(); } } diff --git a/Console/Program.cs b/Console/Program.cs index 44752f4f..7dd5f903 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -430,18 +430,15 @@ static void Main(string[] args) var loader = new MetadataProvider.Loader(host); var assembly = loader.LoadAssembly("../../../Examples/bin/Debug/Examples.dll"); var methods = assembly.RootNamespace.Namespaces[4].Types[0].Methods; - - var method = methods[1]; - method.Body = new Disassembler(method).Execute(); // to tac - var assembler = new Assembler(method); - var newBody = assembler.Execute(); - - //RunSomeTests(); - // RunGenericsTests(); - //RunInterPointsToTests(); - System.Console.WriteLine("Done!"); - // System.Console.ReadKey(); + foreach (var method in methods.Where(method => method.HasBody)) + { + method.Body = new Disassembler(method).Execute(); // to tac + var newBody = new Assembler(method).Execute(); + + } + + System.Console.WriteLine("Done!"); } } } \ No newline at end of file From f7e55a0562913538fea364b2bb59e55778c1ed60 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 6 Jun 2020 20:52:07 -0300 Subject: [PATCH 163/256] draft --- Backend/Transformations/Assembler.cs | 88 ++++++++++++++++++++++--- Backend/Transformations/Disassembler.cs | 5 +- Backend/Utils/OperationHelper.cs | 15 ++++- Console/Program.cs | 32 ++++++--- MetadataProvider/AssemblyExtractor.cs | 29 +++++++- Model/ThreeAddressCode/Instructions.cs | 14 +++- 6 files changed, 158 insertions(+), 25 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 491b1b8d..2d13a468 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -39,10 +39,10 @@ public MethodBody Execute() { var body = new MethodBody(MethodBodyKind.Bytecode); - body.MaxStack = method.Body.MaxStack; + body.MaxStack = method.Body.MaxStack; // FIXME body.Parameters.AddRange(method.Body.Parameters); body.LocalVariables.AddRange(method.Body.LocalVariables); - body.ExceptionInformation.AddRange(method.Body.ExceptionInformation); // FIXME this needs to be generated + // body.ExceptionInformation.AddRange(method.Body.ExceptionInformation); // FIXME this needs to be generated if (method.Body.Instructions.Count > 0) { @@ -83,7 +83,76 @@ public override void Visit(LoadInstruction instruction) // loadStaticFieldAddress, loadInnstanceFieldAddress, loadIndirect, loadConstant, loadVariable, loadVariableAddress, // loadStaticMethodAddress, loadVirtualMethodAddress, // StoreInstruction? CreateObjectInstruction? (se genera una en el visit de ambos) - throw new Exception(); + + Bytecode.Instruction loadInstruction; + if (instruction.Operand is TemporalVariable && instruction.Result is TemporalVariable) + { + if (instruction.Operand.Equals(instruction.Result)) + { + return; + } + else + { + loadInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Dup); + } + } + else + { + switch (instruction.Operand) + { + case Constant constant: + loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant); + break; + case TemporalVariable _: + loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Content, instruction.Result); + break; + case Dereference dereference: + loadInstruction = new Bytecode.LoadIndirectInstruction(instruction.Offset, dereference.Type); + break; + case Reference reference: + switch (reference.Value) + { + case ArrayElementAccess arrayElementAccess: + case LocalVariable localVariable: + loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Address, + instruction.Result); + break; + default: + throw new Exception(); + } + + break; + case LocalVariable _: throw new Exception(); + case ArrayLengthAccess _: + loadInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LoadArrayLength); + break; + case StaticMethodReference staticMethodReference: + loadInstruction = new Bytecode.LoadMethodAddressInstruction( + instruction.Offset, + Bytecode.LoadMethodAddressOperation.Static, + staticMethodReference.Method); + break; + case InstanceFieldAccess instanceFieldAccess: + // fixme es content? + loadInstruction = new Bytecode.LoadFieldInstruction(instruction.Offset, Bytecode.LoadFieldOperation.Content, + instanceFieldAccess.Field); + break; + case StaticFieldAccess staticFieldAccess: + // fixme es content? + loadInstruction = new Bytecode.LoadFieldInstruction(instruction.Offset, Bytecode.LoadFieldOperation.Content, + staticFieldAccess.Field); + break; + case ArrayElementAccess arrayElementAccess: + loadInstruction = new Bytecode.LoadArrayElementInstruction( + instruction.Offset, + Bytecode.LoadArrayElementOperation.Content, + (ArrayType) arrayElementAccess.Array.Type); + break; + default: throw new Exception(); + } + } + + body.Instructions.Add(loadInstruction); } public override void Visit(StoreInstruction instruction) @@ -124,22 +193,22 @@ public override void Visit(BreakpointInstruction instruction) public override void Visit(TryInstruction instruction) { - // TODO + throw new Exception(); } public override void Visit(FaultInstruction instruction) { - // TODO + throw new Exception(); } public override void Visit(FinallyInstruction instruction) { - // TODO + throw new Exception(); } public override void Visit(CatchInstruction instruction) { - // TODO + throw new Exception(); } public override void Visit(ConvertInstruction instruction) @@ -167,12 +236,11 @@ public override void Visit(ThrowInstruction instruction) body.Instructions.Add(basicInstruction); } - // TODO branch, leave, false, true public override void Visit(UnconditionalBranchInstruction instruction) { var unconditionalBranchInstruction = new Bytecode.BranchInstruction( instruction.Offset, - Bytecode.BranchOperation.Branch, + OperationHelper.ToBranchOperation(instruction.Operation), Convert.ToUInt32(instruction.Target.Substring(2), 16)); body.Instructions.Add(unconditionalBranchInstruction); } @@ -181,7 +249,7 @@ public override void Visit(ConditionalBranchInstruction instruction) { var conditionalBranchInstruction = new Bytecode.BranchInstruction( instruction.Offset, - OperationHelper.ToBranchOperation(instruction.Operation), + OperationHelper.ToBranchOperation(instruction.Operation, instruction.RightOperand), Convert.ToUInt32(instruction.Target.Substring(2), 16)); body.Instructions.Add(conditionalBranchInstruction); } diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 0e859a23..dd3a5a70 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -465,7 +465,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); } } @@ -537,6 +537,7 @@ private void ProcessLoadArrayElement(Bytecode.LoadArrayElementInstruction op) } var array = stack.Pop(); + array = new TemporalVariable(array.Prefix, array.Index) { Type = op.Array }; indices.Reverse(); @@ -557,6 +558,7 @@ private void ProcessLoadArrayElementAddress(Bytecode.LoadArrayElementInstruction } var array = stack.Pop(); + array = new TemporalVariable(array.Prefix, array.Index) { Type = op.Array }; indices.Reverse(); @@ -736,6 +738,7 @@ private void ProcessLoadInstanceFieldAddress(Bytecode.LoadFieldInstruction op) public override void Visit(Bytecode.LoadIndirectInstruction op) { var address = stack.Pop(); + address = new TemporalVariable(address.Prefix, address.Index) { Type = new PointerType(op.Type) }; var dest = stack.Push(); var source = new Dereference(address); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); diff --git a/Backend/Utils/OperationHelper.cs b/Backend/Utils/OperationHelper.cs index f3975e98..a4635b0d 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; @@ -138,10 +139,12 @@ public static bool IsBranch(Bytecode.Instruction instruction) return result; } - public static Bytecode.BranchOperation ToBranchOperation(Tac.BranchOperation operation) + public static Bytecode.BranchOperation ToBranchOperation(Tac.BranchOperation operation, IInmediateValue value) { switch (operation) { + case Tac.BranchOperation.Eq when new Constant(true).Equals(value): return Bytecode.BranchOperation.True; + case Tac.BranchOperation.Eq when new Constant(false).Equals(value): return Bytecode.BranchOperation.False; case Tac.BranchOperation.Eq: return Bytecode.BranchOperation.Eq; case Tac.BranchOperation.Neq: return Bytecode.BranchOperation.Neq; case Tac.BranchOperation.Lt: return Bytecode.BranchOperation.Lt; @@ -207,5 +210,15 @@ public static Bytecode.MethodCallOperation ToMethodCallOperation(Tac.MethodCallO default: throw operation.ToUnknownValueException(); } } + + public static Bytecode.BranchOperation ToBranchOperation(Tac.UnconditionalBranchOperation operation) + { + switch (operation) + { + case Tac.UnconditionalBranchOperation.Branch: return Bytecode.BranchOperation.Branch; + case Tac.UnconditionalBranchOperation.Leave: return Bytecode.BranchOperation.Leave; + default: throw operation.ToUnknownValueException(); + } + } } } diff --git a/Console/Program.cs b/Console/Program.cs index 7dd5f903..0f67cab5 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -423,21 +423,33 @@ static void Main(string[] args) } } */ - var host = new Host(); + foreach (var input in inputs) + { + foreach (var file in input) + { + System.Console.WriteLine("Processing file: " + file); + var host = new Host(); - PlatformTypes.Resolve(host); + PlatformTypes.Resolve(host); - var loader = new MetadataProvider.Loader(host); - var assembly = loader.LoadAssembly("../../../Examples/bin/Debug/Examples.dll"); - var methods = assembly.RootNamespace.Namespaces[4].Types[0].Methods; + var loader = new Loader(host); + var assembly = loader.LoadAssembly(file); + var methods = + from types in assembly.RootNamespace.GetAllTypes() + from m in types.Methods + where m.HasBody + select m; - foreach (var method in methods.Where(method => method.HasBody)) - { - method.Body = new Disassembler(method).Execute(); // to tac - var newBody = new Assembler(method).Execute(); - + foreach (var method in methods) + { + method.Body = new Disassembler(method).Execute(); // to tac + var newBody = new Assembler(method).Execute(); // to bytecode + } + } } + + System.Console.WriteLine("Done!"); } } diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index a391e6a6..d7594fe8 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1415,11 +1415,38 @@ private IMethodReference GetMethodReference(SRM.MethodSpecificationHandle handle CreateGenericParameterReferences(GenericParameterKind.Method, genericArguments.Length); var method = GetMethodReference(methodspec.Method); - method = method.Instantiate(genericArguments); + method = new MethodInstantiationProxy(method, genericArguments); BindGenericParameterReferences(GenericParameterKind.Method, method); return method; } + + // TODO make copies of collections + private class MethodInstantiationProxy : IMethodReference + { + public IBasicType ContainingType => method.ContainingType; + public ISet Attributes => method.Attributes; + public int GenericParameterCount => method.GenericParameterCount; + public IType ReturnType => method.ReturnType; + public string Name => method.Name; + public string GenericName => method.GenericName; + public IList Parameters => method.Parameters; + public IList GenericArguments => genericArguments; + public IMethodReference GenericMethod => method; + public MethodDefinition ResolvedMethod => throw new NotImplementedException(); + public bool IsStatic => method.IsStatic; + public bool IsVirtual => method.IsVirtual; + + private readonly IMethodReference method; + private readonly IList genericArguments; + + public MethodInstantiationProxy(IMethodReference method, IEnumerable genericArguments) + { + this.method = method; + this.genericArguments = new List(); + this.genericArguments.AddRange(genericArguments); + } + } private IMethodReference GetMethodReference(SRM.EntityHandle handle) { diff --git a/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index 14400747..a0507336 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -46,6 +46,12 @@ public enum BranchOperation Gt, Ge } + + public enum UnconditionalBranchOperation + { + Branch, + Leave + } public enum ConvertOperation { @@ -724,14 +730,18 @@ public override string ToString() public class UnconditionalBranchInstruction : BranchInstruction { - public UnconditionalBranchInstruction(uint offset, uint target) + public UnconditionalBranchOperation Operation { get; set; } + + public UnconditionalBranchInstruction(uint offset, uint target, UnconditionalBranchOperation operation = UnconditionalBranchOperation.Branch) : base(offset, target) { + this.Operation = operation; } - public UnconditionalBranchInstruction(uint offset, string target) + public UnconditionalBranchInstruction(uint offset, string target, UnconditionalBranchOperation operation = UnconditionalBranchOperation.Branch) : base(offset, target) { + this.Operation = operation; } public override void Accept(IInstructionVisitor visitor) From b9256fbfe885abaea59514e4f7dd2e024ae570ce Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 8 Jun 2020 09:00:05 -0300 Subject: [PATCH 164/256] exception handling draft --- Backend/Transformations/Assembler.cs | 169 +++++++++++++++--- Backend/Utils/OperationHelper.cs | 10 -- .../Visitor/InstructionVisitor.cs | 1 + 3 files changed, 150 insertions(+), 30 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 2d13a468..ecde4ac7 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using Backend.Utils; using Model; using Model.ThreeAddressCode.Instructions; @@ -42,7 +44,6 @@ public MethodBody Execute() body.MaxStack = method.Body.MaxStack; // FIXME body.Parameters.AddRange(method.Body.Parameters); body.LocalVariables.AddRange(method.Body.LocalVariables); - // body.ExceptionInformation.AddRange(method.Body.ExceptionInformation); // FIXME this needs to be generated if (method.Body.Instructions.Count > 0) { @@ -55,6 +56,7 @@ public MethodBody Execute() private class InstructionTranslator : InstructionVisitor { private readonly MethodBody body; + private readonly Stack exceptionBlocks = new Stack(); public InstructionTranslator(MethodBody body) { @@ -83,6 +85,7 @@ public override void Visit(LoadInstruction instruction) // loadStaticFieldAddress, loadInnstanceFieldAddress, loadIndirect, loadConstant, loadVariable, loadVariableAddress, // loadStaticMethodAddress, loadVirtualMethodAddress, // StoreInstruction? CreateObjectInstruction? (se genera una en el visit de ambos) + // FIXME revisar los casos, hay algunos que no estoy seguro de que esten bien. Bytecode.Instruction loadInstruction; if (instruction.Operand is TemporalVariable && instruction.Result is TemporalVariable) @@ -112,17 +115,21 @@ public override void Visit(LoadInstruction instruction) case Reference reference: switch (reference.Value) { - case ArrayElementAccess arrayElementAccess: - case LocalVariable localVariable: - loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Address, + case ArrayElementAccess _: + case LocalVariable _: + loadInstruction = new Bytecode.LoadInstruction( + instruction.Offset, + Bytecode.LoadOperation.Address, instruction.Result); break; default: - throw new Exception(); + throw new Exception(); // TODO } break; - case LocalVariable _: throw new Exception(); + case LocalVariable localVariable: + loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Content, localVariable); + break; case ArrayLengthAccess _: loadInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LoadArrayLength); break; @@ -148,7 +155,7 @@ public override void Visit(LoadInstruction instruction) Bytecode.LoadArrayElementOperation.Content, (ArrayType) arrayElementAccess.Array.Type); break; - default: throw new Exception(); + default: throw new Exception(); // TODO } } @@ -181,8 +188,20 @@ public override void Visit(StoreInstruction instruction) public override void Visit(NopInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop); - body.Instructions.Add(basicInstruction); + var endsFilterOrFinally = exceptionBlocks.Count > 0 && ( + ExceptionHandlerBlockKind.Filter.Equals(exceptionBlocks.Peek().HandlerBlockKind.Value) || + ExceptionHandlerBlockKind.Finally.Equals(exceptionBlocks.Peek().HandlerBlockKind.Value)); + if (endsFilterOrFinally) + { + var exceptionBlockBuilder = exceptionBlocks.Pop(); + exceptionBlockBuilder.HandlerEnd = instruction.Offset; + body.ExceptionInformation.Add(exceptionBlockBuilder.Build()); + } + else + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop); + body.Instructions.Add(basicInstruction); + } } public override void Visit(BreakpointInstruction instruction) @@ -191,24 +210,49 @@ public override void Visit(BreakpointInstruction instruction) body.Instructions.Add(basicInstruction); } + // TODO en el bytecode no hay instrucciones de todo lo que es exception handling. + // Hay que usar estas del tac que si hay para crear el exceptionInformation del method me parece usando las mismas para + // tener bien los labels en dodne estan. Hay que ver que los handlers y las excepciones si es que esta todo o habra que agregar algo. + // la idea es que voy pusheando a la pila los bloques asi los voy completando y cuadno tengo la instruccion que lo termina ( + // la que sale del bloque) lo construyo, lo saco de la pila y lo agrego. + // El tema es que + // - Para lo que es endFilter/endFinally, La traduccion de Bytecode a Tac genera un Nop. Hay que ver si lo que hice en el nop esta bien. + // Mismo con el leave. Ver esos metodos de extensions de CanFallThrough, IsExitingMethod, etc. + public override void Visit(TryInstruction instruction) { - throw new Exception(); + var exceptionBlockBuilder = new ExceptionBlockBuilder {TryStart = instruction.Offset}; + exceptionBlocks.Push(exceptionBlockBuilder); } public override void Visit(FaultInstruction instruction) { - throw new Exception(); + var exceptionBlockBuilder = exceptionBlocks.Last(); + exceptionBlockBuilder.HandlerStart = instruction.Offset; + exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Fault; } public override void Visit(FinallyInstruction instruction) { - throw new Exception(); + var exceptionBlockBuilder = exceptionBlocks.Last(); + exceptionBlockBuilder.HandlerStart = instruction.Offset; + exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Finally; + } + + public override void Visit(FilterInstruction instruction) + { + var exceptionBlockBuilder = exceptionBlocks.Last(); + exceptionBlockBuilder.HandlerStart = null; //FIXME + exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Filter; + exceptionBlockBuilder.ExceptionType = instruction.ExceptionType; } public override void Visit(CatchInstruction instruction) { - throw new Exception(); + var exceptionBlockBuilder = exceptionBlocks.Last(); + exceptionBlockBuilder.HandlerStart = instruction.Offset; + exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Catch; + exceptionBlockBuilder.ExceptionType = instruction.ExceptionType; } public override void Visit(ConvertInstruction instruction) @@ -232,17 +276,59 @@ public override void Visit(ReturnInstruction instruction) public override void Visit(ThrowInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Throw); - body.Instructions.Add(basicInstruction); + if (exceptionBlocks.Count > 0) + { + var exceptionBlockBuilder = exceptionBlocks.Peek(); + if (exceptionBlockBuilder.HandlerStart == null) // fixme mismo comentario que en el leave + { + exceptionBlockBuilder.TryEnd = instruction.Offset; + } + else + { + // rethrow + exceptionBlockBuilder = exceptionBlocks.Pop(); + exceptionBlockBuilder.HandlerEnd = instruction.Offset; + // exceptionBlockBuilder.ExceptionType = null; // FIXME ? al ser un rethrow, ya esta seteado esto por un anterior throw? + // fixme sin embargo en la rama del if, no habria que setear la excepcion? + } + } + else + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Throw); + body.Instructions.Add(basicInstruction); + } } public override void Visit(UnconditionalBranchInstruction instruction) { - var unconditionalBranchInstruction = new Bytecode.BranchInstruction( - instruction.Offset, - OperationHelper.ToBranchOperation(instruction.Operation), - Convert.ToUInt32(instruction.Target.Substring(2), 16)); - body.Instructions.Add(unconditionalBranchInstruction); + switch (instruction.Operation) + { + // FIXME leave can be used for another purpose than exiting a protected region? + case UnconditionalBranchOperation.Leave when exceptionBlocks.Count == 0: + case UnconditionalBranchOperation.Branch: + var unconditionalBranchInstruction = new Bytecode.BranchInstruction( + instruction.Offset, + Bytecode.BranchOperation.Branch, + Convert.ToUInt32(instruction.Target.Substring(2), 16)); + body.Instructions.Add(unconditionalBranchInstruction); + break; + case UnconditionalBranchOperation.Leave: + var exceptionBlockBuilder = exceptionBlocks.Peek(); + if (exceptionBlockBuilder.HandlerStart == null) // FIXME estoy asumiendo que si no se seteo el handler es porque es un try aun + // FIXME es correcto esto? Si lo es quiza puedo poner un metodo que diga que todavia estoy en el try asi se entiende mas + { + exceptionBlockBuilder.TryEnd = instruction.Offset; + } + else + { + exceptionBlockBuilder = exceptionBlocks.Pop(); + exceptionBlockBuilder.HandlerEnd = instruction.Offset; + body.ExceptionInformation.Add(exceptionBlockBuilder.Build()); + } + + break; + default: throw instruction.Operation.ToUnknownValueException(); + } } public override void Visit(ConditionalBranchInstruction instruction) @@ -339,6 +425,49 @@ public override void Visit(PhiInstruction instruction) { throw new Exception(); } + + private class ExceptionBlockBuilder + { + public uint? TryStart; + public uint? TryEnd; + public uint? HandlerStart; + public uint? HandlerEnd; + public ExceptionHandlerBlockKind? HandlerBlockKind; + public IType ExceptionType; + + public ProtectedBlock Build() + { + if (TryStart == null) throw new Exception("TryStart not set"); + if (TryEnd == null) throw new Exception("TryEnd not set"); + if (HandlerStart == null) throw new Exception("HandlerStart not set"); + if (HandlerEnd == null) throw new Exception("HandlerEnd not set"); + if (HandlerBlockKind == null) throw new Exception("HandlerBlockKind not set"); + IExceptionHandler handler; + switch (HandlerBlockKind) + { + case ExceptionHandlerBlockKind.Filter: + if (ExceptionType == null) throw new Exception("ExceptionType not set"); + handler = new FilterExceptionHandler(TryEnd.Value, HandlerStart.Value, HandlerEnd.Value, ExceptionType); + break; + case ExceptionHandlerBlockKind.Catch: + if (ExceptionType == null) throw new Exception("ExceptionType not set"); + handler = new CatchExceptionHandler(HandlerStart.Value, HandlerEnd.Value, ExceptionType); + break; + case ExceptionHandlerBlockKind.Fault: + handler = new FaultExceptionHandler(HandlerStart.Value, HandlerEnd.Value); + break; + case ExceptionHandlerBlockKind.Finally: + handler = new FinallyExceptionHandler(HandlerStart.Value, HandlerEnd.Value); + break; + default: throw new UnknownValueException(HandlerBlockKind.Value); + } + + return new ProtectedBlock(TryStart.Value, TryEnd.Value) + { + Handler = handler + }; + } + } } } } \ No newline at end of file diff --git a/Backend/Utils/OperationHelper.cs b/Backend/Utils/OperationHelper.cs index a4635b0d..3bcb4633 100644 --- a/Backend/Utils/OperationHelper.cs +++ b/Backend/Utils/OperationHelper.cs @@ -210,15 +210,5 @@ public static Bytecode.MethodCallOperation ToMethodCallOperation(Tac.MethodCallO default: throw operation.ToUnknownValueException(); } } - - public static Bytecode.BranchOperation ToBranchOperation(Tac.UnconditionalBranchOperation operation) - { - switch (operation) - { - case Tac.UnconditionalBranchOperation.Branch: return Bytecode.BranchOperation.Branch; - case Tac.UnconditionalBranchOperation.Leave: return Bytecode.BranchOperation.Leave; - default: throw operation.ToUnknownValueException(); - } - } } } diff --git a/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs b/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs index 4d1043da..67ba4976 100644 --- a/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs +++ b/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs @@ -28,6 +28,7 @@ public virtual void Visit(StoreInstruction instruction) { } public virtual void Visit(NopInstruction instruction) { } public virtual void Visit(BreakpointInstruction instruction) { } public virtual void Visit(TryInstruction instruction) { } + public virtual void Visit(FilterInstruction instruction) { } public virtual void Visit(FaultInstruction instruction) { } public virtual void Visit(FinallyInstruction instruction) { } public virtual void Visit(CatchInstruction instruction) { } From d43d61ae2c2d7029332a5aefbc97c9e4f551e408 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 10 Jun 2020 08:56:03 -0300 Subject: [PATCH 165/256] tunning exception handling --- Backend/Transformations/Assembler.cs | 41 ++++++++----------- Backend/Transformations/Disassembler.cs | 17 ++++++-- Examples/Examples.cs | 24 ++++++++++- ExamplesEXE/ExamplesEXE.cs | 2 +- Model/ThreeAddressCode/Instructions.cs | 22 ++++++++-- .../Visitor/IInstructionVisitor.cs | 1 + 6 files changed, 73 insertions(+), 34 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index ecde4ac7..9a74932c 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -188,20 +188,8 @@ public override void Visit(StoreInstruction instruction) public override void Visit(NopInstruction instruction) { - var endsFilterOrFinally = exceptionBlocks.Count > 0 && ( - ExceptionHandlerBlockKind.Filter.Equals(exceptionBlocks.Peek().HandlerBlockKind.Value) || - ExceptionHandlerBlockKind.Finally.Equals(exceptionBlocks.Peek().HandlerBlockKind.Value)); - if (endsFilterOrFinally) - { - var exceptionBlockBuilder = exceptionBlocks.Pop(); - exceptionBlockBuilder.HandlerEnd = instruction.Offset; - body.ExceptionInformation.Add(exceptionBlockBuilder.Build()); - } - else - { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop); - body.Instructions.Add(basicInstruction); - } + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop); + body.Instructions.Add(basicInstruction); } public override void Visit(BreakpointInstruction instruction) @@ -210,15 +198,6 @@ public override void Visit(BreakpointInstruction instruction) body.Instructions.Add(basicInstruction); } - // TODO en el bytecode no hay instrucciones de todo lo que es exception handling. - // Hay que usar estas del tac que si hay para crear el exceptionInformation del method me parece usando las mismas para - // tener bien los labels en dodne estan. Hay que ver que los handlers y las excepciones si es que esta todo o habra que agregar algo. - // la idea es que voy pusheando a la pila los bloques asi los voy completando y cuadno tengo la instruccion que lo termina ( - // la que sale del bloque) lo construyo, lo saco de la pila y lo agrego. - // El tema es que - // - Para lo que es endFilter/endFinally, La traduccion de Bytecode a Tac genera un Nop. Hay que ver si lo que hice en el nop esta bien. - // Mismo con el leave. Ver esos metodos de extensions de CanFallThrough, IsExitingMethod, etc. - public override void Visit(TryInstruction instruction) { var exceptionBlockBuilder = new ExceptionBlockBuilder {TryStart = instruction.Offset}; @@ -239,10 +218,11 @@ public override void Visit(FinallyInstruction instruction) exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Finally; } + //FIXME ajustar ahora que estan separados la parte del filter del handler del filter. Hay que cambiar tmb cuando sale del block de filter public override void Visit(FilterInstruction instruction) { var exceptionBlockBuilder = exceptionBlocks.Last(); - exceptionBlockBuilder.HandlerStart = null; //FIXME + exceptionBlockBuilder.HandlerStart = instruction.Offset; exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Filter; exceptionBlockBuilder.ExceptionType = instruction.ExceptionType; } @@ -299,6 +279,7 @@ public override void Visit(ThrowInstruction instruction) } } + // todo emprolijar public override void Visit(UnconditionalBranchInstruction instruction) { switch (instruction.Operation) @@ -306,13 +287,24 @@ public override void Visit(UnconditionalBranchInstruction instruction) // FIXME leave can be used for another purpose than exiting a protected region? case UnconditionalBranchOperation.Leave when exceptionBlocks.Count == 0: case UnconditionalBranchOperation.Branch: + { var unconditionalBranchInstruction = new Bytecode.BranchInstruction( instruction.Offset, Bytecode.BranchOperation.Branch, Convert.ToUInt32(instruction.Target.Substring(2), 16)); body.Instructions.Add(unconditionalBranchInstruction); break; + } + case UnconditionalBranchOperation.EndFinally: + case UnconditionalBranchOperation.EndFilter: //FIXME adaptar por lo nuevo del filter + { + var exceptionBlockBuilder = exceptionBlocks.Pop(); + exceptionBlockBuilder.HandlerEnd = instruction.Offset; + body.ExceptionInformation.Add(exceptionBlockBuilder.Build()); + break; + } case UnconditionalBranchOperation.Leave: + { var exceptionBlockBuilder = exceptionBlocks.Peek(); if (exceptionBlockBuilder.HandlerStart == null) // FIXME estoy asumiendo que si no se seteo el handler es porque es un try aun // FIXME es correcto esto? Si lo es quiza puedo poner un metodo que diga que todavia estoy en el try asi se entiende mas @@ -327,6 +319,7 @@ public override void Visit(UnconditionalBranchInstruction instruction) } break; + } default: throw instruction.Operation.ToUnknownValueException(); } } diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index dd3a5a70..dc2fc40e 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -256,7 +256,8 @@ private void ProcessEndFinally(Bytecode.BasicInstruction op) { stack.Clear(); - ProcessEmptyOperation(op); + var instruction = new Tac.UnconditionalBranchInstruction(op.Offset, op.Offset+1, 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, @@ -281,7 +282,8 @@ private void ProcessEndFilter(Bytecode.BasicInstruction op) { stack.Clear(); - ProcessEmptyOperation(op); + var instruction = new Tac.UnconditionalBranchInstruction(op.Offset, op.Offset+1, Tac.UnconditionalBranchOperation.EndFilter); + body.Instructions.Add(instruction); } private void ProcessLocalAllocation(Bytecode.BasicInstruction op) @@ -1014,6 +1016,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); @@ -1049,8 +1055,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: diff --git a/Examples/Examples.cs b/Examples/Examples.cs index f6f342d1..f21a09b1 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1030,18 +1030,38 @@ public void ExceptionHandlingTryCatchSpecific(int x) } - public void ExceptionHandlingTryCatchFilter(int x) + public void ExceptionHandlingTryCatchMultipleFilter(int x) { try { var y = 1 / x; } + catch (EntryPointNotFoundException e) when (e.Message.Contains("")) + { + Console.WriteLine(e.Message); + } catch (Exception ex) when (ex.Message.Contains("by zero")) { Console.WriteLine(ex.Message); } } - + + public void ExceptionHandlingMultipleCatchs(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + /* FIXME finally end label is wrong in the model (one more that it should be, that label does not exist)? this example results in an FIXME unmarked label. The IL though is generated correctly public void ExceptionHandlingTryCatchFinally(Exception e) diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index f969fbff..241dc59c 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -37,7 +37,7 @@ public static void Main(string[] args) Console.WriteLine(methodBodyExamples.StoreValue(100)); methodBodyExamples.ExceptionHandlingTryCatchSpecific(0); methodBodyExamples.ExceptionHandlingTryCatch(0); - methodBodyExamples.ExceptionHandlingTryCatchFilter(0); + methodBodyExamples.ExceptionHandlingTryCatchMultipleFilter(0); Console.WriteLine(methodBodyExamples.LoadField()); Console.WriteLine(methodBodyExamples.StoreField()); methodBodyExamples.Calls(sc, e => 5); diff --git a/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index a0507336..b2e2ce6c 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -50,7 +50,9 @@ public enum BranchOperation public enum UnconditionalBranchOperation { Branch, - Leave + Leave, + EndFinally, + EndFilter } public enum ConvertOperation @@ -70,6 +72,13 @@ public enum MethodCallOperation Jump } + // FIXME names + public enum FilterInstructionKind + { + FilterSection, + FilterHandler + } + public abstract class Instruction : IInstruction { public uint Offset { get; set; } @@ -478,10 +487,13 @@ public class FilterInstruction : DefinitionInstruction { public IType ExceptionType { get; set; } - public FilterInstruction(uint offset, IVariable result, IType exceptionType) + public FilterInstructionKind kind { get; private set; } + + public FilterInstruction(uint offset, IVariable result, IType exceptionType, FilterInstructionKind kind) : base(offset, result) { this.ExceptionType = exceptionType; + this.kind = kind; } public override void Accept(IInstructionVisitor visitor) @@ -497,7 +509,11 @@ public override IExpression ToExpression() public override string ToString() { - return this.ToString("filter {0} {1}", this.ExceptionType, this.Result); + return this.ToString( + "filter {0} {1} {2}", + kind == FilterInstructionKind.FilterSection ? "section" : "handler", + this.ExceptionType, + this.Result); } } diff --git a/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs b/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs index 9373b35a..b429d180 100644 --- a/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs +++ b/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs @@ -22,6 +22,7 @@ public interface IInstructionVisitor void Visit(TryInstruction instruction); void Visit(FaultInstruction instruction); void Visit(FinallyInstruction instruction); + void Visit(FilterInstruction instruction); void Visit(CatchInstruction instruction); void Visit(ConvertInstruction instruction); void Visit(ReturnInstruction instruction); From 27366a0dd61e1fa3d35bbf5e5e5974ad2ee497ae Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 13 Jun 2020 10:31:13 -0300 Subject: [PATCH 166/256] fix exception translation --- Backend/Transformations/Assembler.cs | 24 +++++++++++++++++------- Examples/Examples.cs | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 9a74932c..a34e5f08 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -85,7 +85,7 @@ public override void Visit(LoadInstruction instruction) // loadStaticFieldAddress, loadInnstanceFieldAddress, loadIndirect, loadConstant, loadVariable, loadVariableAddress, // loadStaticMethodAddress, loadVirtualMethodAddress, // StoreInstruction? CreateObjectInstruction? (se genera una en el visit de ambos) - // FIXME revisar los casos, hay algunos que no estoy seguro de que esten bien. + // FIXME revisar los casos, hay algunos que no estoy seguro de que esten bien. se repiten caminos ademas (sobretodo por el reference) Bytecode.Instruction loadInstruction; if (instruction.Operand is TemporalVariable && instruction.Result is TemporalVariable) @@ -122,6 +122,11 @@ public override void Visit(LoadInstruction instruction) Bytecode.LoadOperation.Address, instruction.Result); break; + case InstanceFieldAccess instanceFieldAccess: + // fixme es content? + loadInstruction = new Bytecode.LoadFieldInstruction(instruction.Offset, Bytecode.LoadFieldOperation.Content, + instanceFieldAccess.Field); + break; default: throw new Exception(); // TODO } @@ -206,22 +211,21 @@ public override void Visit(TryInstruction instruction) public override void Visit(FaultInstruction instruction) { - var exceptionBlockBuilder = exceptionBlocks.Last(); + var exceptionBlockBuilder = exceptionBlocks.Peek(); exceptionBlockBuilder.HandlerStart = instruction.Offset; exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Fault; } public override void Visit(FinallyInstruction instruction) { - var exceptionBlockBuilder = exceptionBlocks.Last(); + var exceptionBlockBuilder = exceptionBlocks.Peek(); exceptionBlockBuilder.HandlerStart = instruction.Offset; exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Finally; } - //FIXME ajustar ahora que estan separados la parte del filter del handler del filter. Hay que cambiar tmb cuando sale del block de filter public override void Visit(FilterInstruction instruction) { - var exceptionBlockBuilder = exceptionBlocks.Last(); + var exceptionBlockBuilder = exceptionBlocks.Peek(); exceptionBlockBuilder.HandlerStart = instruction.Offset; exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Filter; exceptionBlockBuilder.ExceptionType = instruction.ExceptionType; @@ -229,7 +233,7 @@ public override void Visit(FilterInstruction instruction) public override void Visit(CatchInstruction instruction) { - var exceptionBlockBuilder = exceptionBlocks.Last(); + var exceptionBlockBuilder = exceptionBlocks.Peek(); exceptionBlockBuilder.HandlerStart = instruction.Offset; exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Catch; exceptionBlockBuilder.ExceptionType = instruction.ExceptionType; @@ -296,13 +300,17 @@ public override void Visit(UnconditionalBranchInstruction instruction) break; } case UnconditionalBranchOperation.EndFinally: - case UnconditionalBranchOperation.EndFilter: //FIXME adaptar por lo nuevo del filter { var exceptionBlockBuilder = exceptionBlocks.Pop(); exceptionBlockBuilder.HandlerEnd = instruction.Offset; body.ExceptionInformation.Add(exceptionBlockBuilder.Build()); break; } + case UnconditionalBranchOperation.EndFilter: + { + // nothing since filter area is the gap between try end and handler start + break; + } case UnconditionalBranchOperation.Leave: { var exceptionBlockBuilder = exceptionBlocks.Peek(); @@ -422,7 +430,9 @@ public override void Visit(PhiInstruction instruction) private class ExceptionBlockBuilder { public uint? TryStart; + public uint? TryEnd; + public uint? HandlerStart; public uint? HandlerEnd; public ExceptionHandlerBlockKind? HandlerBlockKind; diff --git a/Examples/Examples.cs b/Examples/Examples.cs index f21a09b1..9853dea4 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1030,7 +1030,7 @@ public void ExceptionHandlingTryCatchSpecific(int x) } - public void ExceptionHandlingTryCatchMultipleFilter(int x) + public void ExceptionHandlingMultipleFilter(int x) { try { From f2831ebcb55db268caae4ea9022afc4f4b3f6cc6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 14 Jun 2020 10:59:44 -0300 Subject: [PATCH 167/256] better exception generation --- Backend/Transformations/Assembler.cs | 282 +++++++++++++++++++++------ Console/Program.cs | 11 +- Examples/Examples.cs | 33 ++++ ExamplesEXE/ExamplesEXE.cs | 2 +- 4 files changed, 260 insertions(+), 68 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index a34e5f08..82d48529 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -56,7 +56,7 @@ public MethodBody Execute() private class InstructionTranslator : InstructionVisitor { private readonly MethodBody body; - private readonly Stack exceptionBlocks = new Stack(); + private readonly Stack protectedBlocks = new Stack(); public InstructionTranslator(MethodBody body) { @@ -205,38 +205,79 @@ public override void Visit(BreakpointInstruction instruction) public override void Visit(TryInstruction instruction) { - var exceptionBlockBuilder = new ExceptionBlockBuilder {TryStart = instruction.Offset}; - exceptionBlocks.Push(exceptionBlockBuilder); + // try with multiple handlers are modelled as multiple try instructions with the same label but different handlers. + // if label matches with the current try, then increase the number of expected handlers + if (protectedBlocks.Count > 0 && protectedBlocks.Peek().TryStart.Equals(instruction.Offset)) + { + protectedBlocks.Peek().HandlerCount++; + } + else + { + var exceptionBlockBuilder = new ProtectedBlockBuilder {TryStart = instruction.Offset, HandlerCount = 1}; + protectedBlocks.Push(exceptionBlockBuilder); + } } public override void Visit(FaultInstruction instruction) { - var exceptionBlockBuilder = exceptionBlocks.Peek(); - exceptionBlockBuilder.HandlerStart = instruction.Offset; - exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Fault; + protectedBlocks + .Peek() + .Handlers + .Add(new ExceptionHandlerBlockBuilder + { + HandlerStart = instruction.Offset, + HandlerBlockKind = ExceptionHandlerBlockKind.Fault, + }); } public override void Visit(FinallyInstruction instruction) { - var exceptionBlockBuilder = exceptionBlocks.Peek(); - exceptionBlockBuilder.HandlerStart = instruction.Offset; - exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Finally; + protectedBlocks + .Peek() + .Handlers + .Add( + new ExceptionHandlerBlockBuilder + { + HandlerStart = instruction.Offset, + HandlerBlockKind = ExceptionHandlerBlockKind.Finally, + }); } public override void Visit(FilterInstruction instruction) { - var exceptionBlockBuilder = exceptionBlocks.Peek(); - exceptionBlockBuilder.HandlerStart = instruction.Offset; - exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Filter; - exceptionBlockBuilder.ExceptionType = instruction.ExceptionType; + var handlers = protectedBlocks.Peek().Handlers; + switch (instruction.kind) + { + case FilterInstructionKind.FilterSection: + handlers.Add( + new ExceptionHandlerBlockBuilder + { + FilterStart = instruction.Offset, + HandlerBlockKind = ExceptionHandlerBlockKind.Filter, + }); + break; + case FilterInstructionKind.FilterHandler: + var handler = handlers.Last(); + handler.HandlerStart = instruction.Offset; + handler.ExceptionType = instruction.ExceptionType; + break; + default: throw instruction.kind.ToUnknownValueException(); + } } public override void Visit(CatchInstruction instruction) { - var exceptionBlockBuilder = exceptionBlocks.Peek(); - exceptionBlockBuilder.HandlerStart = instruction.Offset; - exceptionBlockBuilder.HandlerBlockKind = ExceptionHandlerBlockKind.Catch; - exceptionBlockBuilder.ExceptionType = instruction.ExceptionType; + protectedBlocks + .Peek() + .Handlers + .Add( + new ExceptionHandlerBlockBuilder() + { + HandlerStart = instruction.Offset, + HandlerBlockKind = ExceptionHandlerBlockKind.Catch, + ExceptionType = instruction.ExceptionType + } + ); } public override void Visit(ConvertInstruction instruction) @@ -260,23 +301,26 @@ public override void Visit(ReturnInstruction instruction) public override void Visit(ThrowInstruction instruction) { - if (exceptionBlocks.Count > 0) + if (protectedBlocks.Count > 0) { - var exceptionBlockBuilder = exceptionBlocks.Peek(); - if (exceptionBlockBuilder.HandlerStart == null) // fixme mismo comentario que en el leave + var exceptionBlockBuilder = protectedBlocks.Peek(); + if (exceptionBlockBuilder.StillOnTrySection()) { exceptionBlockBuilder.TryEnd = instruction.Offset; } - else + else // rethrow { - // rethrow - exceptionBlockBuilder = exceptionBlocks.Pop(); - exceptionBlockBuilder.HandlerEnd = instruction.Offset; + //TODO + + // exceptionBlockBuilder.ExceptionType = null; // FIXME ? al ser un rethrow, ya esta seteado esto por un anterior throw? // fixme sin embargo en la rama del if, no habria que setear la excepcion? + + // exceptionBlockBuilder = protectedBlocks.Pop(); + // exceptionBlockBuilder.HandlerEnd = instruction.Offset; } } - else + else // not used to exit protected block { var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Throw); body.Instructions.Add(basicInstruction); @@ -289,7 +333,7 @@ public override void Visit(UnconditionalBranchInstruction instruction) switch (instruction.Operation) { // FIXME leave can be used for another purpose than exiting a protected region? - case UnconditionalBranchOperation.Leave when exceptionBlocks.Count == 0: + case UnconditionalBranchOperation.Leave when protectedBlocks.Count == 0: case UnconditionalBranchOperation.Branch: { var unconditionalBranchInstruction = new Bytecode.BranchInstruction( @@ -301,9 +345,13 @@ public override void Visit(UnconditionalBranchInstruction instruction) } case UnconditionalBranchOperation.EndFinally: { - var exceptionBlockBuilder = exceptionBlocks.Pop(); - exceptionBlockBuilder.HandlerEnd = instruction.Offset; - body.ExceptionInformation.Add(exceptionBlockBuilder.Build()); + var exceptionBlockBuilder = protectedBlocks.Pop(); // no more handlers after finally + exceptionBlockBuilder.AssertValidHandlerCount(); + exceptionBlockBuilder + .Handlers + .Last() + .HandlerEnd = instruction.Offset; + body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); break; } case UnconditionalBranchOperation.EndFilter: @@ -313,17 +361,30 @@ public override void Visit(UnconditionalBranchInstruction instruction) } case UnconditionalBranchOperation.Leave: { - var exceptionBlockBuilder = exceptionBlocks.Peek(); - if (exceptionBlockBuilder.HandlerStart == null) // FIXME estoy asumiendo que si no se seteo el handler es porque es un try aun - // FIXME es correcto esto? Si lo es quiza puedo poner un metodo que diga que todavia estoy en el try asi se entiende mas + var exceptionBlockBuilder = protectedBlocks.Peek(); + if (exceptionBlockBuilder.StillOnTrySection()) { exceptionBlockBuilder.TryEnd = instruction.Offset; } else { - exceptionBlockBuilder = exceptionBlocks.Pop(); - exceptionBlockBuilder.HandlerEnd = instruction.Offset; - body.ExceptionInformation.Add(exceptionBlockBuilder.Build()); + if (exceptionBlockBuilder.AllHandlersAdded()) + { + // FIXME codigo repetido con el endfinally. + exceptionBlockBuilder = protectedBlocks.Pop(); + exceptionBlockBuilder + .Handlers + .Last() + .HandlerEnd = instruction.Offset; + body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); + } + else + { + exceptionBlockBuilder + .Handlers + .Last() + .HandlerEnd = instruction.Offset; + } } break; @@ -427,48 +488,139 @@ public override void Visit(PhiInstruction instruction) throw new Exception(); } - private class ExceptionBlockBuilder + //TODO en estos builder: validar que las cosas no se seteen mas de una vez, encapsular en metodos que sean mas declarativos, emprolijar, etc + // ver quiza se mover esto a otro archivo. + + // TODO ver de extraer algun lugar esto de hacer que las properties se seteen una sola vez. Ya lo use tmb en el metadata container al menos + + // FIXME los try puede tener multiples catch/filter. En el bytecode esto se traduce a mutiples entradas en el exception information + // FIXME que tienen todas el mismo try pero distinto catch + // FIXME en el tac pasa lo mismo, es decir tengo instrucciones try con labels repetidas + private class ProtectedBlockBuilder { - public uint? TryStart; + private uint? tryStart; + + public uint TryStart + { + get => tryStart ?? throw new Exception("TryStart was not set"); + set + { + if (tryStart != null) throw new Exception("TryStart was already set"); + tryStart = value; + } + } + + private uint? tryEnd; - public uint? TryEnd; + public uint TryEnd + { + get => tryEnd ?? throw new Exception("TryEnd was not set"); + set + { + if (tryEnd != null) throw new Exception("TryEnd was already set"); + tryEnd = value; + } + } + + public bool StillOnTrySection() => tryEnd == null; - public uint? HandlerStart; - public uint? HandlerEnd; - public ExceptionHandlerBlockKind? HandlerBlockKind; - public IType ExceptionType; + public uint HandlerCount { get; set; } - public ProtectedBlock Build() + public void AssertValidHandlerCount() + { + if (HandlerCount != Handlers.Count) throw new Exception("Expected and actual handler count does not match"); + } + + // FIXME naming + public bool AllHandlersAdded() => HandlerCount == Handlers.Count; + + public IList Handlers = new List(); + //FIXME revisar si esto esta bien y como uso last(). Asumo que siempre el ultimo es el que quiero. Creo que tiene sentido + // FIXME por ejemplo en el FIlterInstruction cuando es handler estoy asumiendo que el last es un filter ya + + public IList Build() => + Handlers + .Select(handlerBuilder => handlerBuilder.Build()) + .Select(handler => new ProtectedBlock(TryStart, TryEnd) {Handler = handler}) + .ToList(); + } + + private class ExceptionHandlerBlockBuilder + { + private uint? filterStart; + + public uint FilterStart + { + get => filterStart ?? throw new Exception("FilterStart was not set"); + set + { + if (filterStart != null) throw new Exception("FilterStart was already set"); + filterStart = value; + } + } + + private uint? handlerStart; + + public uint HandlerStart + { + get => handlerStart ?? throw new Exception("HandlerStart was not set"); + set + { + if (handlerStart != null) throw new Exception("HandlerStart was already set"); + handlerStart = value; + } + } + + private uint? handlerEnd; + + public uint 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() { - if (TryStart == null) throw new Exception("TryStart not set"); - if (TryEnd == null) throw new Exception("TryEnd not set"); - if (HandlerStart == null) throw new Exception("HandlerStart not set"); - if (HandlerEnd == null) throw new Exception("HandlerEnd not set"); - if (HandlerBlockKind == null) throw new Exception("HandlerBlockKind not set"); - IExceptionHandler handler; switch (HandlerBlockKind) { case ExceptionHandlerBlockKind.Filter: - if (ExceptionType == null) throw new Exception("ExceptionType not set"); - handler = new FilterExceptionHandler(TryEnd.Value, HandlerStart.Value, HandlerEnd.Value, ExceptionType); - break; + return new FilterExceptionHandler(FilterStart, HandlerStart, HandlerEnd, ExceptionType); case ExceptionHandlerBlockKind.Catch: - if (ExceptionType == null) throw new Exception("ExceptionType not set"); - handler = new CatchExceptionHandler(HandlerStart.Value, HandlerEnd.Value, ExceptionType); - break; + return new CatchExceptionHandler(HandlerStart, HandlerEnd, ExceptionType); case ExceptionHandlerBlockKind.Fault: - handler = new FaultExceptionHandler(HandlerStart.Value, HandlerEnd.Value); - break; + return new FaultExceptionHandler(HandlerStart, HandlerEnd); case ExceptionHandlerBlockKind.Finally: - handler = new FinallyExceptionHandler(HandlerStart.Value, HandlerEnd.Value); - break; - default: throw new UnknownValueException(HandlerBlockKind.Value); + return new FinallyExceptionHandler(HandlerStart, HandlerEnd); + default: throw new UnknownValueException(HandlerBlockKind); } - - return new ProtectedBlock(TryStart.Value, TryEnd.Value) - { - Handler = handler - }; } } } diff --git a/Console/Program.cs b/Console/Program.cs index 0f67cab5..a20d2928 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -389,7 +389,7 @@ static void Main(string[] args) var inputs = new[] { new[] {"../../../Examples/bin/Debug/Examples.dll"}, - new[] + /* new[] { "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll", "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll" @@ -412,7 +412,7 @@ static void Main(string[] args) "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll" - } + }*/ }; /* foreach (var input in inputs) @@ -444,6 +444,13 @@ where m.HasBody { method.Body = new Disassembler(method).Execute(); // to tac var newBody = new Assembler(method).Execute(); // to bytecode + var exOriginal = method.Body.ExceptionInformation; + var exGenerated = newBody.ExceptionInformation; + + // FIXME comparar los dos. Calculo que puede ser que no matcheen exactos los labels porque hay mas instrucciones (no estoy seguro igual) + // FIXME pero lo que seguro tiene que matchear es el comienzo de los catches con final de los try, filters con sus handlers etc. + // FIXME y eso no esta pasando parece. Comparar bien todos los casos de examples.dll + var x = 1; } } } diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 9853dea4..4b68cf81 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection.Metadata; +using System.Runtime.ConstrainedExecution; using Classes; using Enums; using Hierarchy; @@ -1046,6 +1047,38 @@ public void ExceptionHandlingMultipleFilter(int x) } } + public void ExceptionHandlingFilterCatch(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) when (e.Message.Contains("")) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + public void ExceptionHandlingCatchFilter(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) when (ex.Message.Contains("")) + { + Console.WriteLine(ex.Message); + } + } + public void ExceptionHandlingMultipleCatchs(int x) { try diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 241dc59c..af57c01b 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -37,7 +37,7 @@ public static void Main(string[] args) Console.WriteLine(methodBodyExamples.StoreValue(100)); methodBodyExamples.ExceptionHandlingTryCatchSpecific(0); methodBodyExamples.ExceptionHandlingTryCatch(0); - methodBodyExamples.ExceptionHandlingTryCatchMultipleFilter(0); + methodBodyExamples.ExceptionHandlingMultipleFilter(0); Console.WriteLine(methodBodyExamples.LoadField()); Console.WriteLine(methodBodyExamples.StoreField()); methodBodyExamples.Calls(sc, e => 5); From a9f876051c08b62649f536980dfc09d14ba74ba9 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 14 Jun 2020 13:48:07 -0300 Subject: [PATCH 168/256] fix exception generation --- Backend/Transformations/Assembler.cs | 178 ++++++++++++++------------- Console/Program.cs | 8 +- Examples/Examples.cs | 8 +- 3 files changed, 100 insertions(+), 94 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 82d48529..ac90a96d 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.InteropServices; using Backend.Utils; using Model; using Model.ThreeAddressCode.Instructions; @@ -20,7 +19,6 @@ using SwitchInstruction = Model.ThreeAddressCode.Instructions.SwitchInstruction; using Bytecode = Model.Bytecode; - namespace Backend.Transformations { public class Assembler @@ -37,6 +35,8 @@ public Assembler(MethodDefinition method) this.method = method; } + // fixme ver si protectedblocks tiene que ser una pila e ir sacandolo meintras genero o si quiza puede ser una lista e ir cerandolos + // FIXME pero sacarlos y armarlos todos aca en el execute despues public MethodBody Execute() { var body = new MethodBody(MethodBodyKind.Bytecode); @@ -218,10 +218,24 @@ public override void Visit(TryInstruction instruction) } } + // FIXME este codigo se va a repetir entre todos los handlers + // FIXME revisar si siguen haciendo falta la separacion de filter que agregue (section, handler) y los endFIlter y eso public override void Visit(FaultInstruction instruction) { - protectedBlocks - .Peek() + var protectedBlockBuilder = protectedBlocks.Peek(); + if (protectedBlockBuilder.Handlers.Count == 0) // first handler + { + protectedBlockBuilder.TryEnd = instruction.Offset; + } + else // more than 1 handler + { + protectedBlockBuilder + .Handlers + .Last() + .HandlerEnd = instruction.Offset; + } + + protectedBlockBuilder .Handlers .Add(new ExceptionHandlerBlockBuilder { @@ -230,10 +244,23 @@ public override void Visit(FaultInstruction instruction) }); } + // There can only be one finallyBlock and is the last handler of a try block public override void Visit(FinallyInstruction instruction) { - protectedBlocks - .Peek() + var protectedBlockBuilder = protectedBlocks.Peek(); + if (protectedBlockBuilder.Handlers.Count == 0) // try-finally + { + protectedBlockBuilder.TryEnd = instruction.Offset; + } + else // try-catch/filter-finally + { + protectedBlockBuilder + .Handlers + .Last() + .HandlerEnd = instruction.Offset; + } + + protectedBlockBuilder .Handlers .Add( new ExceptionHandlerBlockBuilder @@ -245,11 +272,26 @@ public override void Visit(FinallyInstruction instruction) public override void Visit(FilterInstruction instruction) { - var handlers = protectedBlocks.Peek().Handlers; + var protectedBlockBuilder = protectedBlocks.Peek(); + if (protectedBlockBuilder.Handlers.Count == 0) // first handler + { + protectedBlockBuilder.TryEnd = instruction.Offset; + } + // fixme explain + else if ( + protectedBlockBuilder.Handlers.Last().HandlerBlockKind != ExceptionHandlerBlockKind.Filter || + instruction.kind == FilterInstructionKind.FilterSection) + { + protectedBlockBuilder + .Handlers + .Last() + .HandlerEnd = instruction.Offset; + } + switch (instruction.kind) { case FilterInstructionKind.FilterSection: - handlers.Add( + protectedBlockBuilder.Handlers.Add( new ExceptionHandlerBlockBuilder { FilterStart = instruction.Offset, @@ -257,7 +299,7 @@ public override void Visit(FilterInstruction instruction) }); break; case FilterInstructionKind.FilterHandler: - var handler = handlers.Last(); + var handler = protectedBlockBuilder.Handlers.Last(); handler.HandlerStart = instruction.Offset; handler.ExceptionType = instruction.ExceptionType; break; @@ -267,8 +309,20 @@ public override void Visit(FilterInstruction instruction) public override void Visit(CatchInstruction instruction) { - protectedBlocks - .Peek() + var protectedBlockBuilder = protectedBlocks.Peek(); + if (protectedBlockBuilder.Handlers.Count == 0) // first handler + { + protectedBlockBuilder.TryEnd = instruction.Offset; + } + else // more than one handler + { + protectedBlockBuilder + .Handlers + .Last() + .HandlerEnd = instruction.Offset; + } + + protectedBlockBuilder .Handlers .Add( new ExceptionHandlerBlockBuilder() @@ -301,39 +355,38 @@ public override void Visit(ReturnInstruction instruction) public override void Visit(ThrowInstruction instruction) { - if (protectedBlocks.Count > 0) - { - var exceptionBlockBuilder = protectedBlocks.Peek(); - if (exceptionBlockBuilder.StillOnTrySection()) - { - exceptionBlockBuilder.TryEnd = instruction.Offset; - } - else // rethrow - { - //TODO - - - // exceptionBlockBuilder.ExceptionType = null; // FIXME ? al ser un rethrow, ya esta seteado esto por un anterior throw? - // fixme sin embargo en la rama del if, no habria que setear la excepcion? - - // exceptionBlockBuilder = protectedBlocks.Pop(); - // exceptionBlockBuilder.HandlerEnd = instruction.Offset; - } - } - else // not used to exit protected block - { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Throw); - body.Instructions.Add(basicInstruction); - } + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Throw); + body.Instructions.Add(basicInstruction); } - // todo emprolijar public override void Visit(UnconditionalBranchInstruction instruction) { switch (instruction.Operation) { - // FIXME leave can be used for another purpose than exiting a protected region? - case UnconditionalBranchOperation.Leave when protectedBlocks.Count == 0: + case UnconditionalBranchOperation.Leave: + { + if (protectedBlocks.Count > 0) + { + var exceptionBlockBuilder = protectedBlocks.Peek(); + if (exceptionBlockBuilder.AllHandlersAdded()) + { + // FIXME codigo repetido con el endfinally. + exceptionBlockBuilder = protectedBlocks.Pop(); + exceptionBlockBuilder + .Handlers + .Last() + .HandlerEnd = instruction.Offset; + body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); + } + } + + var unconditionalBranchInstruction = new Bytecode.BranchInstruction( + instruction.Offset, + Bytecode.BranchOperation.Leave, + Convert.ToUInt32(instruction.Target.Substring(2), 16)); + body.Instructions.Add(unconditionalBranchInstruction); + break; + } case UnconditionalBranchOperation.Branch: { var unconditionalBranchInstruction = new Bytecode.BranchInstruction( @@ -346,47 +399,18 @@ public override void Visit(UnconditionalBranchInstruction instruction) case UnconditionalBranchOperation.EndFinally: { var exceptionBlockBuilder = protectedBlocks.Pop(); // no more handlers after finally - exceptionBlockBuilder.AssertValidHandlerCount(); exceptionBlockBuilder .Handlers .Last() .HandlerEnd = instruction.Offset; body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); + body.Instructions.Add(new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFinally)); break; } case UnconditionalBranchOperation.EndFilter: { - // nothing since filter area is the gap between try end and handler start - break; - } - case UnconditionalBranchOperation.Leave: - { - var exceptionBlockBuilder = protectedBlocks.Peek(); - if (exceptionBlockBuilder.StillOnTrySection()) - { - exceptionBlockBuilder.TryEnd = instruction.Offset; - } - else - { - if (exceptionBlockBuilder.AllHandlersAdded()) - { - // FIXME codigo repetido con el endfinally. - exceptionBlockBuilder = protectedBlocks.Pop(); - exceptionBlockBuilder - .Handlers - .Last() - .HandlerEnd = instruction.Offset; - body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); - } - else - { - exceptionBlockBuilder - .Handlers - .Last() - .HandlerEnd = instruction.Offset; - } - } - + // nothing is done with protectedBlocks since filter area is the gap between try end and handler start + body.Instructions.Add(new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFilter)); break; } default: throw instruction.Operation.ToUnknownValueException(); @@ -488,14 +512,6 @@ public override void Visit(PhiInstruction instruction) throw new Exception(); } - //TODO en estos builder: validar que las cosas no se seteen mas de una vez, encapsular en metodos que sean mas declarativos, emprolijar, etc - // ver quiza se mover esto a otro archivo. - - // TODO ver de extraer algun lugar esto de hacer que las properties se seteen una sola vez. Ya lo use tmb en el metadata container al menos - - // FIXME los try puede tener multiples catch/filter. En el bytecode esto se traduce a mutiples entradas en el exception information - // FIXME que tienen todas el mismo try pero distinto catch - // FIXME en el tac pasa lo mismo, es decir tengo instrucciones try con labels repetidas private class ProtectedBlockBuilder { private uint? tryStart; @@ -522,14 +538,8 @@ public uint TryEnd } } - public bool StillOnTrySection() => tryEnd == null; - public uint HandlerCount { get; set; } - public void AssertValidHandlerCount() - { - if (HandlerCount != Handlers.Count) throw new Exception("Expected and actual handler count does not match"); - } // FIXME naming public bool AllHandlersAdded() => HandlerCount == Handlers.Count; diff --git a/Console/Program.cs b/Console/Program.cs index a20d2928..9a34394a 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -389,7 +389,7 @@ static void Main(string[] args) var inputs = new[] { new[] {"../../../Examples/bin/Debug/Examples.dll"}, - /* new[] + new[] { "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll", "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll" @@ -412,7 +412,7 @@ static void Main(string[] args) "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll" - }*/ + } }; /* foreach (var input in inputs) @@ -446,10 +446,6 @@ where m.HasBody var newBody = new Assembler(method).Execute(); // to bytecode var exOriginal = method.Body.ExceptionInformation; var exGenerated = newBody.ExceptionInformation; - - // FIXME comparar los dos. Calculo que puede ser que no matcheen exactos los labels porque hay mas instrucciones (no estoy seguro igual) - // FIXME pero lo que seguro tiene que matchear es el comienzo de los catches con final de los try, filters con sus handlers etc. - // FIXME y eso no esta pasando parece. Comparar bien todos los casos de examples.dll var x = 1; } } diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 4b68cf81..437ead01 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1046,7 +1046,7 @@ public void ExceptionHandlingMultipleFilter(int x) Console.WriteLine(ex.Message); } } - + public void ExceptionHandlingFilterCatch(int x) { try @@ -1062,7 +1062,7 @@ public void ExceptionHandlingFilterCatch(int x) Console.WriteLine(ex.Message); } } - + public void ExceptionHandlingCatchFilter(int x) { try @@ -1078,7 +1078,7 @@ public void ExceptionHandlingCatchFilter(int x) Console.WriteLine(ex.Message); } } - + public void ExceptionHandlingMultipleCatchs(int x) { try @@ -1094,7 +1094,7 @@ public void ExceptionHandlingMultipleCatchs(int x) Console.WriteLine(ex.Message); } } - + /* FIXME finally end label is wrong in the model (one more that it should be, that label does not exist)? this example results in an FIXME unmarked label. The IL though is generated correctly public void ExceptionHandlingTryCatchFinally(Exception e) From d7866b8478d4ce61d338db7040904b8aae681aa1 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 14 Jun 2020 15:58:40 -0300 Subject: [PATCH 169/256] refactor exception information generation --- Backend/Transformations/Assembler.cs | 118 ++++++++++----------------- 1 file changed, 43 insertions(+), 75 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index ac90a96d..2a246c70 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -35,8 +35,6 @@ public Assembler(MethodDefinition method) this.method = method; } - // fixme ver si protectedblocks tiene que ser una pila e ir sacandolo meintras genero o si quiza puede ser una lista e ir cerandolos - // FIXME pero sacarlos y armarlos todos aca en el execute despues public MethodBody Execute() { var body = new MethodBody(MethodBodyKind.Bytecode); @@ -218,51 +216,24 @@ public override void Visit(TryInstruction instruction) } } - // FIXME este codigo se va a repetir entre todos los handlers - // FIXME revisar si siguen haciendo falta la separacion de filter que agregue (section, handler) y los endFIlter y eso public override void Visit(FaultInstruction instruction) { - var protectedBlockBuilder = protectedBlocks.Peek(); - if (protectedBlockBuilder.Handlers.Count == 0) // first handler - { - protectedBlockBuilder.TryEnd = instruction.Offset; - } - else // more than 1 handler - { - protectedBlockBuilder - .Handlers - .Last() - .HandlerEnd = instruction.Offset; - } - - protectedBlockBuilder - .Handlers - .Add(new ExceptionHandlerBlockBuilder + protectedBlocks + .Peek() + .EndPreviousRegion(instruction.Offset) + .Handlers.Add(new ExceptionHandlerBlockBuilder { HandlerStart = instruction.Offset, HandlerBlockKind = ExceptionHandlerBlockKind.Fault, }); } - // There can only be one finallyBlock and is the last handler of a try block public override void Visit(FinallyInstruction instruction) { - var protectedBlockBuilder = protectedBlocks.Peek(); - if (protectedBlockBuilder.Handlers.Count == 0) // try-finally - { - protectedBlockBuilder.TryEnd = instruction.Offset; - } - else // try-catch/filter-finally - { - protectedBlockBuilder - .Handlers - .Last() - .HandlerEnd = instruction.Offset; - } - - protectedBlockBuilder - .Handlers - .Add( + protectedBlocks + .Peek() + .EndPreviousRegion(instruction.Offset) + .Handlers.Add( new ExceptionHandlerBlockBuilder { HandlerStart = instruction.Offset, @@ -273,20 +244,13 @@ public override void Visit(FinallyInstruction instruction) public override void Visit(FilterInstruction instruction) { var protectedBlockBuilder = protectedBlocks.Peek(); - if (protectedBlockBuilder.Handlers.Count == 0) // first handler - { - protectedBlockBuilder.TryEnd = instruction.Offset; - } - // fixme explain - else if ( - protectedBlockBuilder.Handlers.Last().HandlerBlockKind != ExceptionHandlerBlockKind.Filter || - instruction.kind == FilterInstructionKind.FilterSection) - { - protectedBlockBuilder - .Handlers - .Last() - .HandlerEnd = instruction.Offset; - } + + // filter is a special case since it has a two regions (filter and handler). A filter in this TAC is moddeled as two FilterInstruction + // with different kinds. If the previous region is a Filter, it must be ended only if it is in it's handler part. + bool EndPreviousHandlerCondition() => protectedBlockBuilder.Handlers.Last().HandlerBlockKind != ExceptionHandlerBlockKind.Filter || + instruction.kind == FilterInstructionKind.FilterSection; + + protectedBlockBuilder.EndPreviousRegion(instruction.Offset, EndPreviousHandlerCondition); switch (instruction.kind) { @@ -309,20 +273,9 @@ public override void Visit(FilterInstruction instruction) public override void Visit(CatchInstruction instruction) { - var protectedBlockBuilder = protectedBlocks.Peek(); - if (protectedBlockBuilder.Handlers.Count == 0) // first handler - { - protectedBlockBuilder.TryEnd = instruction.Offset; - } - else // more than one handler - { - protectedBlockBuilder - .Handlers - .Last() - .HandlerEnd = instruction.Offset; - } - - protectedBlockBuilder + protectedBlocks + .Peek() + .EndPreviousRegion(instruction.Offset) .Handlers .Add( new ExceptionHandlerBlockBuilder() @@ -367,11 +320,9 @@ public override void Visit(UnconditionalBranchInstruction instruction) { if (protectedBlocks.Count > 0) { - var exceptionBlockBuilder = protectedBlocks.Peek(); - if (exceptionBlockBuilder.AllHandlersAdded()) + if (protectedBlocks.Peek().AllHandlersAdded()) { - // FIXME codigo repetido con el endfinally. - exceptionBlockBuilder = protectedBlocks.Pop(); + var exceptionBlockBuilder = protectedBlocks.Pop(); exceptionBlockBuilder .Handlers .Last() @@ -512,6 +463,9 @@ public override void Visit(PhiInstruction instruction) throw new Exception(); } + + #region ExceptionInformation + private class ProtectedBlockBuilder { private uint? tryStart; @@ -528,7 +482,7 @@ public uint TryStart private uint? tryEnd; - public uint TryEnd + private uint TryEnd { get => tryEnd ?? throw new Exception("TryEnd was not set"); set @@ -540,13 +494,25 @@ public uint TryEnd public uint HandlerCount { get; set; } - - // FIXME naming public bool AllHandlersAdded() => HandlerCount == Handlers.Count; - public IList Handlers = new List(); - //FIXME revisar si esto esta bien y como uso last(). Asumo que siempre el ultimo es el que quiero. Creo que tiene sentido - // FIXME por ejemplo en el FIlterInstruction cuando es handler estoy asumiendo que el last es un filter ya + public readonly IList Handlers = new List(); + + public ProtectedBlockBuilder EndPreviousRegion(uint offset) => EndPreviousRegion(offset, () => true); + + public ProtectedBlockBuilder EndPreviousRegion(uint offset, Func multipleHandlerCondition) + { + if (Handlers.Count == 0) // first handler, ends try region + { + TryEnd = offset; + } + else if (multipleHandlerCondition()) // multiple handlers. End previous handler conditionally + { + Handlers.Last().HandlerEnd = offset; + } + + return this; + } public IList Build() => Handlers @@ -633,6 +599,8 @@ public IExceptionHandler Build() } } } + + #endregion } } } \ No newline at end of file From 938ddbab68edba5839e0134df1d2a2532b4c940e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 19 Jun 2020 08:54:01 -0300 Subject: [PATCH 170/256] clear stack before filter and catch --- Backend/Transformations/Assembler.cs | 6 ++++++ Backend/Transformations/Disassembler.cs | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 2a246c70..93d75bcf 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -136,6 +136,12 @@ public override void Visit(LoadInstruction instruction) case ArrayLengthAccess _: loadInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LoadArrayLength); break; + case VirtualMethodReference virtualMethodReference: + loadInstruction = new Bytecode.LoadMethodAddressInstruction( + instruction.Offset, + Bytecode.LoadMethodAddressOperation.Virtual, + virtualMethodReference.Method); + break; case StaticMethodReference staticMethodReference: loadInstruction = new Bytecode.LoadMethodAddressInstruction( instruction.Offset, diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index dc2fc40e..b14c9d73 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -1053,8 +1053,8 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) break; case ExceptionHandlerBlockKind.Filter: - // Push the exception into the stack - var filterException = stack.Push(); + stack.Clear(); + var filterException = stack.Push(); // Push the exception into the stack var filterBlock = (FilterExceptionHandler) block; var kind = operation.Label.Equals(filterBlock.FilterStart) ? Tac.FilterInstructionKind.FilterSection @@ -1063,8 +1063,8 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) break; case ExceptionHandlerBlockKind.Catch: - // Push the exception into the stack - var catchException = stack.Push(); + stack.Clear(); + var catchException = stack.Push(); // Push the exception into the stack var catchBlock = block as CatchExceptionHandler; instruction = new Tac.CatchInstruction(operation.Offset, catchException, catchBlock.ExceptionType); break; From 4f6b1f1d2e5f95426c6b4c7755094e8642900264 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 21 Jun 2020 13:46:56 -0300 Subject: [PATCH 171/256] ensure type of variables in dissasembler. add tac constrained instruction --- Backend/Transformations/Assembler.cs | 18 +++-- Backend/Transformations/Disassembler.cs | 76 +++++++++---------- Backend/Utils/Extensions.cs | 17 +++++ Console/Program.cs | 8 +- Model/ThreeAddressCode/Instructions.cs | 21 +++++ .../Visitor/IInstructionVisitor.cs | 1 + .../Visitor/InstructionVisitor.cs | 1 + Model/Types/Types.cs | 1 + 8 files changed, 92 insertions(+), 51 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 93d75bcf..2138dacd 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -41,7 +41,7 @@ public MethodBody Execute() body.MaxStack = method.Body.MaxStack; // FIXME body.Parameters.AddRange(method.Body.Parameters); - body.LocalVariables.AddRange(method.Body.LocalVariables); + body.LocalVariables.AddRange(method.Body.LocalVariables.Select(variable => variable.ToLocalVariable())); if (method.Body.Instructions.Count > 0) { @@ -79,12 +79,7 @@ public override void Visit(UnaryInstruction instruction) public override void Visit(LoadInstruction instruction) { - // translate to dup, loadArrayLength, loadArrayElement, loadArrayElementAddress, loadStaticField, loadInstanceField, - // loadStaticFieldAddress, loadInnstanceFieldAddress, loadIndirect, loadConstant, loadVariable, loadVariableAddress, - // loadStaticMethodAddress, loadVirtualMethodAddress, - // StoreInstruction? CreateObjectInstruction? (se genera una en el visit de ambos) // FIXME revisar los casos, hay algunos que no estoy seguro de que esten bien. se repiten caminos ademas (sobretodo por el reference) - Bytecode.Instruction loadInstruction; if (instruction.Operand is TemporalVariable && instruction.Result is TemporalVariable) { @@ -105,7 +100,9 @@ public override void Visit(LoadInstruction instruction) loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant); break; case TemporalVariable _: - loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Content, instruction.Result); + loadInstruction = new Bytecode.LoadInstruction( + instruction.Offset, Bytecode.LoadOperation.Content, + instruction.Result.ToLocalVariable()); break; case Dereference dereference: loadInstruction = new Bytecode.LoadIndirectInstruction(instruction.Offset, dereference.Type); @@ -118,7 +115,7 @@ public override void Visit(LoadInstruction instruction) loadInstruction = new Bytecode.LoadInstruction( instruction.Offset, Bytecode.LoadOperation.Address, - instruction.Result); + instruction.Result.ToLocalVariable()); break; case InstanceFieldAccess instanceFieldAccess: // fixme es content? @@ -469,6 +466,11 @@ public override void Visit(PhiInstruction instruction) throw new Exception(); } + public override void Visit(ConstrainedInstruction instruction) + { + body.Instructions.Add(new Bytecode.ConstrainedInstruction(instruction.Offset, instruction.ThisType)); + } + #region ExceptionInformation diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index b14c9d73..f23b7a21 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -307,8 +307,7 @@ private void ProcessInitializeMemory(Bytecode.BasicInstruction op) public override void Visit(Bytecode.InitObjInstruction op) { - var targetAddress = stack.Pop(); - targetAddress = new TemporalVariable(targetAddress.Prefix, targetAddress.Index) { Type = op.Type}; + var targetAddress = stack.Pop().MakeCopy(op.Type); var instruction = new Tac.InitializeObjectInstruction(op.Offset, targetAddress); body.Instructions.Add(instruction); } @@ -475,8 +474,8 @@ private void ProcessLeave(Bytecode.BranchInstruction op) public override void Visit(Bytecode.ConvertInstruction op) { var operation = OperationHelper.ToConvertOperation(op.Operation); - var operand = stack.Pop(); - var result = stack.Push(); + var operand = stack.Pop().MakeCopy(op.ConversionType); + var result = stack.Push().MakeCopy(op.ConversionType); var instruction = new Tac.ConvertInstruction(op.Offset, result, operand, operation, op.ConversionType); instruction.OverflowCheck = op.OverflowCheck; @@ -507,7 +506,7 @@ public override void Visit(Bytecode.CreateArrayInstruction op) lowerBounds.Reverse(); sizes.Reverse(); - var result = stack.Push(); + var result = stack.Push().MakeCopy(op.Type); var instruction = new Tac.CreateArrayInstruction(op.Offset, result, op.Type.ElementsType, op.Type.Rank, lowerBounds, sizes); body.Instructions.Add(instruction); } @@ -538,13 +537,11 @@ private void ProcessLoadArrayElement(Bytecode.LoadArrayElementInstruction op) indices.Add(operand); } - var array = stack.Pop(); - array = new TemporalVariable(array.Prefix, array.Index) { Type = op.Array }; - + var array = stack.Pop().MakeCopy(op.Array); indices.Reverse(); - var dest = stack.Push(); var source = new ArrayElementAccess(array, indices); + var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -559,14 +556,13 @@ private void ProcessLoadArrayElementAddress(Bytecode.LoadArrayElementInstruction indices.Add(operand); } - var array = stack.Pop(); - array = new TemporalVariable(array.Prefix, array.Index) { Type = op.Array }; + var array = stack.Pop().MakeCopy(op.Array); indices.Reverse(); - var dest = stack.Push(); var access = new ArrayElementAccess(array, indices); var source = new Reference(access); + var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -574,7 +570,7 @@ private void ProcessLoadArrayElementAddress(Bytecode.LoadArrayElementInstruction public override void Visit(Bytecode.StoreArrayElementInstruction op) { var indices = new List(); - var source = stack.Pop(); + var source = stack.Pop().MakeCopy(op.Array.ElementsType); for (uint i = 0; i < op.Array.Rank; i++) { @@ -582,8 +578,7 @@ public override void Visit(Bytecode.StoreArrayElementInstruction op) indices.Add(operand); } - var array = stack.Pop(); - array = new TemporalVariable(array.Prefix, array.Index) { Type = op.Array }; + var array = stack.Pop().MakeCopy(op.Array); indices.Reverse(); var dest = new ArrayElementAccess(array, indices); var instruction = new Tac.StoreInstruction(op.Offset, dest, source); @@ -594,7 +589,7 @@ public override void Visit(Bytecode.CreateObjectInstruction op) { stack.IncrementCapacity(); - var allocationResult = stack.Push(); + var allocationResult = stack.Push().MakeCopy(op.Constructor.ContainingType); stack.Pop(); var arguments = new List(); @@ -624,7 +619,7 @@ public override void Visit(Bytecode.CreateObjectInstruction op) instruction = new Tac.MethodCallInstruction(op.Offset, null, Tac.MethodCallOperation.Static, op.Constructor, arguments); body.Instructions.Add(instruction); - var result = stack.Push(); + var result = stack.Push().MakeCopy(allocationResult.Type); instruction = new Tac.LoadInstruction(op.Offset, result, allocationResult); body.Instructions.Add(instruction); @@ -704,8 +699,8 @@ private void ProcessLoadFieldAddress(Bytecode.LoadFieldInstruction op) private void ProcessLoadStaticField(Bytecode.LoadFieldInstruction op) { - var dest = stack.Push(); var source = new StaticFieldAccess(op.Field); + var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -713,17 +708,17 @@ private void ProcessLoadStaticField(Bytecode.LoadFieldInstruction op) private void ProcessLoadInstanceField(Bytecode.LoadFieldInstruction op) { var obj = stack.Pop(); - var dest = stack.Push(); var source = new InstanceFieldAccess(obj, op.Field); + var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } private void ProcessLoadStaticFieldAddress(Bytecode.LoadFieldInstruction op) { - var dest = stack.Push(); var access = new StaticFieldAccess(op.Field); var source = new Reference(access); + var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -731,18 +726,17 @@ private void ProcessLoadStaticFieldAddress(Bytecode.LoadFieldInstruction op) private void ProcessLoadInstanceFieldAddress(Bytecode.LoadFieldInstruction op) { var obj = stack.Pop(); - var dest = stack.Push(); var access = new InstanceFieldAccess(obj, op.Field); var source = new Reference(access); + var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } public override void Visit(Bytecode.LoadIndirectInstruction op) { - var address = stack.Pop(); - address = new TemporalVariable(address.Prefix, address.Index) { Type = new PointerType(op.Type) }; - var dest = stack.Push(); + var address = stack.Pop().MakeCopy(new PointerType(op.Type)); var source = new Dereference(address); + var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -768,23 +762,23 @@ public override void Visit(Bytecode.LoadInstruction op) private void ProcessLoadConstant(Bytecode.LoadInstruction op) { - var dest = stack.Push(); + var dest = stack.Push().MakeCopy(op.Operand.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, op.Operand); body.Instructions.Add(instruction); } private void ProcessLoadVariable(Bytecode.LoadInstruction op) { - var dest = stack.Push(); + var dest = stack.Push().MakeCopy(op.Operand.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, op.Operand); body.Instructions.Add(instruction); } private void ProcessLoadVariableAddress(Bytecode.LoadInstruction op) { - var dest = stack.Push(); var operand = (IVariable)op.Operand; var source = new Reference(operand); + var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -807,8 +801,8 @@ public override void Visit(Bytecode.LoadMethodAddressInstruction op) public void ProcessLoadStaticMethodAddress(Bytecode.LoadMethodAddressInstruction op) { - var dest = stack.Push(); var source = new StaticMethodReference(op.Method); + var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -816,8 +810,8 @@ public void ProcessLoadStaticMethodAddress(Bytecode.LoadMethodAddressInstruction public void ProcessLoadVirtualMethodAddress(Bytecode.LoadMethodAddressInstruction op) { var obj = stack.Pop(); - var dest = stack.Push(); var source = new VirtualMethodReference(obj, op.Method); + var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -850,7 +844,7 @@ public override void Visit(Bytecode.MethodCallInstruction op) if (!op.Method.IsStatic) { // Adding implicit this parameter - var argThis = stack.Pop(); + var argThis = stack.Pop().MakeCopy(op.Method.ContainingType); arguments.Add(argThis); } @@ -858,7 +852,7 @@ public override void Visit(Bytecode.MethodCallInstruction op) if (!op.Method.ReturnType.Equals(PlatformTypes.Void)) { - result = stack.Push(); + result = stack.Push().MakeCopy(op.Method.ReturnType); } var instruction = new Tac.MethodCallInstruction(op.Offset, result, operation, op.Method, arguments); @@ -867,7 +861,7 @@ public override void Visit(Bytecode.MethodCallInstruction op) public override void Visit(Bytecode.SizeofInstruction op) { - var result = stack.Push(); + var result = stack.Push().MakeCopy(PlatformTypes.Int32); var instruction = new Tac.SizeofInstruction(op.Offset, result, op.MeasuredType); body.Instructions.Add(instruction); } @@ -886,7 +880,7 @@ public override void Visit(Bytecode.StoreFieldInstruction op) private void ProcessStoreStaticField(Bytecode.StoreFieldInstruction op) { - var source = stack.Pop(); + var source = stack.Pop().MakeCopy(op.Field.Type); var dest = new StaticFieldAccess(op.Field); var instruction = new Tac.StoreInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); @@ -894,7 +888,7 @@ private void ProcessStoreStaticField(Bytecode.StoreFieldInstruction op) private void ProcessStoreInstanceField(Bytecode.StoreFieldInstruction op) { - var source = stack.Pop(); + var source = stack.Pop().MakeCopy(op.Field.Type); var obj = stack.Pop(); var dest = new InstanceFieldAccess(obj, op.Field); var instruction = new Tac.StoreInstruction(op.Offset, dest, source); @@ -903,9 +897,8 @@ private void ProcessStoreInstanceField(Bytecode.StoreFieldInstruction op) public override void Visit(Bytecode.StoreIndirectInstruction op) { - var source = stack.Pop(); - var address = stack.Pop(); - address = new TemporalVariable(address.Prefix, address.Index) { Type = new PointerType(op.Type) }; + var source = stack.Pop().MakeCopy(op.Type); + var address = stack.Pop().MakeCopy(new PointerType(op.Type)); var dest = new Dereference(address); var instruction = new Tac.StoreInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); @@ -913,17 +906,22 @@ public override void Visit(Bytecode.StoreIndirectInstruction op) public override void Visit(Bytecode.StoreInstruction op) { - var source = stack.Pop(); + var source = stack.Pop().MakeCopy(op.Target.Type); var instruction = new Tac.LoadInstruction(op.Offset, op.Target, source); body.Instructions.Add(instruction); } public override void Visit(Bytecode.SwitchInstruction op) { - var operand = stack.Pop(); + var operand = stack.Pop().MakeCopy(PlatformTypes.List); var instruction = new Tac.SwitchInstruction(op.Offset, operand, op.Targets); body.Instructions.Add(instruction); } + + public override void Visit(Bytecode.ConstrainedInstruction instruction) + { + body.Instructions.Add(new Tac.ConstrainedInstruction(instruction.Offset, instruction.ThisType)); + } } #endregion diff --git a/Backend/Utils/Extensions.cs b/Backend/Utils/Extensions.cs index 41b9f830..0b36ed5b 100644 --- a/Backend/Utils/Extensions.cs +++ b/Backend/Utils/Extensions.cs @@ -1015,5 +1015,22 @@ from node in escInfo.EscapingNodes return escapeInfo; } + public static TemporalVariable MakeCopy(this TemporalVariable temporalVariable, IType type) => + new TemporalVariable(temporalVariable.Prefix, temporalVariable.Index) { Type = type }; + + public static LocalVariable ToLocalVariable(this IVariable variable) + { + switch (variable) + { + case TemporalVariable temporalVariable: + return new LocalVariable(temporalVariable.Name, temporalVariable.IsParameter) + { + Type = temporalVariable.Type, + Index = (int?) temporalVariable.Index + }; + case LocalVariable localVariable: return localVariable; + default: throw new NotImplementedException(); + } + } } } diff --git a/Console/Program.cs b/Console/Program.cs index 9a34394a..932e446e 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -415,15 +415,15 @@ static void Main(string[] args) } }; - /* foreach (var input in inputs) + foreach (var input in inputs) { foreach (var file in input) { DisassembleAndThenAssemble(file); } } -*/ - foreach (var input in inputs) + +/* foreach (var input in inputs) { foreach (var file in input) { @@ -449,7 +449,7 @@ where m.HasBody var x = 1; } } - } + }*/ diff --git a/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index b2e2ce6c..498ea6ce 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -1412,4 +1412,25 @@ public override string ToString() return this.ToString("{0} = Φ({1})", this.Result, arguments); } } + + public class ConstrainedInstruction : Instruction + { + public IType ThisType { get; private set; } + + public ConstrainedInstruction(uint label, IType thisType) : base(label) + { + this.ThisType = thisType; + } + + public override void Accept(IInstructionVisitor visitor) + { + base.Accept(visitor); + visitor.Visit(this); + } + + public override string ToString() + { + return String.Format("constrain virtual call to type: {0}", ThisType.ToString()); + } + } } diff --git a/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs b/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs index b429d180..2cb07f2a 100644 --- a/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs +++ b/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs @@ -44,5 +44,6 @@ public interface IInstructionVisitor void Visit(CopyObjectInstruction instruction); void Visit(CreateArrayInstruction instruction); void Visit(PhiInstruction instruction); + void Visit(ConstrainedInstruction instruction); } } diff --git a/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs b/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs index 67ba4976..7dcef6b1 100644 --- a/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs +++ b/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs @@ -52,5 +52,6 @@ public virtual void Visit(InitializeObjectInstruction instruction) { } public virtual void Visit(CopyObjectInstruction instruction) { } public virtual void Visit(CreateArrayInstruction instruction) { } public virtual void Visit(PhiInstruction instruction) { } + public virtual void Visit(ConstrainedInstruction instruction) { } } } diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index 992549b0..28a26fd8 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -75,6 +75,7 @@ public static class PlatformTypes public static readonly BasicType PureAttribute = New("mscorlib", "System.Diagnostics.Contracts", "PureAttribute", TypeKind.ReferenceType); public static readonly BasicType ICollection = New("mscorlib", "System.Collections", "ICollection", TypeKind.ReferenceType); + public static readonly BasicType List = New("mscorlib", "System.Collections.Generic", "List", TypeKind.ReferenceType); public static readonly BasicType IEnumerable = New("mscorlib", "System.Collections", "IEnumerable", TypeKind.ReferenceType); public static readonly BasicType IEnumerator = New("mscorlib", "System.Collections", "IEnumerator", TypeKind.ReferenceType); public static readonly BasicType GenericICollection = New("mscorlib", "System.Collections.Generic", "ICollection", TypeKind.ReferenceType, 1); From 77261be44deb0c3e0fdb1788a2096b31eb25dffb Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 23 Jun 2020 08:46:06 -0300 Subject: [PATCH 172/256] assembler offset generation draft --- Backend/Transformations/Assembler.cs | 408 +++++++++++++++--- Console/Program.cs | 4 +- MetadataGenerator/Extensions.cs | 4 - .../Methods/Body/MethodBodyGenerator.cs | 1 + .../Generators/Methods/MethodGenerator.cs | 8 + MetadataGenerator/MetadataGenerator.csproj | 4 + Model/Extensions.cs | 17 + 7 files changed, 369 insertions(+), 77 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 2138dacd..84b63afb 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -54,6 +54,7 @@ public MethodBody Execute() private class InstructionTranslator : InstructionVisitor { private readonly MethodBody body; + private uint offset; private readonly Stack protectedBlocks = new Stack(); public InstructionTranslator(MethodBody body) @@ -63,18 +64,30 @@ public InstructionTranslator(MethodBody body) public override void Visit(BinaryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, OperationHelper.ToBasicOperation(instruction.Operation)) + var basicInstruction = new Bytecode.BasicInstruction(offset, OperationHelper.ToBasicOperation(instruction.Operation)) { OverflowCheck = instruction.OverflowCheck, UnsignedOperands = instruction.UnsignedOperands }; body.Instructions.Add(basicInstruction); + switch (basicInstruction.Operation) + { + case Bytecode.BasicOperation.Gt: + case Bytecode.BasicOperation.Lt: + case Bytecode.BasicOperation.Eq: + offset += 2; // 2ByteOpcode + break; + default: + offset++; + break; + } } public override void Visit(UnaryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, OperationHelper.ToBasicOperation(instruction.Operation)); + var basicInstruction = new Bytecode.BasicInstruction(offset, OperationHelper.ToBasicOperation(instruction.Operation)); body.Instructions.Add(basicInstruction); + offset++; } public override void Visit(LoadInstruction instruction) @@ -89,7 +102,8 @@ public override void Visit(LoadInstruction instruction) } else { - loadInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Dup); + loadInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Dup); + offset++; } } else @@ -97,70 +111,230 @@ public override void Visit(LoadInstruction instruction) switch (instruction.Operand) { case Constant constant: - loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant); + loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Value, constant); + if (constant.Value == null) + { + // ldnull -> 14 (1) + offset++; + } + else if (constant.Type.Equals(PlatformTypes.String)) + { + // ldstr string -> 72 (1 + 4) + offset += 5; + } + else + { + switch (constant.Value) + { + case -1: + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + offset++; + break; + default: + if (constant.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.UInt8)) + { + // ldc.i4.s num -> 1F (1 + 1) + offset += 2; + } + else if (constant.Type.IsOneOf(PlatformTypes.Int16, PlatformTypes.Int32, PlatformTypes.UInt16, + PlatformTypes.UInt32)) + { + // ldc.i4 num -> 20 (1 + 4) + offset += 5; + } + else if (constant.Type.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) + { + // ldc.i8 num-> 21 (1 + 8) + offset += 9; + } + else if (constant.Type.Equals(PlatformTypes.Float32)) + { + // ldc.r4 num -> 22 (1 + 4) + offset += 5; + } + else if (constant.Type.Equals(PlatformTypes.Float64)) + { + // ldc.r8 num -> 23 (1 + 8) + offset += 9; + } + + break; + } + } + + break; case TemporalVariable _: - loadInstruction = new Bytecode.LoadInstruction( - instruction.Offset, Bytecode.LoadOperation.Content, - instruction.Result.ToLocalVariable()); + { + var operand = instruction.Result.ToLocalVariable(); + loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, operand); + switch (operand.Index.Value) + { + // ldloc.0,1,2,3 ldarg.0,1,2,3 + case 0: + case 1: + case 2: + case 3: + offset++; + break; + default: + // ldloc indx -> FE 0C (2 + 2) + // ldloc.s indx -> 11 (1 + 1) + // ldarg num -> FE 09 (2 + 2) + // ldarg.s num -> 0E (1 + 1) + offset += (uint) (operand.Index.Value > byte.MaxValue ? 4 : 2); + break; + } + break; + } + case LocalVariable localVariable: + { + loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, localVariable); + // fixme igual al caso de arriba? o estoy mezclando los casos? Creo que esta bien porque local y temporal ambas pueden + // fixme ser parameter (esto determina si es ldloc o ldarg) + switch (localVariable.Index.Value) + { + // ldloc.0,1,2,3 ldarg.0,1,2,3 + case 0: + case 1: + case 2: + case 3: + offset++; + break; + default: + // ldloc indx -> FE 0C (2 + 2) + // ldloc.s indx -> 11 (1 + 1) + // ldarg num -> FE 09 (2 + 2) + // ldarg.s num -> 0E (1 + 1) + offset += (uint) (localVariable.Index.Value > byte.MaxValue ? 4 : 2); + break; + } + + break; + } case Dereference dereference: - loadInstruction = new Bytecode.LoadIndirectInstruction(instruction.Offset, dereference.Type); + { + var type = dereference.Type; + loadInstruction = new Bytecode.LoadIndirectInstruction(offset, type); + if (type.IsIntType() || type.IsFloatType() || type.Equals(PlatformTypes.IntPtr) || type.Equals(PlatformTypes.Object)) + { + // 1 byte opcode + offset++; + } + else + { + // ldobj typeTok -> 71 (1 + 4) + offset += 5; + } + break; + } case Reference reference: switch (reference.Value) { case ArrayElementAccess _: + { + var operand = instruction.Result.ToLocalVariable(); + loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Address, operand); + // ldelema typeTok -> 8F (1 + 4) + offset += 5; + break; + } + case LocalVariable _: - loadInstruction = new Bytecode.LoadInstruction( - instruction.Offset, - Bytecode.LoadOperation.Address, - instruction.Result.ToLocalVariable()); + { + var operand = instruction.Result.ToLocalVariable(); + loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Address, operand); + // ldloca indx -> FE 0D (2 + 2) + // ldloca.s indx -> 12 (1 + 1) + // ldarga argNum -> FE 0A (2 + 2) + // ldarga.s argNum -> 0F (1 + 1) + offset += (uint) (operand.Index.Value > byte.MaxValue ? 4 : 2); break; + } case InstanceFieldAccess instanceFieldAccess: - // fixme es content? - loadInstruction = new Bytecode.LoadFieldInstruction(instruction.Offset, Bytecode.LoadFieldOperation.Content, + loadInstruction = new Bytecode.LoadFieldInstruction( + offset, + Bytecode.LoadFieldOperation.Address, instanceFieldAccess.Field); + // ldsflda field -> 0x7F (1 + 4) + // ldflda field -> 0x7C (1 + 4) + offset += 5; break; default: throw new Exception(); // TODO } - break; - case LocalVariable localVariable: - loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Content, localVariable); break; case ArrayLengthAccess _: - loadInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LoadArrayLength); + loadInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.LoadArrayLength); + offset++; break; case VirtualMethodReference virtualMethodReference: loadInstruction = new Bytecode.LoadMethodAddressInstruction( - instruction.Offset, + offset, Bytecode.LoadMethodAddressOperation.Virtual, virtualMethodReference.Method); + // ldvirtftn method -> FE 07 (2 + 4) + offset += 6; break; case StaticMethodReference staticMethodReference: loadInstruction = new Bytecode.LoadMethodAddressInstruction( - instruction.Offset, + offset, Bytecode.LoadMethodAddressOperation.Static, staticMethodReference.Method); + // ldftn method -> FE 06 (2 + 4) + offset += 6; break; case InstanceFieldAccess instanceFieldAccess: - // fixme es content? - loadInstruction = new Bytecode.LoadFieldInstruction(instruction.Offset, Bytecode.LoadFieldOperation.Content, + loadInstruction = new Bytecode.LoadFieldInstruction( + offset, + Bytecode.LoadFieldOperation.Content, instanceFieldAccess.Field); + // ldfld field -> 7B (1 + 4) + offset += 5; break; case StaticFieldAccess staticFieldAccess: - // fixme es content? - loadInstruction = new Bytecode.LoadFieldInstruction(instruction.Offset, Bytecode.LoadFieldOperation.Content, + loadInstruction = new Bytecode.LoadFieldInstruction( + offset, + Bytecode.LoadFieldOperation.Content, staticFieldAccess.Field); + // ldsfld field -> 7E (1 + 4) + offset += 5; break; case ArrayElementAccess arrayElementAccess: + { + var type = (ArrayType) arrayElementAccess.Array.Type; loadInstruction = new Bytecode.LoadArrayElementInstruction( - instruction.Offset, + offset, Bytecode.LoadArrayElementOperation.Content, - (ArrayType) arrayElementAccess.Array.Type); + type); + + if (type.ElementsType.IsIntType() || + type.ElementsType.IsFloatType() || + type.ElementsType.Equals(PlatformTypes.IntPtr) || + type.ElementsType.Equals(PlatformTypes.Object)) + { + // 1 byte opcode + offset++; + } + else + { + // ldelem typeTok -> A3 (1 + 4) + offset += 5; + } + break; + } default: throw new Exception(); // TODO } } @@ -174,16 +348,51 @@ public override void Visit(StoreInstruction instruction) switch (instruction.Result) { case ArrayElementAccess arrayElementAccess: - storeInstruction = new Bytecode.StoreArrayElementInstruction(instruction.Offset, (ArrayType) arrayElementAccess.Array.Type); + { + var type = (ArrayType) arrayElementAccess.Array.Type; + storeInstruction = new Bytecode.StoreArrayElementInstruction(offset, type); + if (type.ElementsType.IsIntType() || + type.ElementsType.IsFloatType() || + type.ElementsType.Equals(PlatformTypes.IntPtr) || + type.ElementsType.Equals(PlatformTypes.Object)) + { + // 1 byte opcode + offset++; + } + else + { + // stelem typeTok -> A4 (1 + 4) + offset += 5; + } + break; + } case Dereference dereference: - storeInstruction = new Bytecode.StoreIndirectInstruction(instruction.Offset, dereference.Type); + { + var type = dereference.Type; + storeInstruction = new Bytecode.StoreIndirectInstruction(offset, dereference.Type); + if (type.IsIntType() || type.IsFloatType() || type.Equals(PlatformTypes.IntPtr) || type.Equals(PlatformTypes.Object)) + { + // 1 byte opcode + offset++; + } + else + { + // stobj typeTok -> 81 (1 + 4) + offset += 5; + } + break; + } case InstanceFieldAccess instanceFieldAccess: - storeInstruction = new Bytecode.StoreFieldInstruction(instruction.Offset, instanceFieldAccess.Field); + storeInstruction = new Bytecode.StoreFieldInstruction(offset, instanceFieldAccess.Field); + // stfld field -> 7D (1 + 4) + offset += 5; break; case StaticFieldAccess staticFieldAccess: - storeInstruction = new Bytecode.StoreFieldInstruction(instruction.Offset, staticFieldAccess.Field); + storeInstruction = new Bytecode.StoreFieldInstruction(offset, staticFieldAccess.Field); + // stsfld field -> 80 (1 + 4) + offset += 5; break; default: throw new Exception(); // TODO msg @@ -194,27 +403,29 @@ public override void Visit(StoreInstruction instruction) public override void Visit(NopInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop); + var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Nop); body.Instructions.Add(basicInstruction); + offset++; } public override void Visit(BreakpointInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Breakpoint); + var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Breakpoint); body.Instructions.Add(basicInstruction); + offset++; } public override void Visit(TryInstruction instruction) { // try with multiple handlers are modelled as multiple try instructions with the same label but different handlers. // if label matches with the current try, then increase the number of expected handlers - if (protectedBlocks.Count > 0 && protectedBlocks.Peek().TryStart.Equals(instruction.Offset)) + if (protectedBlocks.Count > 0 && protectedBlocks.Peek().TryStart.Equals(offset)) { protectedBlocks.Peek().HandlerCount++; } else { - var exceptionBlockBuilder = new ProtectedBlockBuilder {TryStart = instruction.Offset, HandlerCount = 1}; + var exceptionBlockBuilder = new ProtectedBlockBuilder {TryStart = offset, HandlerCount = 1}; protectedBlocks.Push(exceptionBlockBuilder); } } @@ -223,10 +434,10 @@ public override void Visit(FaultInstruction instruction) { protectedBlocks .Peek() - .EndPreviousRegion(instruction.Offset) + .EndPreviousRegion(offset) .Handlers.Add(new ExceptionHandlerBlockBuilder { - HandlerStart = instruction.Offset, + HandlerStart = offset, HandlerBlockKind = ExceptionHandlerBlockKind.Fault, }); } @@ -235,11 +446,11 @@ public override void Visit(FinallyInstruction instruction) { protectedBlocks .Peek() - .EndPreviousRegion(instruction.Offset) + .EndPreviousRegion(offset) .Handlers.Add( new ExceptionHandlerBlockBuilder { - HandlerStart = instruction.Offset, + HandlerStart = offset, HandlerBlockKind = ExceptionHandlerBlockKind.Finally, }); } @@ -253,7 +464,7 @@ public override void Visit(FilterInstruction instruction) bool EndPreviousHandlerCondition() => protectedBlockBuilder.Handlers.Last().HandlerBlockKind != ExceptionHandlerBlockKind.Filter || instruction.kind == FilterInstructionKind.FilterSection; - protectedBlockBuilder.EndPreviousRegion(instruction.Offset, EndPreviousHandlerCondition); + protectedBlockBuilder.EndPreviousRegion(offset, EndPreviousHandlerCondition); switch (instruction.kind) { @@ -261,13 +472,13 @@ bool EndPreviousHandlerCondition() => protectedBlockBuilder.Handlers.Last().Hand protectedBlockBuilder.Handlers.Add( new ExceptionHandlerBlockBuilder { - FilterStart = instruction.Offset, + FilterStart = offset, HandlerBlockKind = ExceptionHandlerBlockKind.Filter, }); break; case FilterInstructionKind.FilterHandler: var handler = protectedBlockBuilder.Handlers.Last(); - handler.HandlerStart = instruction.Offset; + handler.HandlerStart = offset; handler.ExceptionType = instruction.ExceptionType; break; default: throw instruction.kind.ToUnknownValueException(); @@ -278,12 +489,12 @@ public override void Visit(CatchInstruction instruction) { protectedBlocks .Peek() - .EndPreviousRegion(instruction.Offset) + .EndPreviousRegion(offset) .Handlers .Add( new ExceptionHandlerBlockBuilder() { - HandlerStart = instruction.Offset, + HandlerStart = offset, HandlerBlockKind = ExceptionHandlerBlockKind.Catch, ExceptionType = instruction.ExceptionType } @@ -293,7 +504,7 @@ public override void Visit(CatchInstruction instruction) public override void Visit(ConvertInstruction instruction) { var convertInstruction = new Bytecode.ConvertInstruction( - instruction.Offset, + offset, OperationHelper.ToConvertOperation(instruction.Operation), instruction.ConversionType) { @@ -301,18 +512,36 @@ public override void Visit(ConvertInstruction instruction) UnsignedOperands = instruction.UnsignedOperands, }; body.Instructions.Add(convertInstruction); + switch (convertInstruction.Operation) + { + case Bytecode.ConvertOperation.Conv: + offset++; + break; + default: + // box typeTok -> 8C (1 + 4) + // castclass typeTok -> 74 (1 + 4) + // isinst typeTok -> 75 (1 + 4) + // unbox valuetype -> 79 (1 + 4) + // unbox.any typeTok -> A5 (1 + 4) + offset += 5; + break; + } } public override void Visit(ReturnInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Return); + var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Return); body.Instructions.Add(basicInstruction); + offset++; } public override void Visit(ThrowInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Throw); + // FIXME rethrow se modela como ThrowInstruction, hay que generarla. Habria que ver si esta dentro de un catch creo para saber si es o no. + // FIXME admeas el offset cambia si es rethrow. + var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Throw); body.Instructions.Add(basicInstruction); + offset++; } public override void Visit(UnconditionalBranchInstruction instruction) @@ -329,25 +558,30 @@ public override void Visit(UnconditionalBranchInstruction instruction) exceptionBlockBuilder .Handlers .Last() - .HandlerEnd = instruction.Offset; + .HandlerEnd = offset; body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); } } - var unconditionalBranchInstruction = new Bytecode.BranchInstruction( - instruction.Offset, - Bytecode.BranchOperation.Leave, - Convert.ToUInt32(instruction.Target.Substring(2), 16)); + var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); + var unconditionalBranchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Leave, target); body.Instructions.Add(unconditionalBranchInstruction); + // leave target -> DD (1 + 4) + // leave.s target -> DE (1 + 1) + offset += (uint) (target > byte.MaxValue ? 5 : 2); break; } case UnconditionalBranchOperation.Branch: { + var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); var unconditionalBranchInstruction = new Bytecode.BranchInstruction( - instruction.Offset, + offset, Bytecode.BranchOperation.Branch, - Convert.ToUInt32(instruction.Target.Substring(2), 16)); + target); body.Instructions.Add(unconditionalBranchInstruction); + // leave target -> 38 (1 + 4) + // leave.s target -> 2B (1 + 1) + offset += (uint) (target > byte.MaxValue ? 5 : 2); break; } case UnconditionalBranchOperation.EndFinally: @@ -356,15 +590,17 @@ public override void Visit(UnconditionalBranchInstruction instruction) exceptionBlockBuilder .Handlers .Last() - .HandlerEnd = instruction.Offset; + .HandlerEnd = offset; body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); - body.Instructions.Add(new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFinally)); + body.Instructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFinally)); + offset++; break; } case UnconditionalBranchOperation.EndFilter: { // nothing is done with protectedBlocks since filter area is the gap between try end and handler start - body.Instructions.Add(new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFilter)); + body.Instructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFilter)); + offset += 2; // 2byte opcode break; } default: throw instruction.Operation.ToUnknownValueException(); @@ -373,92 +609,119 @@ public override void Visit(UnconditionalBranchInstruction instruction) public override void Visit(ConditionalBranchInstruction instruction) { + var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); var conditionalBranchInstruction = new Bytecode.BranchInstruction( - instruction.Offset, + offset, OperationHelper.ToBranchOperation(instruction.Operation, instruction.RightOperand), - Convert.ToUInt32(instruction.Target.Substring(2), 16)); + target); body.Instructions.Add(conditionalBranchInstruction); + // br* target -> 1ByteOpcode (1 + 4) + // br*.s target -> 1ByteOpcode (1 + 1) + offset += (uint) (target > byte.MaxValue ? 5 : 2); } public override void Visit(SwitchInstruction instruction) { var targets = instruction.Targets.Select(target => Convert.ToUInt32(target.Substring(2), 16)).ToList(); - var switchInstruction = new Bytecode.SwitchInstruction(instruction.Offset, targets); + var switchInstruction = new Bytecode.SwitchInstruction(offset, targets); body.Instructions.Add(switchInstruction); + // switch number t1 t2 t3 ... -> 45 .... (1 + 4 + n*4) + offset += (uint) (1 + 4 + 4 * targets.Count); } public override void Visit(SizeofInstruction instruction) { - var sizeofInstruction = new Bytecode.SizeofInstruction(instruction.Offset, instruction.MeasuredType); + var sizeofInstruction = new Bytecode.SizeofInstruction(offset, instruction.MeasuredType); body.Instructions.Add(sizeofInstruction); + // sizeof typetok -> FE 1C (2 + 4) + offset += 6; } public override void Visit(LoadTokenInstruction instruction) { - var loadTokenInstruction = new Bytecode.LoadTokenInstruction(instruction.Offset, instruction.Token); + var loadTokenInstruction = new Bytecode.LoadTokenInstruction(offset, instruction.Token); body.Instructions.Add(loadTokenInstruction); + // ldtoken token -> D0 (1 + 4) + offset += 5; } public override void Visit(MethodCallInstruction instruction) { var methodCallInstruction = new Bytecode.MethodCallInstruction( - instruction.Offset, + offset, OperationHelper.ToMethodCallOperation(instruction.Operation), instruction.Method ); body.Instructions.Add(methodCallInstruction); + // call method -> 28 (1 + 4) + // callvirt method -> 6F (1 + 4) + offset += 5; } public override void Visit(IndirectMethodCallInstruction instruction) { - var indirectMethodCallInstruction = new Bytecode.IndirectMethodCallInstruction(instruction.Offset, instruction.Function); + var indirectMethodCallInstruction = new Bytecode.IndirectMethodCallInstruction(offset, instruction.Function); body.Instructions.Add(indirectMethodCallInstruction); + // calli callsitedescr -> 29 (1 + 4) + offset += 5; } public override void Visit(CreateObjectInstruction instruction) { - var createObjectInstruction = new Bytecode.CreateObjectInstruction(instruction.Offset, instruction.Constructor); + var createObjectInstruction = new Bytecode.CreateObjectInstruction(offset, instruction.Constructor); body.Instructions.Add(createObjectInstruction); + // newobj ctor -> 73 (1 + 4) + offset += 5; } public override void Visit(CopyMemoryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyBlock); + var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.CopyBlock); body.Instructions.Add(basicInstruction); + offset += 2; // 2ByteOpcode } public override void Visit(LocalAllocationInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LocalAllocation); + var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.LocalAllocation); body.Instructions.Add(basicInstruction); + offset += 2; // 2ByteOpcode } public override void Visit(InitializeMemoryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.InitBlock); + var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.InitBlock); body.Instructions.Add(basicInstruction); + offset += 2; // 2ByteOpcode } public override void Visit(InitializeObjectInstruction instruction) { - var initObjInstruction = new Bytecode.InitObjInstruction(instruction.Offset, instruction.TargetAddress.Type); + var initObjInstruction = new Bytecode.InitObjInstruction(offset, instruction.TargetAddress.Type); body.Instructions.Add(initObjInstruction); + // initobj typeTok -> FE 15 (2 + 4) + offset += 6; } public override void Visit(CopyObjectInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyObject); + var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.CopyObject); body.Instructions.Add(basicInstruction); + // cpobj typeTok-> 70 (1 + 4) + offset += 5; } public override void Visit(CreateArrayInstruction instruction) { var createArrayInstruction = - new Bytecode.CreateArrayInstruction(instruction.Offset, new ArrayType(instruction.ElementType, instruction.Rank)) + new Bytecode.CreateArrayInstruction(offset, new ArrayType(instruction.ElementType, instruction.Rank)) { WithLowerBound = instruction.LowerBounds.Any() }; body.Instructions.Add(createArrayInstruction); + // newobj ctor -> 73 (1 + 4) + // newarr etype -> 8D (1 + 4) + offset += 5; } public override void Visit(PhiInstruction instruction) @@ -466,9 +729,12 @@ public override void Visit(PhiInstruction instruction) throw new Exception(); } + // FIXME ahora que calculo a mano los offsets, se puede sacar esta instruccion y ver bien cuando ponerla en el virtual call? public override void Visit(ConstrainedInstruction instruction) { - body.Instructions.Add(new Bytecode.ConstrainedInstruction(instruction.Offset, instruction.ThisType)); + body.Instructions.Add(new Bytecode.ConstrainedInstruction(offset, instruction.ThisType)); + // constrained. thisType -> FE 16 (2 + 4) + offset += 6; } diff --git a/Console/Program.cs b/Console/Program.cs index 932e446e..5298fdc6 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -389,7 +389,7 @@ static void Main(string[] args) var inputs = new[] { new[] {"../../../Examples/bin/Debug/Examples.dll"}, - new[] + /* new[] { "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll", "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll" @@ -412,7 +412,7 @@ static void Main(string[] args) "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll" - } + }*/ }; foreach (var input in inputs) diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index 12185ca0..2d5a4aa5 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -16,10 +16,6 @@ public static T FirstOr(this IEnumerable enumerable, T defaultValue) return first.Equals(default(T)) ? defaultValue : first; } - public static bool IsOneOf(this Enum value, params Enum[] values) => ImmutableList.Create(values).Contains(value); - - public static bool IsOneOf(this IType type, params IType[] types) => ImmutableList.Create(types).Contains(type); - public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.EntityHandle methodReference) { encoder.OpCode(SRM.ILOpCode.Callvirt); diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index e0b34c90..04d154d5 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -2,6 +2,7 @@ using System.Globalization; using System.Linq; using MetadataGenerator.Metadata; +using Model; using Model.Bytecode; using Model.ThreeAddressCode.Values; using Model.Types; diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 5d1b8d94..641ce3d4 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -36,6 +36,14 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var methodBodyOffset = -1; if (method.HasBody) { + var og = method.Body; + var tac = new Backend.Transformations.Disassembler(method).Execute(); + method.Body = tac; + var bytecode = new Backend.Transformations.Assembler(method).Execute(); + method.Body = bytecode; + // method.Body = og; + + // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated // programatically then the maxStack is gonna be missing var maxStack = method.Body.MaxStack; diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index b0f0c9ff..8c8c0f41 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -46,6 +46,10 @@ + + {45c7b613-e32d-43e8-8030-932d509602eb} + Backend + {F08216AD-E55C-44B1-A253-AB8B024B7597} Model diff --git a/Model/Extensions.cs b/Model/Extensions.cs index 50475a80..4dad3866 100644 --- a/Model/Extensions.cs +++ b/Model/Extensions.cs @@ -570,5 +570,22 @@ public static TypeKind ToTypeKind(this TypeDefinitionKind kind) default: throw kind.ToUnknownValueException(); } } + + public static bool IsIntType(this IType type) => + new[] + { + PlatformTypes.Int8, + PlatformTypes.UInt8, + PlatformTypes.Int16, + PlatformTypes.UInt16, + PlatformTypes.Int32, + PlatformTypes.UInt32, + PlatformTypes.Int64, + PlatformTypes.UInt64 + }.Contains(type); + + public static bool IsFloatType(this IType type) => new[] {PlatformTypes.Float32, PlatformTypes.Float64}.Contains(type); + + public static bool IsOneOf(this IType type, params IType[] types) => types.Contains(type); } } From 8208bdfda2891b031a48be05fe940f3f51ce437a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 24 Jun 2020 08:57:38 -0300 Subject: [PATCH 173/256] fix load offset generation --- Backend/Transformations/Assembler.cs | 124 +++++++++++++++------------ 1 file changed, 71 insertions(+), 53 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 84b63afb..bac941bf 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -112,62 +112,80 @@ public override void Visit(LoadInstruction instruction) { case Constant constant: loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Value, constant); - if (constant.Value == null) + switch (constant.Value) { - // ldnull -> 14 (1) - offset++; - } - else if (constant.Type.Equals(PlatformTypes.String)) - { - // ldstr string -> 72 (1 + 4) - offset += 5; - } - else - { - switch (constant.Value) + case null: + offset++; // ldnull -> 14 (1) + break; + case string _: + offset += 5; // ldstr string -> 72 (1 + 4) + break; + case -1: + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + offset++; + break; + case object _ when constant.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.Int16, PlatformTypes.Int32): { - case -1: - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - offset++; - break; - default: - if (constant.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.UInt8)) - { - // ldc.i4.s num -> 1F (1 + 1) - offset += 2; - } - else if (constant.Type.IsOneOf(PlatformTypes.Int16, PlatformTypes.Int32, PlatformTypes.UInt16, - PlatformTypes.UInt32)) - { - // ldc.i4 num -> 20 (1 + 4) - offset += 5; - } - else if (constant.Type.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) - { - // ldc.i8 num-> 21 (1 + 8) - offset += 9; - } - else if (constant.Type.Equals(PlatformTypes.Float32)) - { - // ldc.r4 num -> 22 (1 + 4) - offset += 5; - } - else if (constant.Type.Equals(PlatformTypes.Float64)) - { - // ldc.r8 num -> 23 (1 + 8) - offset += 9; - } - - break; + var value = (int) constant.Value; + if (value >= sbyte.MinValue && value <= sbyte.MaxValue) + { + offset += 2; // ldc.i4.s num -> 1F (1 + 1) + } + else + { + offset += 5; // ldc.i4 num -> 20 (1 + 4) + } + + break; + } + case object _ when constant.Type.Equals(PlatformTypes.Int64): + offset += 9; // ldc.i8 num-> 21 (1 + 8) + break; + case object _ when constant.Type.IsOneOf(PlatformTypes.UInt8, PlatformTypes.UInt16, PlatformTypes.UInt32): + { + var value = (uint) constant.Value; + if (value <= byte.MaxValue) + { + offset += 2; // ldc.i4.s num -> 1F (1 + 1) + } + else + { + offset += 5; // ldc.i4 num -> 20 (1 + 4) + } + + break; } + case object _ when constant.Type.Equals(PlatformTypes.UInt64): + offset += 9; // ldc.i8 num-> 21 (1 + 8) + break; + + case object _ when constant.Type.Equals(PlatformTypes.Float32): + offset += 5; // ldc.r4 num -> 22 (1 + 4) + break; + case object _ when constant.Type.Equals(PlatformTypes.Float64): + { + var value = (double) constant.Value; + if (value >= float.MinValue && value <= float.MaxValue) + { + offset += 5; // ldc.r4 num -> 22 (1 + 4) + } + else + { + offset += 9; // ldc.r8 num -> 23 (1 + 8) + } + + break; + } + default: + throw new Exception(); } From 9e28c71f16f753c805b048d64edd1188a4bd20ed Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 26 Jun 2020 08:54:11 -0300 Subject: [PATCH 174/256] some offsets and types fixes --- Backend/Transformations/Assembler.cs | 20 ++++++----------- Backend/Transformations/Disassembler.cs | 22 +++++++++++++------ Console/Program.cs | 4 ++-- .../Methods/Body/MethodBodyGenerator.cs | 2 +- Model/Bytecode/Instructions.cs | 2 +- Model/ThreeAddressCode/Instructions.cs | 2 +- Model/Types/TypeDefinitions.cs | 2 +- 7 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index bac941bf..7ebe1b48 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -172,16 +172,7 @@ public override void Visit(LoadInstruction instruction) break; case object _ when constant.Type.Equals(PlatformTypes.Float64): { - var value = (double) constant.Value; - if (value >= float.MinValue && value <= float.MaxValue) - { - offset += 5; // ldc.r4 num -> 22 (1 + 4) - } - else - { - offset += 9; // ldc.r8 num -> 23 (1 + 8) - } - + offset += 9; // ldc.r8 num -> 23 (1 + 8) break; } default: @@ -259,10 +250,13 @@ public override void Visit(LoadInstruction instruction) case Reference reference: switch (reference.Value) { - case ArrayElementAccess _: + case ArrayElementAccess arrayElementAccess: { - var operand = instruction.Result.ToLocalVariable(); - loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Address, operand); + loadInstruction = new Bytecode.LoadArrayElementInstruction( + offset, + Bytecode.LoadArrayElementOperation.Address, + (ArrayType) arrayElementAccess.Array.Type); + // ldelema typeTok -> 8F (1 + 4) offset += 5; break; diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index f23b7a21..909e8afd 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -247,7 +247,15 @@ private void ProcessPop(Bytecode.BasicInstruction op) private void ProcessDup(Bytecode.BasicInstruction op) { var source = stack.Top(); - var dest = stack.Push(); + // recover type + var type = body.Instructions + .Reverse() + .Select(instructions => instructions.Variables) + .First(variables => variables.Any(variable => variable.Equals(source))) + .First(variable => variable.Equals(source)) + .Type; + source = source.MakeCopy(type); + var dest = stack.Push().MakeCopy(type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -594,9 +602,9 @@ public override void Visit(Bytecode.CreateObjectInstruction op) var arguments = new List(); - foreach (var par in op.Constructor.Parameters) + foreach (var parameter in op.Constructor.Parameters) { - var arg = stack.Pop(); + var arg = stack.Pop().MakeCopy(parameter.Type); arguments.Add(arg); } @@ -633,9 +641,9 @@ public override void Visit(Bytecode.IndirectMethodCallInstruction op) var arguments = new List(); IVariable result = null; - foreach (var par in op.Function.Parameters) + foreach (var parameter in op.Function.Parameters) { - var arg = stack.Pop(); + var arg = stack.Pop().MakeCopy(parameter.Type); arguments.Add(arg); } @@ -829,9 +837,9 @@ public override void Visit(Bytecode.MethodCallInstruction op) var arguments = new List(); IVariable result = null; - foreach (var par in op.Method.Parameters) + foreach (var parameter in op.Method.Parameters) { - var arg = stack.Pop(); + var arg = stack.Pop().MakeCopy(parameter.Type); arguments.Add(arg); } diff --git a/Console/Program.cs b/Console/Program.cs index 5298fdc6..932e446e 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -389,7 +389,7 @@ static void Main(string[] args) var inputs = new[] { new[] {"../../../Examples/bin/Debug/Examples.dll"}, - /* new[] + new[] { "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll", "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll" @@ -412,7 +412,7 @@ static void Main(string[] args) "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll" - }*/ + } }; foreach (var input in inputs) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 04d154d5..0974acdc 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -30,7 +30,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) foreach (var instruction in body.Instructions) { controlFlowGenerator.MarkCurrentLabel(); - if (instruction.Offset != instructionEncoder.Offset) throw new Exception(); + if (instruction.Offset != instructionEncoder.Offset) throw new Exception("Real offset does not match with expected one"); switch (instruction) { diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index ab3f3ae2..75cbf01e 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -273,7 +273,7 @@ public override void Accept(IInstructionVisitor visitor) public override string ToString() { - return String.Format("constrain virtual call to type: {0}", ThisType.ToString()); + return this.ToString("constrain virtual call to type: {0}", ThisType.ToString()); } } diff --git a/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index 498ea6ce..41e8d103 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -1430,7 +1430,7 @@ public override void Accept(IInstructionVisitor visitor) public override string ToString() { - return String.Format("constrain virtual call to type: {0}", ThisType.ToString()); + return this.ToString("constrain virtual call to type: {0}", ThisType.ToString()); } } } diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 8a6c92b2..42fc0bd6 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -820,7 +820,7 @@ public class MethodBody : IInstructionContainer { public IList Parameters { get; private set; } public IList LocalVariables { get; private set; } - public IList Instructions { get; set; } // fixme undo, just for testing + public IList Instructions { get; private set; } public IList ExceptionInformation { get; private set; } public ushort MaxStack { get; set; } public MethodBodyKind Kind { get; set; } From c682c0f5993fbe883aa237e1f90480c7ba8250a8 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 29 Jun 2020 08:54:25 -0300 Subject: [PATCH 175/256] draft --- Backend/Transformations/Assembler.cs | 533 ++++++++++-------- Backend/Transformations/Disassembler.cs | 19 +- .../Body/MethodLocalsSignatureGenerator.cs | 1 + .../Generators/Methods/MethodGenerator.cs | 3 +- .../Metadata/MetadataResolver.cs | 14 + Model/ThreeAddressCode/Instructions.cs | 25 +- Model/ThreeAddressCode/Operands.cs | 3 +- .../Visitor/IInstructionVisitor.cs | 1 + .../Visitor/InstructionVisitor.cs | 9 +- 9 files changed, 365 insertions(+), 243 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 7ebe1b48..6d8ab4f9 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -41,11 +41,19 @@ public MethodBody Execute() body.MaxStack = method.Body.MaxStack; // FIXME body.Parameters.AddRange(method.Body.Parameters); - body.LocalVariables.AddRange(method.Body.LocalVariables.Select(variable => variable.ToLocalVariable())); if (method.Body.Instructions.Count > 0) { - new InstructionTranslator(body).Visit(method.Body); + new InstructionTranslator(body, method.Body).Visit(method.Body); + } + + foreach (var bodyInstruction in body.Instructions.Where(i => i.Variables.Count > 0)) + { + foreach (var loc in bodyInstruction.Variables) + { + // filter this???? + if (!body.LocalVariables.Contains(loc) && !loc.Name.Equals("this")) body.LocalVariables.Add(loc); + } } return body; @@ -54,12 +62,27 @@ public MethodBody Execute() private class InstructionTranslator : InstructionVisitor { private readonly MethodBody body; + private readonly MethodBody bodyToProcess; private uint offset; private readonly Stack protectedBlocks = new Stack(); + private readonly IDictionary ignoreInstruction = new Dictionary(); - public InstructionTranslator(MethodBody body) + public InstructionTranslator(MethodBody body, MethodBody bodyToProcess) { this.body = body; + this.bodyToProcess = bodyToProcess; + } + + public override bool ShouldVisit(Instruction instruction) + { + var shouldProcessInstruction = !ignoreInstruction.TryGetValue(bodyToProcess.Instructions.IndexOf(instruction), out _); + return shouldProcessInstruction; + } + + public override void Visit(PopInstruction instruction) + { + body.Instructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Pop)); + offset++; } public override void Visit(BinaryInstruction instruction) @@ -93,7 +116,7 @@ public override void Visit(UnaryInstruction instruction) public override void Visit(LoadInstruction instruction) { // FIXME revisar los casos, hay algunos que no estoy seguro de que esten bien. se repiten caminos ademas (sobretodo por el reference) - Bytecode.Instruction loadInstruction; + Bytecode.Instruction bytecodeInstruction; if (instruction.Operand is TemporalVariable && instruction.Result is TemporalVariable) { if (instruction.Operand.Equals(instruction.Result)) @@ -102,256 +125,287 @@ public override void Visit(LoadInstruction instruction) } else { - loadInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Dup); + bytecodeInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Dup); offset++; } } else { - switch (instruction.Operand) + if (instruction.Result is LocalVariable loc) { - case Constant constant: - loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Value, constant); - switch (constant.Value) + bytecodeInstruction = new Bytecode.StoreInstruction(offset, loc); + if (loc.IsParameter) + { + // starg num -> FE 0B (2 + 2) + // starg.s num -> 10 (1 + 1) + offset += (uint) (loc.Index.Value > byte.MaxValue ? 4 : 2); + } + else + { + switch (loc.Index.Value) { - case null: - offset++; // ldnull -> 14 (1) - break; - case string _: - offset += 5; // ldstr string -> 72 (1 + 4) - break; - case -1: case 0: case 1: case 2: case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - offset++; + offset++; // 1byte OpCode + break; + default: + // stloc indx -> FE 0E (2 + 2) + // stloc.s indx -> 13 (1 + 1) + offset += (uint) (loc.Index.Value > byte.MaxValue ? 4 : 2); break; - case object _ when constant.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.Int16, PlatformTypes.Int32): + } + } + } + else + { + switch (instruction.Operand) + { + case Constant constant: + bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Value, constant); + switch (constant.Value) { - var value = (int) constant.Value; - if (value >= sbyte.MinValue && value <= sbyte.MaxValue) - { - offset += 2; // ldc.i4.s num -> 1F (1 + 1) - } - else + case null: + offset++; // ldnull -> 14 (1) + break; + case string _: + offset += 5; // ldstr string -> 72 (1 + 4) + break; + case -1: + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + offset++; + break; + case object _ when constant.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.Int16, PlatformTypes.Int32): { - offset += 5; // ldc.i4 num -> 20 (1 + 4) + var value = (int) constant.Value; + if (value >= sbyte.MinValue && value <= sbyte.MaxValue) + { + offset += 2; // ldc.i4.s num -> 1F (1 + 1) + } + else + { + offset += 5; // ldc.i4 num -> 20 (1 + 4) + } + + break; } - - break; - } - case object _ when constant.Type.Equals(PlatformTypes.Int64): - offset += 9; // ldc.i8 num-> 21 (1 + 8) - break; - case object _ when constant.Type.IsOneOf(PlatformTypes.UInt8, PlatformTypes.UInt16, PlatformTypes.UInt32): - { - var value = (uint) constant.Value; - if (value <= byte.MaxValue) + case object _ when constant.Type.Equals(PlatformTypes.Int64): + offset += 9; // ldc.i8 num-> 21 (1 + 8) + break; + case object _ when constant.Type.IsOneOf(PlatformTypes.UInt8, PlatformTypes.UInt16, PlatformTypes.UInt32): { - offset += 2; // ldc.i4.s num -> 1F (1 + 1) + var value = (uint) constant.Value; + if (value <= byte.MaxValue) + { + offset += 2; // ldc.i4.s num -> 1F (1 + 1) + } + else + { + offset += 5; // ldc.i4 num -> 20 (1 + 4) + } + + break; } - else + case object _ when constant.Type.Equals(PlatformTypes.UInt64): + offset += 9; // ldc.i8 num-> 21 (1 + 8) + break; + + case object _ when constant.Type.Equals(PlatformTypes.Float32): + offset += 5; // ldc.r4 num -> 22 (1 + 4) + break; + case object _ when constant.Type.Equals(PlatformTypes.Float64): { - offset += 5; // ldc.i4 num -> 20 (1 + 4) + offset += 9; // ldc.r8 num -> 23 (1 + 8) + break; } - - break; + default: + throw new Exception(); } - case object _ when constant.Type.Equals(PlatformTypes.UInt64): - offset += 9; // ldc.i8 num-> 21 (1 + 8) - break; - case object _ when constant.Type.Equals(PlatformTypes.Float32): - offset += 5; // ldc.r4 num -> 22 (1 + 4) - break; - case object _ when constant.Type.Equals(PlatformTypes.Float64): + + break; + case TemporalVariable _: + { + // FIXME hay casos sin sentido? a este no se entra nunca creo. Hay que revisar todo. + var operand = instruction.Result.ToLocalVariable(); // fixme operand como en l otro caso qie cambie? + bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, operand); + switch (operand.Index.Value) { - offset += 9; // ldc.r8 num -> 23 (1 + 8) - break; + // ldloc.0,1,2,3 ldarg.0,1,2,3 + case 0: + case 1: + case 2: + case 3: + offset++; + break; + default: + // ldloc indx -> FE 0C (2 + 2) + // ldloc.s indx -> 11 (1 + 1) + // ldarg num -> FE 09 (2 + 2) + // ldarg.s num -> 0E (1 + 1) + offset += (uint) (operand.Index.Value > byte.MaxValue ? 4 : 2); + break; } - default: - throw new Exception(); - } - - break; - case TemporalVariable _: - { - var operand = instruction.Result.ToLocalVariable(); - loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, operand); - switch (operand.Index.Value) - { - // ldloc.0,1,2,3 ldarg.0,1,2,3 - case 0: - case 1: - case 2: - case 3: - offset++; - break; - default: - // ldloc indx -> FE 0C (2 + 2) - // ldloc.s indx -> 11 (1 + 1) - // ldarg num -> FE 09 (2 + 2) - // ldarg.s num -> 0E (1 + 1) - offset += (uint) (operand.Index.Value > byte.MaxValue ? 4 : 2); - break; + break; } - - break; - } - case LocalVariable localVariable: - { - loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, localVariable); - // fixme igual al caso de arriba? o estoy mezclando los casos? Creo que esta bien porque local y temporal ambas pueden - // fixme ser parameter (esto determina si es ldloc o ldarg) - switch (localVariable.Index.Value) + case LocalVariable localVariable: { - // ldloc.0,1,2,3 ldarg.0,1,2,3 - case 0: - case 1: - case 2: - case 3: - offset++; - break; - default: - // ldloc indx -> FE 0C (2 + 2) - // ldloc.s indx -> 11 (1 + 1) - // ldarg num -> FE 09 (2 + 2) - // ldarg.s num -> 0E (1 + 1) - offset += (uint) (localVariable.Index.Value > byte.MaxValue ? 4 : 2); - break; - } + bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, localVariable); + // fixme igual al caso de arriba? o estoy mezclando los casos? Creo que esta bien porque local y temporal ambas pueden + // fixme ser parameter (esto determina si es ldloc o ldarg) + switch (localVariable.Index.Value) + { + // ldloc.0,1,2,3 ldarg.0,1,2,3 + case 0: + case 1: + case 2: + case 3: + offset++; + break; + default: + // ldloc indx -> FE 0C (2 + 2) + // ldloc.s indx -> 11 (1 + 1) + // ldarg num -> FE 09 (2 + 2) + // ldarg.s num -> 0E (1 + 1) + offset += (uint) (localVariable.Index.Value > byte.MaxValue ? 4 : 2); + break; + } - break; - } - case Dereference dereference: - { - var type = dereference.Type; - loadInstruction = new Bytecode.LoadIndirectInstruction(offset, type); - if (type.IsIntType() || type.IsFloatType() || type.Equals(PlatformTypes.IntPtr) || type.Equals(PlatformTypes.Object)) - { - // 1 byte opcode - offset++; + break; } - else + case Dereference dereference: { - // ldobj typeTok -> 71 (1 + 4) - offset += 5; - } - - break; - } - case Reference reference: - switch (reference.Value) - { - case ArrayElementAccess arrayElementAccess: + var type = dereference.Type; + bytecodeInstruction = new Bytecode.LoadIndirectInstruction(offset, type); + if (type.IsIntType() || type.IsFloatType() || type.Equals(PlatformTypes.IntPtr) || type.Equals(PlatformTypes.Object)) { - loadInstruction = new Bytecode.LoadArrayElementInstruction( - offset, - Bytecode.LoadArrayElementOperation.Address, - (ArrayType) arrayElementAccess.Array.Type); - - // ldelema typeTok -> 8F (1 + 4) + // 1 byte opcode + offset++; + } + else + { + // ldobj typeTok -> 71 (1 + 4) offset += 5; - break; } - case LocalVariable _: + break; + } + case Reference reference: + switch (reference.Value) { - var operand = instruction.Result.ToLocalVariable(); - loadInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Address, operand); - // ldloca indx -> FE 0D (2 + 2) - // ldloca.s indx -> 12 (1 + 1) - // ldarga argNum -> FE 0A (2 + 2) - // ldarga.s argNum -> 0F (1 + 1) - offset += (uint) (operand.Index.Value > byte.MaxValue ? 4 : 2); - break; + case ArrayElementAccess arrayElementAccess: + { + bytecodeInstruction = new Bytecode.LoadArrayElementInstruction( + offset, + Bytecode.LoadArrayElementOperation.Address, + (ArrayType) arrayElementAccess.Array.Type) {Method = arrayElementAccess.Method}; + + // ldelema typeTok -> 8F (1 + 4) + offset += 5; + break; + } + + case LocalVariable localVariable: + { + bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Address, localVariable); + // ldloca indx -> FE 0D (2 + 2) + // ldloca.s indx -> 12 (1 + 1) + // ldarga argNum -> FE 0A (2 + 2) + // ldarga.s argNum -> 0F (1 + 1) + offset += (uint) (localVariable.Index.Value > byte.MaxValue ? 4 : 2); + break; + } + case InstanceFieldAccess instanceFieldAccess: + bytecodeInstruction = new Bytecode.LoadFieldInstruction( + offset, + Bytecode.LoadFieldOperation.Address, + instanceFieldAccess.Field); + // ldsflda field -> 0x7F (1 + 4) + // ldflda field -> 0x7C (1 + 4) + offset += 5; + break; + default: + throw new Exception(); // TODO } - case InstanceFieldAccess instanceFieldAccess: - loadInstruction = new Bytecode.LoadFieldInstruction( - offset, - Bytecode.LoadFieldOperation.Address, - instanceFieldAccess.Field); - // ldsflda field -> 0x7F (1 + 4) - // ldflda field -> 0x7C (1 + 4) - offset += 5; - break; - default: - throw new Exception(); // TODO - } - break; - case ArrayLengthAccess _: - loadInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.LoadArrayLength); - offset++; - break; - case VirtualMethodReference virtualMethodReference: - loadInstruction = new Bytecode.LoadMethodAddressInstruction( - offset, - Bytecode.LoadMethodAddressOperation.Virtual, - virtualMethodReference.Method); - // ldvirtftn method -> FE 07 (2 + 4) - offset += 6; - break; - case StaticMethodReference staticMethodReference: - loadInstruction = new Bytecode.LoadMethodAddressInstruction( - offset, - Bytecode.LoadMethodAddressOperation.Static, - staticMethodReference.Method); - // ldftn method -> FE 06 (2 + 4) - offset += 6; - break; - case InstanceFieldAccess instanceFieldAccess: - loadInstruction = new Bytecode.LoadFieldInstruction( - offset, - Bytecode.LoadFieldOperation.Content, - instanceFieldAccess.Field); - // ldfld field -> 7B (1 + 4) - offset += 5; - break; - case StaticFieldAccess staticFieldAccess: - loadInstruction = new Bytecode.LoadFieldInstruction( - offset, - Bytecode.LoadFieldOperation.Content, - staticFieldAccess.Field); - // ldsfld field -> 7E (1 + 4) - offset += 5; - break; - case ArrayElementAccess arrayElementAccess: - { - var type = (ArrayType) arrayElementAccess.Array.Type; - loadInstruction = new Bytecode.LoadArrayElementInstruction( - offset, - Bytecode.LoadArrayElementOperation.Content, - type); - - if (type.ElementsType.IsIntType() || - type.ElementsType.IsFloatType() || - type.ElementsType.Equals(PlatformTypes.IntPtr) || - type.ElementsType.Equals(PlatformTypes.Object)) - { - // 1 byte opcode + break; + case ArrayLengthAccess _: + bytecodeInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.LoadArrayLength); offset++; - } - else - { - // ldelem typeTok -> A3 (1 + 4) + break; + case VirtualMethodReference virtualMethodReference: + bytecodeInstruction = new Bytecode.LoadMethodAddressInstruction( + offset, + Bytecode.LoadMethodAddressOperation.Virtual, + virtualMethodReference.Method); + // ldvirtftn method -> FE 07 (2 + 4) + offset += 6; + break; + case StaticMethodReference staticMethodReference: + bytecodeInstruction = new Bytecode.LoadMethodAddressInstruction( + offset, + Bytecode.LoadMethodAddressOperation.Static, + staticMethodReference.Method); + // ldftn method -> FE 06 (2 + 4) + offset += 6; + break; + case InstanceFieldAccess instanceFieldAccess: + bytecodeInstruction = new Bytecode.LoadFieldInstruction( + offset, + Bytecode.LoadFieldOperation.Content, + instanceFieldAccess.Field); + // ldfld field -> 7B (1 + 4) offset += 5; - } + break; + case StaticFieldAccess staticFieldAccess: + bytecodeInstruction = new Bytecode.LoadFieldInstruction( + offset, + Bytecode.LoadFieldOperation.Content, + staticFieldAccess.Field); + // ldsfld field -> 7E (1 + 4) + offset += 5; + break; + case ArrayElementAccess arrayElementAccess: + { + var type = (ArrayType) arrayElementAccess.Array.Type; + bytecodeInstruction = new Bytecode.LoadArrayElementInstruction( + offset, + Bytecode.LoadArrayElementOperation.Content, + type) {Method = arrayElementAccess.Method}; + + if ((type.ElementsType.IsIntType() || + type.ElementsType.IsFloatType() || + type.ElementsType.Equals(PlatformTypes.IntPtr) || + type.ElementsType.Equals(PlatformTypes.Object)) && ((ArrayType) arrayElementAccess.Array.Type).IsVector) + /// fixme cuaqluiera ese isvector? + { + // 1 byte opcode + offset++; + } + else + { + // ldelem typeTok -> A3 (1 + 4) + offset += 5; + } - break; + break; + } + default: throw new Exception(); // TODO } - default: throw new Exception(); // TODO } } - body.Instructions.Add(loadInstruction); + body.Instructions.Add(bytecodeInstruction); } public override void Visit(StoreInstruction instruction) @@ -362,11 +416,14 @@ public override void Visit(StoreInstruction instruction) case ArrayElementAccess arrayElementAccess: { var type = (ArrayType) arrayElementAccess.Array.Type; - storeInstruction = new Bytecode.StoreArrayElementInstruction(offset, type); - if (type.ElementsType.IsIntType() || - type.ElementsType.IsFloatType() || - type.ElementsType.Equals(PlatformTypes.IntPtr) || - type.ElementsType.Equals(PlatformTypes.Object)) + storeInstruction = new Bytecode.StoreArrayElementInstruction(offset, type) {Method = arrayElementAccess.Method}; + if ( + (type.ElementsType.IsIntType() || + type.ElementsType.IsFloatType() || + type.ElementsType.Equals(PlatformTypes.IntPtr) || + type.ElementsType.Equals(PlatformTypes.Object) + ) && ((ArrayType) arrayElementAccess.Array.Type).IsVector /// fixme cuaqluiera ese isvector? + ) { // 1 byte opcode offset++; @@ -562,6 +619,15 @@ public override void Visit(UnconditionalBranchInstruction instruction) { case UnconditionalBranchOperation.Leave: { + var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); + var unconditionalBranchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Leave, target); + + body.Instructions.Add(unconditionalBranchInstruction); + // leave target -> DD (1 + 4) + // leave.s target -> DE (1 + 1) + offset += (uint) (IsShortForm(instruction) ? 2 : 5); + + if (protectedBlocks.Count > 0) { if (protectedBlocks.Peek().AllHandlersAdded()) @@ -575,12 +641,6 @@ public override void Visit(UnconditionalBranchInstruction instruction) } } - var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); - var unconditionalBranchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Leave, target); - body.Instructions.Add(unconditionalBranchInstruction); - // leave target -> DD (1 + 4) - // leave.s target -> DE (1 + 1) - offset += (uint) (target > byte.MaxValue ? 5 : 2); break; } case UnconditionalBranchOperation.Branch: @@ -593,19 +653,19 @@ public override void Visit(UnconditionalBranchInstruction instruction) body.Instructions.Add(unconditionalBranchInstruction); // leave target -> 38 (1 + 4) // leave.s target -> 2B (1 + 1) - offset += (uint) (target > byte.MaxValue ? 5 : 2); + offset += (uint) (IsShortForm(instruction) ? 2 : 5); break; } case UnconditionalBranchOperation.EndFinally: { + body.Instructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFinally)); + offset++; var exceptionBlockBuilder = protectedBlocks.Pop(); // no more handlers after finally exceptionBlockBuilder .Handlers .Last() .HandlerEnd = offset; body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); - body.Instructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFinally)); - offset++; break; } case UnconditionalBranchOperation.EndFilter: @@ -629,7 +689,7 @@ public override void Visit(ConditionalBranchInstruction instruction) body.Instructions.Add(conditionalBranchInstruction); // br* target -> 1ByteOpcode (1 + 4) // br*.s target -> 1ByteOpcode (1 + 1) - offset += (uint) (target > byte.MaxValue ? 5 : 2); + offset += (uint) (IsShortForm(instruction) ? 2 : 5); } public override void Visit(SwitchInstruction instruction) @@ -680,7 +740,12 @@ public override void Visit(IndirectMethodCallInstruction instruction) public override void Visit(CreateObjectInstruction instruction) { - var createObjectInstruction = new Bytecode.CreateObjectInstruction(offset, instruction.Constructor); + var index = bodyToProcess.Instructions.IndexOf(instruction); + var methodCallInstruction = (MethodCallInstruction) bodyToProcess.Instructions[index + 1]; + ignoreInstruction.Add(index + 1, true); // method call + ignoreInstruction.Add(index + 2, true); // load + + var createObjectInstruction = new Bytecode.CreateObjectInstruction(offset, methodCallInstruction.Method); body.Instructions.Add(createObjectInstruction); // newobj ctor -> 73 (1 + 4) offset += 5; @@ -728,7 +793,8 @@ public override void Visit(CreateArrayInstruction instruction) var createArrayInstruction = new Bytecode.CreateArrayInstruction(offset, new ArrayType(instruction.ElementType, instruction.Rank)) { - WithLowerBound = instruction.LowerBounds.Any() + WithLowerBound = instruction.LowerBounds.Any(), + Constructor = instruction.Constructor }; body.Instructions.Add(createArrayInstruction); // newobj ctor -> 73 (1 + 4) @@ -750,6 +816,17 @@ public override void Visit(ConstrainedInstruction instruction) } + private bool IsShortForm(BranchInstruction instruction) + { + var nextInstructionOffset = + Convert.ToInt32(bodyToProcess.Instructions[bodyToProcess.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); + var currentInstructionOffset = Convert.ToInt32(instruction.Label.Substring(2), 16); + // short forms are 1 byte opcode + 1 byte target. normal forms are 1 byte opcode + 4 byte target + var isShortForm = nextInstructionOffset - currentInstructionOffset == 2; + return isShortForm; + } + + #region ExceptionInformation private class ProtectedBlockBuilder diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 909e8afd..d2f7a0bb 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -242,6 +242,7 @@ private void ProcessEmptyOperation(Bytecode.BasicInstruction op) private void ProcessPop(Bytecode.BasicInstruction op) { stack.Pop(); + body.Instructions.Add(new Tac.PopInstruction(op.Offset)); } private void ProcessDup(Bytecode.BasicInstruction op) @@ -515,7 +516,10 @@ public override void Visit(Bytecode.CreateArrayInstruction op) sizes.Reverse(); var result = stack.Push().MakeCopy(op.Type); - 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); } @@ -548,7 +552,7 @@ private void ProcessLoadArrayElement(Bytecode.LoadArrayElementInstruction op) var array = stack.Pop().MakeCopy(op.Array); indices.Reverse(); - var source = new ArrayElementAccess(array, indices); + var source = new ArrayElementAccess(array, indices) { Method = op.Method}; var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); @@ -568,7 +572,7 @@ private void ProcessLoadArrayElementAddress(Bytecode.LoadArrayElementInstruction indices.Reverse(); - var access = new ArrayElementAccess(array, indices); + var access = new ArrayElementAccess(array, indices) { Method = op.Method};; var source = new Reference(access); var dest = stack.Push().MakeCopy(source.Type); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); @@ -588,7 +592,7 @@ public override void Visit(Bytecode.StoreArrayElementInstruction op) var array = stack.Pop().MakeCopy(op.Array); 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); } @@ -618,10 +622,7 @@ public override void Visit(Bytecode.CreateObjectInstruction op) arguments.Add(allocationResult); arguments.Reverse(); - IInstruction instruction = new Tac.CreateObjectInstruction(op.Offset, allocationResult, op.Constructor.ContainingType) - { - Constructor = op.Constructor - }; + IInstruction instruction = new Tac.CreateObjectInstruction(op.Offset, allocationResult, op.Constructor.ContainingType); body.Instructions.Add(instruction); instruction = new Tac.MethodCallInstruction(op.Offset, null, Tac.MethodCallOperation.Static, op.Constructor, arguments); @@ -826,7 +827,7 @@ public void ProcessLoadVirtualMethodAddress(Bytecode.LoadMethodAddressInstructio public override void Visit(Bytecode.LoadTokenInstruction op) { - var result = stack.Push(); + var result = stack.Push().MakeCopy(TypeHelper.TokenType(op.Token)); var instruction = new Tac.LoadTokenInstruction(op.Offset, result, op.Token); body.Instructions.Add(instruction); } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs index 988921bb..f8c8d9ea 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using MetadataGenerator.Metadata; using Model.ThreeAddressCode.Values; +using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 641ce3d4..b31510ad 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -36,12 +36,13 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var methodBodyOffset = -1; if (method.HasBody) { + // FIXME undo this. Just for testing assembler var og = method.Body; var tac = new Backend.Transformations.Disassembler(method).Execute(); method.Body = tac; var bytecode = new Backend.Transformations.Assembler(method).Execute(); method.Body = bytecode; - // method.Body = og; + // method.Body = og; // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 9d6e363f..46232dac 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -316,6 +316,20 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) break; } + case ManagedPointerType managedPointerType: // FIXME tiene sentido esto? Es igual al pointer type.... + { + var targetType = managedPointerType.TargetType; + if (targetType.Equals(PlatformTypes.Void)) + { + encoder.VoidPointer(); + } + else + { + Encode(targetType, encoder.Pointer()); + } + + break; + } case FunctionPointerType _: { encoder.FunctionPointer(); diff --git a/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index 41e8d103..3747df7b 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -406,6 +406,25 @@ public override string ToString() return this.ToString("nop"); } } + + public class PopInstruction : Instruction + { + public PopInstruction(uint offset) + : base(offset) + { + } + + public override void Accept(IInstructionVisitor visitor) + { + base.Accept(visitor); + visitor.Visit(this); + } + + public override string ToString() + { + return this.ToString("pop"); + } + } public class BreakpointInstruction : Instruction { @@ -1103,9 +1122,7 @@ public override string ToString() public class CreateObjectInstruction : DefinitionInstruction { public IType AllocationType { get; set; } - - public IMethodReference Constructor { get; set; } - + public CreateObjectInstruction(uint offset, IVariable result, IType allocationType) : base(offset, result) { @@ -1313,6 +1330,8 @@ public class CreateArrayInstruction : DefinitionInstruction public uint Rank { get; set; } public IList LowerBounds { get; private set; } public IList Sizes { get; private set; } + + public IMethodReference Constructor { get; set; } public CreateArrayInstruction(uint offset, IVariable result, IType elementType, uint rank, IEnumerable lowerBounds, IEnumerable sizes) : base(offset, result) diff --git a/Model/ThreeAddressCode/Operands.cs b/Model/ThreeAddressCode/Operands.cs index 39ab1072..432e1a49 100644 --- a/Model/ThreeAddressCode/Operands.cs +++ b/Model/ThreeAddressCode/Operands.cs @@ -787,7 +787,8 @@ public class ArrayElementAccess : IAssignableValue, IReferenceable, IExpression { public IVariable Array { get; set; } public IList Indices { get; set; } - + + public IMethodReference Method { get; set; } public ArrayElementAccess(IVariable array, IEnumerable indices) { this.Array = array; diff --git a/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs b/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs index 2cb07f2a..ed70fdd5 100644 --- a/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs +++ b/Model/ThreeAddressCode/Visitor/IInstructionVisitor.cs @@ -45,5 +45,6 @@ public interface IInstructionVisitor void Visit(CreateArrayInstruction instruction); void Visit(PhiInstruction instruction); void Visit(ConstrainedInstruction instruction); + void Visit(PopInstruction instruction); } } diff --git a/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs b/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs index 7dcef6b1..b0daf076 100644 --- a/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs +++ b/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs @@ -15,7 +15,11 @@ public virtual void Visit(IInstructionContainer container) foreach (var instruction in container.Instructions) { var tacInstruction = instruction as Instruction; - tacInstruction.Accept(this); + if (ShouldVisit(tacInstruction)) + { + tacInstruction.Accept(this); + } + } } @@ -53,5 +57,8 @@ public virtual void Visit(CopyObjectInstruction instruction) { } public virtual void Visit(CreateArrayInstruction instruction) { } public virtual void Visit(PhiInstruction instruction) { } public virtual void Visit(ConstrainedInstruction instruction) { } + public virtual void Visit(PopInstruction instruction) { } + + public virtual bool ShouldVisit(Instruction instruction) => true; } } From 1c3be9733d0b03b8dac4ed5aa71eb24d5389fba2 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 30 Jun 2020 09:02:30 -0300 Subject: [PATCH 176/256] fix local variables translation --- Backend/Transformations/Assembler.cs | 16 +++++++--------- Model/ThreeAddressCode/Operands.cs | 5 +++-- Model/Types/TypeDefinitions.cs | 2 ++ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 6d8ab4f9..2327e42e 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -40,21 +40,19 @@ public MethodBody Execute() var body = new MethodBody(MethodBodyKind.Bytecode); body.MaxStack = method.Body.MaxStack; // FIXME - body.Parameters.AddRange(method.Body.Parameters); + body.Parameters.AddRange(method.Body.Parameters); // FIXME esto queda igual? + // this is updated later on. Needed to preserver variables that are declared but not used + body.LocalVariables.AddRange(method.Body.LocalVariables); if (method.Body.Instructions.Count > 0) { new InstructionTranslator(body, method.Body).Visit(method.Body); } - foreach (var bodyInstruction in body.Instructions.Where(i => i.Variables.Count > 0)) - { - foreach (var loc in bodyInstruction.Variables) - { - // filter this???? - if (!body.LocalVariables.Contains(loc) && !loc.Name.Equals("this")) body.LocalVariables.Add(loc); - } - } + body.UpdateVariables(); + var newLocals = body.LocalVariables.OfType().OrderBy(local => local.Index.Value).ToList(); + body.LocalVariables.Clear(); + body.LocalVariables.AddRange(newLocals); return body; } diff --git a/Model/ThreeAddressCode/Operands.cs b/Model/ThreeAddressCode/Operands.cs index 432e1a49..8872ad04 100644 --- a/Model/ThreeAddressCode/Operands.cs +++ b/Model/ThreeAddressCode/Operands.cs @@ -328,12 +328,13 @@ public override bool Equals(object obj) var other = obj as LocalVariable; return other != null && - this.Name.Equals(other.Name); + this.Name.Equals(other.Name) && + this.Index.Value.Equals(this.Index.Value); // FIXME Hacer que no sea nullable, sino en el CCI por ejemplo fallaria por no estar seteado } public override int GetHashCode() { - return this.Name.GetHashCode(); + return (Name.GetHashCode() * 397) ^ Index.Value.GetHashCode(); } public override string ToString() diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 42fc0bd6..e602c871 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -836,6 +836,7 @@ public MethodBody(MethodBodyKind kind) public void UpdateVariables() { + var previousLocals = LocalVariables.ToSet(); this.LocalVariables.Clear(); //this.LocalVariables.AddRange(this.Parameters); @@ -849,6 +850,7 @@ public void UpdateVariables() } locals.ExceptWith(this.Parameters); + locals.UnionWith(previousLocals); // this ensures that local variables that were declared but not used are included this.LocalVariables.AddRange(locals); } From afaad4c96f7e50ff997d4a204bb3ab3364feed35 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 1 Jul 2020 21:00:23 -0300 Subject: [PATCH 177/256] translate correctly throw and rethrow instructions --- Backend/Transformations/Assembler.cs | 55 ++++++++++++------- .../Generators/Methods/MethodGenerator.cs | 3 +- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 2327e42e..1b0c966a 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -46,7 +46,9 @@ public MethodBody Execute() if (method.Body.Instructions.Count > 0) { - new InstructionTranslator(body, method.Body).Visit(method.Body); + var instructionTranslator = new InstructionTranslator(body, method.Body); + instructionTranslator.Visit(method.Body); + instructionTranslator.AssertNoProtectedBlocks(); } body.UpdateVariables(); @@ -65,6 +67,11 @@ private class InstructionTranslator : InstructionVisitor private readonly Stack protectedBlocks = new Stack(); private readonly IDictionary ignoreInstruction = new Dictionary(); + public void AssertNoProtectedBlocks() + { + if (protectedBlocks.Count > 0) throw new Exception("Protected Blocks not generated correctly"); + } + public InstructionTranslator(MethodBody body, MethodBody bodyToProcess) { this.body = body; @@ -604,11 +611,20 @@ public override void Visit(ReturnInstruction instruction) public override void Visit(ThrowInstruction instruction) { - // FIXME rethrow se modela como ThrowInstruction, hay que generarla. Habria que ver si esta dentro de un catch creo para saber si es o no. - // FIXME admeas el offset cambia si es rethrow. - var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Throw); + Bytecode.BasicInstruction basicInstruction; + if (instruction.HasOperand) + { + basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Throw); + offset++; + } + else + { + basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Rethrow); + offset += 2; // 2byte opcode + } + + EndProtectedBlockIfApplies(); body.Instructions.Add(basicInstruction); - offset++; } public override void Visit(UnconditionalBranchInstruction instruction) @@ -624,21 +640,7 @@ public override void Visit(UnconditionalBranchInstruction instruction) // leave target -> DD (1 + 4) // leave.s target -> DE (1 + 1) offset += (uint) (IsShortForm(instruction) ? 2 : 5); - - - if (protectedBlocks.Count > 0) - { - if (protectedBlocks.Peek().AllHandlersAdded()) - { - var exceptionBlockBuilder = protectedBlocks.Pop(); - exceptionBlockBuilder - .Handlers - .Last() - .HandlerEnd = offset; - body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); - } - } - + EndProtectedBlockIfApplies(); break; } case UnconditionalBranchOperation.Branch: @@ -824,6 +826,19 @@ private bool IsShortForm(BranchInstruction instruction) return isShortForm; } + private void EndProtectedBlockIfApplies() + { + if (protectedBlocks.Count > 0 && protectedBlocks.Peek().AllHandlersAdded()) + { + var exceptionBlockBuilder = protectedBlocks.Pop(); + exceptionBlockBuilder + .Handlers + .Last() + .HandlerEnd = offset; + body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); + } + } + #region ExceptionInformation diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index b31510ad..517ee955 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -37,14 +37,13 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) if (method.HasBody) { // FIXME undo this. Just for testing assembler - var og = method.Body; + // var og = method.Body; var tac = new Backend.Transformations.Disassembler(method).Execute(); method.Body = tac; var bytecode = new Backend.Transformations.Assembler(method).Execute(); method.Body = bytecode; // method.Body = og; - // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated // programatically then the maxStack is gonna be missing var maxStack = method.Body.MaxStack; From eaeba991343a443bf8406b921aaed2edebc3a844 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 5 Jul 2020 11:19:36 -0300 Subject: [PATCH 178/256] make property non nullable --- Model/ThreeAddressCode/Operands.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Model/ThreeAddressCode/Operands.cs b/Model/ThreeAddressCode/Operands.cs index 39ab1072..00128698 100644 --- a/Model/ThreeAddressCode/Operands.cs +++ b/Model/ThreeAddressCode/Operands.cs @@ -292,9 +292,7 @@ public class LocalVariable : IVariable public string Name { get; set; } public IType Type { get; set; } public bool IsParameter { get; set; } - - // int? because int defaults to 0 if not present - public int? Index { get; set; } + public int Index { get; set; } public LocalVariable(string name, bool isParameter = false) { From 2ae6eb5e44a8565e560ac2d46b88916084330803 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 5 Jul 2020 11:22:28 -0300 Subject: [PATCH 179/256] non nullable index --- .../Generators/Methods/Body/MethodBodyGenerator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index e0b34c90..241f7f9d 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -422,7 +422,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case LoadOperation.Address: { var variable = (LocalVariable) loadInstruction.Operand; - var index = variable.Index.Value; + var index = variable.Index; if (variable.IsParameter) { instructionEncoder.LoadArgumentAddress(index); @@ -437,7 +437,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case LoadOperation.Content: { var variable = (LocalVariable) loadInstruction.Operand; - var index = variable.Index.Value; + var index = variable.Index; if (variable.IsParameter) { instructionEncoder.LoadArgument(index); @@ -615,7 +615,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } case StoreInstruction storeInstruction: { - var index = ((LocalVariable) storeInstruction.Target).Index.Value; + var index = ((LocalVariable) storeInstruction.Target).Index; if (storeInstruction.Target.IsParameter) { instructionEncoder.StoreArgument(index); From b7f07ce1e9e32e6aebaff66873aa450adee34ae7 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 5 Jul 2020 12:29:40 -0300 Subject: [PATCH 180/256] refactor --- Backend/Backend.csproj | 3 +- .../{ => Assembly}/Assembler.cs | 212 ++---------------- .../Assembly/ExceptionInformation.cs | 142 ++++++++++++ Backend/Utils/Extensions.cs | 15 -- .../Generators/Methods/MethodGenerator.cs | 5 +- Model/ThreeAddressCode/Operands.cs | 4 +- 6 files changed, 173 insertions(+), 208 deletions(-) rename Backend/Transformations/{ => Assembly}/Assembler.cs (82%) create mode 100644 Backend/Transformations/Assembly/ExceptionInformation.cs diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj index cec0f167..5dd4062d 100644 --- a/Backend/Backend.csproj +++ b/Backend/Backend.csproj @@ -62,7 +62,8 @@ - + + diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs similarity index 82% rename from Backend/Transformations/Assembler.cs rename to Backend/Transformations/Assembly/Assembler.cs index 1b0c966a..0984f2f7 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -7,6 +7,7 @@ using Model.ThreeAddressCode.Values; using Model.ThreeAddressCode.Visitor; using Model.Types; +using BranchInstruction = Model.ThreeAddressCode.Instructions.BranchInstruction; using ConvertInstruction = Model.ThreeAddressCode.Instructions.ConvertInstruction; using CreateArrayInstruction = Model.ThreeAddressCode.Instructions.CreateArrayInstruction; using CreateObjectInstruction = Model.ThreeAddressCode.Instructions.CreateObjectInstruction; @@ -18,8 +19,10 @@ 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 +namespace Backend.Transformations.Assembly { public class Assembler { @@ -40,7 +43,7 @@ public MethodBody Execute() var body = new MethodBody(MethodBodyKind.Bytecode); body.MaxStack = method.Body.MaxStack; // FIXME - body.Parameters.AddRange(method.Body.Parameters); // FIXME esto queda igual? + body.Parameters.AddRange(method.Body.Parameters); // this is updated later on. Needed to preserver variables that are declared but not used body.LocalVariables.AddRange(method.Body.LocalVariables); @@ -52,7 +55,7 @@ public MethodBody Execute() } body.UpdateVariables(); - var newLocals = body.LocalVariables.OfType().OrderBy(local => local.Index.Value).ToList(); + var newLocals = body.LocalVariables.OfType().OrderBy(local => local.Index).ToList(); body.LocalVariables.Clear(); body.LocalVariables.AddRange(newLocals); @@ -67,17 +70,17 @@ private class InstructionTranslator : InstructionVisitor private readonly Stack protectedBlocks = new Stack(); private readonly IDictionary ignoreInstruction = new Dictionary(); - public void AssertNoProtectedBlocks() - { - if (protectedBlocks.Count > 0) throw new Exception("Protected Blocks not generated correctly"); - } - public InstructionTranslator(MethodBody body, MethodBody bodyToProcess) { this.body = body; this.bodyToProcess = bodyToProcess; } + public void AssertNoProtectedBlocks() + { + if (protectedBlocks.Count > 0) throw new Exception("Protected Blocks not generated correctly"); + } + public override bool ShouldVisit(Instruction instruction) { var shouldProcessInstruction = !ignoreInstruction.TryGetValue(bodyToProcess.Instructions.IndexOf(instruction), out _); @@ -143,11 +146,11 @@ public override void Visit(LoadInstruction instruction) { // starg num -> FE 0B (2 + 2) // starg.s num -> 10 (1 + 1) - offset += (uint) (loc.Index.Value > byte.MaxValue ? 4 : 2); + offset += (uint) (loc.Index > byte.MaxValue ? 4 : 2); } else { - switch (loc.Index.Value) + switch (loc.Index) { case 0: case 1: @@ -158,7 +161,7 @@ public override void Visit(LoadInstruction instruction) default: // stloc indx -> FE 0E (2 + 2) // stloc.s indx -> 13 (1 + 1) - offset += (uint) (loc.Index.Value > byte.MaxValue ? 4 : 2); + offset += (uint) (loc.Index > byte.MaxValue ? 4 : 2); break; } } @@ -238,37 +241,10 @@ public override void Visit(LoadInstruction instruction) break; - case TemporalVariable _: - { - // FIXME hay casos sin sentido? a este no se entra nunca creo. Hay que revisar todo. - var operand = instruction.Result.ToLocalVariable(); // fixme operand como en l otro caso qie cambie? - bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, operand); - switch (operand.Index.Value) - { - // ldloc.0,1,2,3 ldarg.0,1,2,3 - case 0: - case 1: - case 2: - case 3: - offset++; - break; - default: - // ldloc indx -> FE 0C (2 + 2) - // ldloc.s indx -> 11 (1 + 1) - // ldarg num -> FE 09 (2 + 2) - // ldarg.s num -> 0E (1 + 1) - offset += (uint) (operand.Index.Value > byte.MaxValue ? 4 : 2); - break; - } - - break; - } case LocalVariable localVariable: { bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, localVariable); - // fixme igual al caso de arriba? o estoy mezclando los casos? Creo que esta bien porque local y temporal ambas pueden - // fixme ser parameter (esto determina si es ldloc o ldarg) - switch (localVariable.Index.Value) + switch (localVariable.Index) { // ldloc.0,1,2,3 ldarg.0,1,2,3 case 0: @@ -282,7 +258,7 @@ public override void Visit(LoadInstruction instruction) // ldloc.s indx -> 11 (1 + 1) // ldarg num -> FE 09 (2 + 2) // ldarg.s num -> 0E (1 + 1) - offset += (uint) (localVariable.Index.Value > byte.MaxValue ? 4 : 2); + offset += (uint) (localVariable.Index > byte.MaxValue ? 4 : 2); break; } @@ -316,6 +292,7 @@ public override void Visit(LoadInstruction instruction) (ArrayType) arrayElementAccess.Array.Type) {Method = arrayElementAccess.Method}; // ldelema typeTok -> 8F (1 + 4) + // ldobj typeTok -> 71 (1 + 4) offset += 5; break; } @@ -327,7 +304,7 @@ public override void Visit(LoadInstruction instruction) // ldloca.s indx -> 12 (1 + 1) // ldarga argNum -> FE 0A (2 + 2) // ldarga.s argNum -> 0F (1 + 1) - offset += (uint) (localVariable.Index.Value > byte.MaxValue ? 4 : 2); + offset += (uint) (localVariable.Index > byte.MaxValue ? 4 : 2); break; } case InstanceFieldAccess instanceFieldAccess: @@ -388,11 +365,11 @@ public override void Visit(LoadInstruction instruction) Bytecode.LoadArrayElementOperation.Content, type) {Method = arrayElementAccess.Method}; - if ((type.ElementsType.IsIntType() || + if (type.IsVector && + (type.ElementsType.IsIntType() || type.ElementsType.IsFloatType() || type.ElementsType.Equals(PlatformTypes.IntPtr) || - type.ElementsType.Equals(PlatformTypes.Object)) && ((ArrayType) arrayElementAccess.Array.Type).IsVector) - /// fixme cuaqluiera ese isvector? + type.ElementsType.Equals(PlatformTypes.Object))) { // 1 byte opcode offset++; @@ -422,13 +399,11 @@ public override void Visit(StoreInstruction instruction) { var type = (ArrayType) arrayElementAccess.Array.Type; storeInstruction = new Bytecode.StoreArrayElementInstruction(offset, type) {Method = arrayElementAccess.Method}; - if ( + if (type.IsVector && (type.ElementsType.IsIntType() || type.ElementsType.IsFloatType() || type.ElementsType.Equals(PlatformTypes.IntPtr) || - type.ElementsType.Equals(PlatformTypes.Object) - ) && ((ArrayType) arrayElementAccess.Array.Type).IsVector /// fixme cuaqluiera ese isvector? - ) + type.ElementsType.Equals(PlatformTypes.Object))) { // 1 byte opcode offset++; @@ -807,7 +782,6 @@ public override void Visit(PhiInstruction instruction) throw new Exception(); } - // FIXME ahora que calculo a mano los offsets, se puede sacar esta instruccion y ver bien cuando ponerla en el virtual call? public override void Visit(ConstrainedInstruction instruction) { body.Instructions.Add(new Bytecode.ConstrainedInstruction(offset, instruction.ThisType)); @@ -816,6 +790,7 @@ public override void Visit(ConstrainedInstruction instruction) } + // FIXME: duplicate with method body generator private bool IsShortForm(BranchInstruction instruction) { var nextInstructionOffset = @@ -838,145 +813,6 @@ private void EndProtectedBlockIfApplies() body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); } } - - - #region ExceptionInformation - - private class ProtectedBlockBuilder - { - private uint? tryStart; - - public uint TryStart - { - get => tryStart ?? throw new Exception("TryStart was not set"); - set - { - if (tryStart != null) throw new Exception("TryStart was already set"); - tryStart = value; - } - } - - private uint? tryEnd; - - private uint 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 EndPreviousRegion(uint offset) => EndPreviousRegion(offset, () => true); - - public ProtectedBlockBuilder EndPreviousRegion(uint offset, Func multipleHandlerCondition) - { - if (Handlers.Count == 0) // first handler, ends try region - { - TryEnd = offset; - } - else if (multipleHandlerCondition()) // multiple handlers. End previous handler conditionally - { - Handlers.Last().HandlerEnd = offset; - } - - return this; - } - - public IList Build() => - Handlers - .Select(handlerBuilder => handlerBuilder.Build()) - .Select(handler => new ProtectedBlock(TryStart, TryEnd) {Handler = handler}) - .ToList(); - } - - private class ExceptionHandlerBlockBuilder - { - private uint? filterStart; - - public uint FilterStart - { - get => filterStart ?? throw new Exception("FilterStart was not set"); - set - { - if (filterStart != null) throw new Exception("FilterStart was already set"); - filterStart = value; - } - } - - private uint? handlerStart; - - public uint HandlerStart - { - get => handlerStart ?? throw new Exception("HandlerStart was not set"); - set - { - if (handlerStart != null) throw new Exception("HandlerStart was already set"); - handlerStart = value; - } - } - - private uint? handlerEnd; - - public uint 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); - } - } - } - - #endregion } } } \ No newline at end of file diff --git a/Backend/Transformations/Assembly/ExceptionInformation.cs b/Backend/Transformations/Assembly/ExceptionInformation.cs new file mode 100644 index 00000000..f2132ae9 --- /dev/null +++ b/Backend/Transformations/Assembly/ExceptionInformation.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Model; +using Model.Types; + +namespace Backend.Transformations.Assembly +{ + internal class ProtectedBlockBuilder + { + private uint? tryStart; + + public uint TryStart + { + get => tryStart ?? throw new Exception("TryStart was not set"); + set + { + if (tryStart != null) throw new Exception("TryStart was already set"); + tryStart = value; + } + } + + private uint? tryEnd; + + private uint 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 EndPreviousRegion(uint offset) => EndPreviousRegion(offset, () => true); + + public ProtectedBlockBuilder EndPreviousRegion(uint offset, Func multipleHandlerCondition) + { + if (Handlers.Count == 0) // first handler, ends try region + { + TryEnd = offset; + } + else if (multipleHandlerCondition()) // multiple handlers. End previous handler conditionally + { + Handlers.Last().HandlerEnd = offset; + } + + return this; + } + + public IList Build() => + Handlers + .Select(handlerBuilder => handlerBuilder.Build()) + .Select(handler => new ProtectedBlock(TryStart, TryEnd) {Handler = handler}) + .ToList(); + } + + internal class ExceptionHandlerBlockBuilder + { + private uint? filterStart; + + public uint FilterStart + { + get => filterStart ?? throw new Exception("FilterStart was not set"); + set + { + if (filterStart != null) throw new Exception("FilterStart was already set"); + filterStart = value; + } + } + + private uint? handlerStart; + + public uint HandlerStart + { + get => handlerStart ?? throw new Exception("HandlerStart was not set"); + set + { + if (handlerStart != null) throw new Exception("HandlerStart was already set"); + handlerStart = value; + } + } + + private uint? handlerEnd; + + public uint 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/Utils/Extensions.cs b/Backend/Utils/Extensions.cs index 0b36ed5b..8fb6bfbd 100644 --- a/Backend/Utils/Extensions.cs +++ b/Backend/Utils/Extensions.cs @@ -1017,20 +1017,5 @@ from node in escInfo.EscapingNodes } public static TemporalVariable MakeCopy(this TemporalVariable temporalVariable, IType type) => new TemporalVariable(temporalVariable.Prefix, temporalVariable.Index) { Type = type }; - - public static LocalVariable ToLocalVariable(this IVariable variable) - { - switch (variable) - { - case TemporalVariable temporalVariable: - return new LocalVariable(temporalVariable.Name, temporalVariable.IsParameter) - { - Type = temporalVariable.Type, - Index = (int?) temporalVariable.Index - }; - case LocalVariable localVariable: return localVariable; - default: throw new NotImplementedException(); - } - } } } diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 517ee955..337305c9 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -1,4 +1,5 @@ -using MetadataGenerator.Generators.Methods.Body; +using Backend.Transformations.Assembly; +using MetadataGenerator.Generators.Methods.Body; using MetadataGenerator.Metadata; using Model.Types; using static MetadataGenerator.Metadata.AttributesProvider; @@ -40,7 +41,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) // var og = method.Body; var tac = new Backend.Transformations.Disassembler(method).Execute(); method.Body = tac; - var bytecode = new Backend.Transformations.Assembler(method).Execute(); + var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); method.Body = bytecode; // method.Body = og; diff --git a/Model/ThreeAddressCode/Operands.cs b/Model/ThreeAddressCode/Operands.cs index 9c9a7cea..d28b5295 100644 --- a/Model/ThreeAddressCode/Operands.cs +++ b/Model/ThreeAddressCode/Operands.cs @@ -327,12 +327,12 @@ public override bool Equals(object obj) return other != null && this.Name.Equals(other.Name) && - this.Index.Value.Equals(this.Index.Value); // FIXME Hacer que no sea nullable, sino en el CCI por ejemplo fallaria por no estar seteado + this.Index.Equals(this.Index); } public override int GetHashCode() { - return (Name.GetHashCode() * 397) ^ Index.Value.GetHashCode(); + return (Name.GetHashCode() * 397) ^ Index.GetHashCode(); } public override string ToString() From 9ba2d9dd33ad58b593c9d7a672af2972dc7d55ba Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 5 Jul 2020 14:00:17 -0300 Subject: [PATCH 181/256] renames and relocation --- Backend/Transformations/Assembly/Assembler.cs | 147 +++++++++--------- .../Assembly/ExceptionInformation.cs | 8 +- 2 files changed, 79 insertions(+), 76 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 0984f2f7..a2b3214c 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -44,6 +44,7 @@ public MethodBody Execute() body.MaxStack = method.Body.MaxStack; // FIXME body.Parameters.AddRange(method.Body.Parameters); + // this is updated later on. Needed to preserver variables that are declared but not used body.LocalVariables.AddRange(method.Body.LocalVariables); @@ -76,11 +77,6 @@ public InstructionTranslator(MethodBody body, MethodBody bodyToProcess) this.bodyToProcess = bodyToProcess; } - public void AssertNoProtectedBlocks() - { - if (protectedBlocks.Count > 0) throw new Exception("Protected Blocks not generated correctly"); - } - public override bool ShouldVisit(Instruction instruction) { var shouldProcessInstruction = !ignoreInstruction.TryGetValue(bodyToProcess.Instructions.IndexOf(instruction), out _); @@ -89,8 +85,9 @@ public override bool ShouldVisit(Instruction instruction) public override void Visit(PopInstruction instruction) { - body.Instructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Pop)); - offset++; + var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Pop); + body.Instructions.Add(basicInstruction); + offset++; // 1 Byte OpCode } public override void Visit(BinaryInstruction instruction) @@ -106,10 +103,10 @@ public override void Visit(BinaryInstruction instruction) case Bytecode.BasicOperation.Gt: case Bytecode.BasicOperation.Lt: case Bytecode.BasicOperation.Eq: - offset += 2; // 2ByteOpcode + offset += 2; // 2 Byte OpCode break; default: - offset++; + offset++; // 1 Byte OpCode break; } } @@ -118,12 +115,12 @@ public override void Visit(UnaryInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, OperationHelper.ToBasicOperation(instruction.Operation)); body.Instructions.Add(basicInstruction); - offset++; + offset++; // 1 Byte OpCode } + // FIXME revisar los casos, hay algunos que no estoy seguro de que esten bien. se repiten caminos ademas (sobretodo por el reference) public override void Visit(LoadInstruction instruction) { - // FIXME revisar los casos, hay algunos que no estoy seguro de que esten bien. se repiten caminos ademas (sobretodo por el reference) Bytecode.Instruction bytecodeInstruction; if (instruction.Operand is TemporalVariable && instruction.Result is TemporalVariable) { @@ -390,6 +387,7 @@ public override void Visit(LoadInstruction instruction) body.Instructions.Add(bytecodeInstruction); } + // FIXME revisar public override void Visit(StoreInstruction instruction) { Bytecode.Instruction storeInstruction; @@ -454,28 +452,29 @@ public override void Visit(NopInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Nop); body.Instructions.Add(basicInstruction); - offset++; + offset++; // 1 Byte OpCode } public override void Visit(BreakpointInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Breakpoint); body.Instructions.Add(basicInstruction); - offset++; + offset++; // 1 Byte OpCode } public override void Visit(TryInstruction instruction) { - // try with multiple handlers are modelled as multiple try instructions with the same label but different handlers. + // try with multiple handlers is modelled as multiple try instructions with the same label but different handlers. // if label matches with the current try, then increase the number of expected handlers + // if not, it is a new try block if (protectedBlocks.Count > 0 && protectedBlocks.Peek().TryStart.Equals(offset)) { protectedBlocks.Peek().HandlerCount++; } else { - var exceptionBlockBuilder = new ProtectedBlockBuilder {TryStart = offset, HandlerCount = 1}; - protectedBlocks.Push(exceptionBlockBuilder); + var protectedBlockBuilder = new ProtectedBlockBuilder {TryStart = offset, HandlerCount = 1}; + protectedBlocks.Push(protectedBlockBuilder); } } @@ -483,8 +482,8 @@ public override void Visit(FaultInstruction instruction) { protectedBlocks .Peek() - .EndPreviousRegion(offset) - .Handlers.Add(new ExceptionHandlerBlockBuilder + .EndPreviousRegionWith(offset) + .Handlers.Add(new ProtectedBlockHandlerBuilder { HandlerStart = offset, HandlerBlockKind = ExceptionHandlerBlockKind.Fault, @@ -495,35 +494,33 @@ public override void Visit(FinallyInstruction instruction) { protectedBlocks .Peek() - .EndPreviousRegion(offset) - .Handlers.Add( - new ExceptionHandlerBlockBuilder - { - HandlerStart = offset, - HandlerBlockKind = ExceptionHandlerBlockKind.Finally, - }); + .EndPreviousRegionWith(offset) + .Handlers.Add(new ProtectedBlockHandlerBuilder + { + HandlerStart = offset, + HandlerBlockKind = ExceptionHandlerBlockKind.Finally, + }); } public override void Visit(FilterInstruction instruction) { var protectedBlockBuilder = protectedBlocks.Peek(); - // filter is a special case since it has a two regions (filter and handler). A filter in this TAC is moddeled as two FilterInstruction - // with different kinds. If the previous region is a Filter, it must be ended only if it is in it's handler part. + // 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. bool EndPreviousHandlerCondition() => protectedBlockBuilder.Handlers.Last().HandlerBlockKind != ExceptionHandlerBlockKind.Filter || instruction.kind == FilterInstructionKind.FilterSection; - protectedBlockBuilder.EndPreviousRegion(offset, EndPreviousHandlerCondition); + protectedBlockBuilder.EndPreviousRegionWith(offset, EndPreviousHandlerCondition); switch (instruction.kind) { case FilterInstructionKind.FilterSection: - protectedBlockBuilder.Handlers.Add( - new ExceptionHandlerBlockBuilder - { - FilterStart = offset, - HandlerBlockKind = ExceptionHandlerBlockKind.Filter, - }); + protectedBlockBuilder.Handlers.Add(new ProtectedBlockHandlerBuilder + { + FilterStart = offset, + HandlerBlockKind = ExceptionHandlerBlockKind.Filter, + }); break; case FilterInstructionKind.FilterHandler: var handler = protectedBlockBuilder.Handlers.Last(); @@ -538,10 +535,10 @@ public override void Visit(CatchInstruction instruction) { protectedBlocks .Peek() - .EndPreviousRegion(offset) + .EndPreviousRegionWith(offset) .Handlers .Add( - new ExceptionHandlerBlockBuilder() + new ProtectedBlockHandlerBuilder { HandlerStart = offset, HandlerBlockKind = ExceptionHandlerBlockKind.Catch, @@ -550,58 +547,25 @@ public override void Visit(CatchInstruction instruction) ); } - public override void Visit(ConvertInstruction instruction) - { - var convertInstruction = new Bytecode.ConvertInstruction( - offset, - OperationHelper.ToConvertOperation(instruction.Operation), - instruction.ConversionType) - { - OverflowCheck = instruction.OverflowCheck, - UnsignedOperands = instruction.UnsignedOperands, - }; - body.Instructions.Add(convertInstruction); - switch (convertInstruction.Operation) - { - case Bytecode.ConvertOperation.Conv: - offset++; - break; - default: - // box typeTok -> 8C (1 + 4) - // castclass typeTok -> 74 (1 + 4) - // isinst typeTok -> 75 (1 + 4) - // unbox valuetype -> 79 (1 + 4) - // unbox.any typeTok -> A5 (1 + 4) - offset += 5; - break; - } - } - - public override void Visit(ReturnInstruction instruction) - { - var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Return); - body.Instructions.Add(basicInstruction); - offset++; - } - public override void Visit(ThrowInstruction instruction) { Bytecode.BasicInstruction basicInstruction; if (instruction.HasOperand) { basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Throw); - offset++; + offset++; // 1 Byte OpCode } else { basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Rethrow); - offset += 2; // 2byte opcode + offset += 2; // 2 Byte OpCode } EndProtectedBlockIfApplies(); body.Instructions.Add(basicInstruction); } + // fixme revisar de aca en adelante public override void Visit(UnconditionalBranchInstruction instruction) { switch (instruction.Operation) @@ -654,6 +618,40 @@ public override void Visit(UnconditionalBranchInstruction instruction) } } + public override void Visit(ConvertInstruction instruction) + { + var convertInstruction = new Bytecode.ConvertInstruction( + offset, + OperationHelper.ToConvertOperation(instruction.Operation), + instruction.ConversionType) + { + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands, + }; + body.Instructions.Add(convertInstruction); + switch (convertInstruction.Operation) + { + case Bytecode.ConvertOperation.Conv: + offset++; + break; + default: + // box typeTok -> 8C (1 + 4) + // castclass typeTok -> 74 (1 + 4) + // isinst typeTok -> 75 (1 + 4) + // unbox valuetype -> 79 (1 + 4) + // unbox.any typeTok -> A5 (1 + 4) + offset += 5; + break; + } + } + + public override void Visit(ReturnInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Return); + body.Instructions.Add(basicInstruction); + offset++; + } + public override void Visit(ConditionalBranchInstruction instruction) { var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); @@ -813,6 +811,11 @@ private void EndProtectedBlockIfApplies() body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); } } + + public void AssertNoProtectedBlocks() + { + if (protectedBlocks.Count > 0) throw new Exception("Protected Blocks not generated correctly"); + } } } } \ No newline at end of file diff --git a/Backend/Transformations/Assembly/ExceptionInformation.cs b/Backend/Transformations/Assembly/ExceptionInformation.cs index f2132ae9..32ad3f36 100644 --- a/Backend/Transformations/Assembly/ExceptionInformation.cs +++ b/Backend/Transformations/Assembly/ExceptionInformation.cs @@ -36,11 +36,11 @@ private uint TryEnd public bool AllHandlersAdded() => HandlerCount == Handlers.Count; - public readonly IList Handlers = new List(); + public readonly IList Handlers = new List(); - public ProtectedBlockBuilder EndPreviousRegion(uint offset) => EndPreviousRegion(offset, () => true); + public ProtectedBlockBuilder EndPreviousRegionWith(uint offset) => EndPreviousRegionWith(offset, () => true); - public ProtectedBlockBuilder EndPreviousRegion(uint offset, Func multipleHandlerCondition) + public ProtectedBlockBuilder EndPreviousRegionWith(uint offset, Func multipleHandlerCondition) { if (Handlers.Count == 0) // first handler, ends try region { @@ -61,7 +61,7 @@ public IList Build() => .ToList(); } - internal class ExceptionHandlerBlockBuilder + internal class ProtectedBlockHandlerBuilder { private uint? filterStart; From c6a9a0f34cf40eb50d1b8344118c11872f9e3f68 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 6 Jul 2020 08:17:37 -0300 Subject: [PATCH 182/256] refactor exception information --- Backend/Transformations/Assembly/Assembler.cs | 168 ++++-------- .../Assembly/ExceptionInformation.cs | 257 ++++++++++++------ 2 files changed, 219 insertions(+), 206 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index a2b3214c..02bd9bb2 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -50,9 +50,11 @@ public MethodBody Execute() if (method.Body.Instructions.Count > 0) { - var instructionTranslator = new InstructionTranslator(body, method.Body); + var instructionTranslator = new InstructionTranslator(method.Body); instructionTranslator.Visit(method.Body); - instructionTranslator.AssertNoProtectedBlocks(); + + body.ExceptionInformation.AddRange(instructionTranslator.exceptionInformationBuilder.Build()); + body.Instructions.AddRange(instructionTranslator.translatedInstructions); } body.UpdateVariables(); @@ -65,15 +67,15 @@ public MethodBody Execute() private class InstructionTranslator : InstructionVisitor { - private readonly MethodBody body; + public readonly IList translatedInstructions = new List(); + public readonly ExceptionInformationBuilder exceptionInformationBuilder = new ExceptionInformationBuilder(); + private readonly MethodBody bodyToProcess; private uint offset; - private readonly Stack protectedBlocks = new Stack(); private readonly IDictionary ignoreInstruction = new Dictionary(); - public InstructionTranslator(MethodBody body, MethodBody bodyToProcess) + public InstructionTranslator(MethodBody bodyToProcess) { - this.body = body; this.bodyToProcess = bodyToProcess; } @@ -86,7 +88,7 @@ public override bool ShouldVisit(Instruction instruction) public override void Visit(PopInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Pop); - body.Instructions.Add(basicInstruction); + translatedInstructions.Add(basicInstruction); offset++; // 1 Byte OpCode } @@ -97,7 +99,7 @@ public override void Visit(BinaryInstruction instruction) OverflowCheck = instruction.OverflowCheck, UnsignedOperands = instruction.UnsignedOperands }; - body.Instructions.Add(basicInstruction); + translatedInstructions.Add(basicInstruction); switch (basicInstruction.Operation) { case Bytecode.BasicOperation.Gt: @@ -114,7 +116,7 @@ public override void Visit(BinaryInstruction instruction) public override void Visit(UnaryInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, OperationHelper.ToBasicOperation(instruction.Operation)); - body.Instructions.Add(basicInstruction); + translatedInstructions.Add(basicInstruction); offset++; // 1 Byte OpCode } @@ -384,7 +386,7 @@ public override void Visit(LoadInstruction instruction) } } - body.Instructions.Add(bytecodeInstruction); + translatedInstructions.Add(bytecodeInstruction); } // FIXME revisar @@ -445,106 +447,55 @@ public override void Visit(StoreInstruction instruction) throw new Exception(); // TODO msg } - body.Instructions.Add(storeInstruction); + translatedInstructions.Add(storeInstruction); } public override void Visit(NopInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Nop); - body.Instructions.Add(basicInstruction); + translatedInstructions.Add(basicInstruction); offset++; // 1 Byte OpCode } public override void Visit(BreakpointInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Breakpoint); - body.Instructions.Add(basicInstruction); + translatedInstructions.Add(basicInstruction); offset++; // 1 Byte OpCode } public override void Visit(TryInstruction instruction) { // try with multiple handlers is modelled as multiple try instructions with the same label but different handlers. - // if label matches with the current try, then increase the number of expected handlers - // if not, it is a new try block - if (protectedBlocks.Count > 0 && protectedBlocks.Peek().TryStart.Equals(offset)) + // if label matches with the current try, then increase the number of expected handlers. If not, begin a new try block + if (exceptionInformationBuilder.CurrentProtectedBlockStartsAt(offset)) { - protectedBlocks.Peek().HandlerCount++; + exceptionInformationBuilder.IncrementCurrentProtectedBlockExpectedHandlers(); } else { - var protectedBlockBuilder = new ProtectedBlockBuilder {TryStart = offset, HandlerCount = 1}; - protectedBlocks.Push(protectedBlockBuilder); + exceptionInformationBuilder.BeginProtectedBlockAt(offset); } } public override void Visit(FaultInstruction instruction) { - protectedBlocks - .Peek() - .EndPreviousRegionWith(offset) - .Handlers.Add(new ProtectedBlockHandlerBuilder - { - HandlerStart = offset, - HandlerBlockKind = ExceptionHandlerBlockKind.Fault, - }); + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(offset, ExceptionHandlerBlockKind.Fault); } public override void Visit(FinallyInstruction instruction) { - protectedBlocks - .Peek() - .EndPreviousRegionWith(offset) - .Handlers.Add(new ProtectedBlockHandlerBuilder - { - HandlerStart = offset, - HandlerBlockKind = ExceptionHandlerBlockKind.Finally, - }); + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(offset, ExceptionHandlerBlockKind.Finally); } public override void Visit(FilterInstruction instruction) { - var protectedBlockBuilder = protectedBlocks.Peek(); - - // 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. - bool EndPreviousHandlerCondition() => protectedBlockBuilder.Handlers.Last().HandlerBlockKind != ExceptionHandlerBlockKind.Filter || - instruction.kind == FilterInstructionKind.FilterSection; - - protectedBlockBuilder.EndPreviousRegionWith(offset, EndPreviousHandlerCondition); - - switch (instruction.kind) - { - case FilterInstructionKind.FilterSection: - protectedBlockBuilder.Handlers.Add(new ProtectedBlockHandlerBuilder - { - FilterStart = offset, - HandlerBlockKind = ExceptionHandlerBlockKind.Filter, - }); - break; - case FilterInstructionKind.FilterHandler: - var handler = protectedBlockBuilder.Handlers.Last(); - handler.HandlerStart = offset; - handler.ExceptionType = instruction.ExceptionType; - break; - default: throw instruction.kind.ToUnknownValueException(); - } + exceptionInformationBuilder.AddFilterHandlerToCurrentProtectedBlock(offset, instruction.kind, instruction.ExceptionType); } public override void Visit(CatchInstruction instruction) { - protectedBlocks - .Peek() - .EndPreviousRegionWith(offset) - .Handlers - .Add( - new ProtectedBlockHandlerBuilder - { - HandlerStart = offset, - HandlerBlockKind = ExceptionHandlerBlockKind.Catch, - ExceptionType = instruction.ExceptionType - } - ); + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(offset, ExceptionHandlerBlockKind.Catch, instruction.ExceptionType); } public override void Visit(ThrowInstruction instruction) @@ -561,8 +512,8 @@ public override void Visit(ThrowInstruction instruction) offset += 2; // 2 Byte OpCode } - EndProtectedBlockIfApplies(); - body.Instructions.Add(basicInstruction); + exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(offset); + translatedInstructions.Add(basicInstruction); } // fixme revisar de aca en adelante @@ -574,12 +525,12 @@ public override void Visit(UnconditionalBranchInstruction instruction) { var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); var unconditionalBranchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Leave, target); + translatedInstructions.Add(unconditionalBranchInstruction); - body.Instructions.Add(unconditionalBranchInstruction); // leave target -> DD (1 + 4) // leave.s target -> DE (1 + 1) offset += (uint) (IsShortForm(instruction) ? 2 : 5); - EndProtectedBlockIfApplies(); + exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(offset); break; } case UnconditionalBranchOperation.Branch: @@ -589,7 +540,7 @@ public override void Visit(UnconditionalBranchInstruction instruction) offset, Bytecode.BranchOperation.Branch, target); - body.Instructions.Add(unconditionalBranchInstruction); + translatedInstructions.Add(unconditionalBranchInstruction); // leave target -> 38 (1 + 4) // leave.s target -> 2B (1 + 1) offset += (uint) (IsShortForm(instruction) ? 2 : 5); @@ -597,20 +548,15 @@ public override void Visit(UnconditionalBranchInstruction instruction) } case UnconditionalBranchOperation.EndFinally: { - body.Instructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFinally)); + translatedInstructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFinally)); offset++; - var exceptionBlockBuilder = protectedBlocks.Pop(); // no more handlers after finally - exceptionBlockBuilder - .Handlers - .Last() - .HandlerEnd = offset; - body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); + exceptionInformationBuilder.EndCurrentProtectedBlockAt(offset); // no more handlers after finally break; } case UnconditionalBranchOperation.EndFilter: { - // nothing is done with protectedBlocks since filter area is the gap between try end and handler start - body.Instructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFilter)); + // nothing is done with exceptionInformation since filter area is the gap between try end and handler start + translatedInstructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFilter)); offset += 2; // 2byte opcode break; } @@ -628,7 +574,7 @@ public override void Visit(ConvertInstruction instruction) OverflowCheck = instruction.OverflowCheck, UnsignedOperands = instruction.UnsignedOperands, }; - body.Instructions.Add(convertInstruction); + translatedInstructions.Add(convertInstruction); switch (convertInstruction.Operation) { case Bytecode.ConvertOperation.Conv: @@ -648,7 +594,7 @@ public override void Visit(ConvertInstruction instruction) public override void Visit(ReturnInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Return); - body.Instructions.Add(basicInstruction); + translatedInstructions.Add(basicInstruction); offset++; } @@ -659,7 +605,7 @@ public override void Visit(ConditionalBranchInstruction instruction) offset, OperationHelper.ToBranchOperation(instruction.Operation, instruction.RightOperand), target); - body.Instructions.Add(conditionalBranchInstruction); + translatedInstructions.Add(conditionalBranchInstruction); // br* target -> 1ByteOpcode (1 + 4) // br*.s target -> 1ByteOpcode (1 + 1) offset += (uint) (IsShortForm(instruction) ? 2 : 5); @@ -669,7 +615,7 @@ public override void Visit(SwitchInstruction instruction) { var targets = instruction.Targets.Select(target => Convert.ToUInt32(target.Substring(2), 16)).ToList(); var switchInstruction = new Bytecode.SwitchInstruction(offset, targets); - body.Instructions.Add(switchInstruction); + translatedInstructions.Add(switchInstruction); // switch number t1 t2 t3 ... -> 45 .... (1 + 4 + n*4) offset += (uint) (1 + 4 + 4 * targets.Count); } @@ -677,7 +623,7 @@ public override void Visit(SwitchInstruction instruction) public override void Visit(SizeofInstruction instruction) { var sizeofInstruction = new Bytecode.SizeofInstruction(offset, instruction.MeasuredType); - body.Instructions.Add(sizeofInstruction); + translatedInstructions.Add(sizeofInstruction); // sizeof typetok -> FE 1C (2 + 4) offset += 6; } @@ -685,7 +631,7 @@ public override void Visit(SizeofInstruction instruction) public override void Visit(LoadTokenInstruction instruction) { var loadTokenInstruction = new Bytecode.LoadTokenInstruction(offset, instruction.Token); - body.Instructions.Add(loadTokenInstruction); + translatedInstructions.Add(loadTokenInstruction); // ldtoken token -> D0 (1 + 4) offset += 5; } @@ -697,7 +643,7 @@ public override void Visit(MethodCallInstruction instruction) OperationHelper.ToMethodCallOperation(instruction.Operation), instruction.Method ); - body.Instructions.Add(methodCallInstruction); + translatedInstructions.Add(methodCallInstruction); // call method -> 28 (1 + 4) // callvirt method -> 6F (1 + 4) offset += 5; @@ -706,7 +652,7 @@ public override void Visit(MethodCallInstruction instruction) public override void Visit(IndirectMethodCallInstruction instruction) { var indirectMethodCallInstruction = new Bytecode.IndirectMethodCallInstruction(offset, instruction.Function); - body.Instructions.Add(indirectMethodCallInstruction); + translatedInstructions.Add(indirectMethodCallInstruction); // calli callsitedescr -> 29 (1 + 4) offset += 5; } @@ -719,7 +665,7 @@ public override void Visit(CreateObjectInstruction instruction) ignoreInstruction.Add(index + 2, true); // load var createObjectInstruction = new Bytecode.CreateObjectInstruction(offset, methodCallInstruction.Method); - body.Instructions.Add(createObjectInstruction); + translatedInstructions.Add(createObjectInstruction); // newobj ctor -> 73 (1 + 4) offset += 5; } @@ -727,28 +673,28 @@ public override void Visit(CreateObjectInstruction instruction) public override void Visit(CopyMemoryInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.CopyBlock); - body.Instructions.Add(basicInstruction); + translatedInstructions.Add(basicInstruction); offset += 2; // 2ByteOpcode } public override void Visit(LocalAllocationInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.LocalAllocation); - body.Instructions.Add(basicInstruction); + translatedInstructions.Add(basicInstruction); offset += 2; // 2ByteOpcode } public override void Visit(InitializeMemoryInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.InitBlock); - body.Instructions.Add(basicInstruction); + translatedInstructions.Add(basicInstruction); offset += 2; // 2ByteOpcode } public override void Visit(InitializeObjectInstruction instruction) { var initObjInstruction = new Bytecode.InitObjInstruction(offset, instruction.TargetAddress.Type); - body.Instructions.Add(initObjInstruction); + translatedInstructions.Add(initObjInstruction); // initobj typeTok -> FE 15 (2 + 4) offset += 6; } @@ -756,7 +702,7 @@ public override void Visit(InitializeObjectInstruction instruction) public override void Visit(CopyObjectInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.CopyObject); - body.Instructions.Add(basicInstruction); + translatedInstructions.Add(basicInstruction); // cpobj typeTok-> 70 (1 + 4) offset += 5; } @@ -769,7 +715,7 @@ public override void Visit(CreateArrayInstruction instruction) WithLowerBound = instruction.LowerBounds.Any(), Constructor = instruction.Constructor }; - body.Instructions.Add(createArrayInstruction); + translatedInstructions.Add(createArrayInstruction); // newobj ctor -> 73 (1 + 4) // newarr etype -> 8D (1 + 4) offset += 5; @@ -782,7 +728,7 @@ public override void Visit(PhiInstruction instruction) public override void Visit(ConstrainedInstruction instruction) { - body.Instructions.Add(new Bytecode.ConstrainedInstruction(offset, instruction.ThisType)); + translatedInstructions.Add(new Bytecode.ConstrainedInstruction(offset, instruction.ThisType)); // constrained. thisType -> FE 16 (2 + 4) offset += 6; } @@ -798,24 +744,6 @@ private bool IsShortForm(BranchInstruction instruction) var isShortForm = nextInstructionOffset - currentInstructionOffset == 2; return isShortForm; } - - private void EndProtectedBlockIfApplies() - { - if (protectedBlocks.Count > 0 && protectedBlocks.Peek().AllHandlersAdded()) - { - var exceptionBlockBuilder = protectedBlocks.Pop(); - exceptionBlockBuilder - .Handlers - .Last() - .HandlerEnd = offset; - body.ExceptionInformation.AddRange(exceptionBlockBuilder.Build()); - } - } - - public void AssertNoProtectedBlocks() - { - if (protectedBlocks.Count > 0) throw new Exception("Protected Blocks not generated correctly"); - } } } } \ No newline at end of file diff --git a/Backend/Transformations/Assembly/ExceptionInformation.cs b/Backend/Transformations/Assembly/ExceptionInformation.cs index 32ad3f36..2b7dd3b5 100644 --- a/Backend/Transformations/Assembly/ExceptionInformation.cs +++ b/Backend/Transformations/Assembly/ExceptionInformation.cs @@ -2,140 +2,225 @@ using System.Collections.Generic; using System.Linq; using Model; +using Model.ThreeAddressCode.Instructions; using Model.Types; namespace Backend.Transformations.Assembly { - internal class ProtectedBlockBuilder + internal class ExceptionInformationBuilder { - private uint? tryStart; + private readonly Stack protectedBlocks = new Stack(); + private readonly IList result = new List(); - public uint TryStart + public IList Build() { - get => tryStart ?? throw new Exception("TryStart was not set"); - set - { - if (tryStart != null) throw new Exception("TryStart was already set"); - tryStart = value; - } + if (protectedBlocks.Count > 0) throw new Exception("Protected Blocks not generated correctly"); + return result; } - private uint? tryEnd; + public void BeginProtectedBlockAt(uint offset) + { + var protectedBlockBuilder = new ProtectedBlockBuilder {TryStart = offset, HandlerCount = 1}; + protectedBlocks.Push(protectedBlockBuilder); + } - private uint TryEnd + public bool CurrentProtectedBlockStartsAt(uint offset) => protectedBlocks.Count > 0 && protectedBlocks.Peek().TryStart.Equals(offset); + public void IncrementCurrentProtectedBlockExpectedHandlers() => protectedBlocks.Peek().HandlerCount++; + + public void AddHandlerToCurrentProtectedBlock(uint offset, ExceptionHandlerBlockKind handlerBlockKind, IType exceptionType) => + protectedBlocks + .Peek() + .EndPreviousRegionAt(offset) + .Handlers.Add(new ProtectedBlockHandlerBuilder + { + HandlerStart = offset, + HandlerBlockKind = handlerBlockKind, + ExceptionType = exceptionType + }); + + public void AddHandlerToCurrentProtectedBlock(uint offset, ExceptionHandlerBlockKind handlerBlockKind) => + AddHandlerToCurrentProtectedBlock(offset, 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(uint offset, FilterInstructionKind kind, IType exceptionType) { - get => tryEnd ?? throw new Exception("TryEnd was not set"); - set + var protectedBlockBuilder = protectedBlocks.Peek(); + + bool EndPreviousHandlerCondition() => protectedBlockBuilder.Handlers.Last().HandlerBlockKind != ExceptionHandlerBlockKind.Filter || + kind == FilterInstructionKind.FilterSection; + + protectedBlockBuilder.EndPreviousRegionAt(offset, EndPreviousHandlerCondition); + + switch (kind) { - if (tryEnd != null) throw new Exception("TryEnd was already set"); - tryEnd = value; + case FilterInstructionKind.FilterSection: + protectedBlockBuilder.Handlers.Add(new ProtectedBlockHandlerBuilder + { + FilterStart = offset, + HandlerBlockKind = ExceptionHandlerBlockKind.Filter + }); + break; + case FilterInstructionKind.FilterHandler: + var handler = protectedBlockBuilder.Handlers.Last(); + handler.HandlerStart = offset; + handler.ExceptionType = exceptionType; + break; + default: throw kind.ToUnknownValueException(); } } - public uint HandlerCount { get; set; } - - public bool AllHandlersAdded() => HandlerCount == Handlers.Count; + public void EndCurrentProtectedBlockIfAppliesAt(uint offset) + { + if (protectedBlocks.Count > 0 && protectedBlocks.Peek().AllHandlersAdded()) + { + EndCurrentProtectedBlockAt(offset); + } + } - public readonly IList Handlers = new List(); + public void EndCurrentProtectedBlockAt(uint offset) + { + var exceptionBlockBuilder = protectedBlocks.Pop(); + exceptionBlockBuilder + .Handlers + .Last() + .HandlerEnd = offset; + result.AddRange(exceptionBlockBuilder.Build()); + } - public ProtectedBlockBuilder EndPreviousRegionWith(uint offset) => EndPreviousRegionWith(offset, () => true); - public ProtectedBlockBuilder EndPreviousRegionWith(uint offset, Func multipleHandlerCondition) + private class ProtectedBlockBuilder { - if (Handlers.Count == 0) // first handler, ends try region + private uint? tryStart; + + public uint TryStart { - TryEnd = offset; + get => tryStart ?? throw new Exception("TryStart was not set"); + set + { + if (tryStart != null) throw new Exception("TryStart was already set"); + tryStart = value; + } } - else if (multipleHandlerCondition()) // multiple handlers. End previous handler conditionally + + private uint? tryEnd; + + private uint TryEnd { - Handlers.Last().HandlerEnd = offset; + get => tryEnd ?? throw new Exception("TryEnd was not set"); + set + { + if (tryEnd != null) throw new Exception("TryEnd was already set"); + tryEnd = value; + } } - return this; - } + public uint HandlerCount { get; set; } - public IList Build() => - Handlers - .Select(handlerBuilder => handlerBuilder.Build()) - .Select(handler => new ProtectedBlock(TryStart, TryEnd) {Handler = handler}) - .ToList(); - } + public bool AllHandlersAdded() => HandlerCount == Handlers.Count; - internal class ProtectedBlockHandlerBuilder - { - private uint? filterStart; + public readonly IList Handlers = new List(); - public uint FilterStart - { - get => filterStart ?? throw new Exception("FilterStart was not set"); - set + public ProtectedBlockBuilder EndPreviousRegionAt(uint offset) => EndPreviousRegionAt(offset, () => true); + + public ProtectedBlockBuilder EndPreviousRegionAt(uint offset, Func multipleHandlerCondition) { - if (filterStart != null) throw new Exception("FilterStart was already set"); - filterStart = value; + if (Handlers.Count == 0) // first handler, ends try region + { + TryEnd = offset; + } + else if (multipleHandlerCondition()) // multiple handlers. End previous handler conditionally + { + Handlers.Last().HandlerEnd = offset; + } + + return this; } - } - private uint? handlerStart; + // 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(); + } - public uint HandlerStart + private class ProtectedBlockHandlerBuilder { - get => handlerStart ?? throw new Exception("HandlerStart was not set"); - set + private uint? filterStart; + + public uint FilterStart { - if (handlerStart != null) throw new Exception("HandlerStart was already set"); - handlerStart = value; + get => filterStart ?? throw new Exception("FilterStart was not set"); + set + { + if (filterStart != null) throw new Exception("FilterStart was already set"); + filterStart = value; + } } - } - private uint? handlerEnd; + private uint? handlerStart; - public uint HandlerEnd - { - get => handlerEnd ?? throw new Exception("HandlerEnd was not set"); - set + public uint HandlerStart { - if (handlerEnd != null) throw new Exception("HandlerEnd was already set"); - handlerEnd = value; + get => handlerStart ?? throw new Exception("HandlerStart was not set"); + set + { + if (handlerStart != null) throw new Exception("HandlerStart was already set"); + handlerStart = value; + } } - } - private ExceptionHandlerBlockKind? handlerBlockKind; + private uint? handlerEnd; - public ExceptionHandlerBlockKind HandlerBlockKind - { - get => handlerBlockKind ?? throw new Exception("HandlerBlockKind was not set"); - set + public uint HandlerEnd { - if (handlerBlockKind != null) throw new Exception("HandlerBlockKind was already set"); - handlerBlockKind = value; + get => handlerEnd ?? throw new Exception("HandlerEnd was not set"); + set + { + if (handlerEnd != null) throw new Exception("HandlerEnd was already set"); + handlerEnd = value; + } } - } - private IType exceptionType; + private ExceptionHandlerBlockKind? handlerBlockKind; - public IType ExceptionType - { - get => exceptionType ?? throw new Exception("ExceptionType was not set"); - set + public ExceptionHandlerBlockKind HandlerBlockKind { - if (exceptionType != null) throw new Exception("ExceptionType was already set"); - exceptionType = value; + get => handlerBlockKind ?? throw new Exception("HandlerBlockKind was not set"); + set + { + if (handlerBlockKind != null) throw new Exception("HandlerBlockKind was already set"); + handlerBlockKind = value; + } } - } - public IExceptionHandler Build() - { - switch (HandlerBlockKind) + 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() { - 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); + 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); + } } } } From f20dc4e79ecc715910047a69510103e6dd27032c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 6 Jul 2020 08:34:56 -0300 Subject: [PATCH 183/256] refactor --- Backend/Transformations/Assembly/Assembler.cs | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 02bd9bb2..33c737ac 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -516,17 +516,15 @@ public override void Visit(ThrowInstruction instruction) translatedInstructions.Add(basicInstruction); } - // fixme revisar de aca en adelante public override void Visit(UnconditionalBranchInstruction instruction) { + var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); + Bytecode.Instruction branchInstruction; switch (instruction.Operation) { case UnconditionalBranchOperation.Leave: { - var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); - var unconditionalBranchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Leave, target); - translatedInstructions.Add(unconditionalBranchInstruction); - + branchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Leave, target); // leave target -> DD (1 + 4) // leave.s target -> DE (1 + 1) offset += (uint) (IsShortForm(instruction) ? 2 : 5); @@ -535,12 +533,7 @@ public override void Visit(UnconditionalBranchInstruction instruction) } case UnconditionalBranchOperation.Branch: { - var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); - var unconditionalBranchInstruction = new Bytecode.BranchInstruction( - offset, - Bytecode.BranchOperation.Branch, - target); - translatedInstructions.Add(unconditionalBranchInstruction); + branchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Branch, target); // leave target -> 38 (1 + 4) // leave.s target -> 2B (1 + 1) offset += (uint) (IsShortForm(instruction) ? 2 : 5); @@ -548,20 +541,22 @@ public override void Visit(UnconditionalBranchInstruction instruction) } case UnconditionalBranchOperation.EndFinally: { - translatedInstructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFinally)); - offset++; + branchInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFinally); + offset++; // 1 Byte OpCode exceptionInformationBuilder.EndCurrentProtectedBlockAt(offset); // no more handlers after finally break; } case UnconditionalBranchOperation.EndFilter: { // nothing is done with exceptionInformation since filter area is the gap between try end and handler start - translatedInstructions.Add(new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFilter)); - offset += 2; // 2byte opcode + branchInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFilter); + offset += 2; // 2 Byte OpCode break; } default: throw instruction.Operation.ToUnknownValueException(); } + + translatedInstructions.Add(branchInstruction); } public override void Visit(ConvertInstruction instruction) @@ -578,7 +573,7 @@ public override void Visit(ConvertInstruction instruction) switch (convertInstruction.Operation) { case Bytecode.ConvertOperation.Conv: - offset++; + offset++; // 1 Byte OpCode break; default: // box typeTok -> 8C (1 + 4) @@ -595,17 +590,17 @@ public override void Visit(ReturnInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Return); translatedInstructions.Add(basicInstruction); - offset++; + offset++; // 1 Byte OpCode } public override void Visit(ConditionalBranchInstruction instruction) { var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); - var conditionalBranchInstruction = new Bytecode.BranchInstruction( + var branchInstruction = new Bytecode.BranchInstruction( offset, OperationHelper.ToBranchOperation(instruction.Operation, instruction.RightOperand), target); - translatedInstructions.Add(conditionalBranchInstruction); + translatedInstructions.Add(branchInstruction); // br* target -> 1ByteOpcode (1 + 4) // br*.s target -> 1ByteOpcode (1 + 1) offset += (uint) (IsShortForm(instruction) ? 2 : 5); @@ -674,21 +669,21 @@ public override void Visit(CopyMemoryInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.CopyBlock); translatedInstructions.Add(basicInstruction); - offset += 2; // 2ByteOpcode + offset += 2; // 2 Byte OpCode } public override void Visit(LocalAllocationInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.LocalAllocation); translatedInstructions.Add(basicInstruction); - offset += 2; // 2ByteOpcode + offset += 2; // 2 Byte OpCode } public override void Visit(InitializeMemoryInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.InitBlock); translatedInstructions.Add(basicInstruction); - offset += 2; // 2ByteOpcode + offset += 2; // 2 Byte OpCode } public override void Visit(InitializeObjectInstruction instruction) @@ -709,12 +704,12 @@ public override void Visit(CopyObjectInstruction instruction) public override void Visit(CreateArrayInstruction instruction) { - var createArrayInstruction = - new Bytecode.CreateArrayInstruction(offset, new ArrayType(instruction.ElementType, instruction.Rank)) - { - WithLowerBound = instruction.LowerBounds.Any(), - Constructor = instruction.Constructor - }; + var arrayType = new ArrayType(instruction.ElementType, instruction.Rank); + var createArrayInstruction = new Bytecode.CreateArrayInstruction(offset, arrayType) + { + WithLowerBound = instruction.LowerBounds.Any(), + Constructor = instruction.Constructor + }; translatedInstructions.Add(createArrayInstruction); // newobj ctor -> 73 (1 + 4) // newarr etype -> 8D (1 + 4) From 165a81c18ef2c3bfd84828774ad960716f7538f2 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 7 Jul 2020 08:57:15 -0300 Subject: [PATCH 184/256] Offset refactor --- Backend/Backend.csproj | 1 + Backend/Transformations/Assembly/Assembler.cs | 364 +++--------------- .../Assembly/CilInstructionSizeCalculator.cs | 344 +++++++++++++++++ 3 files changed, 396 insertions(+), 313 deletions(-) create mode 100644 Backend/Transformations/Assembly/CilInstructionSizeCalculator.cs diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj index 5dd4062d..712fd013 100644 --- a/Backend/Backend.csproj +++ b/Backend/Backend.csproj @@ -64,6 +64,7 @@ + diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 33c737ac..330eace1 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -7,7 +7,6 @@ using Model.ThreeAddressCode.Values; using Model.ThreeAddressCode.Visitor; using Model.Types; -using BranchInstruction = Model.ThreeAddressCode.Instructions.BranchInstruction; using ConvertInstruction = Model.ThreeAddressCode.Instructions.ConvertInstruction; using CreateArrayInstruction = Model.ThreeAddressCode.Instructions.CreateArrayInstruction; using CreateObjectInstruction = Model.ThreeAddressCode.Instructions.CreateObjectInstruction; @@ -79,6 +78,12 @@ public InstructionTranslator(MethodBody bodyToProcess) this.bodyToProcess = bodyToProcess; } + private void Add(Bytecode.Instruction instruction, uint nextInstructionOffset) + { + translatedInstructions.Add(instruction); + offset += CilInstructionSizeCalculator.SizeOf(instruction, nextInstructionOffset); + } + public override bool ShouldVisit(Instruction instruction) { var shouldProcessInstruction = !ignoreInstruction.TryGetValue(bodyToProcess.Instructions.IndexOf(instruction), out _); @@ -88,8 +93,7 @@ public override bool ShouldVisit(Instruction instruction) public override void Visit(PopInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Pop); - translatedInstructions.Add(basicInstruction); - offset++; // 1 Byte OpCode + Add(basicInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(BinaryInstruction instruction) @@ -99,25 +103,13 @@ public override void Visit(BinaryInstruction instruction) OverflowCheck = instruction.OverflowCheck, UnsignedOperands = instruction.UnsignedOperands }; - translatedInstructions.Add(basicInstruction); - switch (basicInstruction.Operation) - { - case Bytecode.BasicOperation.Gt: - case Bytecode.BasicOperation.Lt: - case Bytecode.BasicOperation.Eq: - offset += 2; // 2 Byte OpCode - break; - default: - offset++; // 1 Byte OpCode - break; - } + Add(basicInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(UnaryInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, OperationHelper.ToBasicOperation(instruction.Operation)); - translatedInstructions.Add(basicInstruction); - offset++; // 1 Byte OpCode + Add(basicInstruction, NextInstructionOffsetFor(instruction)); } // FIXME revisar los casos, hay algunos que no estoy seguro de que esten bien. se repiten caminos ademas (sobretodo por el reference) @@ -133,7 +125,6 @@ public override void Visit(LoadInstruction instruction) else { bytecodeInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Dup); - offset++; } } else @@ -141,29 +132,6 @@ public override void Visit(LoadInstruction instruction) if (instruction.Result is LocalVariable loc) { bytecodeInstruction = new Bytecode.StoreInstruction(offset, loc); - if (loc.IsParameter) - { - // starg num -> FE 0B (2 + 2) - // starg.s num -> 10 (1 + 1) - offset += (uint) (loc.Index > byte.MaxValue ? 4 : 2); - } - else - { - switch (loc.Index) - { - case 0: - case 1: - case 2: - case 3: - offset++; // 1byte OpCode - break; - default: - // stloc indx -> FE 0E (2 + 2) - // stloc.s indx -> 13 (1 + 1) - offset += (uint) (loc.Index > byte.MaxValue ? 4 : 2); - break; - } - } } else { @@ -171,113 +139,15 @@ public override void Visit(LoadInstruction instruction) { case Constant constant: bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Value, constant); - switch (constant.Value) - { - case null: - offset++; // ldnull -> 14 (1) - break; - case string _: - offset += 5; // ldstr string -> 72 (1 + 4) - break; - case -1: - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - offset++; - break; - case object _ when constant.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.Int16, PlatformTypes.Int32): - { - var value = (int) constant.Value; - if (value >= sbyte.MinValue && value <= sbyte.MaxValue) - { - offset += 2; // ldc.i4.s num -> 1F (1 + 1) - } - else - { - offset += 5; // ldc.i4 num -> 20 (1 + 4) - } - - break; - } - case object _ when constant.Type.Equals(PlatformTypes.Int64): - offset += 9; // ldc.i8 num-> 21 (1 + 8) - break; - case object _ when constant.Type.IsOneOf(PlatformTypes.UInt8, PlatformTypes.UInt16, PlatformTypes.UInt32): - { - var value = (uint) constant.Value; - if (value <= byte.MaxValue) - { - offset += 2; // ldc.i4.s num -> 1F (1 + 1) - } - else - { - offset += 5; // ldc.i4 num -> 20 (1 + 4) - } - - break; - } - case object _ when constant.Type.Equals(PlatformTypes.UInt64): - offset += 9; // ldc.i8 num-> 21 (1 + 8) - break; - - case object _ when constant.Type.Equals(PlatformTypes.Float32): - offset += 5; // ldc.r4 num -> 22 (1 + 4) - break; - case object _ when constant.Type.Equals(PlatformTypes.Float64): - { - offset += 9; // ldc.r8 num -> 23 (1 + 8) - break; - } - default: - throw new Exception(); - } - - break; case LocalVariable localVariable: { bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, localVariable); - switch (localVariable.Index) - { - // ldloc.0,1,2,3 ldarg.0,1,2,3 - case 0: - case 1: - case 2: - case 3: - offset++; - break; - default: - // ldloc indx -> FE 0C (2 + 2) - // ldloc.s indx -> 11 (1 + 1) - // ldarg num -> FE 09 (2 + 2) - // ldarg.s num -> 0E (1 + 1) - offset += (uint) (localVariable.Index > byte.MaxValue ? 4 : 2); - break; - } - break; } case Dereference dereference: { - var type = dereference.Type; - bytecodeInstruction = new Bytecode.LoadIndirectInstruction(offset, type); - if (type.IsIntType() || type.IsFloatType() || type.Equals(PlatformTypes.IntPtr) || type.Equals(PlatformTypes.Object)) - { - // 1 byte opcode - offset++; - } - else - { - // ldobj typeTok -> 71 (1 + 4) - offset += 5; - } - + bytecodeInstruction = new Bytecode.LoadIndirectInstruction(offset, dereference.Type); break; } case Reference reference: @@ -289,21 +159,12 @@ public override void Visit(LoadInstruction instruction) offset, Bytecode.LoadArrayElementOperation.Address, (ArrayType) arrayElementAccess.Array.Type) {Method = arrayElementAccess.Method}; - - // ldelema typeTok -> 8F (1 + 4) - // ldobj typeTok -> 71 (1 + 4) - offset += 5; break; } case LocalVariable localVariable: { bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Address, localVariable); - // ldloca indx -> FE 0D (2 + 2) - // ldloca.s indx -> 12 (1 + 1) - // ldarga argNum -> FE 0A (2 + 2) - // ldarga.s argNum -> 0F (1 + 1) - offset += (uint) (localVariable.Index > byte.MaxValue ? 4 : 2); break; } case InstanceFieldAccess instanceFieldAccess: @@ -311,9 +172,6 @@ public override void Visit(LoadInstruction instruction) offset, Bytecode.LoadFieldOperation.Address, instanceFieldAccess.Field); - // ldsflda field -> 0x7F (1 + 4) - // ldflda field -> 0x7C (1 + 4) - offset += 5; break; default: throw new Exception(); // TODO @@ -322,39 +180,30 @@ public override void Visit(LoadInstruction instruction) break; case ArrayLengthAccess _: bytecodeInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.LoadArrayLength); - offset++; break; case VirtualMethodReference virtualMethodReference: bytecodeInstruction = new Bytecode.LoadMethodAddressInstruction( offset, Bytecode.LoadMethodAddressOperation.Virtual, virtualMethodReference.Method); - // ldvirtftn method -> FE 07 (2 + 4) - offset += 6; break; case StaticMethodReference staticMethodReference: bytecodeInstruction = new Bytecode.LoadMethodAddressInstruction( offset, Bytecode.LoadMethodAddressOperation.Static, staticMethodReference.Method); - // ldftn method -> FE 06 (2 + 4) - offset += 6; break; case InstanceFieldAccess instanceFieldAccess: bytecodeInstruction = new Bytecode.LoadFieldInstruction( offset, Bytecode.LoadFieldOperation.Content, instanceFieldAccess.Field); - // ldfld field -> 7B (1 + 4) - offset += 5; break; case StaticFieldAccess staticFieldAccess: bytecodeInstruction = new Bytecode.LoadFieldInstruction( offset, Bytecode.LoadFieldOperation.Content, staticFieldAccess.Field); - // ldsfld field -> 7E (1 + 4) - offset += 5; break; case ArrayElementAccess arrayElementAccess: { @@ -364,21 +213,6 @@ public override void Visit(LoadInstruction instruction) Bytecode.LoadArrayElementOperation.Content, type) {Method = arrayElementAccess.Method}; - if (type.IsVector && - (type.ElementsType.IsIntType() || - type.ElementsType.IsFloatType() || - type.ElementsType.Equals(PlatformTypes.IntPtr) || - type.ElementsType.Equals(PlatformTypes.Object))) - { - // 1 byte opcode - offset++; - } - else - { - // ldelem typeTok -> A3 (1 + 4) - offset += 5; - } - break; } default: throw new Exception(); // TODO @@ -386,7 +220,7 @@ public override void Visit(LoadInstruction instruction) } } - translatedInstructions.Add(bytecodeInstruction); + Add(bytecodeInstruction, NextInstructionOffsetFor(instruction)); } // FIXME revisar @@ -399,69 +233,36 @@ public override void Visit(StoreInstruction instruction) { var type = (ArrayType) arrayElementAccess.Array.Type; storeInstruction = new Bytecode.StoreArrayElementInstruction(offset, type) {Method = arrayElementAccess.Method}; - if (type.IsVector && - (type.ElementsType.IsIntType() || - type.ElementsType.IsFloatType() || - type.ElementsType.Equals(PlatformTypes.IntPtr) || - type.ElementsType.Equals(PlatformTypes.Object))) - { - // 1 byte opcode - offset++; - } - else - { - // stelem typeTok -> A4 (1 + 4) - offset += 5; - } - break; } case Dereference dereference: { - var type = dereference.Type; storeInstruction = new Bytecode.StoreIndirectInstruction(offset, dereference.Type); - if (type.IsIntType() || type.IsFloatType() || type.Equals(PlatformTypes.IntPtr) || type.Equals(PlatformTypes.Object)) - { - // 1 byte opcode - offset++; - } - else - { - // stobj typeTok -> 81 (1 + 4) - offset += 5; - } - break; } case InstanceFieldAccess instanceFieldAccess: storeInstruction = new Bytecode.StoreFieldInstruction(offset, instanceFieldAccess.Field); - // stfld field -> 7D (1 + 4) - offset += 5; break; case StaticFieldAccess staticFieldAccess: storeInstruction = new Bytecode.StoreFieldInstruction(offset, staticFieldAccess.Field); - // stsfld field -> 80 (1 + 4) - offset += 5; break; default: throw new Exception(); // TODO msg } - translatedInstructions.Add(storeInstruction); + Add(storeInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(NopInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Nop); - translatedInstructions.Add(basicInstruction); - offset++; // 1 Byte OpCode + Add(basicInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(BreakpointInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Breakpoint); - translatedInstructions.Add(basicInstruction); - offset++; // 1 Byte OpCode + Add(basicInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(TryInstruction instruction) @@ -500,63 +301,47 @@ public override void Visit(CatchInstruction instruction) public override void Visit(ThrowInstruction instruction) { - Bytecode.BasicInstruction basicInstruction; - if (instruction.HasOperand) - { - basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Throw); - offset++; // 1 Byte OpCode - } - else - { - basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Rethrow); - offset += 2; // 2 Byte OpCode - } - + var basicInstruction = instruction.HasOperand + ? new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Throw) + : new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Rethrow); + Add(basicInstruction, NextInstructionOffsetFor(instruction)); exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(offset); - translatedInstructions.Add(basicInstruction); } public override void Visit(UnconditionalBranchInstruction instruction) { var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); - Bytecode.Instruction branchInstruction; switch (instruction.Operation) { case UnconditionalBranchOperation.Leave: { - branchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Leave, target); - // leave target -> DD (1 + 4) - // leave.s target -> DE (1 + 1) - offset += (uint) (IsShortForm(instruction) ? 2 : 5); + var branchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Leave, target); + Add(branchInstruction, NextInstructionOffsetFor(instruction)); exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(offset); break; } case UnconditionalBranchOperation.Branch: { - branchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Branch, target); - // leave target -> 38 (1 + 4) - // leave.s target -> 2B (1 + 1) - offset += (uint) (IsShortForm(instruction) ? 2 : 5); + var branchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Branch, target); + Add(branchInstruction, NextInstructionOffsetFor(instruction)); break; } case UnconditionalBranchOperation.EndFinally: { - branchInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFinally); - offset++; // 1 Byte OpCode + var branchInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFinally); + Add(branchInstruction, NextInstructionOffsetFor(instruction)); exceptionInformationBuilder.EndCurrentProtectedBlockAt(offset); // no more handlers after finally break; } case UnconditionalBranchOperation.EndFilter: { // nothing is done with exceptionInformation since filter area is the gap between try end and handler start - branchInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFilter); - offset += 2; // 2 Byte OpCode + var branchInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFilter); + Add(branchInstruction, NextInstructionOffsetFor(instruction)); break; } default: throw instruction.Operation.ToUnknownValueException(); } - - translatedInstructions.Add(branchInstruction); } public override void Visit(ConvertInstruction instruction) @@ -569,28 +354,13 @@ public override void Visit(ConvertInstruction instruction) OverflowCheck = instruction.OverflowCheck, UnsignedOperands = instruction.UnsignedOperands, }; - translatedInstructions.Add(convertInstruction); - switch (convertInstruction.Operation) - { - case Bytecode.ConvertOperation.Conv: - offset++; // 1 Byte OpCode - break; - default: - // box typeTok -> 8C (1 + 4) - // castclass typeTok -> 74 (1 + 4) - // isinst typeTok -> 75 (1 + 4) - // unbox valuetype -> 79 (1 + 4) - // unbox.any typeTok -> A5 (1 + 4) - offset += 5; - break; - } + Add(convertInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(ReturnInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Return); - translatedInstructions.Add(basicInstruction); - offset++; // 1 Byte OpCode + Add(basicInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(ConditionalBranchInstruction instruction) @@ -600,35 +370,26 @@ public override void Visit(ConditionalBranchInstruction instruction) offset, OperationHelper.ToBranchOperation(instruction.Operation, instruction.RightOperand), target); - translatedInstructions.Add(branchInstruction); - // br* target -> 1ByteOpcode (1 + 4) - // br*.s target -> 1ByteOpcode (1 + 1) - offset += (uint) (IsShortForm(instruction) ? 2 : 5); + Add(branchInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(SwitchInstruction instruction) { var targets = instruction.Targets.Select(target => Convert.ToUInt32(target.Substring(2), 16)).ToList(); var switchInstruction = new Bytecode.SwitchInstruction(offset, targets); - translatedInstructions.Add(switchInstruction); - // switch number t1 t2 t3 ... -> 45 .... (1 + 4 + n*4) - offset += (uint) (1 + 4 + 4 * targets.Count); + Add(switchInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(SizeofInstruction instruction) { var sizeofInstruction = new Bytecode.SizeofInstruction(offset, instruction.MeasuredType); - translatedInstructions.Add(sizeofInstruction); - // sizeof typetok -> FE 1C (2 + 4) - offset += 6; + Add(sizeofInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(LoadTokenInstruction instruction) { var loadTokenInstruction = new Bytecode.LoadTokenInstruction(offset, instruction.Token); - translatedInstructions.Add(loadTokenInstruction); - // ldtoken token -> D0 (1 + 4) - offset += 5; + Add(loadTokenInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(MethodCallInstruction instruction) @@ -638,18 +399,13 @@ public override void Visit(MethodCallInstruction instruction) OperationHelper.ToMethodCallOperation(instruction.Operation), instruction.Method ); - translatedInstructions.Add(methodCallInstruction); - // call method -> 28 (1 + 4) - // callvirt method -> 6F (1 + 4) - offset += 5; + Add(methodCallInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(IndirectMethodCallInstruction instruction) { var indirectMethodCallInstruction = new Bytecode.IndirectMethodCallInstruction(offset, instruction.Function); - translatedInstructions.Add(indirectMethodCallInstruction); - // calli callsitedescr -> 29 (1 + 4) - offset += 5; + Add(indirectMethodCallInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(CreateObjectInstruction instruction) @@ -660,46 +416,38 @@ public override void Visit(CreateObjectInstruction instruction) ignoreInstruction.Add(index + 2, true); // load var createObjectInstruction = new Bytecode.CreateObjectInstruction(offset, methodCallInstruction.Method); - translatedInstructions.Add(createObjectInstruction); - // newobj ctor -> 73 (1 + 4) - offset += 5; + var nextInstructionOffset = NextInstructionOffsetFor((Instruction) bodyToProcess.Instructions[index + 3]); + Add(createObjectInstruction, nextInstructionOffset); } public override void Visit(CopyMemoryInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.CopyBlock); - translatedInstructions.Add(basicInstruction); - offset += 2; // 2 Byte OpCode + Add(basicInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(LocalAllocationInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.LocalAllocation); - translatedInstructions.Add(basicInstruction); - offset += 2; // 2 Byte OpCode + Add(basicInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(InitializeMemoryInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.InitBlock); - translatedInstructions.Add(basicInstruction); - offset += 2; // 2 Byte OpCode + Add(basicInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(InitializeObjectInstruction instruction) { var initObjInstruction = new Bytecode.InitObjInstruction(offset, instruction.TargetAddress.Type); - translatedInstructions.Add(initObjInstruction); - // initobj typeTok -> FE 15 (2 + 4) - offset += 6; + Add(initObjInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(CopyObjectInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.CopyObject); - translatedInstructions.Add(basicInstruction); - // cpobj typeTok-> 70 (1 + 4) - offset += 5; + Add(basicInstruction, NextInstructionOffsetFor(instruction)); } public override void Visit(CreateArrayInstruction instruction) @@ -710,34 +458,24 @@ public override void Visit(CreateArrayInstruction instruction) WithLowerBound = instruction.LowerBounds.Any(), Constructor = instruction.Constructor }; - translatedInstructions.Add(createArrayInstruction); - // newobj ctor -> 73 (1 + 4) - // newarr etype -> 8D (1 + 4) - offset += 5; + Add(createArrayInstruction, NextInstructionOffsetFor(instruction)); } - public override void Visit(PhiInstruction instruction) - { - throw new Exception(); - } + public override void Visit(PhiInstruction instruction) => throw new Exception(); public override void Visit(ConstrainedInstruction instruction) { - translatedInstructions.Add(new Bytecode.ConstrainedInstruction(offset, instruction.ThisType)); - // constrained. thisType -> FE 16 (2 + 4) - offset += 6; + var constrainedInstruction = new Bytecode.ConstrainedInstruction(offset, instruction.ThisType); + Add(constrainedInstruction, NextInstructionOffsetFor(instruction)); } - - // FIXME: duplicate with method body generator - private bool IsShortForm(BranchInstruction instruction) + // FIXME mmm medio medio esto + private uint NextInstructionOffsetFor(Instruction instruction) { - var nextInstructionOffset = - Convert.ToInt32(bodyToProcess.Instructions[bodyToProcess.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); - var currentInstructionOffset = Convert.ToInt32(instruction.Label.Substring(2), 16); - // short forms are 1 byte opcode + 1 byte target. normal forms are 1 byte opcode + 4 byte target - var isShortForm = nextInstructionOffset - currentInstructionOffset == 2; - return isShortForm; + var indexOf = bodyToProcess.Instructions.IndexOf(instruction) + 1; + return indexOf == bodyToProcess.Instructions.Count + ? instruction.Offset + : bodyToProcess.Instructions[indexOf].Offset; } } } diff --git a/Backend/Transformations/Assembly/CilInstructionSizeCalculator.cs b/Backend/Transformations/Assembly/CilInstructionSizeCalculator.cs new file mode 100644 index 00000000..fef9cfeb --- /dev/null +++ b/Backend/Transformations/Assembly/CilInstructionSizeCalculator.cs @@ -0,0 +1,344 @@ +using System; +using Model; +using Model.Bytecode; +using Model.ThreeAddressCode.Values; +using Model.Types; + +namespace Backend.Transformations.Assembly +{ + public static class CilInstructionSizeCalculator + { + public static uint SizeOf(Instruction instruction, uint nexInstructionOffset) + { + switch (instruction) + { + case BasicInstruction basicInstruction: return SizeOf(basicInstruction); + case ConstrainedInstruction constrainedInstruction: return SizeOf(constrainedInstruction); + case CreateArrayInstruction createArrayInstruction: return SizeOf(createArrayInstruction); + case InitObjInstruction initObjInstruction: return SizeOf(initObjInstruction); + case CreateObjectInstruction createObjectInstruction: return SizeOf(createObjectInstruction); + case IndirectMethodCallInstruction indirectMethodCallInstruction: return SizeOf(indirectMethodCallInstruction); + case MethodCallInstruction methodCallInstruction: return SizeOf(methodCallInstruction); + case LoadTokenInstruction loadTokenInstruction: return SizeOf(loadTokenInstruction); + case SizeofInstruction sizeofInstruction: return SizeOf(sizeofInstruction); + case SwitchInstruction switchInstruction: return SizeOf(switchInstruction); + case ConvertInstruction convertInstruction: return SizeOf(convertInstruction); + case StoreIndirectInstruction storeIndirectInstruction: return SizeOf(storeIndirectInstruction); + case StoreFieldInstruction storeFieldInstruction: return SizeOf(storeFieldInstruction); + case StoreArrayElementInstruction storeArrayElementInstruction: return SizeOf(storeArrayElementInstruction); + case BranchInstruction branchInstruction: return SizeOf(branchInstruction, nexInstructionOffset); + case StoreInstruction storeInstruction: return SizeOf(storeInstruction); + case LoadInstruction loadInstruction: return SizeOf(loadInstruction); + case LoadIndirectInstruction loadIndirectInstruction: return SizeOf(loadIndirectInstruction); + case LoadArrayElementInstruction loadArrayElementInstruction: return SizeOf(loadArrayElementInstruction); + case LoadFieldInstruction loadFieldInstruction: return SizeOf(loadFieldInstruction); + case LoadMethodAddressInstruction loadMethodAddressInstruction: return SizeOf(loadMethodAddressInstruction); + default: throw new Exception(); // TODO + } + } + + private static uint SizeOf(LoadMethodAddressInstruction loadMethodAddressInstruction) + { + // ldvirtftn method -> FE 07 (2 + 4) + // ldftn method -> FE 06 (2 + 4) + switch (loadMethodAddressInstruction.Operation) + { + case LoadMethodAddressOperation.Static: + case LoadMethodAddressOperation.Virtual: + return 6; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private static uint SizeOf(LoadFieldInstruction loadFieldInstruction) + { + // ldfld field -> 7B (1 + 4) + // ldsfld field -> 7E (1 + 4) + // ldflda field -> 0x7C (1 + 4) + // ldsflda field -> 0x7F (1 + 4) + switch (loadFieldInstruction.Operation) + { + case LoadFieldOperation.Content: + case LoadFieldOperation.Address: return 5; + default: throw new ArgumentOutOfRangeException(); + } + } + + private static uint SizeOf(LoadArrayElementInstruction loadArrayElementInstruction) + { + switch (loadArrayElementInstruction.Operation) + { + case LoadArrayElementOperation.Content: + var type = loadArrayElementInstruction.Array; + if (type.IsVector && + (type.ElementsType.IsIntType() || + type.ElementsType.IsFloatType() || + type.ElementsType.Equals(PlatformTypes.IntPtr) || + type.ElementsType.Equals(PlatformTypes.Object))) + { + // 1 byte opcode + return 1; + } + else + { + // ldelem typeTok -> A3 (1 + 4) + return 5; + } + case LoadArrayElementOperation.Address: + // ldelema typeTok -> 8F (1 + 4) + // ldobj typeTok -> 71 (1 + 4) + return 5; + default: + throw new ArgumentOutOfRangeException(); + // FIXME quiza puedo usar esta que es la defualt para estos casos siempre para el caso default en vez de hacer una yo + } + } + + private static uint SizeOf(LoadIndirectInstruction loadIndirectInstruction) + { + var type = loadIndirectInstruction.Type; + return (uint) (type.IsIntType() || type.IsFloatType() || type.Equals(PlatformTypes.IntPtr) || type.Equals(PlatformTypes.Object) + ? 1 // 1 byte opcode + : 5); // ldobj typeTok -> 71 (1 + 4) + } + + private static uint SizeOf(LoadInstruction loadInstruction) + { + switch (loadInstruction.Operation) + { + case LoadOperation.Value: + var constant = (Constant) loadInstruction.Operand; + switch (constant.Value) + { + case -1: + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case null: + return 1; // ldnull -> 14 (1) + case string _: + return 5; // ldstr string -> 72 (1 + 4) + case object _ when constant.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.Int16, PlatformTypes.Int32): + { + // ldc.i4.s num -> 1F (1 + 1) + // ldc.i4 num -> 20 (1 + 4) + var value = (int) constant.Value; + return (uint) (value >= sbyte.MinValue && value <= sbyte.MaxValue ? 2 : 5); + } + case object _ when constant.Type.Equals(PlatformTypes.Int64): return 9; // ldc.i8 num-> 21 (1 + 8) + case object _ when constant.Type.IsOneOf(PlatformTypes.UInt8, PlatformTypes.UInt16, PlatformTypes.UInt32): + { + // ldc.i4.s num -> 1F (1 + 1) + // ldc.i4 num -> 20 (1 + 4) + var value = (uint) constant.Value; + return (uint) (value <= byte.MaxValue ? 2 : 5); + } + case object _ when constant.Type.Equals(PlatformTypes.UInt64): return 9; // ldc.i8 num-> 21 (1 + 8) + case object _ when constant.Type.Equals(PlatformTypes.Float32): return 5; // ldc.r4 num -> 22 (1 + 4) + case object _ when constant.Type.Equals(PlatformTypes.Float64): return 9; // ldc.r8 num -> 23 (1 + 8) + default: throw new Exception(); + } + + case LoadOperation.Content: + { + var localVariable = (LocalVariable) loadInstruction.Operand; + switch (localVariable.Index) + { + // ldloc.0,1,2,3 ldarg.0,1,2,3 + case 0: + case 1: + case 2: + case 3: + return 1; + default: + // ldloc indx -> FE 0C (2 + 2) + // ldloc.s indx -> 11 (1 + 1) + // ldarg num -> FE 09 (2 + 2) + // ldarg.s num -> 0E (1 + 1) + return (uint) (localVariable.Index > byte.MaxValue ? 4 : 2); + } + } + case LoadOperation.Address: + { + // ldloca indx -> FE 0D (2 + 2) + // ldloca.s indx -> 12 (1 + 1) + // ldarga argNum -> FE 0A (2 + 2) + // ldarga.s argNum -> 0F (1 + 1) + var localVariable = (LocalVariable) loadInstruction.Operand; + return (uint) (localVariable.Index > byte.MaxValue ? 4 : 2); + } + default: throw new Exception(); // TODO + } + } + + private static uint SizeOf(StoreInstruction storeInstruction) + { + var local = (LocalVariable) storeInstruction.Target; + if (local.IsParameter) + { + // starg num -> FE 0B (2 + 2) + // starg.s num -> 10 (1 + 1) + return (uint) (local.Index > byte.MaxValue ? 4 : 2); + } + else + { + switch (local.Index) + { + case 0: + case 1: + case 2: + case 3: + return 1; // 1byte OpCode + default: + // stloc indx -> FE 0E (2 + 2) + // stloc.s indx -> 13 (1 + 1) + return (uint) (local.Index > byte.MaxValue ? 4 : 2); + } + } + } + // leave target -> DD (1 + 4) + // leave.s target -> DE (1 + 1) + // br target -> 38 (1 + 4) + // br.s target -> 2B (1 + 1) + // br* target -> 1ByteOpcode (1 + 4) + // br*.s target -> 1ByteOpcode (1 + 1) + + private static uint SizeOf(this BranchInstruction branchInstruction, uint nextInstructionOffset) + { + // short forms are 1 byte opcode + 1 byte target. normal forms are 1 byte opcode + 4 byte target + var isShortForm = nextInstructionOffset - branchInstruction.Offset == 2; + return (uint) (isShortForm ? 2 : 5); + } + + private static uint SizeOf(StoreArrayElementInstruction storeArrayElementInstruction) + { + var type = storeArrayElementInstruction.Array; + if (type.IsVector && + (type.ElementsType.IsIntType() || + type.ElementsType.IsFloatType() || + type.ElementsType.Equals(PlatformTypes.IntPtr) || + type.ElementsType.Equals(PlatformTypes.Object))) + { + // 1 byte opcode + return 1; + } + else + { + // stelem typeTok -> A4 (1 + 4) + return 5; + } + } + + // stfld field -> 7D (1 + 4) + // stsfld field -> 80 (1 + 4) + private static uint SizeOf(StoreFieldInstruction storeFieldInstruction) => 5; + + private static uint SizeOf(StoreIndirectInstruction storeIndirectInstruction) + { + var type = storeIndirectInstruction.Type; + if (type.IsIntType() || type.IsFloatType() || type.Equals(PlatformTypes.IntPtr) || type.Equals(PlatformTypes.Object)) + { + // 1 byte opcode + return 1; + } + else + { + // stobj typeTok -> 81 (1 + 4) + return 5; + } + } + + private static uint SizeOf(ConvertInstruction convertInstruction) + { + switch (convertInstruction.Operation) + { + case ConvertOperation.Conv: + return 1; // 1 Byte OpCode + case ConvertOperation.IsInst: + case ConvertOperation.Cast: + case ConvertOperation.Box: + case ConvertOperation.Unbox: + case ConvertOperation.UnboxPtr: + // box typeTok -> 8C (1 + 4) + // castclass typeTok -> 74 (1 + 4) + // isinst typeTok -> 75 (1 + 4) + // unbox valuetype -> 79 (1 + 4) + // unbox.any typeTok -> A5 (1 + 4) + return 5; + default: throw new Exception(); + } + } + + // switch number t1 t2 t3 ... -> 45 .... (1 + 4 + n*4) + private static uint SizeOf(SwitchInstruction switchInstruction) => (uint) (1 + 4 + 4 * switchInstruction.Targets.Count); + + // sizeof typetok -> FE 1C (2 + 4) + private static uint SizeOf(SizeofInstruction sizeofInstruction) => 6; + + private static uint SizeOf(LoadTokenInstruction loadTokenInstruction) => 5; // ldtoken token -> D0 (1 + 4) + + // call method -> 28 (1 + 4) + // callvirt method -> 6F (1 + 4) + private static uint SizeOf(MethodCallInstruction methodCallInstruction) => 5; + + private static uint SizeOf(IndirectMethodCallInstruction indirectMethodCallInstruction) => 5; // calli callsitedescr -> 29 (1 + 4) + + private static uint SizeOf(CreateObjectInstruction createObjectInstruction) => 5; // newobj ctor -> 73 (1 + 4) + + private static uint SizeOf(InitObjInstruction initObjInstruction) => 6; // initobj typeTok -> FE 15 (2 + 4) + + // newobj ctor -> 73 (1 + 4) + // newarr etype -> 8D (1 + 4) + private static uint SizeOf(CreateArrayInstruction createArrayInstruction) => 5; + + private static uint SizeOf(ConstrainedInstruction constrainedInstruction) => 6; // constrained. thisType -> FE 16 (2 + 4) + + private static uint SizeOf(this BasicInstruction instruction) // fixme rename + { + switch (instruction.Operation) + { + case BasicOperation.Add: + case BasicOperation.Sub: + case BasicOperation.Mul: + case BasicOperation.Div: + case BasicOperation.Rem: + case BasicOperation.And: + case BasicOperation.Or: + case BasicOperation.Xor: + case BasicOperation.Shl: + case BasicOperation.Shr: + case BasicOperation.Not: + case BasicOperation.Neg: + case BasicOperation.Nop: + case BasicOperation.Pop: + case BasicOperation.Dup: + case BasicOperation.EndFinally: + case BasicOperation.Throw: + case BasicOperation.LoadArrayLength: + case BasicOperation.Breakpoint: + case BasicOperation.Return: + return 1; // 1 Byte OpCode + case BasicOperation.Eq: + case BasicOperation.Lt: + case BasicOperation.Gt: + case BasicOperation.Rethrow: + case BasicOperation.EndFilter: + case BasicOperation.LocalAllocation: + case BasicOperation.InitBlock: + case BasicOperation.CopyBlock: + return 2; // 2 Byte OpCode + case BasicOperation.CopyObject: + return 5; // cpobj typeTok-> 70 (1 + 4) + default: + throw new ArgumentOutOfRangeException(); + } + } + } +} \ No newline at end of file From e1efc51753f107124289fd5f07eebf401ff280e8 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 19 Jul 2020 19:49:58 -0300 Subject: [PATCH 185/256] unique labels draft --- Backend/Backend.csproj | 2 +- Backend/Transformations/Assembly/Assembler.cs | 209 ++++++----- .../Assembly/CilInstructionSizeCalculator.cs | 344 ------------------ Backend/Transformations/Disassembler.cs | 4 +- .../TacUniqueLabelGenerator.cs | 80 ++++ .../Body/MethodBodyControlFlowGenerator.cs | 15 +- .../Methods/Body/MethodBodyGenerator.cs | 24 +- .../Generators/Methods/MethodGenerator.cs | 2 +- Model/ThreeAddressCode/Instructions.cs | 2 +- 9 files changed, 220 insertions(+), 462 deletions(-) delete mode 100644 Backend/Transformations/Assembly/CilInstructionSizeCalculator.cs create mode 100644 Backend/Transformations/TacUniqueLabelGenerator.cs diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj index 712fd013..0d833003 100644 --- a/Backend/Backend.csproj +++ b/Backend/Backend.csproj @@ -64,13 +64,13 @@ - + diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 330eace1..5e17e4f7 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -70,7 +70,6 @@ private class InstructionTranslator : InstructionVisitor public readonly ExceptionInformationBuilder exceptionInformationBuilder = new ExceptionInformationBuilder(); private readonly MethodBody bodyToProcess; - private uint offset; private readonly IDictionary ignoreInstruction = new Dictionary(); public InstructionTranslator(MethodBody bodyToProcess) @@ -78,12 +77,6 @@ public InstructionTranslator(MethodBody bodyToProcess) this.bodyToProcess = bodyToProcess; } - private void Add(Bytecode.Instruction instruction, uint nextInstructionOffset) - { - translatedInstructions.Add(instruction); - offset += CilInstructionSizeCalculator.SizeOf(instruction, nextInstructionOffset); - } - public override bool ShouldVisit(Instruction instruction) { var shouldProcessInstruction = !ignoreInstruction.TryGetValue(bodyToProcess.Instructions.IndexOf(instruction), out _); @@ -92,24 +85,26 @@ public override bool ShouldVisit(Instruction instruction) public override void Visit(PopInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Pop); - Add(basicInstruction, NextInstructionOffsetFor(instruction)); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Pop); + translatedInstructions.Add(basicInstruction); } public override void Visit(BinaryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(offset, OperationHelper.ToBasicOperation(instruction.Operation)) + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, + OperationHelper.ToBasicOperation(instruction.Operation)) { OverflowCheck = instruction.OverflowCheck, UnsignedOperands = instruction.UnsignedOperands }; - Add(basicInstruction, NextInstructionOffsetFor(instruction)); + translatedInstructions.Add(basicInstruction); } public override void Visit(UnaryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(offset, OperationHelper.ToBasicOperation(instruction.Operation)); - Add(basicInstruction, NextInstructionOffsetFor(instruction)); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, + OperationHelper.ToBasicOperation(instruction.Operation)); + translatedInstructions.Add(basicInstruction); } // FIXME revisar los casos, hay algunos que no estoy seguro de que esten bien. se repiten caminos ademas (sobretodo por el reference) @@ -124,30 +119,32 @@ public override void Visit(LoadInstruction instruction) } else { - bytecodeInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Dup); + bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Dup); } } else { if (instruction.Result is LocalVariable loc) { - bytecodeInstruction = new Bytecode.StoreInstruction(offset, loc); + bytecodeInstruction = new Bytecode.StoreInstruction(instruction.Offset, loc); } else { switch (instruction.Operand) { case Constant constant: - bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Value, constant); + bytecodeInstruction = new Bytecode.LoadInstruction(instruction.Offset, + Bytecode.LoadOperation.Value, constant); break; case LocalVariable localVariable: { - bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, localVariable); + bytecodeInstruction = new Bytecode.LoadInstruction(instruction.Offset, + Bytecode.LoadOperation.Content, localVariable); break; } case Dereference dereference: { - bytecodeInstruction = new Bytecode.LoadIndirectInstruction(offset, dereference.Type); + bytecodeInstruction = new Bytecode.LoadIndirectInstruction(instruction.Offset, dereference.Type); break; } case Reference reference: @@ -156,7 +153,7 @@ public override void Visit(LoadInstruction instruction) case ArrayElementAccess arrayElementAccess: { bytecodeInstruction = new Bytecode.LoadArrayElementInstruction( - offset, + instruction.Offset, Bytecode.LoadArrayElementOperation.Address, (ArrayType) arrayElementAccess.Array.Type) {Method = arrayElementAccess.Method}; break; @@ -164,12 +161,14 @@ public override void Visit(LoadInstruction instruction) case LocalVariable localVariable: { - bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Address, localVariable); + bytecodeInstruction = new Bytecode.LoadInstruction(instruction.Offset, + Bytecode.LoadOperation.Address, + localVariable); break; } case InstanceFieldAccess instanceFieldAccess: bytecodeInstruction = new Bytecode.LoadFieldInstruction( - offset, + instruction.Offset, Bytecode.LoadFieldOperation.Address, instanceFieldAccess.Field); break; @@ -179,29 +178,30 @@ public override void Visit(LoadInstruction instruction) break; case ArrayLengthAccess _: - bytecodeInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.LoadArrayLength); + bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, + Bytecode.BasicOperation.LoadArrayLength); break; case VirtualMethodReference virtualMethodReference: bytecodeInstruction = new Bytecode.LoadMethodAddressInstruction( - offset, + instruction.Offset, Bytecode.LoadMethodAddressOperation.Virtual, virtualMethodReference.Method); break; case StaticMethodReference staticMethodReference: bytecodeInstruction = new Bytecode.LoadMethodAddressInstruction( - offset, + instruction.Offset, Bytecode.LoadMethodAddressOperation.Static, staticMethodReference.Method); break; case InstanceFieldAccess instanceFieldAccess: bytecodeInstruction = new Bytecode.LoadFieldInstruction( - offset, + instruction.Offset, Bytecode.LoadFieldOperation.Content, instanceFieldAccess.Field); break; case StaticFieldAccess staticFieldAccess: bytecodeInstruction = new Bytecode.LoadFieldInstruction( - offset, + instruction.Offset, Bytecode.LoadFieldOperation.Content, staticFieldAccess.Field); break; @@ -209,7 +209,7 @@ public override void Visit(LoadInstruction instruction) { var type = (ArrayType) arrayElementAccess.Array.Type; bytecodeInstruction = new Bytecode.LoadArrayElementInstruction( - offset, + instruction.Offset, Bytecode.LoadArrayElementOperation.Content, type) {Method = arrayElementAccess.Method}; @@ -220,7 +220,7 @@ public override void Visit(LoadInstruction instruction) } } - Add(bytecodeInstruction, NextInstructionOffsetFor(instruction)); + translatedInstructions.Add(bytecodeInstruction); } // FIXME revisar @@ -232,43 +232,48 @@ public override void Visit(StoreInstruction instruction) case ArrayElementAccess arrayElementAccess: { var type = (ArrayType) arrayElementAccess.Array.Type; - storeInstruction = new Bytecode.StoreArrayElementInstruction(offset, type) {Method = arrayElementAccess.Method}; + storeInstruction = new Bytecode.StoreArrayElementInstruction(instruction.Offset, type) + {Method = arrayElementAccess.Method}; break; } case Dereference dereference: { - storeInstruction = new Bytecode.StoreIndirectInstruction(offset, dereference.Type); + storeInstruction = new Bytecode.StoreIndirectInstruction(instruction.Offset, dereference.Type); break; } case InstanceFieldAccess instanceFieldAccess: - storeInstruction = new Bytecode.StoreFieldInstruction(offset, instanceFieldAccess.Field); + storeInstruction = new Bytecode.StoreFieldInstruction(instruction.Offset, instanceFieldAccess.Field); break; case StaticFieldAccess staticFieldAccess: - storeInstruction = new Bytecode.StoreFieldInstruction(offset, staticFieldAccess.Field); + storeInstruction = new Bytecode.StoreFieldInstruction(instruction.Offset, staticFieldAccess.Field); break; default: throw new Exception(); // TODO msg } - Add(storeInstruction, NextInstructionOffsetFor(instruction)); + translatedInstructions.Add(storeInstruction); } public override void Visit(NopInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Nop); - Add(basicInstruction, NextInstructionOffsetFor(instruction)); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop); + translatedInstructions.Add(basicInstruction); } public override void Visit(BreakpointInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Breakpoint); - Add(basicInstruction, NextInstructionOffsetFor(instruction)); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Breakpoint); + translatedInstructions.Add(basicInstruction); } public override void Visit(TryInstruction instruction) { // try with multiple handlers is modelled as multiple try instructions with the same label but different handlers. - // if label matches with the current try, then increase the number of expected handlers. If not, begin a new try block + // if label matches with the current try, then increase the number of expected handlers. If not, begin a new try block + // FIxme add comment + var offset = bodyToProcess.Instructions + .First(i => i.Offset > instruction.Offset && !(i is TryInstruction)) + .Offset; if (exceptionInformationBuilder.CurrentProtectedBlockStartsAt(offset)) { exceptionInformationBuilder.IncrementCurrentProtectedBlockExpectedHandlers(); @@ -281,31 +286,38 @@ public override void Visit(TryInstruction instruction) public override void Visit(FaultInstruction instruction) { - exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(offset, ExceptionHandlerBlockKind.Fault); + // fixme estas deberian ser offset+1 tmb? replicar comment + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(instruction.Offset+1, ExceptionHandlerBlockKind.Fault); } public override void Visit(FinallyInstruction instruction) { - exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(offset, ExceptionHandlerBlockKind.Finally); + // fixme estas deberian ser offset+1 tmb? + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(instruction.Offset+1, ExceptionHandlerBlockKind.Finally); } public override void Visit(FilterInstruction instruction) { - exceptionInformationBuilder.AddFilterHandlerToCurrentProtectedBlock(offset, instruction.kind, instruction.ExceptionType); + // fixme estas deberian ser offset+1 tmb? + exceptionInformationBuilder.AddFilterHandlerToCurrentProtectedBlock(instruction.Offset+1, instruction.kind, instruction.ExceptionType); } public override void Visit(CatchInstruction instruction) { - exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(offset, ExceptionHandlerBlockKind.Catch, instruction.ExceptionType); + // fixme estas deberian ser offset+1 tmb? replicar comment + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock( + instruction.Offset + 1, + ExceptionHandlerBlockKind.Catch, + instruction.ExceptionType); } public override void Visit(ThrowInstruction instruction) { var basicInstruction = instruction.HasOperand - ? new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Throw) - : new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Rethrow); - Add(basicInstruction, NextInstructionOffsetFor(instruction)); - exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(offset); + ? new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Throw) + : new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Rethrow); + translatedInstructions.Add(basicInstruction); + exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(instruction.Offset + 1); // block ends after instruction } public override void Visit(UnconditionalBranchInstruction instruction) @@ -315,29 +327,34 @@ public override void Visit(UnconditionalBranchInstruction instruction) { case UnconditionalBranchOperation.Leave: { - var branchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Leave, target); - Add(branchInstruction, NextInstructionOffsetFor(instruction)); - exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(offset); + var branchInstruction = + new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Leave, target); + translatedInstructions.Add(branchInstruction); + exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(instruction.Offset + 1); // block ends after instruction break; } case UnconditionalBranchOperation.Branch: { - var branchInstruction = new Bytecode.BranchInstruction(offset, Bytecode.BranchOperation.Branch, target); - Add(branchInstruction, NextInstructionOffsetFor(instruction)); + var branchInstruction = + new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Branch, target); + translatedInstructions.Add(branchInstruction); break; } case UnconditionalBranchOperation.EndFinally: { - var branchInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFinally); - Add(branchInstruction, NextInstructionOffsetFor(instruction)); - exceptionInformationBuilder.EndCurrentProtectedBlockAt(offset); // no more handlers after finally + var branchInstruction = + new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFinally); + translatedInstructions.Add(branchInstruction); + // no more handlers after finally + exceptionInformationBuilder.EndCurrentProtectedBlockAt(instruction.Offset + 1); // 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 - var branchInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.EndFilter); - Add(branchInstruction, NextInstructionOffsetFor(instruction)); + var branchInstruction = + new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFilter); + translatedInstructions.Add(branchInstruction); break; } default: throw instruction.Operation.ToUnknownValueException(); @@ -347,65 +364,68 @@ public override void Visit(UnconditionalBranchInstruction instruction) public override void Visit(ConvertInstruction instruction) { var convertInstruction = new Bytecode.ConvertInstruction( - offset, + instruction.Offset, OperationHelper.ToConvertOperation(instruction.Operation), instruction.ConversionType) { OverflowCheck = instruction.OverflowCheck, UnsignedOperands = instruction.UnsignedOperands, }; - Add(convertInstruction, NextInstructionOffsetFor(instruction)); + translatedInstructions.Add(convertInstruction); } public override void Visit(ReturnInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.Return); - Add(basicInstruction, NextInstructionOffsetFor(instruction)); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Return); + translatedInstructions.Add(basicInstruction); } public override void Visit(ConditionalBranchInstruction instruction) { var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); var branchInstruction = new Bytecode.BranchInstruction( - offset, + instruction.Offset, OperationHelper.ToBranchOperation(instruction.Operation, instruction.RightOperand), target); - Add(branchInstruction, NextInstructionOffsetFor(instruction)); + translatedInstructions.Add(branchInstruction); } public override void Visit(SwitchInstruction instruction) { - var targets = instruction.Targets.Select(target => Convert.ToUInt32(target.Substring(2), 16)).ToList(); - var switchInstruction = new Bytecode.SwitchInstruction(offset, targets); - Add(switchInstruction, NextInstructionOffsetFor(instruction)); + var targets = instruction.Targets + .Select(target => Convert.ToUInt32(target.Substring(2), 16)) + .ToList(); + var switchInstruction = new Bytecode.SwitchInstruction(instruction.Offset, targets); + translatedInstructions.Add(switchInstruction); } public override void Visit(SizeofInstruction instruction) { - var sizeofInstruction = new Bytecode.SizeofInstruction(offset, instruction.MeasuredType); - Add(sizeofInstruction, NextInstructionOffsetFor(instruction)); + var sizeofInstruction = new Bytecode.SizeofInstruction(instruction.Offset, instruction.MeasuredType); + translatedInstructions.Add(sizeofInstruction); } public override void Visit(LoadTokenInstruction instruction) { - var loadTokenInstruction = new Bytecode.LoadTokenInstruction(offset, instruction.Token); - Add(loadTokenInstruction, NextInstructionOffsetFor(instruction)); + var loadTokenInstruction = new Bytecode.LoadTokenInstruction(instruction.Offset, instruction.Token); + translatedInstructions.Add(loadTokenInstruction); } public override void Visit(MethodCallInstruction instruction) { var methodCallInstruction = new Bytecode.MethodCallInstruction( - offset, + instruction.Offset, OperationHelper.ToMethodCallOperation(instruction.Operation), instruction.Method ); - Add(methodCallInstruction, NextInstructionOffsetFor(instruction)); + translatedInstructions.Add(methodCallInstruction); } public override void Visit(IndirectMethodCallInstruction instruction) { - var indirectMethodCallInstruction = new Bytecode.IndirectMethodCallInstruction(offset, instruction.Function); - Add(indirectMethodCallInstruction, NextInstructionOffsetFor(instruction)); + var indirectMethodCallInstruction = + new Bytecode.IndirectMethodCallInstruction(instruction.Offset, instruction.Function); + translatedInstructions.Add(indirectMethodCallInstruction); } public override void Visit(CreateObjectInstruction instruction) @@ -415,67 +435,58 @@ public override void Visit(CreateObjectInstruction instruction) ignoreInstruction.Add(index + 1, true); // method call ignoreInstruction.Add(index + 2, true); // load - var createObjectInstruction = new Bytecode.CreateObjectInstruction(offset, methodCallInstruction.Method); - var nextInstructionOffset = NextInstructionOffsetFor((Instruction) bodyToProcess.Instructions[index + 3]); - Add(createObjectInstruction, nextInstructionOffset); + var createObjectInstruction = + new Bytecode.CreateObjectInstruction(instruction.Offset, methodCallInstruction.Method); + translatedInstructions.Add(createObjectInstruction); } public override void Visit(CopyMemoryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.CopyBlock); - Add(basicInstruction, NextInstructionOffsetFor(instruction)); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyBlock); + translatedInstructions.Add(basicInstruction); } public override void Visit(LocalAllocationInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.LocalAllocation); - Add(basicInstruction, NextInstructionOffsetFor(instruction)); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LocalAllocation); + translatedInstructions.Add(basicInstruction); } public override void Visit(InitializeMemoryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.InitBlock); - Add(basicInstruction, NextInstructionOffsetFor(instruction)); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.InitBlock); + translatedInstructions.Add(basicInstruction); } public override void Visit(InitializeObjectInstruction instruction) { - var initObjInstruction = new Bytecode.InitObjInstruction(offset, instruction.TargetAddress.Type); - Add(initObjInstruction, NextInstructionOffsetFor(instruction)); + var initObjInstruction = new Bytecode.InitObjInstruction(instruction.Offset, instruction.TargetAddress.Type); + translatedInstructions.Add(initObjInstruction); } public override void Visit(CopyObjectInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(offset, Bytecode.BasicOperation.CopyObject); - Add(basicInstruction, NextInstructionOffsetFor(instruction)); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyObject); + translatedInstructions.Add(basicInstruction); } public override void Visit(CreateArrayInstruction instruction) { var arrayType = new ArrayType(instruction.ElementType, instruction.Rank); - var createArrayInstruction = new Bytecode.CreateArrayInstruction(offset, arrayType) + var createArrayInstruction = new Bytecode.CreateArrayInstruction(instruction.Offset, arrayType) { WithLowerBound = instruction.LowerBounds.Any(), Constructor = instruction.Constructor }; - Add(createArrayInstruction, NextInstructionOffsetFor(instruction)); + translatedInstructions.Add(createArrayInstruction); } public override void Visit(PhiInstruction instruction) => throw new Exception(); public override void Visit(ConstrainedInstruction instruction) { - var constrainedInstruction = new Bytecode.ConstrainedInstruction(offset, instruction.ThisType); - Add(constrainedInstruction, NextInstructionOffsetFor(instruction)); - } - - // FIXME mmm medio medio esto - private uint NextInstructionOffsetFor(Instruction instruction) - { - var indexOf = bodyToProcess.Instructions.IndexOf(instruction) + 1; - return indexOf == bodyToProcess.Instructions.Count - ? instruction.Offset - : bodyToProcess.Instructions[indexOf].Offset; + var constrainedInstruction = new Bytecode.ConstrainedInstruction(instruction.Offset, instruction.ThisType); + translatedInstructions.Add(constrainedInstruction); } } } diff --git a/Backend/Transformations/Assembly/CilInstructionSizeCalculator.cs b/Backend/Transformations/Assembly/CilInstructionSizeCalculator.cs deleted file mode 100644 index fef9cfeb..00000000 --- a/Backend/Transformations/Assembly/CilInstructionSizeCalculator.cs +++ /dev/null @@ -1,344 +0,0 @@ -using System; -using Model; -using Model.Bytecode; -using Model.ThreeAddressCode.Values; -using Model.Types; - -namespace Backend.Transformations.Assembly -{ - public static class CilInstructionSizeCalculator - { - public static uint SizeOf(Instruction instruction, uint nexInstructionOffset) - { - switch (instruction) - { - case BasicInstruction basicInstruction: return SizeOf(basicInstruction); - case ConstrainedInstruction constrainedInstruction: return SizeOf(constrainedInstruction); - case CreateArrayInstruction createArrayInstruction: return SizeOf(createArrayInstruction); - case InitObjInstruction initObjInstruction: return SizeOf(initObjInstruction); - case CreateObjectInstruction createObjectInstruction: return SizeOf(createObjectInstruction); - case IndirectMethodCallInstruction indirectMethodCallInstruction: return SizeOf(indirectMethodCallInstruction); - case MethodCallInstruction methodCallInstruction: return SizeOf(methodCallInstruction); - case LoadTokenInstruction loadTokenInstruction: return SizeOf(loadTokenInstruction); - case SizeofInstruction sizeofInstruction: return SizeOf(sizeofInstruction); - case SwitchInstruction switchInstruction: return SizeOf(switchInstruction); - case ConvertInstruction convertInstruction: return SizeOf(convertInstruction); - case StoreIndirectInstruction storeIndirectInstruction: return SizeOf(storeIndirectInstruction); - case StoreFieldInstruction storeFieldInstruction: return SizeOf(storeFieldInstruction); - case StoreArrayElementInstruction storeArrayElementInstruction: return SizeOf(storeArrayElementInstruction); - case BranchInstruction branchInstruction: return SizeOf(branchInstruction, nexInstructionOffset); - case StoreInstruction storeInstruction: return SizeOf(storeInstruction); - case LoadInstruction loadInstruction: return SizeOf(loadInstruction); - case LoadIndirectInstruction loadIndirectInstruction: return SizeOf(loadIndirectInstruction); - case LoadArrayElementInstruction loadArrayElementInstruction: return SizeOf(loadArrayElementInstruction); - case LoadFieldInstruction loadFieldInstruction: return SizeOf(loadFieldInstruction); - case LoadMethodAddressInstruction loadMethodAddressInstruction: return SizeOf(loadMethodAddressInstruction); - default: throw new Exception(); // TODO - } - } - - private static uint SizeOf(LoadMethodAddressInstruction loadMethodAddressInstruction) - { - // ldvirtftn method -> FE 07 (2 + 4) - // ldftn method -> FE 06 (2 + 4) - switch (loadMethodAddressInstruction.Operation) - { - case LoadMethodAddressOperation.Static: - case LoadMethodAddressOperation.Virtual: - return 6; - default: - throw new ArgumentOutOfRangeException(); - } - } - - private static uint SizeOf(LoadFieldInstruction loadFieldInstruction) - { - // ldfld field -> 7B (1 + 4) - // ldsfld field -> 7E (1 + 4) - // ldflda field -> 0x7C (1 + 4) - // ldsflda field -> 0x7F (1 + 4) - switch (loadFieldInstruction.Operation) - { - case LoadFieldOperation.Content: - case LoadFieldOperation.Address: return 5; - default: throw new ArgumentOutOfRangeException(); - } - } - - private static uint SizeOf(LoadArrayElementInstruction loadArrayElementInstruction) - { - switch (loadArrayElementInstruction.Operation) - { - case LoadArrayElementOperation.Content: - var type = loadArrayElementInstruction.Array; - if (type.IsVector && - (type.ElementsType.IsIntType() || - type.ElementsType.IsFloatType() || - type.ElementsType.Equals(PlatformTypes.IntPtr) || - type.ElementsType.Equals(PlatformTypes.Object))) - { - // 1 byte opcode - return 1; - } - else - { - // ldelem typeTok -> A3 (1 + 4) - return 5; - } - case LoadArrayElementOperation.Address: - // ldelema typeTok -> 8F (1 + 4) - // ldobj typeTok -> 71 (1 + 4) - return 5; - default: - throw new ArgumentOutOfRangeException(); - // FIXME quiza puedo usar esta que es la defualt para estos casos siempre para el caso default en vez de hacer una yo - } - } - - private static uint SizeOf(LoadIndirectInstruction loadIndirectInstruction) - { - var type = loadIndirectInstruction.Type; - return (uint) (type.IsIntType() || type.IsFloatType() || type.Equals(PlatformTypes.IntPtr) || type.Equals(PlatformTypes.Object) - ? 1 // 1 byte opcode - : 5); // ldobj typeTok -> 71 (1 + 4) - } - - private static uint SizeOf(LoadInstruction loadInstruction) - { - switch (loadInstruction.Operation) - { - case LoadOperation.Value: - var constant = (Constant) loadInstruction.Operand; - switch (constant.Value) - { - case -1: - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case null: - return 1; // ldnull -> 14 (1) - case string _: - return 5; // ldstr string -> 72 (1 + 4) - case object _ when constant.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.Int16, PlatformTypes.Int32): - { - // ldc.i4.s num -> 1F (1 + 1) - // ldc.i4 num -> 20 (1 + 4) - var value = (int) constant.Value; - return (uint) (value >= sbyte.MinValue && value <= sbyte.MaxValue ? 2 : 5); - } - case object _ when constant.Type.Equals(PlatformTypes.Int64): return 9; // ldc.i8 num-> 21 (1 + 8) - case object _ when constant.Type.IsOneOf(PlatformTypes.UInt8, PlatformTypes.UInt16, PlatformTypes.UInt32): - { - // ldc.i4.s num -> 1F (1 + 1) - // ldc.i4 num -> 20 (1 + 4) - var value = (uint) constant.Value; - return (uint) (value <= byte.MaxValue ? 2 : 5); - } - case object _ when constant.Type.Equals(PlatformTypes.UInt64): return 9; // ldc.i8 num-> 21 (1 + 8) - case object _ when constant.Type.Equals(PlatformTypes.Float32): return 5; // ldc.r4 num -> 22 (1 + 4) - case object _ when constant.Type.Equals(PlatformTypes.Float64): return 9; // ldc.r8 num -> 23 (1 + 8) - default: throw new Exception(); - } - - case LoadOperation.Content: - { - var localVariable = (LocalVariable) loadInstruction.Operand; - switch (localVariable.Index) - { - // ldloc.0,1,2,3 ldarg.0,1,2,3 - case 0: - case 1: - case 2: - case 3: - return 1; - default: - // ldloc indx -> FE 0C (2 + 2) - // ldloc.s indx -> 11 (1 + 1) - // ldarg num -> FE 09 (2 + 2) - // ldarg.s num -> 0E (1 + 1) - return (uint) (localVariable.Index > byte.MaxValue ? 4 : 2); - } - } - case LoadOperation.Address: - { - // ldloca indx -> FE 0D (2 + 2) - // ldloca.s indx -> 12 (1 + 1) - // ldarga argNum -> FE 0A (2 + 2) - // ldarga.s argNum -> 0F (1 + 1) - var localVariable = (LocalVariable) loadInstruction.Operand; - return (uint) (localVariable.Index > byte.MaxValue ? 4 : 2); - } - default: throw new Exception(); // TODO - } - } - - private static uint SizeOf(StoreInstruction storeInstruction) - { - var local = (LocalVariable) storeInstruction.Target; - if (local.IsParameter) - { - // starg num -> FE 0B (2 + 2) - // starg.s num -> 10 (1 + 1) - return (uint) (local.Index > byte.MaxValue ? 4 : 2); - } - else - { - switch (local.Index) - { - case 0: - case 1: - case 2: - case 3: - return 1; // 1byte OpCode - default: - // stloc indx -> FE 0E (2 + 2) - // stloc.s indx -> 13 (1 + 1) - return (uint) (local.Index > byte.MaxValue ? 4 : 2); - } - } - } - // leave target -> DD (1 + 4) - // leave.s target -> DE (1 + 1) - // br target -> 38 (1 + 4) - // br.s target -> 2B (1 + 1) - // br* target -> 1ByteOpcode (1 + 4) - // br*.s target -> 1ByteOpcode (1 + 1) - - private static uint SizeOf(this BranchInstruction branchInstruction, uint nextInstructionOffset) - { - // short forms are 1 byte opcode + 1 byte target. normal forms are 1 byte opcode + 4 byte target - var isShortForm = nextInstructionOffset - branchInstruction.Offset == 2; - return (uint) (isShortForm ? 2 : 5); - } - - private static uint SizeOf(StoreArrayElementInstruction storeArrayElementInstruction) - { - var type = storeArrayElementInstruction.Array; - if (type.IsVector && - (type.ElementsType.IsIntType() || - type.ElementsType.IsFloatType() || - type.ElementsType.Equals(PlatformTypes.IntPtr) || - type.ElementsType.Equals(PlatformTypes.Object))) - { - // 1 byte opcode - return 1; - } - else - { - // stelem typeTok -> A4 (1 + 4) - return 5; - } - } - - // stfld field -> 7D (1 + 4) - // stsfld field -> 80 (1 + 4) - private static uint SizeOf(StoreFieldInstruction storeFieldInstruction) => 5; - - private static uint SizeOf(StoreIndirectInstruction storeIndirectInstruction) - { - var type = storeIndirectInstruction.Type; - if (type.IsIntType() || type.IsFloatType() || type.Equals(PlatformTypes.IntPtr) || type.Equals(PlatformTypes.Object)) - { - // 1 byte opcode - return 1; - } - else - { - // stobj typeTok -> 81 (1 + 4) - return 5; - } - } - - private static uint SizeOf(ConvertInstruction convertInstruction) - { - switch (convertInstruction.Operation) - { - case ConvertOperation.Conv: - return 1; // 1 Byte OpCode - case ConvertOperation.IsInst: - case ConvertOperation.Cast: - case ConvertOperation.Box: - case ConvertOperation.Unbox: - case ConvertOperation.UnboxPtr: - // box typeTok -> 8C (1 + 4) - // castclass typeTok -> 74 (1 + 4) - // isinst typeTok -> 75 (1 + 4) - // unbox valuetype -> 79 (1 + 4) - // unbox.any typeTok -> A5 (1 + 4) - return 5; - default: throw new Exception(); - } - } - - // switch number t1 t2 t3 ... -> 45 .... (1 + 4 + n*4) - private static uint SizeOf(SwitchInstruction switchInstruction) => (uint) (1 + 4 + 4 * switchInstruction.Targets.Count); - - // sizeof typetok -> FE 1C (2 + 4) - private static uint SizeOf(SizeofInstruction sizeofInstruction) => 6; - - private static uint SizeOf(LoadTokenInstruction loadTokenInstruction) => 5; // ldtoken token -> D0 (1 + 4) - - // call method -> 28 (1 + 4) - // callvirt method -> 6F (1 + 4) - private static uint SizeOf(MethodCallInstruction methodCallInstruction) => 5; - - private static uint SizeOf(IndirectMethodCallInstruction indirectMethodCallInstruction) => 5; // calli callsitedescr -> 29 (1 + 4) - - private static uint SizeOf(CreateObjectInstruction createObjectInstruction) => 5; // newobj ctor -> 73 (1 + 4) - - private static uint SizeOf(InitObjInstruction initObjInstruction) => 6; // initobj typeTok -> FE 15 (2 + 4) - - // newobj ctor -> 73 (1 + 4) - // newarr etype -> 8D (1 + 4) - private static uint SizeOf(CreateArrayInstruction createArrayInstruction) => 5; - - private static uint SizeOf(ConstrainedInstruction constrainedInstruction) => 6; // constrained. thisType -> FE 16 (2 + 4) - - private static uint SizeOf(this BasicInstruction instruction) // fixme rename - { - switch (instruction.Operation) - { - case BasicOperation.Add: - case BasicOperation.Sub: - case BasicOperation.Mul: - case BasicOperation.Div: - case BasicOperation.Rem: - case BasicOperation.And: - case BasicOperation.Or: - case BasicOperation.Xor: - case BasicOperation.Shl: - case BasicOperation.Shr: - case BasicOperation.Not: - case BasicOperation.Neg: - case BasicOperation.Nop: - case BasicOperation.Pop: - case BasicOperation.Dup: - case BasicOperation.EndFinally: - case BasicOperation.Throw: - case BasicOperation.LoadArrayLength: - case BasicOperation.Breakpoint: - case BasicOperation.Return: - return 1; // 1 Byte OpCode - case BasicOperation.Eq: - case BasicOperation.Lt: - case BasicOperation.Gt: - case BasicOperation.Rethrow: - case BasicOperation.EndFilter: - case BasicOperation.LocalAllocation: - case BasicOperation.InitBlock: - case BasicOperation.CopyBlock: - return 2; // 2 Byte OpCode - case BasicOperation.CopyObject: - return 5; // cpobj typeTok-> 70 (1 + 4) - default: - throw new ArgumentOutOfRangeException(); - } - } - } -} \ No newline at end of file diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index d2f7a0bb..65e66b0e 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -955,7 +955,7 @@ 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); +// body.ExceptionInformation.AddRange(method.Body.ExceptionInformation); fixme creo que esto no habria que hacerlo, ya que en tac son instrucciones todo lo del exception handling if (method.Body.Instructions.Count > 0) { @@ -1014,6 +1014,8 @@ public MethodBody Execute() //body.LocalVariables.AddRange(stack.Variables); body.UpdateVariables(); } + + new TacUniqueLabelGenerator(body.Instructions.Cast().ToList()).Execute(); return body; } diff --git a/Backend/Transformations/TacUniqueLabelGenerator.cs b/Backend/Transformations/TacUniqueLabelGenerator.cs new file mode 100644 index 00000000..3e0728f7 --- /dev/null +++ b/Backend/Transformations/TacUniqueLabelGenerator.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.Linq; +using Model; +using Model.ThreeAddressCode.Instructions; + +namespace Backend.Transformations +{ + public class TacUniqueLabelGenerator + { + private readonly IList instructions; + private uint offset; + + public TacUniqueLabelGenerator(IList instructions) + { + this.instructions = instructions; + } + + // FIXME Si esto anda, documentar donde se usa, esto de que para agregar isntrucciones hay que agregarlas con el mismo label + // de la instruccion anterior a donde agrego, etc + // ver ademas si tiene sentido hacerlo aca, o mientras se genera el tac. Tener en cuenta que las instrumentaciones se harian + // post generacion del tac. + // FIXME se puede optimizar? son varias pasadas sino por las instrucciones + public void Execute() + { + var originalTargets = new HashSet(); + foreach (var instruction in instructions) + { + switch (instruction) + { + case BranchInstruction branchInstruction: + originalTargets.Add(branchInstruction.Target); + break; + case SwitchInstruction switchInstruction: + originalTargets.AddRange(switchInstruction.Targets); + break; + } + } + + var newBranchTargets = new Dictionary(); + + foreach (var instruction in instructions) + { + // fixme lo de chequear que no este es para no pisarla si es una repetida + if (originalTargets.Contains(instruction.Label) && !newBranchTargets.TryGetValue(instruction.Label, out _)) + { + newBranchTargets[instruction.Label] = string.Format("L_{0:X4}", offset); + } + + instruction.Offset = offset; + instruction.Label = string.Format("L_{0:X4}", offset); + offset++; + } + + foreach (var instruction in instructions) + { + // FIXME esto es porque no necesariamente necesita traduccion. Ejemplo, hay algunas branch que saltan al siguiente entonces + // hay mas casos? Esta bien esto? + switch (instruction) + { + case BranchInstruction branchInstruction: + { + if (newBranchTargets.TryGetValue(branchInstruction.Target, out var newTarget)) + { + branchInstruction.Target = newTarget; + } + + break; + } + case SwitchInstruction switchInstruction: + switchInstruction.Targets = switchInstruction.Targets + .Select(target => newBranchTargets.TryGetValue(target, out var newTarget) + ? newTarget + : target) + .ToList(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index c8ea2495..b03b82bc 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; +using System.Linq; using MetadataGenerator.Metadata; using Model; using Model.Bytecode; using ECMA335 = System.Reflection.Metadata.Ecma335; +using SwitchInstruction = Model.ThreeAddressCode.Instructions.SwitchInstruction; namespace MetadataGenerator.Generators.Methods.Body { @@ -31,7 +33,7 @@ public ECMA335.LabelHandle LabelHandleFor(string label) } // FIXME name, quiza hacer tmb con las exception information asi es mas prolijo? y despues en el labelHandle solo levantarla y nunca crearla - public void DefineNeededBranchLabels(IList instructions) + public void DefineNeededLabels(IList instructions) { foreach (var instruction in instructions) { @@ -39,12 +41,19 @@ public void DefineNeededBranchLabels(IList instructions) { LabelHandleFor(branchInstruction.Target); } + else if (instruction is SwitchInstruction switchInstruction) + { + foreach (var target in switchInstruction.Targets) + { + LabelHandleFor(target); + } + } } } - public void MarkCurrentLabel() + public void MarkCurrentLabelIfNeeded(string label) { - if (labelHandles.TryGetValue(instructionEncoder.CurrentLabelString(), out var labelHandle)) + if (labelHandles.TryGetValue(label.ToLower(), out var labelHandle)) { instructionEncoder.MarkLabel(labelHandle); } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 4b22c498..e9149906 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -25,12 +25,14 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), new ECMA335.ControlFlowBuilder()); var controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); - controlFlowGenerator.DefineNeededBranchLabels(body.Instructions); + controlFlowGenerator.DefineNeededLabels(body.Instructions); foreach (var instruction in body.Instructions) { - controlFlowGenerator.MarkCurrentLabel(); - if (instruction.Offset != instructionEncoder.Offset) throw new Exception("Real offset does not match with expected one"); + controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); + // FIXME sacar + // if (instruction.Offset != instructionEncoder.Offset) throw new Exception("Real offset does not match with expected one"); se iria + // y se va tambien lo de que mmiro los labels del branch para saber? deberia irse tmb mepa porque ahora los labels ahora no incluyen los offsets switch (instruction) { @@ -153,11 +155,8 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case BranchInstruction branchInstruction: { SRM.ILOpCode opCode; - var nextInstructionOffset = - Convert.ToInt32(body.Instructions[body.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); - var currentInstructionOffset = Convert.ToInt32(branchInstruction.Label.Substring(2), 16); - // short forms are 1 byte opcode + 1 byte target. normal forms are 1 byte opcode + 4 byte target - var isShortForm = nextInstructionOffset - currentInstructionOffset == 2; + var isShortForm = false; + // FIXME logica de saber si es short o no. Mirando el target deberia salir. Leer bien el ecma de estas intrucciones switch (branchInstruction.Operation) { case BranchOperation.False: @@ -226,7 +225,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) throw new UnhandledCase(); } - instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(branchInstruction.Target)); break; @@ -634,13 +632,15 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case SwitchInstruction switchInstruction: { - var nextInstructionOffset = - Convert.ToInt32(body.Instructions[body.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); + // FIXME revisar pero casi seguro de que esto era cualquiera. Leer ecma. Como se lee no quiere decir que haya que restarle o si? + // FIXME probar con algun ejemplo +// var nextInstructionOffset = + // Convert.ToInt32(body.Instructions[body.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); instructionEncoder.OpCode(SRM.ILOpCode.Switch); instructionEncoder.Token(switchInstruction.Targets.Count); switchInstruction.Targets .Select(label => Convert.ToInt32(label.Substring(2), 16)) - .Select(targetOffset => targetOffset - nextInstructionOffset) + // .Select(targetOffset => targetOffset - nextInstructionOffset) .ToList() .ForEach(instructionEncoder.Token); break; diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 337305c9..3c5e1ad8 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -38,7 +38,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) if (method.HasBody) { // FIXME undo this. Just for testing assembler - // var og = method.Body; + var og = method.Body; var tac = new Backend.Transformations.Disassembler(method).Execute(); method.Body = tac; var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); diff --git a/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index 3747df7b..39c1d6d7 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -860,7 +860,7 @@ public override string ToString() public class SwitchInstruction : Instruction { public IVariable Operand { get; set; } - public IList Targets { get; private set; } + public IList Targets { get; set; } public SwitchInstruction(uint offset, IVariable operand, IEnumerable targets) : base(offset) From ecf18569269f66dfbcdcd36becf0887b2a9dc9b3 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 22 Jul 2020 08:54:49 -0300 Subject: [PATCH 186/256] fix switch generation --- .../Methods/Body/MethodBodyGenerator.cs | 73 +++++++++++++++---- .../Generators/Methods/MethodGenerator.cs | 7 +- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index e9149906..919a3f27 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,5 +1,5 @@ using System; -using System.Globalization; +using System.Collections.Generic; using System.Linq; using MetadataGenerator.Metadata; using Model; @@ -26,14 +26,15 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); controlFlowGenerator.DefineNeededLabels(body.Instructions); + var labelToEncoderOffset = new Dictionary(); + var switchInstructionsPlaceHolders = new List(); foreach (var instruction in body.Instructions) { - controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); - // FIXME sacar - // if (instruction.Offset != instructionEncoder.Offset) throw new Exception("Real offset does not match with expected one"); se iria - // y se va tambien lo de que mmiro los labels del branch para saber? deberia irse tmb mepa porque ahora los labels ahora no incluyen los offsets + labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; + + controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); switch (instruction) { case BasicInstruction basicInstruction: @@ -155,8 +156,9 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case BranchInstruction branchInstruction: { SRM.ILOpCode opCode; + // FIXME sacar lo de short form y explicar que no puedo hacerlo bien ya que no conozco bien los labels y demas. + // (al menos en el caso de volver del tac) var isShortForm = false; - // FIXME logica de saber si es short o no. Mirando el target deberia salir. Leer bien el ecma de estas intrucciones switch (branchInstruction.Operation) { case BranchOperation.False: @@ -632,17 +634,20 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case SwitchInstruction switchInstruction: { - // FIXME revisar pero casi seguro de que esto era cualquiera. Leer ecma. Como se lee no quiere decir que haya que restarle o si? - // FIXME probar con algun ejemplo -// var nextInstructionOffset = - // Convert.ToInt32(body.Instructions[body.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); + // fixme comments explicando + var targetsCount = switchInstruction.Targets.Count; instructionEncoder.OpCode(SRM.ILOpCode.Switch); - instructionEncoder.Token(switchInstruction.Targets.Count); - switchInstruction.Targets - .Select(label => Convert.ToInt32(label.Substring(2), 16)) - // .Select(targetOffset => targetOffset - nextInstructionOffset) - .ToList() - .ForEach(instructionEncoder.Token); + instructionEncoder.Token(targetsCount); + var placeholderTargetsSection = instructionEncoder.CodeBuilder.ReserveBytes(sizeof(int) * targetsCount); + + switchInstructionsPlaceHolders.Add( + new SwitchInstructionPlaceholderInfo( + instructionEncoder.Offset, + placeholderTargetsSection, + switchInstruction.Targets, + labelToEncoderOffset + ) + ); break; } case SizeofInstruction sizeofInstruction: @@ -806,8 +811,44 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } } + foreach (var switchInstructionPlaceholder in switchInstructionsPlaceHolders) + { + switchInstructionPlaceholder.WriteRealTargets(); + } + return instructionEncoder; } + + private class SwitchInstructionPlaceholderInfo //FIXME rename + { + private readonly SRM.Blob blob; + private readonly IList targets; + private readonly IDictionary labelToEncoderOffset; + private readonly int nextInstructionOffset; + + public SwitchInstructionPlaceholderInfo( + int nextInstructionOffset, + SRM.Blob blob, + IList targets, + IDictionary labelToEncoderOffset) + { + this.nextInstructionOffset = nextInstructionOffset; + this.blob = blob; + this.targets = targets; + this.labelToEncoderOffset = labelToEncoderOffset; + } + + public void WriteRealTargets() // fixme rename + { + var writer = new SRM.BlobWriter(blob); + foreach (var target in targets) + { + // switch targets are offsets relative to the beginning of the next instruction. + var offset = labelToEncoderOffset[target] - nextInstructionOffset; + writer.WriteInt32(offset); + } + } + } } internal class UnhandledCase : Exception diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 3c5e1ad8..7f78f2b7 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -1,6 +1,8 @@ -using Backend.Transformations.Assembly; +using System.Linq; +using Backend.Transformations.Assembly; using MetadataGenerator.Generators.Methods.Body; using MetadataGenerator.Metadata; +using Model.Bytecode; using Model.Types; using static MetadataGenerator.Metadata.AttributesProvider; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -37,7 +39,8 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var methodBodyOffset = -1; if (method.HasBody) { - // FIXME undo this. Just for testing assembler + // FIXME undo this. Just for testing assembler. + // TODO probar que anda con y sin transofmracion del tac var og = method.Body; var tac = new Backend.Transformations.Disassembler(method).Execute(); method.Body = tac; From b9de51570771292e4e441b4d8494f7abc813c60e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 22 Jul 2020 20:21:45 -0300 Subject: [PATCH 187/256] draft --- Backend/Backend.csproj | 2 +- Backend/Transformations/Disassembler.cs | 4 +- ...nerator.cs => TacUniqueLabelsGenerator.cs} | 27 +++++------ .../Body/MethodBodyControlFlowGenerator.cs | 9 ---- .../Methods/Body/MethodBodyGenerator.cs | 48 ++++++++----------- 5 files changed, 33 insertions(+), 57 deletions(-) rename Backend/Transformations/{TacUniqueLabelGenerator.cs => TacUniqueLabelsGenerator.cs} (62%) diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj index 0d833003..a1ef2204 100644 --- a/Backend/Backend.csproj +++ b/Backend/Backend.csproj @@ -70,7 +70,7 @@ - + diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 65e66b0e..9e136759 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; @@ -1015,7 +1013,7 @@ public MethodBody Execute() body.UpdateVariables(); } - new TacUniqueLabelGenerator(body.Instructions.Cast().ToList()).Execute(); + new TacUniqueLabelsGenerator(body.Instructions.Cast().ToList()).Execute(); return body; } diff --git a/Backend/Transformations/TacUniqueLabelGenerator.cs b/Backend/Transformations/TacUniqueLabelsGenerator.cs similarity index 62% rename from Backend/Transformations/TacUniqueLabelGenerator.cs rename to Backend/Transformations/TacUniqueLabelsGenerator.cs index 3e0728f7..68450087 100644 --- a/Backend/Transformations/TacUniqueLabelGenerator.cs +++ b/Backend/Transformations/TacUniqueLabelsGenerator.cs @@ -5,24 +5,23 @@ namespace Backend.Transformations { - public class TacUniqueLabelGenerator + public class TacUniqueLabelsGenerator { private readonly IList instructions; private uint offset; - public TacUniqueLabelGenerator(IList instructions) + public TacUniqueLabelsGenerator(IList instructions) { this.instructions = instructions; } - // FIXME Si esto anda, documentar donde se usa, esto de que para agregar isntrucciones hay que agregarlas con el mismo label + // FIXME documentar donde se usa, esto de que para agregar isntrucciones hay que agregarlas con el mismo label // de la instruccion anterior a donde agrego, etc - // ver ademas si tiene sentido hacerlo aca, o mientras se genera el tac. Tener en cuenta que las instrumentaciones se harian - // post generacion del tac. // FIXME se puede optimizar? son varias pasadas sino por las instrucciones public void Execute() { var originalTargets = new HashSet(); + var newTargets = new Dictionary(); foreach (var instruction in instructions) { switch (instruction) @@ -36,30 +35,28 @@ public void Execute() } } - var newBranchTargets = new Dictionary(); - + // generate unique labels for all instructions and gather new target labels foreach (var instruction in instructions) { - // fixme lo de chequear que no este es para no pisarla si es una repetida - if (originalTargets.Contains(instruction.Label) && !newBranchTargets.TryGetValue(instruction.Label, out _)) + var newLabel = $"L_{offset:X4}"; + if (originalTargets.Contains(instruction.Label) && !newTargets.TryGetValue(instruction.Label, out _)) { - newBranchTargets[instruction.Label] = string.Format("L_{0:X4}", offset); + newTargets[instruction.Label] = newLabel; } instruction.Offset = offset; - instruction.Label = string.Format("L_{0:X4}", offset); + instruction.Label = newLabel; offset++; } + // replace old targets foreach (var instruction in instructions) { - // FIXME esto es porque no necesariamente necesita traduccion. Ejemplo, hay algunas branch que saltan al siguiente entonces - // hay mas casos? Esta bien esto? switch (instruction) { case BranchInstruction branchInstruction: { - if (newBranchTargets.TryGetValue(branchInstruction.Target, out var newTarget)) + if (newTargets.TryGetValue(branchInstruction.Target, out var newTarget)) { branchInstruction.Target = newTarget; } @@ -68,7 +65,7 @@ public void Execute() } case SwitchInstruction switchInstruction: switchInstruction.Targets = switchInstruction.Targets - .Select(target => newBranchTargets.TryGetValue(target, out var newTarget) + .Select(target => newTargets.TryGetValue(target, out var newTarget) ? newTarget : target) .ToList(); diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index b03b82bc..0d8ac59f 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -1,10 +1,8 @@ using System.Collections.Generic; -using System.Linq; using MetadataGenerator.Metadata; using Model; using Model.Bytecode; using ECMA335 = System.Reflection.Metadata.Ecma335; -using SwitchInstruction = Model.ThreeAddressCode.Instructions.SwitchInstruction; namespace MetadataGenerator.Generators.Methods.Body { @@ -41,13 +39,6 @@ public void DefineNeededLabels(IList instructions) { LabelHandleFor(branchInstruction.Target); } - else if (instruction is SwitchInstruction switchInstruction) - { - foreach (var target in switchInstruction.Targets) - { - LabelHandleFor(target); - } - } } } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 919a3f27..3d7769a5 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using MetadataGenerator.Metadata; using Model; using Model.Bytecode; @@ -27,13 +26,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); controlFlowGenerator.DefineNeededLabels(body.Instructions); var labelToEncoderOffset = new Dictionary(); - var switchInstructionsPlaceHolders = new List(); + var switchInstructionsPlaceHolders = new List(); foreach (var instruction in body.Instructions) { labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; - - controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); switch (instruction) { @@ -634,20 +631,18 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case SwitchInstruction switchInstruction: { - // fixme comments explicando + // switch is encoded as OpCode NumberOfTargets target1, target2, .... + // the targets in SwitchInstruction are labels that refer to the Instructions in the method body + // but when encoded they must be be offsets relative to the instructionEncoder offsets (real Cil offsets) + // this offsets can't be determined until the whole body is generated so a space is reserved for the targets and filled up later var targetsCount = switchInstruction.Targets.Count; instructionEncoder.OpCode(SRM.ILOpCode.Switch); instructionEncoder.Token(targetsCount); - var placeholderTargetsSection = instructionEncoder.CodeBuilder.ReserveBytes(sizeof(int) * targetsCount); - - switchInstructionsPlaceHolders.Add( - new SwitchInstructionPlaceholderInfo( - instructionEncoder.Offset, - placeholderTargetsSection, - switchInstruction.Targets, - labelToEncoderOffset - ) - ); + var switchInstructionPlaceholder = new SwitchInstructionPlaceholder( + instructionEncoder.Offset, + instructionEncoder.CodeBuilder.ReserveBytes(sizeof(int) * targetsCount), + switchInstruction.Targets); + switchInstructionsPlaceHolders.Add(switchInstructionPlaceholder); break; } case SizeofInstruction sizeofInstruction: @@ -813,38 +808,33 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) foreach (var switchInstructionPlaceholder in switchInstructionsPlaceHolders) { - switchInstructionPlaceholder.WriteRealTargets(); + switchInstructionPlaceholder.FillWithRealTargets(labelToEncoderOffset); } return instructionEncoder; } - private class SwitchInstructionPlaceholderInfo //FIXME rename + private class SwitchInstructionPlaceholder { + private readonly int nextInstructionEncoderOffset; private readonly SRM.Blob blob; private readonly IList targets; - private readonly IDictionary labelToEncoderOffset; - private readonly int nextInstructionOffset; - - public SwitchInstructionPlaceholderInfo( - int nextInstructionOffset, - SRM.Blob blob, - IList targets, - IDictionary labelToEncoderOffset) + + public SwitchInstructionPlaceholder(int nextInstructionEncoderOffset, SRM.Blob blob, IList targets) { - this.nextInstructionOffset = nextInstructionOffset; + this.nextInstructionEncoderOffset = nextInstructionEncoderOffset; this.blob = blob; this.targets = targets; - this.labelToEncoderOffset = labelToEncoderOffset; } - public void WriteRealTargets() // fixme rename + // labelToEncoderOffset is the translation of method body labels to the real cil offsets after generation + public void FillWithRealTargets(IDictionary labelToEncoderOffset) { var writer = new SRM.BlobWriter(blob); foreach (var target in targets) { // switch targets are offsets relative to the beginning of the next instruction. - var offset = labelToEncoderOffset[target] - nextInstructionOffset; + var offset = labelToEncoderOffset[target] - nextInstructionEncoderOffset; writer.WriteInt32(offset); } } From e1e1f57187b6cd315fcb15d81c4e11ab0877c9c5 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 25 Jul 2020 19:23:47 -0300 Subject: [PATCH 188/256] fix switch generation --- .../Generators/Methods/Body/MethodBodyGenerator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 3d7769a5..2229c152 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -638,9 +638,10 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var targetsCount = switchInstruction.Targets.Count; instructionEncoder.OpCode(SRM.ILOpCode.Switch); instructionEncoder.Token(targetsCount); + var targetsReserveBytes = instructionEncoder.CodeBuilder.ReserveBytes(sizeof(int) * targetsCount); var switchInstructionPlaceholder = new SwitchInstructionPlaceholder( instructionEncoder.Offset, - instructionEncoder.CodeBuilder.ReserveBytes(sizeof(int) * targetsCount), + targetsReserveBytes, switchInstruction.Targets); switchInstructionsPlaceHolders.Add(switchInstructionPlaceholder); break; From 7e65d2a2d541f78e89772697ecd7cc6dc6dc1e33 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 26 Jul 2020 14:46:10 -0300 Subject: [PATCH 189/256] merge --- Backend/Transformations/Assembler.cs | 18 +++++++++--------- Backend/Utils/Extensions.cs | 2 +- Model/ThreeAddressCode/Operands.cs | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Backend/Transformations/Assembler.cs b/Backend/Transformations/Assembler.cs index 1b0c966a..01e672ac 100644 --- a/Backend/Transformations/Assembler.cs +++ b/Backend/Transformations/Assembler.cs @@ -52,7 +52,7 @@ public MethodBody Execute() } body.UpdateVariables(); - var newLocals = body.LocalVariables.OfType().OrderBy(local => local.Index.Value).ToList(); + var newLocals = body.LocalVariables.OfType().OrderBy(local => local.Index).ToList(); body.LocalVariables.Clear(); body.LocalVariables.AddRange(newLocals); @@ -143,11 +143,11 @@ public override void Visit(LoadInstruction instruction) { // starg num -> FE 0B (2 + 2) // starg.s num -> 10 (1 + 1) - offset += (uint) (loc.Index.Value > byte.MaxValue ? 4 : 2); + offset += (uint) (loc.Index > byte.MaxValue ? 4 : 2); } else { - switch (loc.Index.Value) + switch (loc.Index) { case 0: case 1: @@ -158,7 +158,7 @@ public override void Visit(LoadInstruction instruction) default: // stloc indx -> FE 0E (2 + 2) // stloc.s indx -> 13 (1 + 1) - offset += (uint) (loc.Index.Value > byte.MaxValue ? 4 : 2); + offset += (uint) (loc.Index > byte.MaxValue ? 4 : 2); break; } } @@ -243,7 +243,7 @@ public override void Visit(LoadInstruction instruction) // FIXME hay casos sin sentido? a este no se entra nunca creo. Hay que revisar todo. var operand = instruction.Result.ToLocalVariable(); // fixme operand como en l otro caso qie cambie? bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, operand); - switch (operand.Index.Value) + switch (operand.Index) { // ldloc.0,1,2,3 ldarg.0,1,2,3 case 0: @@ -257,7 +257,7 @@ public override void Visit(LoadInstruction instruction) // ldloc.s indx -> 11 (1 + 1) // ldarg num -> FE 09 (2 + 2) // ldarg.s num -> 0E (1 + 1) - offset += (uint) (operand.Index.Value > byte.MaxValue ? 4 : 2); + offset += (uint) (operand.Index > byte.MaxValue ? 4 : 2); break; } @@ -268,7 +268,7 @@ public override void Visit(LoadInstruction instruction) bytecodeInstruction = new Bytecode.LoadInstruction(offset, Bytecode.LoadOperation.Content, localVariable); // fixme igual al caso de arriba? o estoy mezclando los casos? Creo que esta bien porque local y temporal ambas pueden // fixme ser parameter (esto determina si es ldloc o ldarg) - switch (localVariable.Index.Value) + switch (localVariable.Index) { // ldloc.0,1,2,3 ldarg.0,1,2,3 case 0: @@ -282,7 +282,7 @@ public override void Visit(LoadInstruction instruction) // ldloc.s indx -> 11 (1 + 1) // ldarg num -> FE 09 (2 + 2) // ldarg.s num -> 0E (1 + 1) - offset += (uint) (localVariable.Index.Value > byte.MaxValue ? 4 : 2); + offset += (uint) (localVariable.Index > byte.MaxValue ? 4 : 2); break; } @@ -327,7 +327,7 @@ public override void Visit(LoadInstruction instruction) // ldloca.s indx -> 12 (1 + 1) // ldarga argNum -> FE 0A (2 + 2) // ldarga.s argNum -> 0F (1 + 1) - offset += (uint) (localVariable.Index.Value > byte.MaxValue ? 4 : 2); + offset += (uint) (localVariable.Index > byte.MaxValue ? 4 : 2); break; } case InstanceFieldAccess instanceFieldAccess: diff --git a/Backend/Utils/Extensions.cs b/Backend/Utils/Extensions.cs index 0b36ed5b..f6a6a2c6 100644 --- a/Backend/Utils/Extensions.cs +++ b/Backend/Utils/Extensions.cs @@ -1026,7 +1026,7 @@ public static LocalVariable ToLocalVariable(this IVariable variable) return new LocalVariable(temporalVariable.Name, temporalVariable.IsParameter) { Type = temporalVariable.Type, - Index = (int?) temporalVariable.Index + Index = (int) temporalVariable.Index }; case LocalVariable localVariable: return localVariable; default: throw new NotImplementedException(); diff --git a/Model/ThreeAddressCode/Operands.cs b/Model/ThreeAddressCode/Operands.cs index 9c9a7cea..d28b5295 100644 --- a/Model/ThreeAddressCode/Operands.cs +++ b/Model/ThreeAddressCode/Operands.cs @@ -327,12 +327,12 @@ public override bool Equals(object obj) return other != null && this.Name.Equals(other.Name) && - this.Index.Value.Equals(this.Index.Value); // FIXME Hacer que no sea nullable, sino en el CCI por ejemplo fallaria por no estar seteado + this.Index.Equals(this.Index); } public override int GetHashCode() { - return (Name.GetHashCode() * 397) ^ Index.Value.GetHashCode(); + return (Name.GetHashCode() * 397) ^ Index.GetHashCode(); } public override string ToString() From 93e6b644484d1148a59a3cf0674fb77ddfd6f72e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 26 Jul 2020 14:50:22 -0300 Subject: [PATCH 190/256] clean --- Backend/Backend.csproj | 1 - Backend/Transformations/Disassembler.cs | 3 - .../TacUniqueLabelsGenerator.cs | 77 ------------------- 3 files changed, 81 deletions(-) delete mode 100644 Backend/Transformations/TacUniqueLabelsGenerator.cs diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj index a1ef2204..5dd4062d 100644 --- a/Backend/Backend.csproj +++ b/Backend/Backend.csproj @@ -70,7 +70,6 @@ - diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 9e136759..b4170fe5 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -953,7 +953,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); fixme creo que esto no habria que hacerlo, ya que en tac son instrucciones todo lo del exception handling if (method.Body.Instructions.Count > 0) { @@ -1013,8 +1012,6 @@ public MethodBody Execute() body.UpdateVariables(); } - new TacUniqueLabelsGenerator(body.Instructions.Cast().ToList()).Execute(); - return body; } diff --git a/Backend/Transformations/TacUniqueLabelsGenerator.cs b/Backend/Transformations/TacUniqueLabelsGenerator.cs deleted file mode 100644 index 68450087..00000000 --- a/Backend/Transformations/TacUniqueLabelsGenerator.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Model; -using Model.ThreeAddressCode.Instructions; - -namespace Backend.Transformations -{ - public class TacUniqueLabelsGenerator - { - private readonly IList instructions; - private uint offset; - - public TacUniqueLabelsGenerator(IList instructions) - { - this.instructions = instructions; - } - - // FIXME documentar donde se usa, esto de que para agregar isntrucciones hay que agregarlas con el mismo label - // de la instruccion anterior a donde agrego, etc - // FIXME se puede optimizar? son varias pasadas sino por las instrucciones - public void Execute() - { - var originalTargets = new HashSet(); - var newTargets = new Dictionary(); - foreach (var instruction in instructions) - { - switch (instruction) - { - case BranchInstruction branchInstruction: - originalTargets.Add(branchInstruction.Target); - break; - case SwitchInstruction switchInstruction: - originalTargets.AddRange(switchInstruction.Targets); - break; - } - } - - // generate unique labels for all instructions and gather new target labels - foreach (var instruction in instructions) - { - var newLabel = $"L_{offset:X4}"; - if (originalTargets.Contains(instruction.Label) && !newTargets.TryGetValue(instruction.Label, out _)) - { - newTargets[instruction.Label] = newLabel; - } - - instruction.Offset = offset; - instruction.Label = newLabel; - offset++; - } - - // replace old targets - foreach (var instruction in instructions) - { - switch (instruction) - { - case BranchInstruction branchInstruction: - { - if (newTargets.TryGetValue(branchInstruction.Target, out var newTarget)) - { - branchInstruction.Target = newTarget; - } - - break; - } - case SwitchInstruction switchInstruction: - switchInstruction.Targets = switchInstruction.Targets - .Select(target => newTargets.TryGetValue(target, out var newTarget) - ? newTarget - : target) - .ToList(); - break; - } - } - } - } -} \ No newline at end of file From 8922ad99aced83da465322877b043cb231a9ab4e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 26 Jul 2020 15:33:46 -0300 Subject: [PATCH 191/256] fix switch instruction and branche instruction generation --- MetadataGenerator/Extensions.cs | 4 +- .../Body/MethodBodyControlFlowGenerator.cs | 4 +- .../Methods/Body/MethodBodyGenerator.cs | 122 +++++++++--------- 3 files changed, 66 insertions(+), 64 deletions(-) diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index 12185ca0..7ef501c1 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -28,9 +28,7 @@ public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.Enti // The next available slot in the corresponding table. If nothing is defined in the module then use row number 1 for the corresponding table public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; - - public static string CurrentLabelString(this ECMA335.InstructionEncoder instructionEncoder) => $"L_{instructionEncoder.Offset:x4}".ToLower(); - + public static bool IsGenericInstantiation(this IBasicType type) => type.GenericType != null; public static bool IsGenericInstantiation(this IMethodReference method) => method.GenericMethod != null; diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index c8ea2495..9468bdb1 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -42,9 +42,9 @@ public void DefineNeededBranchLabels(IList instructions) } } - public void MarkCurrentLabel() + public void MarkCurrentLabelIfNeeded(string label) { - if (labelHandles.TryGetValue(instructionEncoder.CurrentLabelString(), out var labelHandle)) + if (labelHandles.TryGetValue(label.ToLower(), out var labelHandle)) { instructionEncoder.MarkLabel(labelHandle); } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 241f7f9d..c335a8bd 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,6 +1,5 @@ using System; -using System.Globalization; -using System.Linq; +using System.Collections.Generic; using MetadataGenerator.Metadata; using Model.Bytecode; using Model.ThreeAddressCode.Values; @@ -25,11 +24,13 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); controlFlowGenerator.DefineNeededBranchLabels(body.Instructions); + var labelToEncoderOffset = new Dictionary(); + var switchInstructionsPlaceHolders = new List(); foreach (var instruction in body.Instructions) { - controlFlowGenerator.MarkCurrentLabel(); - if (instruction.Offset != instructionEncoder.Offset) throw new Exception(); + labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; + controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); switch (instruction) { @@ -152,74 +153,42 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case BranchInstruction branchInstruction: { SRM.ILOpCode opCode; - var nextInstructionOffset = - Convert.ToInt32(body.Instructions[body.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); - var currentInstructionOffset = Convert.ToInt32(branchInstruction.Label.Substring(2), 16); - // short forms are 1 byte opcode + 1 byte target. normal forms are 1 byte opcode + 4 byte target - var isShortForm = nextInstructionOffset - currentInstructionOffset == 2; + // targets of branch instructions reference other instructions (labels) in the body. But this labels are not going to be + // the same as the ones in the final CIL (the ones that instructionEncoder generates) because the instructions in the model + // do not know about the size they will occupy in CIL. Due to this, it is not possible to know if the branches could be cil + // short forms or not. So regular forms are used in all cases. This does not change functionality, it just means that the + // generated CIL will not be optimal in size. switch (branchInstruction.Operation) { case BranchOperation.False: - opCode = isShortForm ? SRM.ILOpCode.Brfalse_s : SRM.ILOpCode.Brfalse; + opCode = SRM.ILOpCode.Brfalse; break; case BranchOperation.True: - opCode = isShortForm ? SRM.ILOpCode.Brtrue_s : SRM.ILOpCode.Brtrue; + opCode = SRM.ILOpCode.Brtrue; break; case BranchOperation.Eq: - opCode = isShortForm ? SRM.ILOpCode.Beq_s : SRM.ILOpCode.Beq; + opCode = SRM.ILOpCode.Beq; break; case BranchOperation.Neq: - opCode = isShortForm ? SRM.ILOpCode.Bne_un_s : SRM.ILOpCode.Bne_un; + opCode = SRM.ILOpCode.Bne_un; break; case BranchOperation.Lt: - if (branchInstruction.UnsignedOperands) - { - opCode = isShortForm ? SRM.ILOpCode.Blt_un_s : SRM.ILOpCode.Blt_un; - } - else - { - opCode = isShortForm ? SRM.ILOpCode.Blt_s : SRM.ILOpCode.Blt; - } - + opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Blt_un : SRM.ILOpCode.Blt; break; case BranchOperation.Le: - if (branchInstruction.UnsignedOperands) - { - opCode = isShortForm ? SRM.ILOpCode.Ble_un_s : SRM.ILOpCode.Ble_un; - } - else - { - opCode = isShortForm ? SRM.ILOpCode.Ble_s : SRM.ILOpCode.Ble; - } - + opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Ble_un : SRM.ILOpCode.Ble; break; case BranchOperation.Gt: - if (branchInstruction.UnsignedOperands) - { - opCode = isShortForm ? SRM.ILOpCode.Bgt_un_s : SRM.ILOpCode.Bgt_un; - } - else - { - opCode = isShortForm ? SRM.ILOpCode.Bgt_s : SRM.ILOpCode.Bgt; - } - + opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Bgt_un : SRM.ILOpCode.Bgt; break; case BranchOperation.Ge: - if (branchInstruction.UnsignedOperands) - { - opCode = isShortForm ? SRM.ILOpCode.Bge_un_s : SRM.ILOpCode.Bge_un; - } - else - { - opCode = isShortForm ? SRM.ILOpCode.Bge_s : SRM.ILOpCode.Bge; - } - + opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Bge_un : SRM.ILOpCode.Bge; break; case BranchOperation.Branch: - opCode = isShortForm ? SRM.ILOpCode.Br_s : SRM.ILOpCode.Br; + opCode = SRM.ILOpCode.Br; break; case BranchOperation.Leave: - opCode = isShortForm ? SRM.ILOpCode.Leave_s : SRM.ILOpCode.Leave; + opCode = SRM.ILOpCode.Leave; break; default: throw new UnhandledCase(); @@ -633,15 +602,19 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case SwitchInstruction switchInstruction: { - var nextInstructionOffset = - Convert.ToInt32(body.Instructions[body.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); + // switch is encoded as OpCode NumberOfTargets target1, target2, .... + // the targets in SwitchInstruction are labels that refer to the Instructions in the method body + // but when encoded they must be be offsets relative to the instructionEncoder offsets (real Cil offsets) + // this offsets can't be determined until the whole body is generated so a space is reserved for the targets and filled up later + var targetsCount = switchInstruction.Targets.Count; instructionEncoder.OpCode(SRM.ILOpCode.Switch); - instructionEncoder.Token(switchInstruction.Targets.Count); - switchInstruction.Targets - .Select(label => Convert.ToInt32(label.Substring(2), 16)) - .Select(targetOffset => targetOffset - nextInstructionOffset) - .ToList() - .ForEach(instructionEncoder.Token); + instructionEncoder.Token(targetsCount); + var targetsReserveBytes = instructionEncoder.CodeBuilder.ReserveBytes(sizeof(int) * targetsCount); + var switchInstructionPlaceholder = new SwitchInstructionPlaceholder( + instructionEncoder.Offset, + targetsReserveBytes, + switchInstruction.Targets); + switchInstructionsPlaceHolders.Add(switchInstructionPlaceholder); break; } case SizeofInstruction sizeofInstruction: @@ -805,8 +778,39 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } } + foreach (var switchInstructionPlaceholder in switchInstructionsPlaceHolders) + { + switchInstructionPlaceholder.FillWithRealTargets(labelToEncoderOffset); + } + return instructionEncoder; } + + private class SwitchInstructionPlaceholder + { + private readonly int nextInstructionEncoderOffset; + private readonly SRM.Blob blob; + private readonly IList targets; + + public SwitchInstructionPlaceholder(int nextInstructionEncoderOffset, SRM.Blob blob, IList targets) + { + this.nextInstructionEncoderOffset = nextInstructionEncoderOffset; + this.blob = blob; + this.targets = targets; + } + + // labelToEncoderOffset is the translation of method body labels to the real cil offsets after generation + public void FillWithRealTargets(IDictionary labelToEncoderOffset) + { + var writer = new SRM.BlobWriter(blob); + foreach (var target in targets) + { + // switch targets are offsets relative to the beginning of the next instruction. + var offset = labelToEncoderOffset[target] - nextInstructionEncoderOffset; + writer.WriteInt32(offset); + } + } + } } internal class UnhandledCase : Exception From eece3c1ffe7e9f8b3bd652bbfd0f8192a8252d0a Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 26 Jul 2020 15:42:00 -0300 Subject: [PATCH 192/256] revert code generator changes --- .../Body/MethodBodyControlFlowGenerator.cs | 6 +- .../Methods/Body/MethodBodyGenerator.cs | 70 +++++-------------- 2 files changed, 21 insertions(+), 55 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index 0d8ac59f..c8ea2495 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -31,7 +31,7 @@ public ECMA335.LabelHandle LabelHandleFor(string label) } // FIXME name, quiza hacer tmb con las exception information asi es mas prolijo? y despues en el labelHandle solo levantarla y nunca crearla - public void DefineNeededLabels(IList instructions) + public void DefineNeededBranchLabels(IList instructions) { foreach (var instruction in instructions) { @@ -42,9 +42,9 @@ public void DefineNeededLabels(IList instructions) } } - public void MarkCurrentLabelIfNeeded(string label) + public void MarkCurrentLabel() { - if (labelHandles.TryGetValue(label.ToLower(), out var labelHandle)) + if (labelHandles.TryGetValue(instructionEncoder.CurrentLabelString(), out var labelHandle)) { instructionEncoder.MarkLabel(labelHandle); } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 2229c152..d5180e7e 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.Linq; using MetadataGenerator.Metadata; using Model; using Model.Bytecode; @@ -24,14 +24,13 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), new ECMA335.ControlFlowBuilder()); var controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); - controlFlowGenerator.DefineNeededLabels(body.Instructions); - var labelToEncoderOffset = new Dictionary(); - var switchInstructionsPlaceHolders = new List(); + controlFlowGenerator.DefineNeededBranchLabels(body.Instructions); foreach (var instruction in body.Instructions) { - labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; - controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); + controlFlowGenerator.MarkCurrentLabel(); + if (instruction.Offset != instructionEncoder.Offset) throw new Exception("Real offset does not match with expected one"); + switch (instruction) { case BasicInstruction basicInstruction: @@ -153,9 +152,11 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) case BranchInstruction branchInstruction: { SRM.ILOpCode opCode; - // FIXME sacar lo de short form y explicar que no puedo hacerlo bien ya que no conozco bien los labels y demas. - // (al menos en el caso de volver del tac) - var isShortForm = false; + var nextInstructionOffset = + Convert.ToInt32(body.Instructions[body.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); + var currentInstructionOffset = Convert.ToInt32(branchInstruction.Label.Substring(2), 16); + // short forms are 1 byte opcode + 1 byte target. normal forms are 1 byte opcode + 4 byte target + var isShortForm = nextInstructionOffset - currentInstructionOffset == 2; switch (branchInstruction.Operation) { case BranchOperation.False: @@ -631,19 +632,15 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case SwitchInstruction switchInstruction: { - // switch is encoded as OpCode NumberOfTargets target1, target2, .... - // the targets in SwitchInstruction are labels that refer to the Instructions in the method body - // but when encoded they must be be offsets relative to the instructionEncoder offsets (real Cil offsets) - // this offsets can't be determined until the whole body is generated so a space is reserved for the targets and filled up later - var targetsCount = switchInstruction.Targets.Count; + var nextInstructionOffset = + Convert.ToInt32(body.Instructions[body.Instructions.IndexOf(instruction) + 1].Label.Substring(2), 16); instructionEncoder.OpCode(SRM.ILOpCode.Switch); - instructionEncoder.Token(targetsCount); - var targetsReserveBytes = instructionEncoder.CodeBuilder.ReserveBytes(sizeof(int) * targetsCount); - var switchInstructionPlaceholder = new SwitchInstructionPlaceholder( - instructionEncoder.Offset, - targetsReserveBytes, - switchInstruction.Targets); - switchInstructionsPlaceHolders.Add(switchInstructionPlaceholder); + instructionEncoder.Token(switchInstruction.Targets.Count); + switchInstruction.Targets + .Select(label => Convert.ToInt32(label.Substring(2), 16)) + .Select(targetOffset => targetOffset - nextInstructionOffset) + .ToList() + .ForEach(instructionEncoder.Token); break; } case SizeofInstruction sizeofInstruction: @@ -807,39 +804,8 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } } - foreach (var switchInstructionPlaceholder in switchInstructionsPlaceHolders) - { - switchInstructionPlaceholder.FillWithRealTargets(labelToEncoderOffset); - } - return instructionEncoder; } - - private class SwitchInstructionPlaceholder - { - private readonly int nextInstructionEncoderOffset; - private readonly SRM.Blob blob; - private readonly IList targets; - - public SwitchInstructionPlaceholder(int nextInstructionEncoderOffset, SRM.Blob blob, IList targets) - { - this.nextInstructionEncoderOffset = nextInstructionEncoderOffset; - this.blob = blob; - this.targets = targets; - } - - // labelToEncoderOffset is the translation of method body labels to the real cil offsets after generation - public void FillWithRealTargets(IDictionary labelToEncoderOffset) - { - var writer = new SRM.BlobWriter(blob); - foreach (var target in targets) - { - // switch targets are offsets relative to the beginning of the next instruction. - var offset = labelToEncoderOffset[target] - nextInstructionEncoderOffset; - writer.WriteInt32(offset); - } - } - } } internal class UnhandledCase : Exception From 40fd22a4f44bd529add1058eddd8e59a73ab9b93 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 29 Jul 2020 20:31:57 -0300 Subject: [PATCH 193/256] remove comments --- MetadataGenerator/Generators/Methods/MethodGenerator.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 7f78f2b7..e38a67f8 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -40,13 +40,12 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) if (method.HasBody) { // FIXME undo this. Just for testing assembler. - // TODO probar que anda con y sin transofmracion del tac - var og = method.Body; + var og = method.Body; var tac = new Backend.Transformations.Disassembler(method).Execute(); method.Body = tac; var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); - method.Body = bytecode; - // method.Body = og; +// method.Body = bytecode; + method.Body = og; // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated // programatically then the maxStack is gonna be missing From f8029315d68433b4450451f66783332e3c1eb6c3 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 4 Aug 2020 08:53:54 -0300 Subject: [PATCH 194/256] draft --- Backend/Transformations/Assembly/Assembler.cs | 196 +++++++++++++----- Backend/Transformations/Disassembler.cs | 88 ++++---- Backend/Utils/Extensions.cs | 2 - Backend/Utils/OperationHelper.cs | 4 +- Console/Program.cs | 33 ++- Examples/Examples.cs | 13 +- .../Methods/Body/MethodBodyGenerator.cs | 67 +++--- .../Generators/Methods/MethodGenerator.cs | 21 +- .../Metadata/MetadataResolver.cs | 2 +- Model/ThreeAddressCode/Operands.cs | 10 +- Model/Types/TypeDefinitions.cs | 4 +- 11 files changed, 289 insertions(+), 151 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 5e17e4f7..19f8a199 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -21,6 +21,10 @@ using ConstrainedInstruction = Model.ThreeAddressCode.Instructions.ConstrainedInstruction; using Instruction = Model.ThreeAddressCode.Instructions.Instruction; +// FIXME revisar los usos de operand y result. Cuando hay que usar uno y cuando otro? lo mismo lo de mirar si son temporal variables y eso +// FIXME me suena a que esta mal +// FIXME reveer ademas toda la parte de las local variables y demas. La traduccion no tiene que dejar el bytecod eigual al original, sino +// FIXME semanticamente igual. Por ende no tengo porque tener las mismas variables que antes. Puede haber mas, puede haber menos. namespace Backend.Transformations.Assembly { public class Assembler @@ -44,22 +48,27 @@ public MethodBody Execute() body.MaxStack = method.Body.MaxStack; // FIXME body.Parameters.AddRange(method.Body.Parameters); + // FIXME entiendo que no iria esto // this is updated later on. Needed to preserver variables that are declared but not used - body.LocalVariables.AddRange(method.Body.LocalVariables); +// body.LocalVariables.AddRange(method.Body.LocalVariables); if (method.Body.Instructions.Count > 0) { var instructionTranslator = new InstructionTranslator(method.Body); instructionTranslator.Visit(method.Body); - body.ExceptionInformation.AddRange(instructionTranslator.exceptionInformationBuilder.Build()); + // FIXME revisar y generar bien la exception information + // body.ExceptionInformation.AddRange(instructionTranslator.exceptionInformationBuilder.Build()); body.Instructions.AddRange(instructionTranslator.translatedInstructions); + + body.UpdateVariables();// FIXME hay qeu hacer esto? } - body.UpdateVariables(); +/* body.UpdateVariables(); var newLocals = body.LocalVariables.OfType().OrderBy(local => local.Index).ToList(); body.LocalVariables.Clear(); body.LocalVariables.AddRange(newLocals); +*/ return body; } @@ -85,25 +94,45 @@ public override bool ShouldVisit(Instruction instruction) public override void Visit(PopInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Pop); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Pop) {Label = instruction.Label}; translatedInstructions.Add(basicInstruction); } public override void Visit(BinaryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, - OperationHelper.ToBasicOperation(instruction.Operation)) + + // FIXME tiene sentido esto? + if (instruction.Operation == BinaryOperation.Neq) { - OverflowCheck = instruction.OverflowCheck, - UnsignedOperands = instruction.UnsignedOperands - }; - translatedInstructions.Add(basicInstruction); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Eq) + { + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Neg) + { + Label = instruction.Label + }; + 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 override void Visit(UnaryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, - OperationHelper.ToBasicOperation(instruction.Operation)); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, OperationHelper.ToBasicOperation(instruction.Operation)) + { + Label = instruction.Label + }; translatedInstructions.Add(basicInstruction); } @@ -220,6 +249,7 @@ public override void Visit(LoadInstruction instruction) } } + bytecodeInstruction.Label = instruction.Label; translatedInstructions.Add(bytecodeInstruction); } @@ -233,7 +263,9 @@ public override void Visit(StoreInstruction instruction) { var type = (ArrayType) arrayElementAccess.Array.Type; storeInstruction = new Bytecode.StoreArrayElementInstruction(instruction.Offset, type) - {Method = arrayElementAccess.Method}; + { + Method = arrayElementAccess.Method + }; break; } case Dereference dereference: @@ -251,18 +283,25 @@ public override void Visit(StoreInstruction instruction) throw new Exception(); // TODO msg } + storeInstruction.Label = instruction.Label; translatedInstructions.Add(storeInstruction); } public override void Visit(NopInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop) + { + Label = instruction.Label + }; translatedInstructions.Add(basicInstruction); } public override void Visit(BreakpointInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Breakpoint); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Breakpoint) + { + Label = instruction.Label + }; translatedInstructions.Add(basicInstruction); } @@ -271,6 +310,8 @@ public override void Visit(TryInstruction instruction) // try with multiple handlers is modelled as multiple try instructions with the same label but different handlers. // if label matches with the current try, then increase the number of expected handlers. If not, begin a new try block // FIxme add comment + // FIXME revisar esto. No deberia basarme en offsets probablemnente en ningun lado. Ya que la posta son los labels. + // FIXME me podrian venir los offsets en 0 o en cualqueira y los labels no. Arreglar var offset = bodyToProcess.Instructions .First(i => i.Offset > instruction.Offset && !(i is TryInstruction)) .Offset; @@ -284,24 +325,29 @@ public override void Visit(TryInstruction instruction) } } + // FIXME mismo aca, no deberia usar offsets, sino labels. public override void Visit(FaultInstruction instruction) { // fixme estas deberian ser offset+1 tmb? replicar comment - exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(instruction.Offset+1, ExceptionHandlerBlockKind.Fault); + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(instruction.Offset + 1, ExceptionHandlerBlockKind.Fault); } + // FIXME mismo aca, no deberia usar offsets, sino labels. public override void Visit(FinallyInstruction instruction) { // fixme estas deberian ser offset+1 tmb? - exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(instruction.Offset+1, ExceptionHandlerBlockKind.Finally); + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(instruction.Offset + 1, ExceptionHandlerBlockKind.Finally); } + // FIXME mismo aca, no deberia usar offsets, sino labels. public override void Visit(FilterInstruction instruction) { // fixme estas deberian ser offset+1 tmb? - exceptionInformationBuilder.AddFilterHandlerToCurrentProtectedBlock(instruction.Offset+1, instruction.kind, instruction.ExceptionType); + exceptionInformationBuilder.AddFilterHandlerToCurrentProtectedBlock(instruction.Offset + 1, instruction.kind, + instruction.ExceptionType); } + // FIXME mismo aca, no deberia usar offsets, sino labels. public override void Visit(CatchInstruction instruction) { // fixme estas deberian ser offset+1 tmb? replicar comment @@ -316,49 +362,49 @@ public override 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); + // FIXME mismo aca, no deberia usar offsets, sino labels. exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(instruction.Offset + 1); // block ends after instruction } public override void Visit(UnconditionalBranchInstruction instruction) { var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); + Bytecode.Instruction bytecodeInstruction; switch (instruction.Operation) { case UnconditionalBranchOperation.Leave: { - var branchInstruction = - new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Leave, target); - translatedInstructions.Add(branchInstruction); + bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Leave, target); + // FIXME mismo aca, no deberia usar offsets, sino labels. exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(instruction.Offset + 1); // block ends after instruction break; } case UnconditionalBranchOperation.Branch: { - var branchInstruction = - new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Branch, target); - translatedInstructions.Add(branchInstruction); + bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Branch, target); break; } case UnconditionalBranchOperation.EndFinally: { - var branchInstruction = - new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFinally); - translatedInstructions.Add(branchInstruction); + bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFinally); // no more handlers after finally + // FIXME mismo aca, no deberia usar offsets, sino labels. exceptionInformationBuilder.EndCurrentProtectedBlockAt(instruction.Offset + 1); // 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 - var branchInstruction = - new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFilter); - translatedInstructions.Add(branchInstruction); + bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFilter); break; } default: throw instruction.Operation.ToUnknownValueException(); } + + bytecodeInstruction.Label = instruction.Label; + translatedInstructions.Add(bytecodeInstruction); } public override void Visit(ConvertInstruction instruction) @@ -368,25 +414,44 @@ public override void Visit(ConvertInstruction instruction) OperationHelper.ToConvertOperation(instruction.Operation), instruction.ConversionType) { + Label = instruction.Label, OverflowCheck = instruction.OverflowCheck, - UnsignedOperands = instruction.UnsignedOperands, + UnsignedOperands = instruction.UnsignedOperands }; translatedInstructions.Add(convertInstruction); } public override void Visit(ReturnInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Return); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Return) + { + Label = instruction.Label + }; translatedInstructions.Add(basicInstruction); } public override void Visit(ConditionalBranchInstruction instruction) { + // FIXME esto se puede optimizar. Porque esto hace que por ejemplo haga un load false y despues haga un branc eq. EN vez + // FIXME de de una hacer brfalse. Por otro lado, agarro solo los constant (literales) porque los demas casos son variables y se supone + // FIXME que ya se cargaron en la instruccion anterior + switch (instruction.RightOperand) + { + case Constant constant: + var a = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant); + a.Label += "'"; // FIXME + translatedInstructions.Add(a); + break; + } + var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); var branchInstruction = new Bytecode.BranchInstruction( instruction.Offset, - OperationHelper.ToBranchOperation(instruction.Operation, instruction.RightOperand), - target); + OperationHelper.ToBranchOperation(instruction.Operation), + target) + { + Label = instruction.Label + }; translatedInstructions.Add(branchInstruction); } @@ -395,19 +460,28 @@ public override void Visit(SwitchInstruction instruction) var targets = instruction.Targets .Select(target => Convert.ToUInt32(target.Substring(2), 16)) .ToList(); - var switchInstruction = new Bytecode.SwitchInstruction(instruction.Offset, targets); + var switchInstruction = new Bytecode.SwitchInstruction(instruction.Offset, targets) + { + Label = instruction.Label + }; translatedInstructions.Add(switchInstruction); } public override void Visit(SizeofInstruction instruction) { - var sizeofInstruction = new Bytecode.SizeofInstruction(instruction.Offset, instruction.MeasuredType); + var sizeofInstruction = new Bytecode.SizeofInstruction(instruction.Offset, instruction.MeasuredType) + { + Label = instruction.Label + }; translatedInstructions.Add(sizeofInstruction); } public override void Visit(LoadTokenInstruction instruction) { - var loadTokenInstruction = new Bytecode.LoadTokenInstruction(instruction.Offset, instruction.Token); + var loadTokenInstruction = new Bytecode.LoadTokenInstruction(instruction.Offset, instruction.Token) + { + Label = instruction.Label + }; translatedInstructions.Add(loadTokenInstruction); } @@ -417,14 +491,19 @@ public override void Visit(MethodCallInstruction instruction) instruction.Offset, OperationHelper.ToMethodCallOperation(instruction.Operation), instruction.Method - ); + ) + { + Label = instruction.Label + }; translatedInstructions.Add(methodCallInstruction); } public override void Visit(IndirectMethodCallInstruction instruction) { - var indirectMethodCallInstruction = - new Bytecode.IndirectMethodCallInstruction(instruction.Offset, instruction.Function); + var indirectMethodCallInstruction = new Bytecode.IndirectMethodCallInstruction(instruction.Offset, instruction.Function) + { + Label = instruction.Label + }; translatedInstructions.Add(indirectMethodCallInstruction); } @@ -435,38 +514,55 @@ public override void Visit(CreateObjectInstruction instruction) ignoreInstruction.Add(index + 1, true); // method call ignoreInstruction.Add(index + 2, true); // load - var createObjectInstruction = - new Bytecode.CreateObjectInstruction(instruction.Offset, methodCallInstruction.Method); + var createObjectInstruction = new Bytecode.CreateObjectInstruction(instruction.Offset, methodCallInstruction.Method) + { + Label = instruction.Label + }; translatedInstructions.Add(createObjectInstruction); } public override void Visit(CopyMemoryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyBlock); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyBlock) + { + Label = instruction.Label + }; translatedInstructions.Add(basicInstruction); } public override void Visit(LocalAllocationInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LocalAllocation); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LocalAllocation) + { + Label = instruction.Label + }; translatedInstructions.Add(basicInstruction); } public override void Visit(InitializeMemoryInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.InitBlock); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.InitBlock) + { + Label = instruction.Label + }; translatedInstructions.Add(basicInstruction); } public override void Visit(InitializeObjectInstruction instruction) { - var initObjInstruction = new Bytecode.InitObjInstruction(instruction.Offset, instruction.TargetAddress.Type); + var initObjInstruction = new Bytecode.InitObjInstruction(instruction.Offset, instruction.TargetAddress.Type) + { + Label = instruction.Label + }; translatedInstructions.Add(initObjInstruction); } public override void Visit(CopyObjectInstruction instruction) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyObject); + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyObject) + { + Label = instruction.Label + }; translatedInstructions.Add(basicInstruction); } @@ -475,6 +571,7 @@ public override 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 }; @@ -485,7 +582,10 @@ public override void Visit(CreateArrayInstruction instruction) public override void Visit(ConstrainedInstruction instruction) { - var constrainedInstruction = new Bytecode.ConstrainedInstruction(instruction.Offset, instruction.ThisType); + var constrainedInstruction = new Bytecode.ConstrainedInstruction(instruction.Offset, instruction.ThisType) + { + Label = instruction.Label + }; translatedInstructions.Add(constrainedInstruction); } } diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index b4170fe5..d7eda388 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -246,15 +246,7 @@ private void ProcessPop(Bytecode.BasicInstruction op) private void ProcessDup(Bytecode.BasicInstruction op) { var source = stack.Top(); - // recover type - var type = body.Instructions - .Reverse() - .Select(instructions => instructions.Variables) - .First(variables => variables.Any(variable => variable.Equals(source))) - .First(variable => variable.Equals(source)) - .Type; - source = source.MakeCopy(type); - var dest = stack.Push().MakeCopy(type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -263,6 +255,7 @@ private void ProcessEndFinally(Bytecode.BasicInstruction op) { stack.Clear(); + // jump target is always next instruction. This relies on CIL instruction size which is 1 byte var instruction = new Tac.UnconditionalBranchInstruction(op.Offset, op.Offset+1, Tac.UnconditionalBranchOperation.EndFinally); body.Instructions.Add(instruction); @@ -289,7 +282,8 @@ private void ProcessEndFilter(Bytecode.BasicInstruction op) { stack.Clear(); - var instruction = new Tac.UnconditionalBranchInstruction(op.Offset, op.Offset+1, Tac.UnconditionalBranchOperation.EndFilter); + // jump target is always next instruction. This relies on CIL instruction size which is 2 byte + var instruction = new Tac.UnconditionalBranchInstruction(op.Offset, op.Offset+2, Tac.UnconditionalBranchOperation.EndFilter); body.Instructions.Add(instruction); } @@ -314,7 +308,7 @@ private void ProcessInitializeMemory(Bytecode.BasicInstruction op) public override void Visit(Bytecode.InitObjInstruction op) { - var targetAddress = stack.Pop().MakeCopy(op.Type); + var targetAddress = stack.Pop(); var instruction = new Tac.InitializeObjectInstruction(op.Offset, targetAddress); body.Instructions.Add(instruction); } @@ -481,8 +475,8 @@ private void ProcessLeave(Bytecode.BranchInstruction op) public override void Visit(Bytecode.ConvertInstruction op) { var operation = OperationHelper.ToConvertOperation(op.Operation); - var operand = stack.Pop().MakeCopy(op.ConversionType); - var result = stack.Push().MakeCopy(op.ConversionType); + var operand = stack.Pop(); + var result = stack.Push(); var instruction = new Tac.ConvertInstruction(op.Offset, result, operand, operation, op.ConversionType); instruction.OverflowCheck = op.OverflowCheck; @@ -513,7 +507,7 @@ public override void Visit(Bytecode.CreateArrayInstruction op) lowerBounds.Reverse(); sizes.Reverse(); - var result = stack.Push().MakeCopy(op.Type); + var result = stack.Push(); var instruction = new Tac.CreateArrayInstruction(op.Offset, result, op.Type.ElementsType, op.Type.Rank, lowerBounds, sizes) { Constructor = op.Constructor @@ -547,11 +541,11 @@ private void ProcessLoadArrayElement(Bytecode.LoadArrayElementInstruction op) indices.Add(operand); } - var array = stack.Pop().MakeCopy(op.Array); + var array = stack.Pop(); indices.Reverse(); var source = new ArrayElementAccess(array, indices) { Method = op.Method}; - var dest = stack.Push().MakeCopy(source.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -566,13 +560,13 @@ private void ProcessLoadArrayElementAddress(Bytecode.LoadArrayElementInstruction indices.Add(operand); } - var array = stack.Pop().MakeCopy(op.Array); + var array = stack.Pop(); indices.Reverse(); var access = new ArrayElementAccess(array, indices) { Method = op.Method};; var source = new Reference(access); - var dest = stack.Push().MakeCopy(source.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -580,7 +574,7 @@ private void ProcessLoadArrayElementAddress(Bytecode.LoadArrayElementInstruction public override void Visit(Bytecode.StoreArrayElementInstruction op) { var indices = new List(); - var source = stack.Pop().MakeCopy(op.Array.ElementsType); + var source = stack.Pop(); for (uint i = 0; i < op.Array.Rank; i++) { @@ -588,7 +582,7 @@ public override void Visit(Bytecode.StoreArrayElementInstruction op) indices.Add(operand); } - var array = stack.Pop().MakeCopy(op.Array); + var array = stack.Pop(); indices.Reverse(); var dest = new ArrayElementAccess(array, indices) { Method = op.Method}; var instruction = new Tac.StoreInstruction(op.Offset, dest, source); @@ -599,14 +593,14 @@ public override void Visit(Bytecode.CreateObjectInstruction op) { stack.IncrementCapacity(); - var allocationResult = stack.Push().MakeCopy(op.Constructor.ContainingType); + var allocationResult = stack.Push(); stack.Pop(); var arguments = new List(); foreach (var parameter in op.Constructor.Parameters) { - var arg = stack.Pop().MakeCopy(parameter.Type); + var arg = stack.Pop(); arguments.Add(arg); } @@ -624,11 +618,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().MakeCopy(allocationResult.Type); + var result = stack.Push(); instruction = new Tac.LoadInstruction(op.Offset, result, allocationResult); + instruction.Label += "''"; // ensure unique label body.Instructions.Add(instruction); stack.DecrementCapacity(); @@ -642,7 +638,7 @@ public override void Visit(Bytecode.IndirectMethodCallInstruction op) foreach (var parameter in op.Function.Parameters) { - var arg = stack.Pop().MakeCopy(parameter.Type); + var arg = stack.Pop(); arguments.Add(arg); } @@ -707,7 +703,7 @@ private void ProcessLoadFieldAddress(Bytecode.LoadFieldInstruction op) private void ProcessLoadStaticField(Bytecode.LoadFieldInstruction op) { var source = new StaticFieldAccess(op.Field); - var dest = stack.Push().MakeCopy(source.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -716,7 +712,7 @@ private void ProcessLoadInstanceField(Bytecode.LoadFieldInstruction op) { var obj = stack.Pop(); var source = new InstanceFieldAccess(obj, op.Field); - var dest = stack.Push().MakeCopy(source.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -725,7 +721,7 @@ private void ProcessLoadStaticFieldAddress(Bytecode.LoadFieldInstruction op) { var access = new StaticFieldAccess(op.Field); var source = new Reference(access); - var dest = stack.Push().MakeCopy(source.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -735,15 +731,15 @@ private void ProcessLoadInstanceFieldAddress(Bytecode.LoadFieldInstruction op) var obj = stack.Pop(); var access = new InstanceFieldAccess(obj, op.Field); var source = new Reference(access); - var dest = stack.Push().MakeCopy(source.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } public override void Visit(Bytecode.LoadIndirectInstruction op) { - var address = stack.Pop().MakeCopy(new PointerType(op.Type)); + var address = stack.Pop(); var source = new Dereference(address); - var dest = stack.Push().MakeCopy(source.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -769,14 +765,14 @@ public override void Visit(Bytecode.LoadInstruction op) private void ProcessLoadConstant(Bytecode.LoadInstruction op) { - var dest = stack.Push().MakeCopy(op.Operand.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, op.Operand); body.Instructions.Add(instruction); } private void ProcessLoadVariable(Bytecode.LoadInstruction op) { - var dest = stack.Push().MakeCopy(op.Operand.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, op.Operand); body.Instructions.Add(instruction); } @@ -785,7 +781,7 @@ private void ProcessLoadVariableAddress(Bytecode.LoadInstruction op) { var operand = (IVariable)op.Operand; var source = new Reference(operand); - var dest = stack.Push().MakeCopy(source.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -809,7 +805,7 @@ public override void Visit(Bytecode.LoadMethodAddressInstruction op) public void ProcessLoadStaticMethodAddress(Bytecode.LoadMethodAddressInstruction op) { var source = new StaticMethodReference(op.Method); - var dest = stack.Push().MakeCopy(source.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -818,14 +814,14 @@ public void ProcessLoadVirtualMethodAddress(Bytecode.LoadMethodAddressInstructio { var obj = stack.Pop(); var source = new VirtualMethodReference(obj, op.Method); - var dest = stack.Push().MakeCopy(source.Type); + var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } public override void Visit(Bytecode.LoadTokenInstruction op) { - var result = stack.Push().MakeCopy(TypeHelper.TokenType(op.Token)); + var result = stack.Push(); var instruction = new Tac.LoadTokenInstruction(op.Offset, result, op.Token); body.Instructions.Add(instruction); } @@ -838,7 +834,7 @@ public override void Visit(Bytecode.MethodCallInstruction op) foreach (var parameter in op.Method.Parameters) { - var arg = stack.Pop().MakeCopy(parameter.Type); + var arg = stack.Pop(); arguments.Add(arg); } @@ -851,7 +847,7 @@ public override void Visit(Bytecode.MethodCallInstruction op) if (!op.Method.IsStatic) { // Adding implicit this parameter - var argThis = stack.Pop().MakeCopy(op.Method.ContainingType); + var argThis = stack.Pop(); arguments.Add(argThis); } @@ -859,7 +855,7 @@ public override void Visit(Bytecode.MethodCallInstruction op) if (!op.Method.ReturnType.Equals(PlatformTypes.Void)) { - result = stack.Push().MakeCopy(op.Method.ReturnType); + result = stack.Push(); } var instruction = new Tac.MethodCallInstruction(op.Offset, result, operation, op.Method, arguments); @@ -868,7 +864,7 @@ public override void Visit(Bytecode.MethodCallInstruction op) public override void Visit(Bytecode.SizeofInstruction op) { - var result = stack.Push().MakeCopy(PlatformTypes.Int32); + var result = stack.Push(); var instruction = new Tac.SizeofInstruction(op.Offset, result, op.MeasuredType); body.Instructions.Add(instruction); } @@ -887,7 +883,7 @@ public override void Visit(Bytecode.StoreFieldInstruction op) private void ProcessStoreStaticField(Bytecode.StoreFieldInstruction op) { - var source = stack.Pop().MakeCopy(op.Field.Type); + var source = stack.Pop(); var dest = new StaticFieldAccess(op.Field); var instruction = new Tac.StoreInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); @@ -895,7 +891,7 @@ private void ProcessStoreStaticField(Bytecode.StoreFieldInstruction op) private void ProcessStoreInstanceField(Bytecode.StoreFieldInstruction op) { - var source = stack.Pop().MakeCopy(op.Field.Type); + var source = stack.Pop(); var obj = stack.Pop(); var dest = new InstanceFieldAccess(obj, op.Field); var instruction = new Tac.StoreInstruction(op.Offset, dest, source); @@ -904,8 +900,8 @@ private void ProcessStoreInstanceField(Bytecode.StoreFieldInstruction op) public override void Visit(Bytecode.StoreIndirectInstruction op) { - var source = stack.Pop().MakeCopy(op.Type); - var address = stack.Pop().MakeCopy(new PointerType(op.Type)); + 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); @@ -913,14 +909,14 @@ public override void Visit(Bytecode.StoreIndirectInstruction op) public override void Visit(Bytecode.StoreInstruction op) { - var source = stack.Pop().MakeCopy(op.Target.Type); + var source = stack.Pop(); var instruction = new Tac.LoadInstruction(op.Offset, op.Target, source); body.Instructions.Add(instruction); } public override void Visit(Bytecode.SwitchInstruction op) { - var operand = stack.Pop().MakeCopy(PlatformTypes.List); + var operand = stack.Pop(); var instruction = new Tac.SwitchInstruction(op.Offset, operand, op.Targets); body.Instructions.Add(instruction); } diff --git a/Backend/Utils/Extensions.cs b/Backend/Utils/Extensions.cs index 8fb6bfbd..41b9f830 100644 --- a/Backend/Utils/Extensions.cs +++ b/Backend/Utils/Extensions.cs @@ -1015,7 +1015,5 @@ from node in escInfo.EscapingNodes return escapeInfo; } - public static TemporalVariable MakeCopy(this TemporalVariable temporalVariable, IType type) => - new TemporalVariable(temporalVariable.Prefix, temporalVariable.Index) { Type = type }; } } diff --git a/Backend/Utils/OperationHelper.cs b/Backend/Utils/OperationHelper.cs index 3bcb4633..90860dbc 100644 --- a/Backend/Utils/OperationHelper.cs +++ b/Backend/Utils/OperationHelper.cs @@ -139,12 +139,10 @@ public static bool IsBranch(Bytecode.Instruction instruction) return result; } - public static Bytecode.BranchOperation ToBranchOperation(Tac.BranchOperation operation, IInmediateValue value) + public static Bytecode.BranchOperation ToBranchOperation(Tac.BranchOperation operation) { switch (operation) { - case Tac.BranchOperation.Eq when new Constant(true).Equals(value): return Bytecode.BranchOperation.True; - case Tac.BranchOperation.Eq when new Constant(false).Equals(value): return Bytecode.BranchOperation.False; case Tac.BranchOperation.Eq: return Bytecode.BranchOperation.Eq; case Tac.BranchOperation.Neq: return Bytecode.BranchOperation.Neq; case Tac.BranchOperation.Lt: return Bytecode.BranchOperation.Lt; diff --git a/Console/Program.cs b/Console/Program.cs index 932e446e..05ea698c 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -375,6 +375,29 @@ private static void DisassembleAndThenAssemble(string input) System.Console.WriteLine($"Reading {input}"); var loader = new MetadataProvider.Loader(host); loader.LoadAssembly(input); + + /* var allDefinedMethods = from a in host.Assemblies + from t in a.RootNamespace.GetAllTypes() + from m in t.Members.OfType() + where m.HasBody + select m; + + foreach (var method in allDefinedMethods) + { + var tac = new Backend.Transformations.Disassembler(method).Execute(); + method.Body = tac; + + var cfanalysis = new ControlFlowAnalysis(method.Body); + var cfg = cfanalysis.GenerateExceptionalControlFlow(); + + var webAnalysis = new WebAnalysis(cfg); + webAnalysis.Analyze(); + webAnalysis.Transform(); + method.Body.UpdateVariables(); + + var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); + typeInferenceAnalysis.Analyze(); + }*/ var generator = new MetadataGenerator.Generator(); @@ -388,14 +411,14 @@ static void Main(string[] args) { var inputs = new[] { - new[] {"../../../Examples/bin/Debug/Examples.dll"}, - new[] + new[] {"../../../Examples/bin/Debug/Examples.dll"}, //FIXME se rompe/se cuelga el type inference + /* new[] FIXME rompe el type inference { "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll", "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll" }, - - new[] +*/ + /* new[] { "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll", "../../../../DSA/DSA/DSAUnitTests/bin/Debug/net45/DSAUnitTests.dll" @@ -412,7 +435,7 @@ static void Main(string[] args) "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll" - } + }*/ }; foreach (var input in inputs) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 437ead01..bd20570d 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -796,7 +796,7 @@ public void LoadPointer() Action x = LoadAddress; // ldftn $method Action y = null; // ldnull } - +/* public string LoadIndirect(ref int g) { unsafe @@ -852,7 +852,9 @@ out SimpleClass outClass return outByte + outDouble + outClass.readOnlyIntField; } - + + // FIXME rompen estos dos casos de indirect +*/ public bool Compare(int b, int x) { var a = b == 2; // ceq @@ -1030,7 +1032,7 @@ public void ExceptionHandlingTryCatchSpecific(int x) } } - +/* public void ExceptionHandlingMultipleFilter(int x) { try @@ -1046,7 +1048,7 @@ public void ExceptionHandlingMultipleFilter(int x) Console.WriteLine(ex.Message); } } - + public void ExceptionHandlingFilterCatch(int x) { try @@ -1078,7 +1080,8 @@ public void ExceptionHandlingCatchFilter(int x) Console.WriteLine(ex.Message); } } - + // FIXME se cuelga en el type inference +*/ public void ExceptionHandlingMultipleCatchs(int x) { try diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index d0b3d1dc..cc0c47c4 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -420,44 +420,47 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } case LoadOperation.Value: { - if (((Constant) loadInstruction.Operand).Value == null) + var value = (loadInstruction.Operand as Constant).Value; + if (value == null) { instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.String)) + else { - var value = (string) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); - } + if (loadInstruction.Operand.Type.Equals(PlatformTypes.String)) + { + instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString((string) value)); + } - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.UInt8)) - { - var value = (int) (loadInstruction.Operand as Constant).Value; - instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); - instructionEncoder.Token(value); - } - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int16, PlatformTypes.Int32, PlatformTypes.UInt16, - PlatformTypes.UInt32)) - { - var value = (int) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantI4(value); - } - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) - { - var value = (long) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantI8(value); - } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float32)) - { - var value = (float) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantR4(value); - } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float64)) - { - var value = (double) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantR8(value); + else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.UInt8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); + instructionEncoder.Token((int) value); + } + else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int16, PlatformTypes.Int32, PlatformTypes.UInt16, + PlatformTypes.UInt32)) + { + instructionEncoder.LoadConstantI4((int) value); + } + else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) + { + instructionEncoder.LoadConstantI8((long) value); + } + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float32)) + { + instructionEncoder.LoadConstantR4((float) value); + } + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float64)) + { + instructionEncoder.LoadConstantR8((double) value); + } + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Boolean)) + { + var boolAsInt = (bool) value ? 1 : 0; + instructionEncoder.LoadConstantI4(boolAsInt); + } + else throw new UnhandledCase(); } - else throw new UnhandledCase(); break; } diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index e38a67f8..ca4187e2 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -1,4 +1,5 @@ using System.Linq; +using Backend.Analyses; using Backend.Transformations.Assembly; using MetadataGenerator.Generators.Methods.Body; using MetadataGenerator.Metadata; @@ -40,15 +41,25 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) if (method.HasBody) { // FIXME undo this. Just for testing assembler. - var og = method.Body; var tac = new Backend.Transformations.Disassembler(method).Execute(); method.Body = tac; - var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); -// method.Body = bytecode; - method.Body = og; + + var cfanalysis = new ControlFlowAnalysis(method.Body); + var cfg = cfanalysis.GenerateExceptionalControlFlow(); + + var webAnalysis = new WebAnalysis(cfg); + webAnalysis.Analyze(); + webAnalysis.Transform(); + method.Body.UpdateVariables(); + + var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); + typeInferenceAnalysis.Analyze(); + + var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); + method.Body = bytecode; // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated - // programatically then the maxStack is gonna be missing + // programatically then the maxStamck is gonna be missing var maxStack = method.Body.MaxStack; methodBodyOffset = metadataContainer.MethodBodyStream.AddMethodBody( instructionEncoder: methodBodyGenerator.Generate(method.Body), diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 46232dac..16005918 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -84,7 +84,7 @@ public SRM.EntityHandle HandleOf(IMetadataReference metadataReference) { case IBasicType basicType: return GetOrAddTypeReference(basicType); - case IType iType when iType is ArrayType || iType is PointerType || iType is IGenericParameterReference: + case IType iType when iType is ArrayType || iType is PointerType || iType is ManagedPointerType || iType is IGenericParameterReference: return GetOrAddTypeSpecificationFor(iType); default: throw new Exception($"type {type} not yet supported"); diff --git a/Model/ThreeAddressCode/Operands.cs b/Model/ThreeAddressCode/Operands.cs index d28b5295..c5684c42 100644 --- a/Model/ThreeAddressCode/Operands.cs +++ b/Model/ThreeAddressCode/Operands.cs @@ -887,8 +887,14 @@ public IType Type { get { - var pointerType = this.Reference.Type as PointerType; - return pointerType.TargetType; + switch (Reference.Type) + { + case PointerType pointerType: + return pointerType.TargetType; + case ManagedPointerType managedPointerType: + return managedPointerType.TargetType; + default: throw new Exception(); // FIXME + } } } diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index e602c871..c21c1126 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -836,7 +836,7 @@ public MethodBody(MethodBodyKind kind) public void UpdateVariables() { - var previousLocals = LocalVariables.ToSet(); + // var previousLocals = LocalVariables.ToSet(); this.LocalVariables.Clear(); //this.LocalVariables.AddRange(this.Parameters); @@ -850,7 +850,7 @@ public void UpdateVariables() } locals.ExceptWith(this.Parameters); - locals.UnionWith(previousLocals); // this ensures that local variables that were declared but not used are included + // locals.UnionWith(previousLocals); // this ensures that local variables that were declared but not used are included this.LocalVariables.AddRange(locals); } From 8e7f0241c847716137891104f47c034c043f4040 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 5 Aug 2020 07:55:23 -0300 Subject: [PATCH 195/256] draft --- Backend/Transformations/Assembly/Assembler.cs | 18 ++++++++++++++---- Model/Types/TypeDefinitions.cs | 2 -- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 19f8a199..baefc514 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -58,10 +58,21 @@ public MethodBody Execute() instructionTranslator.Visit(method.Body); // FIXME revisar y generar bien la exception information - // body.ExceptionInformation.AddRange(instructionTranslator.exceptionInformationBuilder.Build()); + // body.ExceptionInformation.AddRange(instructionTranslator.exceptionInformationBuilder.Build()); body.Instructions.AddRange(instructionTranslator.translatedInstructions); - - body.UpdateVariables();// FIXME hay qeu hacer esto? + + body.UpdateVariables(); // deja las variables que se usen en base a las instrucciones que hay + // esto de abajo lo que hace es ordenarlas, que no es necesario, pero lo que si es que regenera los indices. Esto es porque + // en la tranformacion al tac y la vuelta, variables que no se usaban por ejemplo se pierden. Y entonces despues esas variables + // tienen indices + var locals = body.LocalVariables.Cast().OrderBy(i => i.Index).ToList(); + for (var index = 0; index < locals.Count; index++) + { + locals[index].Index = index; + } + + body.LocalVariables.Clear(); + body.LocalVariables.AddRange(locals); } /* body.UpdateVariables(); @@ -100,7 +111,6 @@ public override void Visit(PopInstruction instruction) public override void Visit(BinaryInstruction instruction) { - // FIXME tiene sentido esto? if (instruction.Operation == BinaryOperation.Neq) { diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index c21c1126..42fc0bd6 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -836,7 +836,6 @@ public MethodBody(MethodBodyKind kind) public void UpdateVariables() { - // var previousLocals = LocalVariables.ToSet(); this.LocalVariables.Clear(); //this.LocalVariables.AddRange(this.Parameters); @@ -850,7 +849,6 @@ public void UpdateVariables() } locals.ExceptWith(this.Parameters); - // locals.UnionWith(previousLocals); // this ensures that local variables that were declared but not used are included this.LocalVariables.AddRange(locals); } From 267be9435c41eb7380243db5c9ae5528c7da77fe Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 5 Aug 2020 08:49:02 -0300 Subject: [PATCH 196/256] remove index --- MetadataProvider/AssemblyExtractor.cs | 9 +++------ Model/ThreeAddressCode/Operands.cs | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 74fab308..394a8fe1 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -642,8 +642,7 @@ private void ExtractParameters(IList parameters) var v = new LocalVariable("this", true) { - Type = type, - Index = parameters.Count + Type = type }; parameters.Add(v); } @@ -652,8 +651,7 @@ private void ExtractParameters(IList parameters) { var v = new LocalVariable(parameter.Name, true) { - Type = parameter.Type, - Index = parameters.Count + Type = parameter.Type }; parameters.Add(v); @@ -672,8 +670,7 @@ private void ExtractLocalVariables(SRM.MethodBodyBlock bodyBlock, IList Date: Wed, 5 Aug 2020 08:55:18 -0300 Subject: [PATCH 197/256] fix indexes --- .../Methods/Body/MethodBodyGenerator.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index c335a8bd..2f729c62 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -386,18 +386,20 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) break; case LoadInstruction loadInstruction: + { switch (loadInstruction.Operation) { case LoadOperation.Address: { - var variable = (LocalVariable) loadInstruction.Operand; - var index = variable.Index; + var variable = (IVariable) loadInstruction.Operand; if (variable.IsParameter) { + var index = body.Parameters.IndexOf(variable); instructionEncoder.LoadArgumentAddress(index); } else { + var index = body.LocalVariables.IndexOf(variable); instructionEncoder.LoadLocalAddress(index); } @@ -405,14 +407,15 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } case LoadOperation.Content: { - var variable = (LocalVariable) loadInstruction.Operand; - var index = variable.Index; + var variable = (IVariable) loadInstruction.Operand; if (variable.IsParameter) { + var index = body.Parameters.IndexOf(variable); instructionEncoder.LoadArgument(index); } else { + var index = body.LocalVariables.IndexOf(variable); instructionEncoder.LoadLocal(index); } @@ -466,6 +469,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } break; + } case LoadFieldInstruction loadFieldInstruction: switch (loadFieldInstruction.Operation) { @@ -584,13 +588,15 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } case StoreInstruction storeInstruction: { - var index = ((LocalVariable) storeInstruction.Target).Index; - if (storeInstruction.Target.IsParameter) + var target = storeInstruction.Target; + if (target.IsParameter) { + var index = body.Parameters.IndexOf(target); instructionEncoder.StoreArgument(index); } else { + var index = body.LocalVariables.IndexOf(target); instructionEncoder.StoreLocal(index); } From ed68ccc4017d66406957a9d23fb581409a56bcf7 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 5 Aug 2020 08:58:45 -0300 Subject: [PATCH 198/256] remove PDB --- MetadataProvider/AssemblyExtractor.cs | 52 +++------------------------ MetadataProvider/Loader.cs | 9 ++--- 2 files changed, 7 insertions(+), 54 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..28713454 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -88,7 +88,6 @@ public IBasicType ContainingType private SRPE.PEReader reader; private SRM.MetadataReader metadata; - private SRM.MetadataReader pdbMetadata; private GenericContext defGenericContext; private GenericContext refGenericContext; private SignatureTypeProvider signatureTypeProvider; @@ -96,9 +95,8 @@ public IBasicType ContainingType private Namespace currentNamespace; private TypeDefinition currentType; private MethodDefinition currentMethod; - private IDictionary currentMethodLocalVariablesNames; - public AssemblyExtractor(Host host, SRPE.PEReader reader, SRM.MetadataReaderProvider pdbProvider = null) + public AssemblyExtractor(Host host, SRPE.PEReader reader) { this.Host = host; this.reader = reader; @@ -109,12 +107,7 @@ public AssemblyExtractor(Host host, SRPE.PEReader reader, SRM.MetadataReaderProv this.defGenericContext = new GenericContext(); this.refGenericContext = new GenericContext(); this.signatureTypeProvider = new SignatureTypeProvider(this); - - if (pdbProvider != null) - { - this.pdbMetadata = pdbProvider.GetMetadataReader(); - } - } + } public Host Host { get; private set; } @@ -525,7 +518,6 @@ private void ExtractMethod(SRM.MethodDefinitionHandle methoddefHandle) ExtractParameter(signature, handle); } - ExtractLocalVariablesNames(methoddefHandle); ExtractMethodBody(methoddef.RelativeVirtualAddress); defGenericContext.MethodParameters.Clear(); @@ -584,27 +576,7 @@ private Constant ExtractParameterDefaultValue(SRM.Parameter parameterdef) return result; } - - private void ExtractLocalVariablesNames(SRM.MethodDefinitionHandle methoddefHandle) - { - if (pdbMetadata == null) - { - currentMethodLocalVariablesNames = null; - } - else - { - var localVariablesNames = from scopeHandle in pdbMetadata.GetLocalScopes(methoddefHandle) - let localScope = pdbMetadata.GetLocalScope(scopeHandle) - from localHandle in localScope.GetLocalVariables() - let local = pdbMetadata.GetLocalVariable(localHandle) - let name = pdbMetadata.GetString(local.Name) - select new { Name = name, Index = local.Index }; - - currentMethodLocalVariablesNames = localVariablesNames.ToDictionary(x => x.Index, x => x.Name); - } - } - - private void ExtractMethodBody(int relativeVirtualAddress) + private void ExtractMethodBody(int relativeVirtualAddress) { if (relativeVirtualAddress == 0) return; var bodyBlock = SRM.PEReaderExtensions.GetMethodBody(reader, relativeVirtualAddress); @@ -655,7 +627,7 @@ private void ExtractLocalVariables(SRM.MethodBodyBlock bodyBlock, IList handlers) { foreach (var region in bodyBlock.ExceptionRegions) diff --git a/MetadataProvider/Loader.cs b/MetadataProvider/Loader.cs index 47327ea3..2b6f863f 100644 --- a/MetadataProvider/Loader.cs +++ b/MetadataProvider/Loader.cs @@ -47,19 +47,16 @@ public Assembly LoadAssembly(string fileName) return result; }; - var ok = reader.TryOpenAssociatedPortablePdb(fileName, streamProvider, - out SRM.MetadataReaderProvider pdbProvider, out _); - - var assembly = ExtractAssembly(reader, pdbProvider); + var assembly = ExtractAssembly(reader); this.Host.Assemblies.Add(assembly); return assembly; } } - private Assembly ExtractAssembly(SRPE.PEReader reader, SRM.MetadataReaderProvider pdbProvider) + private Assembly ExtractAssembly(SRPE.PEReader reader) { - var extractor = new AssemblyExtractor(this.Host, reader, pdbProvider); + var extractor = new AssemblyExtractor(this.Host, reader); var result = extractor.Extract(); return result; } From f8819f45a3d696818c2723198ffa9a83894a6d4b Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 5 Aug 2020 20:25:37 -0300 Subject: [PATCH 199/256] fixes --- Backend/Analyses/TypeInferenceAnalysis.cs | 5 ++ Backend/Transformations/Assembly/Assembler.cs | 63 ++++++++----- Examples/Examples.cs | 88 ++++++++----------- Model/ThreeAddressCode/Operands.cs | 5 +- 4 files changed, 82 insertions(+), 79 deletions(-) diff --git a/Backend/Analyses/TypeInferenceAnalysis.cs b/Backend/Analyses/TypeInferenceAnalysis.cs index b25cde66..17a875c0 100644 --- a/Backend/Analyses/TypeInferenceAnalysis.cs +++ b/Backend/Analyses/TypeInferenceAnalysis.cs @@ -325,6 +325,11 @@ instruction.RightOperand is Constant && } } } + public override void Visit(FilterInstruction instruction) + { + instruction.Result.Type = instruction.ExceptionType; + } + // FIXME hay varias instrucciones que no estan aca implementadas en este visitor, faltara agregarlas? } #endregion diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index baefc514..35de80a5 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -45,13 +45,9 @@ public MethodBody Execute() { var body = new MethodBody(MethodBodyKind.Bytecode); - body.MaxStack = method.Body.MaxStack; // FIXME + body.MaxStack = 10; // FIXME calcular (ver StackSize) body.Parameters.AddRange(method.Body.Parameters); - // FIXME entiendo que no iria esto - // this is updated later on. Needed to preserver variables that are declared but not used -// body.LocalVariables.AddRange(method.Body.LocalVariables); - if (method.Body.Instructions.Count > 0) { var instructionTranslator = new InstructionTranslator(method.Body); @@ -61,33 +57,18 @@ public MethodBody Execute() // body.ExceptionInformation.AddRange(instructionTranslator.exceptionInformationBuilder.Build()); body.Instructions.AddRange(instructionTranslator.translatedInstructions); - body.UpdateVariables(); // deja las variables que se usen en base a las instrucciones que hay - // esto de abajo lo que hace es ordenarlas, que no es necesario, pero lo que si es que regenera los indices. Esto es porque - // en la tranformacion al tac y la vuelta, variables que no se usaban por ejemplo se pierden. Y entonces despues esas variables - // tienen indices - var locals = body.LocalVariables.Cast().OrderBy(i => i.Index).ToList(); - for (var index = 0; index < locals.Count; index++) - { - locals[index].Index = index; - } - - body.LocalVariables.Clear(); - body.LocalVariables.AddRange(locals); + body.UpdateVariables(); } -/* body.UpdateVariables(); - var newLocals = body.LocalVariables.OfType().OrderBy(local => local.Index).ToList(); - body.LocalVariables.Clear(); - body.LocalVariables.AddRange(newLocals); -*/ - return body; } private class InstructionTranslator : InstructionVisitor { + // FIXMe hay que ver si no es mas prolijo quiza que sean del y que se las pase para que las rellene, mas que que este las tenga public public readonly IList translatedInstructions = new List(); public readonly ExceptionInformationBuilder exceptionInformationBuilder = new ExceptionInformationBuilder(); + public readonly StackSize stackSize; private readonly MethodBody bodyToProcess; private readonly IDictionary ignoreInstruction = new Dictionary(); @@ -95,6 +76,7 @@ private class InstructionTranslator : InstructionVisitor public InstructionTranslator(MethodBody bodyToProcess) { this.bodyToProcess = bodyToProcess; + stackSize = new StackSize(); } public override bool ShouldVisit(Instruction instruction) @@ -389,11 +371,13 @@ public override void Visit(UnconditionalBranchInstruction instruction) bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Leave, target); // FIXME mismo aca, no deberia usar offsets, sino labels. exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(instruction.Offset + 1); // block ends after instruction + break; } case UnconditionalBranchOperation.Branch: { bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Branch, target); + break; } case UnconditionalBranchOperation.EndFinally: @@ -599,5 +583,38 @@ public override void Visit(ConstrainedInstruction instruction) translatedInstructions.Add(constrainedInstruction); } } + + // FIXME se podria ir calculando. Pero ahi hay que ir contando segun la instruccion (si suma o vacia el stack). Es esta la mejor forma? + private class StackSize + { + private uint currentStackSize; + public uint MaxStackSize { get; private set; } + + public StackSize() + { + currentStackSize = 0; + MaxStackSize = 0; + } + + public void Increment() + { + currentStackSize += 1; + if (currentStackSize > MaxStackSize) + { + MaxStackSize = currentStackSize; + } + } + + public void Decrement() + { + if (currentStackSize == 0) throw new Exception("Current stack size is 0"); + currentStackSize -= 1; + } + + public void Clear() + { + currentStackSize = 0; + } + } } } \ No newline at end of file diff --git a/Examples/Examples.cs b/Examples/Examples.cs index bd20570d..a0628a61 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -796,6 +796,7 @@ public void LoadPointer() Action x = LoadAddress; // ldftn $method Action y = null; // ldnull } + /* public string LoadIndirect(ref int g) { @@ -1032,7 +1033,6 @@ public void ExceptionHandlingTryCatchSpecific(int x) } } -/* public void ExceptionHandlingMultipleFilter(int x) { try @@ -1048,40 +1048,40 @@ public void ExceptionHandlingMultipleFilter(int x) Console.WriteLine(ex.Message); } } - - public void ExceptionHandlingFilterCatch(int x) - { - try - { - var y = 1 / x; - } - catch (EntryPointNotFoundException e) when (e.Message.Contains("")) - { - Console.WriteLine(e.Message); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - } - - public void ExceptionHandlingCatchFilter(int x) - { - try - { - var y = 1 / x; - } - catch (EntryPointNotFoundException e) - { - Console.WriteLine(e.Message); - } - catch (Exception ex) when (ex.Message.Contains("")) - { - Console.WriteLine(ex.Message); - } - } - // FIXME se cuelga en el type inference -*/ + + public void ExceptionHandlingFilterCatch(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) when (e.Message.Contains("")) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + public void ExceptionHandlingCatchFilter(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) when (ex.Message.Contains("")) + { + Console.WriteLine(ex.Message); + } + } + // FIXME se cuelga en el type inference + public void ExceptionHandlingMultipleCatchs(int x) { try @@ -1097,24 +1097,6 @@ public void ExceptionHandlingMultipleCatchs(int x) Console.WriteLine(ex.Message); } } - - /* FIXME finally end label is wrong in the model (one more that it should be, that label does not exist)? this example results in an - FIXME unmarked label. The IL though is generated correctly - public void ExceptionHandlingTryCatchFinally(Exception e) - { - try - { - throw e; - } - catch - { - throw; // rethrow - } - finally - { - Console.WriteLine("finally"); - } - }*/ } } diff --git a/Model/ThreeAddressCode/Operands.cs b/Model/ThreeAddressCode/Operands.cs index 351b2f1c..c2a911e8 100644 --- a/Model/ThreeAddressCode/Operands.cs +++ b/Model/ThreeAddressCode/Operands.cs @@ -325,13 +325,12 @@ public override bool Equals(object obj) var other = obj as LocalVariable; return other != null && - this.Name.Equals(other.Name) && - this.Index.Equals(this.Index); + this.Name.Equals(other.Name); } public override int GetHashCode() { - return (Name.GetHashCode() * 397) ^ Index.GetHashCode(); + return this.Name.GetHashCode(); } public override string ToString() From 23e31b1b8e2ab8effd3c37233bbaf73efae8cf92 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 5 Aug 2020 22:03:39 -0300 Subject: [PATCH 200/256] fix exceptions in assembler --- Backend/Transformations/Assembly/Assembler.cs | 75 +++++++++++-------- .../Assembly/ExceptionInformation.cs | 62 ++++++++------- Backend/Transformations/Disassembler.cs | 4 +- .../Generators/Methods/MethodGenerator.cs | 3 + Model/ExceptionHandlers.cs | 53 +++++++++---- 5 files changed, 118 insertions(+), 79 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 35de80a5..df423c82 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -53,8 +53,7 @@ public MethodBody Execute() var instructionTranslator = new InstructionTranslator(method.Body); instructionTranslator.Visit(method.Body); - // FIXME revisar y generar bien la exception information - // body.ExceptionInformation.AddRange(instructionTranslator.exceptionInformationBuilder.Build()); + body.ExceptionInformation.AddRange(instructionTranslator.exceptionInformationBuilder.Build()); body.Instructions.AddRange(instructionTranslator.translatedInstructions); body.UpdateVariables(); @@ -299,52 +298,60 @@ public override void Visit(BreakpointInstruction instruction) public override void Visit(TryInstruction instruction) { - // try with multiple handlers is modelled as multiple try instructions with the same label but different handlers. - // if label matches with the current try, then increase the number of expected handlers. If not, begin a new try block - // FIxme add comment - // FIXME revisar esto. No deberia basarme en offsets probablemnente en ningun lado. Ya que la posta son los labels. - // FIXME me podrian venir los offsets en 0 o en cualqueira y los labels no. Arreglar - var offset = bodyToProcess.Instructions - .First(i => i.Offset > instruction.Offset && !(i is TryInstruction)) - .Offset; - if (exceptionInformationBuilder.CurrentProtectedBlockStartsAt(offset)) + // try with multiple handlers is modelled as multiple consecutive try instructions with different handlers. + var instructionIndex = bodyToProcess.Instructions.IndexOf(instruction); + var previousInstructionIsTry = instructionIndex > 0 && bodyToProcess.Instructions[instructionIndex - 1] is TryInstruction; + if (previousInstructionIsTry) { exceptionInformationBuilder.IncrementCurrentProtectedBlockExpectedHandlers(); } else { - exceptionInformationBuilder.BeginProtectedBlockAt(offset); + // try starts at the instruction following the try instruction. + var label = ""; + for (var i = instructionIndex + 1; i < bodyToProcess.Instructions.Count; i++) + { + var currentInstruction = bodyToProcess.Instructions[i]; + if (!(currentInstruction is TryInstruction)) + { + label = currentInstruction.Label; + break; + } + } + + exceptionInformationBuilder.BeginProtectedBlockAt(label); } } - // FIXME mismo aca, no deberia usar offsets, sino labels. public override void Visit(FaultInstruction instruction) { - // fixme estas deberian ser offset+1 tmb? replicar comment - exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(instruction.Offset + 1, ExceptionHandlerBlockKind.Fault); + // FIXME comment, esta duplicado en todos ademas. Hay una form amas eficiente de hacer esto? + var index = bodyToProcess.Instructions.IndexOf(instruction); + var label = bodyToProcess.Instructions[index + 1].Label; + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(label, ExceptionHandlerBlockKind.Fault); } - // FIXME mismo aca, no deberia usar offsets, sino labels. public override void Visit(FinallyInstruction instruction) { - // fixme estas deberian ser offset+1 tmb? - exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(instruction.Offset + 1, ExceptionHandlerBlockKind.Finally); + var index = bodyToProcess.Instructions.IndexOf(instruction); + var label = bodyToProcess.Instructions[index + 1].Label; + exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(label, ExceptionHandlerBlockKind.Finally); } - // FIXME mismo aca, no deberia usar offsets, sino labels. + public override void Visit(FilterInstruction instruction) { - // fixme estas deberian ser offset+1 tmb? - exceptionInformationBuilder.AddFilterHandlerToCurrentProtectedBlock(instruction.Offset + 1, instruction.kind, - instruction.ExceptionType); + var index = bodyToProcess.Instructions.IndexOf(instruction); + var label = bodyToProcess.Instructions[index + 1].Label; + exceptionInformationBuilder.AddFilterHandlerToCurrentProtectedBlock(label, instruction.kind, instruction.ExceptionType); } - // FIXME mismo aca, no deberia usar offsets, sino labels. public override void Visit(CatchInstruction instruction) { - // fixme estas deberian ser offset+1 tmb? replicar comment + var index = bodyToProcess.Instructions.IndexOf(instruction); + var label = bodyToProcess.Instructions[index + 1].Label; exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock( - instruction.Offset + 1, + label, ExceptionHandlerBlockKind.Catch, instruction.ExceptionType); } @@ -356,8 +363,12 @@ public override void Visit(ThrowInstruction instruction) : new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Rethrow); basicInstruction.Label = instruction.Label; translatedInstructions.Add(basicInstruction); - // FIXME mismo aca, no deberia usar offsets, sino labels. - exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(instruction.Offset + 1); // block ends after instruction + if (!bodyToProcess.Instructions.Last().Equals(instruction)) // FIXME medio choto esto + { + var index = bodyToProcess.Instructions.IndexOf(instruction); + var label = bodyToProcess.Instructions[index + 1].Label; + exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(label); // block ends after instruction + } } public override void Visit(UnconditionalBranchInstruction instruction) @@ -369,8 +380,9 @@ public override void Visit(UnconditionalBranchInstruction instruction) case UnconditionalBranchOperation.Leave: { bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Leave, target); - // FIXME mismo aca, no deberia usar offsets, sino labels. - exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(instruction.Offset + 1); // block ends after instruction + var index = bodyToProcess.Instructions.IndexOf(instruction); + var label = bodyToProcess.Instructions[index + 1].Label; + exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(label); // block ends after instruction break; } @@ -384,8 +396,9 @@ public override void Visit(UnconditionalBranchInstruction instruction) { bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFinally); // no more handlers after finally - // FIXME mismo aca, no deberia usar offsets, sino labels. - exceptionInformationBuilder.EndCurrentProtectedBlockAt(instruction.Offset + 1); // block ends after instruction + var index = bodyToProcess.Instructions.IndexOf(instruction); + var label = bodyToProcess.Instructions[index + 1].Label; + exceptionInformationBuilder.EndCurrentProtectedBlockAt(label); // block ends after instruction break; } case UnconditionalBranchOperation.EndFilter: diff --git a/Backend/Transformations/Assembly/ExceptionInformation.cs b/Backend/Transformations/Assembly/ExceptionInformation.cs index 2b7dd3b5..47baf598 100644 --- a/Backend/Transformations/Assembly/ExceptionInformation.cs +++ b/Backend/Transformations/Assembly/ExceptionInformation.cs @@ -18,82 +18,80 @@ public IList Build() return result; } - public void BeginProtectedBlockAt(uint offset) + public void BeginProtectedBlockAt(string label) { - var protectedBlockBuilder = new ProtectedBlockBuilder {TryStart = offset, HandlerCount = 1}; + var protectedBlockBuilder = new ProtectedBlockBuilder {TryStart = label, HandlerCount = 1}; protectedBlocks.Push(protectedBlockBuilder); } - public bool CurrentProtectedBlockStartsAt(uint offset) => protectedBlocks.Count > 0 && protectedBlocks.Peek().TryStart.Equals(offset); public void IncrementCurrentProtectedBlockExpectedHandlers() => protectedBlocks.Peek().HandlerCount++; - public void AddHandlerToCurrentProtectedBlock(uint offset, ExceptionHandlerBlockKind handlerBlockKind, IType exceptionType) => + public void AddHandlerToCurrentProtectedBlock(string label, ExceptionHandlerBlockKind handlerBlockKind, IType exceptionType) => protectedBlocks .Peek() - .EndPreviousRegionAt(offset) + .EndPreviousRegionAt(label) .Handlers.Add(new ProtectedBlockHandlerBuilder { - HandlerStart = offset, + HandlerStart = label, HandlerBlockKind = handlerBlockKind, ExceptionType = exceptionType }); - public void AddHandlerToCurrentProtectedBlock(uint offset, ExceptionHandlerBlockKind handlerBlockKind) => - AddHandlerToCurrentProtectedBlock(offset, handlerBlockKind, null); + 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(uint offset, FilterInstructionKind kind, IType exceptionType) + 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(offset, EndPreviousHandlerCondition); + protectedBlockBuilder.EndPreviousRegionAt(label, EndPreviousHandlerCondition); switch (kind) { case FilterInstructionKind.FilterSection: protectedBlockBuilder.Handlers.Add(new ProtectedBlockHandlerBuilder { - FilterStart = offset, + FilterStart = label, HandlerBlockKind = ExceptionHandlerBlockKind.Filter }); break; case FilterInstructionKind.FilterHandler: var handler = protectedBlockBuilder.Handlers.Last(); - handler.HandlerStart = offset; + handler.HandlerStart = label; handler.ExceptionType = exceptionType; break; default: throw kind.ToUnknownValueException(); } } - public void EndCurrentProtectedBlockIfAppliesAt(uint offset) + public void EndCurrentProtectedBlockIfAppliesAt(string label) { if (protectedBlocks.Count > 0 && protectedBlocks.Peek().AllHandlersAdded()) { - EndCurrentProtectedBlockAt(offset); + EndCurrentProtectedBlockAt(label); } } - public void EndCurrentProtectedBlockAt(uint offset) + public void EndCurrentProtectedBlockAt(string label) { var exceptionBlockBuilder = protectedBlocks.Pop(); exceptionBlockBuilder .Handlers .Last() - .HandlerEnd = offset; + .HandlerEnd = label; result.AddRange(exceptionBlockBuilder.Build()); } - - + private class ProtectedBlockBuilder { - private uint? tryStart; + private string tryStart; - public uint TryStart + public string TryStart { get => tryStart ?? throw new Exception("TryStart was not set"); set @@ -103,9 +101,9 @@ public uint TryStart } } - private uint? tryEnd; + private string tryEnd; - private uint TryEnd + private string TryEnd { get => tryEnd ?? throw new Exception("TryEnd was not set"); set @@ -121,17 +119,17 @@ private uint TryEnd public readonly IList Handlers = new List(); - public ProtectedBlockBuilder EndPreviousRegionAt(uint offset) => EndPreviousRegionAt(offset, () => true); + public ProtectedBlockBuilder EndPreviousRegionAt(string label) => EndPreviousRegionAt(label, () => true); - public ProtectedBlockBuilder EndPreviousRegionAt(uint offset, Func multipleHandlerCondition) + public ProtectedBlockBuilder EndPreviousRegionAt(string label, Func multipleHandlerCondition) { if (Handlers.Count == 0) // first handler, ends try region { - TryEnd = offset; + TryEnd = label; } else if (multipleHandlerCondition()) // multiple handlers. End previous handler conditionally { - Handlers.Last().HandlerEnd = offset; + Handlers.Last().HandlerEnd = label; } return this; @@ -147,9 +145,9 @@ public IList Build() => private class ProtectedBlockHandlerBuilder { - private uint? filterStart; + private string filterStart; - public uint FilterStart + public string FilterStart { get => filterStart ?? throw new Exception("FilterStart was not set"); set @@ -159,9 +157,9 @@ public uint FilterStart } } - private uint? handlerStart; + private string handlerStart; - public uint HandlerStart + public string HandlerStart { get => handlerStart ?? throw new Exception("HandlerStart was not set"); set @@ -171,9 +169,9 @@ public uint HandlerStart } } - private uint? handlerEnd; + private string handlerEnd; - public uint HandlerEnd + public string HandlerEnd { get => handlerEnd ?? throw new Exception("HandlerEnd was not set"); set diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index d7eda388..3748b419 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -1041,7 +1041,7 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) if (exceptionHandlersStart.ContainsKey(operation.Label)) { var handlerBlocks = exceptionHandlersStart[operation.Label]; - + var labelSuffix = "'"; foreach (var block in handlerBlocks) { Tac.Instruction instruction; @@ -1081,7 +1081,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/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index ca4187e2..dac1b889 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -4,6 +4,7 @@ using MetadataGenerator.Generators.Methods.Body; using MetadataGenerator.Metadata; using Model.Bytecode; +using Model.ThreeAddressCode.Instructions; using Model.Types; using static MetadataGenerator.Metadata.AttributesProvider; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -54,6 +55,8 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); typeInferenceAnalysis.Analyze(); + + var x = method.Body.Instructions.OfType().Count() > 1; var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); method.Body = bytecode; diff --git a/Model/ExceptionHandlers.cs b/Model/ExceptionHandlers.cs index c7b4be2d..f8cf0904 100644 --- a/Model/ExceptionHandlers.cs +++ b/Model/ExceptionHandlers.cs @@ -35,11 +35,15 @@ public class ProtectedBlock : IExceptionHandlerBlock public string End { get; set; } public IExceptionHandler Handler { get; set; } - public ProtectedBlock(uint start, uint end) + public ProtectedBlock(uint start, uint end): this($"L_{start:X4}", $"L_{end:X4}") + { + } + + public ProtectedBlock(string start, string end) { this.Kind = ExceptionHandlerBlockKind.Try; - this.Start = string.Format("L_{0:X4}", start); - this.End = string.Format("L_{0:X4}", end); + this.Start = start; + this.End = end; } public override string ToString() @@ -57,11 +61,16 @@ public class FilterExceptionHandler : IExceptionHandler public IType ExceptionType { get; set; } public FilterExceptionHandler(uint filterStart, uint start, uint end, IType exceptionType) + : this($"L_{filterStart:X4}", $"L_{start:X4}", $"L_{end:X4}", exceptionType) + { + } + + public FilterExceptionHandler(string filterStart, string start, string end, IType exceptionType) { this.Kind = ExceptionHandlerBlockKind.Filter; - this.FilterStart = string.Format("L_{0:X4}", filterStart); - this.Start = string.Format("L_{0:X4}", start); - this.End = string.Format("L_{0:X4}", end); + this.FilterStart = filterStart; + this.Start = start; + this.End = end; this.ExceptionType = exceptionType; } @@ -78,14 +87,19 @@ public class CatchExceptionHandler : IExceptionHandler public string End { get; set; } public IType ExceptionType { get; set; } - public CatchExceptionHandler(uint start, uint end, IType exceptionType) + public CatchExceptionHandler(uint start, uint end, IType exceptionType) : this($"L_{start:X4}", $"L_{end:X4}", exceptionType) + { + } + + public CatchExceptionHandler(string start, string end, IType exceptionType) { this.Kind = ExceptionHandlerBlockKind.Catch; - this.Start = string.Format("L_{0:X4}", start); - this.End = string.Format("L_{0:X4}", end); + this.Start = start; + this.End = end; this.ExceptionType = exceptionType; } + public override string ToString() { return string.Format("catch {0} handler {1} to {2}", this.ExceptionType, this.Start, this.End); @@ -98,13 +112,18 @@ public class FaultExceptionHandler : IExceptionHandler public string Start { get; set; } public string End { get; set; } - public FaultExceptionHandler(uint start, uint end) + public FaultExceptionHandler(uint start, uint end) : this($"L_{start:X4}", $"L_{end:X4}") + { + } + + public FaultExceptionHandler(string start, string end) { this.Kind = ExceptionHandlerBlockKind.Fault; - this.Start = string.Format("L_{0:X4}", start); - this.End = string.Format("L_{0:X4}", end); + this.Start = start; + this.End = end; } + public override string ToString() { return string.Format("fault handler {0} to {1}", this.Start, this.End); @@ -117,11 +136,15 @@ public class FinallyExceptionHandler : IExceptionHandler public string Start { get; set; } public string End { get; set; } - public FinallyExceptionHandler(uint start, uint end) + public FinallyExceptionHandler(uint start, uint end) : this($"L_{start:X4}", $"L_{end:X4}") + { + } + + public FinallyExceptionHandler(string start, string end) { this.Kind = ExceptionHandlerBlockKind.Finally; - this.Start = string.Format("L_{0:X4}", start); - this.End = string.Format("L_{0:X4}", end); + this.Start = start; + this.End = end; } public override string ToString() From bb188bb5be5865fc0d0d2fc359803471f8fe51a2 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 6 Aug 2020 20:27:56 -0300 Subject: [PATCH 201/256] draft --- Backend/Analyses/TypeInferenceAnalysis.cs | 3 +++ Backend/Transformations/Assembly/Assembler.cs | 7 ++++++- Examples/Examples.cs | 5 +---- MetadataGenerator/Generators/Methods/MethodGenerator.cs | 2 -- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Backend/Analyses/TypeInferenceAnalysis.cs b/Backend/Analyses/TypeInferenceAnalysis.cs index 17a875c0..40b9bf34 100644 --- a/Backend/Analyses/TypeInferenceAnalysis.cs +++ b/Backend/Analyses/TypeInferenceAnalysis.cs @@ -329,6 +329,9 @@ public override void Visit(FilterInstruction instruction) { instruction.Result.Type = instruction.ExceptionType; } + + + // FIXME hay varias instrucciones que no estan aca implementadas en este visitor, faltara agregarlas? } diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index df423c82..9aa1a46f 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -68,7 +68,12 @@ private class InstructionTranslator : InstructionVisitor public readonly IList translatedInstructions = new List(); public readonly ExceptionInformationBuilder exceptionInformationBuilder = new ExceptionInformationBuilder(); public readonly StackSize stackSize; - +/* + FIXME + Tema maxStack. quiza convenga validar con edgar como hacerlo. Porque ya veo que quiza hay que usar el CFG en vez de recorrer asi para calcularlo + ver como lo calcula en el dissasembler (eso de stack size at entry y demas) + */ + private readonly MethodBody bodyToProcess; private readonly IDictionary ignoreInstruction = new Dictionary(); diff --git a/Examples/Examples.cs b/Examples/Examples.cs index a0628a61..ebfe00c5 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -797,7 +797,6 @@ public void LoadPointer() Action y = null; // ldnull } -/* public string LoadIndirect(ref int g) { unsafe @@ -853,9 +852,7 @@ out SimpleClass outClass return outByte + outDouble + outClass.readOnlyIntField; } - - // FIXME rompen estos dos casos de indirect -*/ + public bool Compare(int b, int x) { var a = b == 2; // ceq diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index dac1b889..9b627691 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -55,8 +55,6 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); typeInferenceAnalysis.Analyze(); - - var x = method.Body.Instructions.OfType().Count() > 1; var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); method.Body = bytecode; From 8d12a417d89e60de9671541fff240900255fa6f3 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 6 Aug 2020 20:39:18 -0300 Subject: [PATCH 202/256] simplify to a filed instead of a new type --- MetadataProvider/SignatureTypeProvider.cs | 2 +- Model/Types/Types.cs | 47 ++++------------------- 2 files changed, 8 insertions(+), 41 deletions(-) diff --git a/MetadataProvider/SignatureTypeProvider.cs b/MetadataProvider/SignatureTypeProvider.cs index 59699882..657686d8 100644 --- a/MetadataProvider/SignatureTypeProvider.cs +++ b/MetadataProvider/SignatureTypeProvider.cs @@ -149,7 +149,7 @@ public virtual IType GetPointerType(IType targetType) public virtual IType GetByReferenceType(IType targetType) { - var result = new ManagedPointerType(targetType); + var result = new PointerType(targetType, true); return result; } diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index 553a249a..e7b163c2 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -650,53 +650,19 @@ public override bool Equals(object obj) return result; } } - - public class ManagedPointerType : IReferenceType - { - public ISet Attributes { get; private set; } - public IType TargetType { get; set; } - - public ManagedPointerType(IType targetType) - { - this.TargetType = targetType; - this.Attributes = new HashSet(); - } - - public TypeKind TypeKind - { - get { return TypeKind.ReferenceType; } - } - - public override string ToString() - { - return string.Format("{0}&", this.TargetType); - } - - public override int GetHashCode() - { - return this.TargetType.GetHashCode(); - } - - public override bool Equals(object obj) - { - var other = obj as ManagedPointerType; - - var result = other != null && - this.TargetType.Equals(other.TargetType); - - return result; - } - } public class PointerType : IReferenceType { public ISet Attributes { get; private set; } public IType TargetType { get; set; } - public PointerType(IType targetType) + public bool Managed { get; private set; } + + public PointerType(IType targetType, bool managed = false) { this.TargetType = targetType; this.Attributes = new HashSet(); + this.Managed = managed; } public TypeKind TypeKind @@ -711,7 +677,7 @@ public override string ToString() public override int GetHashCode() { - return this.TargetType.GetHashCode(); + return this.TargetType.GetHashCode() ^ this.Managed.GetHashCode(); } public override bool Equals(object obj) @@ -719,7 +685,8 @@ public override bool Equals(object obj) var other = obj as PointerType; var result = other != null && - this.TargetType.Equals(other.TargetType); + this.TargetType.Equals(other.TargetType) && + this.Managed.Equals(other.Managed); return result; } From 54696c0fd088fd806509cd1e671c007f2da2dc48 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 6 Aug 2020 20:53:32 -0300 Subject: [PATCH 203/256] incorporate managed pointer changes --- .../Generators/Methods/MethodSignatureGenerator.cs | 7 +++---- Model/Types/Types.cs | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index b19cab73..e2976faf 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Collections.Immutable; using MetadataGenerator.Metadata; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -69,10 +68,10 @@ private SRM.BlobBuilder GenerateMethodSignature( { var isByRef = false; var type = parameter.Type; - if (parameter.Type is ManagedPointerType managedPointerType) + if (parameter.Type is PointerType pointerType) { - isByRef = true; - type = managedPointerType.TargetType; + isByRef = pointerType.Managed; + type = pointerType.TargetType; } var encoder = parametersEncoder.AddParameter().Type(isByRef); diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index 4c87d43e..2279fd08 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -824,8 +824,6 @@ private int GenericParameterCountOf(IType type) return genericParameterReference.GenericContainer.GenericParameterCount; case ArrayType arrayType: return GenericParameterCountOf(arrayType.ElementsType); - case ManagedPointerType managedPointerType: - return GenericParameterCountOf(managedPointerType.TargetType); case PointerType pointerType: return GenericParameterCountOf(pointerType.TargetType); default: From 633474e56ee2c2d1d969e179628d77889495d1af Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 6 Aug 2020 21:03:34 -0300 Subject: [PATCH 204/256] fix conflicts --- Backend/Transformations/Assembly/Assembler.cs | 3 --- MetadataGenerator/Metadata/MetadataResolver.cs | 14 -------------- Model/ThreeAddressCode/Operands.cs | 5 ++--- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 5e17e4f7..a9efb8f8 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -57,9 +57,6 @@ public MethodBody Execute() } body.UpdateVariables(); - var newLocals = body.LocalVariables.OfType().OrderBy(local => local.Index).ToList(); - body.LocalVariables.Clear(); - body.LocalVariables.AddRange(newLocals); return body; } diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 46232dac..9d6e363f 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -316,20 +316,6 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) break; } - case ManagedPointerType managedPointerType: // FIXME tiene sentido esto? Es igual al pointer type.... - { - var targetType = managedPointerType.TargetType; - if (targetType.Equals(PlatformTypes.Void)) - { - encoder.VoidPointer(); - } - else - { - Encode(targetType, encoder.Pointer()); - } - - break; - } case FunctionPointerType _: { encoder.FunctionPointer(); diff --git a/Model/ThreeAddressCode/Operands.cs b/Model/ThreeAddressCode/Operands.cs index a4eb16f9..d7554c88 100644 --- a/Model/ThreeAddressCode/Operands.cs +++ b/Model/ThreeAddressCode/Operands.cs @@ -325,13 +325,12 @@ public override bool Equals(object obj) var other = obj as LocalVariable; return other != null && - this.Name.Equals(other.Name) && - this.Index.Equals(this.Index); + this.Name.Equals(other.Name); } public override int GetHashCode() { - return (Name.GetHashCode() * 397) ^ Index.GetHashCode(); + return Name.GetHashCode(); } public override string ToString() From 24ac94010935178a8d1d7f3da7a56d65962e113d Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 7 Aug 2020 08:52:02 -0300 Subject: [PATCH 205/256] more fixes --- Backend/Analyses/TypeInferenceAnalysis.cs | 1 + Backend/Transformations/Assembly/Assembler.cs | 6 +- Console/Program.cs | 8 +-- Examples/Examples.cs | 6 +- .../Methods/Body/MethodBodyGenerator.cs | 63 +++++++------------ .../Methods/MethodSignatureGenerator.cs | 2 +- 6 files changed, 38 insertions(+), 48 deletions(-) diff --git a/Backend/Analyses/TypeInferenceAnalysis.cs b/Backend/Analyses/TypeInferenceAnalysis.cs index 40b9bf34..b6074fb4 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 { diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 9aa1a46f..acdaf545 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -67,13 +67,14 @@ private class InstructionTranslator : InstructionVisitor // FIXMe hay que ver si no es mas prolijo quiza que sean del y que se las pase para que las rellene, mas que que este las tenga public public readonly IList translatedInstructions = new List(); public readonly ExceptionInformationBuilder exceptionInformationBuilder = new ExceptionInformationBuilder(); + public readonly StackSize stackSize; /* FIXME Tema maxStack. quiza convenga validar con edgar como hacerlo. Porque ya veo que quiza hay que usar el CFG en vez de recorrer asi para calcularlo ver como lo calcula en el dissasembler (eso de stack size at entry y demas) */ - + private readonly MethodBody bodyToProcess; private readonly IDictionary ignoreInstruction = new Dictionary(); @@ -562,7 +563,8 @@ public override void Visit(InitializeMemoryInstruction instruction) public override void Visit(InitializeObjectInstruction instruction) { - var initObjInstruction = new Bytecode.InitObjInstruction(instruction.Offset, instruction.TargetAddress.Type) + var type = ((PointerType) instruction.TargetAddress.Type).TargetType; + var initObjInstruction = new Bytecode.InitObjInstruction(instruction.Offset, type) { Label = instruction.Label }; diff --git a/Console/Program.cs b/Console/Program.cs index 05ea698c..c91e2914 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -411,19 +411,19 @@ static void Main(string[] args) { var inputs = new[] { - new[] {"../../../Examples/bin/Debug/Examples.dll"}, //FIXME se rompe/se cuelga el type inference - /* new[] FIXME rompe el type inference + new[] {"../../../Examples/bin/Debug/Examples.dll"}, + /* new[] { "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll", "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll" }, */ - /* new[] + new[] { "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll", "../../../../DSA/DSA/DSAUnitTests/bin/Debug/net45/DSAUnitTests.dll" }, - +/* new[] { "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.dll", diff --git a/Examples/Examples.cs b/Examples/Examples.cs index ebfe00c5..4af0faee 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -797,6 +797,7 @@ public void LoadPointer() Action y = null; // ldnull } + /* public string LoadIndirect(ref int g) { unsafe @@ -852,7 +853,8 @@ out SimpleClass outClass return outByte + outDouble + outClass.readOnlyIntField; } - + fixme rompe el type inferer + */ public bool Compare(int b, int x) { var a = b == 2; // ceq @@ -1077,7 +1079,7 @@ public void ExceptionHandlingCatchFilter(int x) Console.WriteLine(ex.Message); } } - // FIXME se cuelga en el type inference + public void ExceptionHandlingMultipleCatchs(int x) { diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 3093250c..71d4af64 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -423,46 +423,31 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } case LoadOperation.Value: { - var value = (loadInstruction.Operand as Constant).Value; - if (value == null) + switch ((loadInstruction.Operand as Constant).Value) { - instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); - } - else - { - if (loadInstruction.Operand.Type.Equals(PlatformTypes.String)) - { - instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString((string) value)); - } - - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.UInt8)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); - instructionEncoder.Token((int) value); - } - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int16, PlatformTypes.Int32, PlatformTypes.UInt16, - PlatformTypes.UInt32)) - { - instructionEncoder.LoadConstantI4((int) value); - } - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) - { - instructionEncoder.LoadConstantI8((long) value); - } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float32)) - { - instructionEncoder.LoadConstantR4((float) value); - } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float64)) - { - instructionEncoder.LoadConstantR8((double) value); - } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Boolean)) - { - var boolAsInt = (bool) value ? 1 : 0; - instructionEncoder.LoadConstantI4(boolAsInt); - } - else throw new UnhandledCase(); + case null: + instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); + break; + case string value: + instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); + break; + case int value: + instructionEncoder.LoadConstantI4(value); + break; + case long value: + instructionEncoder.LoadConstantI8(value); + break; + case float value: + instructionEncoder.LoadConstantR4(value); + break; + case double value: + instructionEncoder.LoadConstantR8(value); + break; + case bool value: + instructionEncoder.LoadConstantI4(value ? 1 : 0); + break; + default: + throw new UnhandledCase(); } break; diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index e2976faf..60ca7040 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -68,7 +68,7 @@ private SRM.BlobBuilder GenerateMethodSignature( { var isByRef = false; var type = parameter.Type; - if (parameter.Type is PointerType pointerType) + if (type is PointerType pointerType) { isByRef = pointerType.Managed; type = pointerType.TargetType; From 5110a8da0f6cdb8f4a890286676bb313a29842e8 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 10 Aug 2020 08:42:46 -0300 Subject: [PATCH 206/256] fixes --- Backend/Analyses/TypeInferenceAnalysis.cs | 21 +- Backend/Transformations/Assembly/Assembler.cs | 228 +++++++++--------- Backend/Utils/OperationHelper.cs | 2 +- Console/Program.cs | 8 +- .../Generators/Methods/MethodGenerator.cs | 6 +- 5 files changed, 137 insertions(+), 128 deletions(-) diff --git a/Backend/Analyses/TypeInferenceAnalysis.cs b/Backend/Analyses/TypeInferenceAnalysis.cs index b6074fb4..e6a661a8 100644 --- a/Backend/Analyses/TypeInferenceAnalysis.cs +++ b/Backend/Analyses/TypeInferenceAnalysis.cs @@ -56,7 +56,26 @@ public override void Visit(MethodCallInstruction instruction) { if (instruction.HasResult) { - instruction.Result.Type = instruction.Method.ReturnType; + + if (instruction.Method.ReturnType is GenericParameterReference genericParameterReference) + { + switch (genericParameterReference.Kind) + { + case GenericParameterKind.Type: + instruction.Result.Type = (genericParameterReference.GenericContainer as IBasicType).GenericArguments[genericParameterReference.Index]; + break; + case GenericParameterKind.Method: + instruction.Result.Type = (genericParameterReference.GenericContainer as IMethodReference).GenericArguments[genericParameterReference.Index]; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + else + { + instruction.Result.Type = instruction.Method.ReturnType; + } + } // Skip implicit "this" parameter. diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index acdaf545..3666c176 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -21,10 +21,6 @@ using ConstrainedInstruction = Model.ThreeAddressCode.Instructions.ConstrainedInstruction; using Instruction = Model.ThreeAddressCode.Instructions.Instruction; -// FIXME revisar los usos de operand y result. Cuando hay que usar uno y cuando otro? lo mismo lo de mirar si son temporal variables y eso -// FIXME me suena a que esta mal -// FIXME reveer ademas toda la parte de las local variables y demas. La traduccion no tiene que dejar el bytecod eigual al original, sino -// FIXME semanticamente igual. Por ende no tengo porque tener las mismas variables que antes. Puede haber mas, puede haber menos. namespace Backend.Transformations.Assembly { public class Assembler @@ -90,6 +86,8 @@ public override bool ShouldVisit(Instruction instruction) return shouldProcessInstruction; } + + // FIXME hace falta esta realmente? public override void Visit(PopInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Pop) {Label = instruction.Label}; @@ -98,7 +96,6 @@ public override void Visit(PopInstruction instruction) public override void Visit(BinaryInstruction instruction) { - // FIXME tiene sentido esto? if (instruction.Operation == BinaryOperation.Neq) { var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Eq) @@ -133,124 +130,111 @@ public override void Visit(UnaryInstruction instruction) translatedInstructions.Add(basicInstruction); } - // FIXME revisar los casos, hay algunos que no estoy seguro de que esten bien. se repiten caminos ademas (sobretodo por el reference) public override void Visit(LoadInstruction instruction) { Bytecode.Instruction bytecodeInstruction; - if (instruction.Operand is TemporalVariable && instruction.Result is TemporalVariable) + if (instruction.Result is TemporalVariable) { - if (instruction.Operand.Equals(instruction.Result)) - { - return; - } - else + switch (instruction.Operand) { - bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Dup); - } - } - else - { - if (instruction.Result is LocalVariable loc) - { - bytecodeInstruction = new Bytecode.StoreInstruction(instruction.Offset, loc); - } - else - { - 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: { - 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.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) { - bytecodeInstruction = new Bytecode.LoadIndirectInstruction(instruction.Offset, dereference.Type); - break; - } - case Reference reference: - switch (reference.Value) + case ArrayElementAccess arrayElementAccess: { - 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 Exception(); // TODO + bytecodeInstruction = new Bytecode.LoadArrayElementInstruction( + instruction.Offset, + Bytecode.LoadArrayElementOperation.Address, + (ArrayType) arrayElementAccess.Array.Type) {Method = arrayElementAccess.Method}; + break; } - 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: - { - var type = (ArrayType) arrayElementAccess.Array.Type; - bytecodeInstruction = new Bytecode.LoadArrayElementInstruction( - instruction.Offset, - Bytecode.LoadArrayElementOperation.Content, - 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 Exception(); // TODO } - default: throw new Exception(); // TODO + + 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 Exception(); // TODO } } + else + { + bytecodeInstruction = new Bytecode.StoreInstruction(instruction.Offset, (LocalVariable) instruction.Result); + } bytecodeInstruction.Label = instruction.Label; translatedInstructions.Add(bytecodeInstruction); } - // FIXME revisar public override void Visit(StoreInstruction instruction) { Bytecode.Instruction storeInstruction; @@ -258,8 +242,7 @@ public override void Visit(StoreInstruction instruction) { case ArrayElementAccess arrayElementAccess: { - var type = (ArrayType) arrayElementAccess.Array.Type; - storeInstruction = new Bytecode.StoreArrayElementInstruction(instruction.Offset, type) + storeInstruction = new Bytecode.StoreArrayElementInstruction(instruction.Offset, (ArrayType) arrayElementAccess.Array.Type) { Method = arrayElementAccess.Method }; @@ -331,7 +314,9 @@ public override void Visit(TryInstruction instruction) public override void Visit(FaultInstruction instruction) { - // FIXME comment, esta duplicado en todos ademas. Hay una form amas eficiente de hacer esto? + // FIXME comment, esta duplicado en todos ademas. Hay una form amas eficiente de hacer esto?. Quiza si no uso el visitor, puedo recorrerlas + // en orden e ir pasando tambien el indice de la instruccion que estoy procesando. Si hago eso, lo de ignore insturctions + // no hace falta que este en el visitor var index = bodyToProcess.Instructions.IndexOf(instruction); var label = bodyToProcess.Instructions[index + 1].Label; exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(label, ExceptionHandlerBlockKind.Fault); @@ -395,7 +380,6 @@ public override void Visit(UnconditionalBranchInstruction instruction) case UnconditionalBranchOperation.Branch: { bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Branch, target); - break; } case UnconditionalBranchOperation.EndFinally: @@ -445,22 +429,30 @@ public override void Visit(ReturnInstruction instruction) public override void Visit(ConditionalBranchInstruction instruction) { - // FIXME esto se puede optimizar. Porque esto hace que por ejemplo haga un load false y despues haga un branc eq. EN vez - // FIXME de de una hacer brfalse. Por otro lado, agarro solo los constant (literales) porque los demas casos son variables y se supone - // FIXME que ya se cargaron en la instruccion anterior - switch (instruction.RightOperand) + var branchOperation = OperationHelper.ToBranchOperation(instruction.Operation); + if (instruction.RightOperand is Constant constant) { - case Constant constant: - var a = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant); - a.Label += "'"; // FIXME - translatedInstructions.Add(a); - break; + switch (constant.Value) + { + case null: + branchOperation = instruction.Operation == BranchOperation.Eq + ? Bytecode.BranchOperation.True + : Bytecode.BranchOperation.False; + break; + default: + var loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant) + { + Label = instruction.Label + "'" + }; + translatedInstructions.Add(loadInstruction); + break; + } } var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); var branchInstruction = new Bytecode.BranchInstruction( instruction.Offset, - OperationHelper.ToBranchOperation(instruction.Operation), + branchOperation, target) { Label = instruction.Label diff --git a/Backend/Utils/OperationHelper.cs b/Backend/Utils/OperationHelper.cs index 90860dbc..dacd86ca 100644 --- a/Backend/Utils/OperationHelper.cs +++ b/Backend/Utils/OperationHelper.cs @@ -161,7 +161,7 @@ public static Bytecode.ConvertOperation ToConvertOperation(Tac.ConvertOperation 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.Unbox; + case Tac.ConvertOperation.UnboxPtr: return Bytecode.ConvertOperation.UnboxPtr; case Tac.ConvertOperation.IsInst: return Bytecode.ConvertOperation.IsInst; default: throw operation.ToUnknownValueException(); } diff --git a/Console/Program.cs b/Console/Program.cs index c91e2914..ca11806d 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -412,30 +412,28 @@ static void Main(string[] args) var inputs = new[] { new[] {"../../../Examples/bin/Debug/Examples.dll"}, - /* new[] + new[] { "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll", "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll" }, -*/ new[] { "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll", "../../../../DSA/DSA/DSAUnitTests/bin/Debug/net45/DSAUnitTests.dll" }, -/* new[] { "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.dll", "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.Tests.dll" - }, + }, new[] { "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Async.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll" - }*/ + } }; foreach (var input in inputs) diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 9b627691..fdb54739 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -44,7 +44,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) // FIXME undo this. Just for testing assembler. var tac = new Backend.Transformations.Disassembler(method).Execute(); method.Body = tac; - + var cfanalysis = new ControlFlowAnalysis(method.Body); var cfg = cfanalysis.GenerateExceptionalControlFlow(); @@ -55,8 +55,8 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); typeInferenceAnalysis.Analyze(); - - var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); + + var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); method.Body = bytecode; // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated From 4295c4572d084b8bc2ac009be5facf4824b2ecc0 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 12 Aug 2020 08:49:16 -0300 Subject: [PATCH 207/256] fix --- Backend/Transformations/Assembly/Assembler.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 3666c176..8f2bf3ea 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -41,7 +41,7 @@ public MethodBody Execute() { var body = new MethodBody(MethodBodyKind.Bytecode); - body.MaxStack = 10; // FIXME calcular (ver StackSize) + body.MaxStack = 20; // FIXME calcular (ver StackSize) body.Parameters.AddRange(method.Body.Parameters); if (method.Body.Instructions.Count > 0) @@ -436,8 +436,8 @@ public override void Visit(ConditionalBranchInstruction instruction) { case null: branchOperation = instruction.Operation == BranchOperation.Eq - ? Bytecode.BranchOperation.True - : Bytecode.BranchOperation.False; + ? Bytecode.BranchOperation.False + : Bytecode.BranchOperation.True; break; default: var loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant) From 51ae09060d2ec4e9be4e91b12a7d94c7fd2ada11 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 13 Aug 2020 21:24:35 -0300 Subject: [PATCH 208/256] fixes --- Backend/Transformations/Assembly/Assembler.cs | 28 ++++++++----------- Console/Program.cs | 6 ++-- Examples/Examples.cs | 3 +- .../Methods/Body/MethodBodyGenerator.cs | 27 ++++++++++++++++-- .../Generators/Methods/MethodGenerator.cs | 4 +++ MetadataProvider/AssemblyExtractor.cs | 6 ++++ 6 files changed, 51 insertions(+), 23 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 8f2bf3ea..7acafb6e 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -100,12 +100,16 @@ public override void Visit(BinaryInstruction instruction) { var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Eq) { - Label = instruction.Label + Label = instruction.Label, + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands }; translatedInstructions.Add(basicInstruction); basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Neg) { - Label = instruction.Label + Label = instruction.Label + "'", + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands }; translatedInstructions.Add(basicInstruction); } @@ -316,7 +320,7 @@ public override void Visit(FaultInstruction instruction) { // FIXME comment, esta duplicado en todos ademas. Hay una form amas eficiente de hacer esto?. Quiza si no uso el visitor, puedo recorrerlas // en orden e ir pasando tambien el indice de la instruccion que estoy procesando. Si hago eso, lo de ignore insturctions - // no hace falta que este en el visitor + // no hace falta que este en el visitor. La realidad es que necesito indices asi que el visitor mucho no me sirve var index = bodyToProcess.Instructions.IndexOf(instruction); var label = bodyToProcess.Instructions[index + 1].Label; exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(label, ExceptionHandlerBlockKind.Fault); @@ -432,21 +436,11 @@ public override void Visit(ConditionalBranchInstruction instruction) var branchOperation = OperationHelper.ToBranchOperation(instruction.Operation); if (instruction.RightOperand is Constant constant) { - switch (constant.Value) + var loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant) { - case null: - branchOperation = instruction.Operation == BranchOperation.Eq - ? Bytecode.BranchOperation.False - : Bytecode.BranchOperation.True; - break; - default: - var loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant) - { - Label = instruction.Label + "'" - }; - translatedInstructions.Add(loadInstruction); - break; - } + Label = instruction.Label + "'" + }; + translatedInstructions.Add(loadInstruction); } var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); diff --git a/Console/Program.cs b/Console/Program.cs index ca11806d..5988b819 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -426,13 +426,13 @@ static void Main(string[] args) { "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.dll", "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.Tests.dll" - }, + }, new[] { + "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Async.dll", "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll", - "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll", - "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll" + "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll" } }; diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 4af0faee..a15066da 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Linq; using System.Reflection.Metadata; using System.Runtime.ConstrainedExecution; using Classes; @@ -1080,7 +1081,7 @@ public void ExceptionHandlingCatchFilter(int x) } } - + public void ExceptionHandlingMultipleCatchs(int x) { try diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 71d4af64..d784b68d 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -28,8 +28,15 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var labelToEncoderOffset = new Dictionary(); var switchInstructionsPlaceHolders = new List(); - foreach (var instruction in body.Instructions) + var ignoreInstructions = new HashSet(); + + for (var i = 0; i < body.Instructions.Count; i++) { + var instruction = body.Instructions[i]; + if (ignoreInstructions.Contains(i)) + continue; // FIXME quiza se puede hacer lo de antes del for en el constructor y que sea de insrtnacia + // fixme y dejar el for con esto de ignore y demas y despues un metodo aparte que hace todo. + labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); @@ -96,7 +103,23 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Shr_un : SRM.ILOpCode.Shr); break; case BasicOperation.Eq: - instructionEncoder.OpCode(SRM.ILOpCode.Ceq); + var previousInstructionIsLoadNull = + body.Instructions[i - 1] is LoadInstruction loadInstruction && + loadInstruction.Operand is Constant constant && + constant.Value == null; + var nexInstructionIsNeg = body.Instructions[i + 1] is BasicInstruction bi && bi.Operation == BasicOperation.Neg; + if (previousInstructionIsLoadNull && nexInstructionIsNeg) + { + // cgt_un is used as a compare-not-equal with null. + // ldnull - ceq - neq => ldnull - cgt_un + instructionEncoder.OpCode(SRM.ILOpCode.Cgt_un); + ignoreInstructions.Add(i + 1); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Ceq); + } + break; case BasicOperation.Lt: instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Clt_un : SRM.ILOpCode.Clt); diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index fdb54739..1580c3fb 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -7,6 +7,8 @@ using Model.ThreeAddressCode.Instructions; using Model.Types; using static MetadataGenerator.Metadata.AttributesProvider; +using BranchInstruction = Model.Bytecode.BranchInstruction; +using BranchOperation = Model.Bytecode.BranchOperation; using ECMA335 = System.Reflection.Metadata.Ecma335; using SR = System.Reflection; using SRM = System.Reflection.Metadata; @@ -41,6 +43,8 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var methodBodyOffset = -1; if (method.HasBody) { + // FIXME PROBAR generar y correr tests (+pedump) CONVIRTIENDO Y SIN CONVERTIR + // FIXME undo this. Just for testing assembler. var tac = new Backend.Transformations.Disassembler(method).Execute(); method.Body = tac; diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 52df952e..e7c73c07 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -678,6 +678,12 @@ private void ExtractParameters(IList parameters) { IType type = currentMethod.ContainingType; + if (currentMethod.ContainingType.GenericParameters.Count > 0) + { + // within a generic method body, "this" is not the generic type itself but its instantiation + type = currentMethod.ContainingType.Instantiate(currentMethod.ContainingType.GenericParameters); + } + if (type.TypeKind == TypeKind.ValueType) { type = signatureTypeProvider.GetByReferenceType(type); From eec5ab120cb4fe06bb3a809a88e3c6c1b79f500e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 13 Aug 2020 21:43:18 -0300 Subject: [PATCH 209/256] remove code generator changes --- Console/Program.cs | 32 +------ Examples/Examples.cs | 64 +++----------- .../Methods/Body/MethodBodyGenerator.cs | 88 ++++++++----------- .../Methods/MethodSignatureGenerator.cs | 2 +- .../Metadata/MetadataResolver.cs | 2 +- 5 files changed, 55 insertions(+), 133 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index 5988b819..7310e8c2 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -443,38 +443,8 @@ static void Main(string[] args) DisassembleAndThenAssemble(file); } } - -/* foreach (var input in inputs) - { - foreach (var file in input) - { - System.Console.WriteLine("Processing file: " + file); - var host = new Host(); - - PlatformTypes.Resolve(host); - - var loader = new Loader(host); - var assembly = loader.LoadAssembly(file); - var methods = - from types in assembly.RootNamespace.GetAllTypes() - from m in types.Methods - where m.HasBody - select m; - - foreach (var method in methods) - { - method.Body = new Disassembler(method).Execute(); // to tac - var newBody = new Assembler(method).Execute(); // to bytecode - var exOriginal = method.Body.ExceptionInformation; - var exGenerated = newBody.ExceptionInformation; - var x = 1; - } - } - }*/ - - - System.Console.WriteLine("Done!"); + System.Console.WriteLine("Done!"); } } } \ No newline at end of file diff --git a/Examples/Examples.cs b/Examples/Examples.cs index a15066da..f6f342d1 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -2,9 +2,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Linq; using System.Reflection.Metadata; -using System.Runtime.ConstrainedExecution; using Classes; using Enums; using Hierarchy; @@ -798,7 +796,6 @@ public void LoadPointer() Action y = null; // ldnull } - /* public string LoadIndirect(ref int g) { unsafe @@ -854,8 +851,7 @@ out SimpleClass outClass return outByte + outDouble + outClass.readOnlyIntField; } - fixme rompe el type inferer - */ + public bool Compare(int b, int x) { var a = b == 2; // ceq @@ -1033,70 +1029,36 @@ public void ExceptionHandlingTryCatchSpecific(int x) } } - public void ExceptionHandlingMultipleFilter(int x) + + public void ExceptionHandlingTryCatchFilter(int x) { try { var y = 1 / x; } - catch (EntryPointNotFoundException e) when (e.Message.Contains("")) - { - Console.WriteLine(e.Message); - } catch (Exception ex) when (ex.Message.Contains("by zero")) { Console.WriteLine(ex.Message); } } - - public void ExceptionHandlingFilterCatch(int x) - { - try - { - var y = 1 / x; - } - catch (EntryPointNotFoundException e) when (e.Message.Contains("")) - { - Console.WriteLine(e.Message); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - } - - public void ExceptionHandlingCatchFilter(int x) - { - try - { - var y = 1 / x; - } - catch (EntryPointNotFoundException e) - { - Console.WriteLine(e.Message); - } - catch (Exception ex) when (ex.Message.Contains("")) - { - Console.WriteLine(ex.Message); - } - } - - - public void ExceptionHandlingMultipleCatchs(int x) + + /* FIXME finally end label is wrong in the model (one more that it should be, that label does not exist)? this example results in an + FIXME unmarked label. The IL though is generated correctly + public void ExceptionHandlingTryCatchFinally(Exception e) { try { - var y = 1 / x; + throw e; } - catch (EntryPointNotFoundException e) + catch { - Console.WriteLine(e.Message); + throw; // rethrow } - catch (Exception ex) + finally { - Console.WriteLine(ex.Message); + Console.WriteLine("finally"); } - } + }*/ } } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index d784b68d..06fc5916 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -28,15 +28,8 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var labelToEncoderOffset = new Dictionary(); var switchInstructionsPlaceHolders = new List(); - var ignoreInstructions = new HashSet(); - - for (var i = 0; i < body.Instructions.Count; i++) + foreach (var instruction in body.Instructions) { - var instruction = body.Instructions[i]; - if (ignoreInstructions.Contains(i)) - continue; // FIXME quiza se puede hacer lo de antes del for en el constructor y que sea de insrtnacia - // fixme y dejar el for con esto de ignore y demas y despues un metodo aparte que hace todo. - labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); @@ -103,23 +96,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Shr_un : SRM.ILOpCode.Shr); break; case BasicOperation.Eq: - var previousInstructionIsLoadNull = - body.Instructions[i - 1] is LoadInstruction loadInstruction && - loadInstruction.Operand is Constant constant && - constant.Value == null; - var nexInstructionIsNeg = body.Instructions[i + 1] is BasicInstruction bi && bi.Operation == BasicOperation.Neg; - if (previousInstructionIsLoadNull && nexInstructionIsNeg) - { - // cgt_un is used as a compare-not-equal with null. - // ldnull - ceq - neq => ldnull - cgt_un - instructionEncoder.OpCode(SRM.ILOpCode.Cgt_un); - ignoreInstructions.Add(i + 1); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Ceq); - } - + instructionEncoder.OpCode(SRM.ILOpCode.Ceq); break; case BasicOperation.Lt: instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Clt_un : SRM.ILOpCode.Clt); @@ -218,6 +195,7 @@ loadInstruction.Operand is Constant constant && throw new UnhandledCase(); } + instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(branchInstruction.Target)); break; @@ -446,32 +424,44 @@ loadInstruction.Operand is Constant constant && } case LoadOperation.Value: { - switch ((loadInstruction.Operand as Constant).Value) + if (((Constant) loadInstruction.Operand).Value == null) { - case null: - instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); - break; - case string value: - instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); - break; - case int value: - instructionEncoder.LoadConstantI4(value); - break; - case long value: - instructionEncoder.LoadConstantI8(value); - break; - case float value: - instructionEncoder.LoadConstantR4(value); - break; - case double value: - instructionEncoder.LoadConstantR8(value); - break; - case bool value: - instructionEncoder.LoadConstantI4(value ? 1 : 0); - break; - default: - throw new UnhandledCase(); + instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); } + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.String)) + { + var value = (string) (loadInstruction.Operand as Constant).Value; + instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); + } + + else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.UInt8)) + { + var value = (int) (loadInstruction.Operand as Constant).Value; + instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); + instructionEncoder.Token(value); + } + else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int16, PlatformTypes.Int32, PlatformTypes.UInt16, + PlatformTypes.UInt32)) + { + var value = (int) (loadInstruction.Operand as Constant).Value; + instructionEncoder.LoadConstantI4(value); + } + else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) + { + var value = (long) (loadInstruction.Operand as Constant).Value; + instructionEncoder.LoadConstantI8(value); + } + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float32)) + { + var value = (float) (loadInstruction.Operand as Constant).Value; + instructionEncoder.LoadConstantR4(value); + } + else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float64)) + { + var value = (double) (loadInstruction.Operand as Constant).Value; + instructionEncoder.LoadConstantR8(value); + } + else throw new UnhandledCase(); break; } diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 60ca7040..e2976faf 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -68,7 +68,7 @@ private SRM.BlobBuilder GenerateMethodSignature( { var isByRef = false; var type = parameter.Type; - if (type is PointerType pointerType) + if (parameter.Type is PointerType pointerType) { isByRef = pointerType.Managed; type = pointerType.TargetType; diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index d78f7542..9d6e363f 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -84,7 +84,7 @@ public SRM.EntityHandle HandleOf(IMetadataReference metadataReference) { case IBasicType basicType: return GetOrAddTypeReference(basicType); - case IType iType when iType is ArrayType || iType is PointerType || iType is IGenericParameterReference: + case IType iType when iType is ArrayType || iType is PointerType || iType is IGenericParameterReference: return GetOrAddTypeSpecificationFor(iType); default: throw new Exception($"type {type} not yet supported"); From a4947a61b4d4e8fea74f6806121be5a500120a7f Mon Sep 17 00:00:00 2001 From: fcurdi Date: Thu, 13 Aug 2020 21:53:53 -0300 Subject: [PATCH 210/256] refactor --- Examples/Examples.cs | 74 ---------------- ExamplesEXE/ExamplesEXE.cs | 4 - .../Methods/Body/MethodBodyGenerator.cs | 85 ++++++++++--------- .../Methods/MethodSignatureGenerator.cs | 2 +- 4 files changed, 48 insertions(+), 117 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index f6f342d1..6b5acb6b 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -796,62 +796,6 @@ public void LoadPointer() Action y = null; // ldnull } - public string LoadIndirect(ref int g) - { - unsafe - { - sbyte a_1 = sbyte.MinValue; - byte a_2 = byte.MinValue; - short b_1 = short.MinValue; - ushort b_2 = ushort.MinValue; - int c_1 = int.MinValue; - uint c_2 = uint.MinValue; - long d = long.MinValue; - float e = float.MinValue; - double f = double.MinValue; - IntPtr h = default; - - var x1 = *&a_1; // ldind.i1 - var x2 = *&a_2; // ldind.u1 - var x3 = *&b_1; // ldind.i2 - var x4 = *&b_2; // ldind.u2 - var x5 = *&c_1; // ldind.i4 - var x6 = *&c_2; // ldind.u4 - var x7 = *&d; // ldind.i8 (ldind.u8 is alias for ldind.i8) - var x8 = *&e; // ldind.r4 - var x9 = *&f; // ldind.r8 - var x10 = *&h; // ldind.i - var x11 = g; // ldind.ref - - return a_1 + c_2.ToString() + x4 + x11 + g.ToString().Length; - } - } - - public double StoreIndirect( - out sbyte outByte, - out short outShort, - out int outInt, - out long outLong, - out float outFloat, - out double outDouble, - out IntPtr outIntPtr, - out SimpleClass outClass - ) - { - IntPtr h = default; - - outByte = 1; // stind.i1 - outShort = 2; // stind.i2 - outInt = 3; // stind.i4 - outLong = 4; // stind.i8 (stind.u8 is alias for stind.i8) - outFloat = 5; // stind.r4 - outDouble = 6; // stind.r8 - outIntPtr = h; // stind.i - outClass = new SimpleClass(1, ""); // stind.ref - - return outByte + outDouble + outClass.readOnlyIntField; - } - public bool Compare(int b, int x) { var a = b == 2; // ceq @@ -1041,24 +985,6 @@ public void ExceptionHandlingTryCatchFilter(int x) Console.WriteLine(ex.Message); } } - - /* FIXME finally end label is wrong in the model (one more that it should be, that label does not exist)? this example results in an - FIXME unmarked label. The IL though is generated correctly - public void ExceptionHandlingTryCatchFinally(Exception e) - { - try - { - throw e; - } - catch - { - throw; // rethrow - } - finally - { - Console.WriteLine("finally"); - } - }*/ } } diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index f969fbff..65e437db 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -44,10 +44,6 @@ public static void Main(string[] args) Console.WriteLine(methodBodyExamples.Nothing(new object())); Console.WriteLine(methodBodyExamples.Alloc()); methodBodyExamples.LoadAddress(4); - Console.WriteLine(methodBodyExamples.LoadIndirect(ref g)); - Console.WriteLine(methodBodyExamples.StoreIndirect(out sbyte b, out short q, out int i, out long l, out float f, out double d, - out IntPtr ip, - out SimpleClass s)); Console.WriteLine(methodBodyExamples.LoadToken()); Console.WriteLine(sc.ReceivesArraysAndReturnsIntArray(new[] {""}, new[] {new Exception()})); unsafe diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 2f729c62..1b92590f 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -27,8 +27,13 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var labelToEncoderOffset = new Dictionary(); var switchInstructionsPlaceHolders = new List(); - foreach (var instruction in body.Instructions) + var ignoreInstructions = new HashSet(); + + for (var i = 0; i < body.Instructions.Count; i++) { + if (ignoreInstructions.Contains(i)) continue; + + var instruction = body.Instructions[i]; labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); @@ -95,7 +100,23 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Shr_un : SRM.ILOpCode.Shr); break; case BasicOperation.Eq: - instructionEncoder.OpCode(SRM.ILOpCode.Ceq); + var previousInstructionIsLoadNull = + body.Instructions[i - 1] is LoadInstruction loadInstruction && + loadInstruction.Operand is Constant constant && + constant.Value == null; + var nexInstructionIsNeg = body.Instructions[i + 1] is BasicInstruction bi && bi.Operation == BasicOperation.Neg; + if (previousInstructionIsLoadNull && nexInstructionIsNeg) + { + // cgt_un is used as a compare-not-equal with null. + // load null - compare eq - negate => ldnull - cgt_un + instructionEncoder.OpCode(SRM.ILOpCode.Cgt_un); + ignoreInstructions.Add(i + 1); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Ceq); + } + break; case BasicOperation.Lt: instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Clt_un : SRM.ILOpCode.Clt); @@ -423,44 +444,32 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } case LoadOperation.Value: { - if (((Constant) loadInstruction.Operand).Value == null) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); - } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.String)) - { - var value = (string) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); - } - - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.UInt8)) - { - var value = (int) (loadInstruction.Operand as Constant).Value; - instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); - instructionEncoder.Token(value); - } - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int16, PlatformTypes.Int32, PlatformTypes.UInt16, - PlatformTypes.UInt32)) - { - var value = (int) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantI4(value); - } - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) + switch ((loadInstruction.Operand as Constant).Value) { - var value = (long) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantI8(value); + case null: + instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); + break; + case string value: + instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); + break; + case int value: + instructionEncoder.LoadConstantI4(value); + break; + case long value: + instructionEncoder.LoadConstantI8(value); + break; + case float value: + instructionEncoder.LoadConstantR4(value); + break; + case double value: + instructionEncoder.LoadConstantR8(value); + break; + case bool value: + instructionEncoder.LoadConstantI4(value ? 1 : 0); + break; + default: + throw new UnhandledCase(); } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float32)) - { - var value = (float) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantR4(value); - } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float64)) - { - var value = (double) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantR8(value); - } - else throw new UnhandledCase(); break; } diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index e2976faf..60ca7040 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -68,7 +68,7 @@ private SRM.BlobBuilder GenerateMethodSignature( { var isByRef = false; var type = parameter.Type; - if (parameter.Type is PointerType pointerType) + if (type is PointerType pointerType) { isByRef = pointerType.Managed; type = pointerType.TargetType; From dddad4be57c5c87e26146214a97f4f6bda751ea6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 14 Aug 2020 07:27:17 -0300 Subject: [PATCH 211/256] undo changes --- Examples/Examples.cs | 55 ++++++++++++++++++- .../Methods/Body/MethodBodyGenerator.cs | 1 - 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index f6f342d1..437ead01 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection.Metadata; +using System.Runtime.ConstrainedExecution; using Classes; using Enums; using Hierarchy; @@ -1030,18 +1031,70 @@ public void ExceptionHandlingTryCatchSpecific(int x) } - public void ExceptionHandlingTryCatchFilter(int x) + public void ExceptionHandlingMultipleFilter(int x) { try { var y = 1 / x; } + catch (EntryPointNotFoundException e) when (e.Message.Contains("")) + { + Console.WriteLine(e.Message); + } catch (Exception ex) when (ex.Message.Contains("by zero")) { Console.WriteLine(ex.Message); } } + public void ExceptionHandlingFilterCatch(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) when (e.Message.Contains("")) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + public void ExceptionHandlingCatchFilter(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) when (ex.Message.Contains("")) + { + Console.WriteLine(ex.Message); + } + } + + public void ExceptionHandlingMultipleCatchs(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + /* FIXME finally end label is wrong in the model (one more that it should be, that label does not exist)? this example results in an FIXME unmarked label. The IL though is generated correctly public void ExceptionHandlingTryCatchFinally(Exception e) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 06fc5916..9d06f568 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -195,7 +195,6 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) throw new UnhandledCase(); } - instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(branchInstruction.Target)); break; From 5248171ef928d1ef1bf80ef3e84497d2ee680853 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 14 Aug 2020 07:51:46 -0300 Subject: [PATCH 212/256] cleanup --- Examples/Examples.cs | 130 ++++++++---------- ExamplesEXE/ExamplesEXE.cs | 8 +- MetadataGenerator/Extensions.cs | 10 +- .../Methods/Body/MethodBodyGenerator.cs | 3 +- 4 files changed, 60 insertions(+), 91 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 6b5acb6b..70f1c222 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -7,6 +7,7 @@ using Enums; using Hierarchy; using Interfaces; +using Nested; using Nested.NestedNamespace.NestedNestedNamesace; using NUnit.Framework; using Structs; @@ -166,7 +167,6 @@ public virtual void VirtualMethod() public abstract void AbstractMethod(); } - // TODO var arggs, optional parameters, named arguments, public class ClassWithMoreComplexFieldsAndParametersOrReturnTypes { public string[] stringArrayField; @@ -486,8 +486,6 @@ public class Generic where H : class, new() where I : List where J : List - // where K : unmanaged FIXME framework read not implemented - // where L : D FIXME framework read is not working { public C genericClassTypeField; public Dictionary genericField; @@ -623,7 +621,6 @@ public void Nothing2() { } - // TODO more generic method calls examples public int Calls(SimpleClass simpleClass, Func func) { Console.WriteLine("A method call"); // static @@ -635,21 +632,7 @@ public int Calls(SimpleClass simpleClass, Func func) var result = func(1); result += l.Count; - // TODO calli (indirect) - - // FIXME - // not working when reading dll - //var g = new Generics.Generic(); - //g.PrintGeneric("hola"); - //g.PrintGeneric(1); - // - Nothing2(); - // FIXME - //not working when reading dll - //Nothing2>(); - //Nothing2.NestedClassThatAddsNewGenericParameters.NestedNestedClassThatDoesNotAddNewGenericParameters>(); - // return result; } @@ -701,14 +684,10 @@ public int Convert(object o) int x4 = (int) x1; // conv.i4 x1 = (long) d; // conv.i8 float f = (float) d; // conv.r4 - //TODO conv.r8 byte x5 = (byte) x1; // conv.u1 ushort x6 = (ushort) x1; // conv.u2 uint x7 = (uint) x1; // conv.u4 var x8 = (ulong) d; // conv.u8 - // TODO conv.i - // TODO conv.u - // TODO conv.r.un string s = (string) (object) "asd"; // castclass $class var x = (int[]) (object) new int[] { }; @@ -718,8 +697,6 @@ public int Convert(object o) object l = 1; // box int int i = (int) l; // unbox.any int - // TODO unbox (unbox ptr) - return i + x6 + s.Length + l.ToString().Length + o.ToString().Length; } @@ -754,7 +731,6 @@ public string LoadArgument(int arg1, string arg2, bool arg3, int arg4) var i2 = arg2; // ldarg.2 var i3 = arg3; // ldarg.3 var i4 = arg4; // ldarg.s $value - // TODO ldarg $value (see ecma) return arg2 + arg1 + i4 + i0; } @@ -772,7 +748,6 @@ public int LoadLocal() var y2 = x2; // ldloc.2 var y3 = x3; // ldloc.3 var y4 = x4; // ldloc.s $index (=4) - // TODO ldloc $index (see ecma) return x0 + x1 + y4 + y2; } @@ -782,9 +757,7 @@ public void LoadAddress(int x) unsafe { var p = default(int*); // ldloca.s 0 + initobj int* - // TODO ldloca $argNum var q = &x; // ldarga.s 0 - // TODO ldarga $argNum Console.WriteLine(*q); } @@ -829,17 +802,6 @@ public int LoadArray(Exception[] x, int[] q) var k = (new double[] {9})[0]; // ldelem.r8 var l = new EmptyStruct[] {new EmptyStruct()}[0]; // ldelem typeTok - // TODO ldelem.i ??? - // - // FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? - // unsafe - // { - // fixed (int* p = &q[0]) // ldelema $type - // { - // } - // } - - var m = (new int[] {1, 2, 3}).Length; // ldlen return m + k.ToString(CultureInfo.InvariantCulture).Length + c + a.Message.Length + q.Length; @@ -852,15 +814,6 @@ public string LoadField() var c = new ClassWithMoreComplexFieldsAndParametersOrReturnTypes().b; // ldfld class $field var d = SimpleClass.staticLongField; // ldsfld - //FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? - // unsafe - // { - // fixed (int* d = &(new Classes.SimpleClass(1, "b")).readOnlyIntField) // ldflda int32 $field - // { } - // } - // TODO ldsflda - - return c.GetType().ToString() + b + d; } @@ -881,10 +834,7 @@ public int StoreValue(int arg) l2 = 1; // stloc.2 l3 = 1; // stloc.3 l4 = 1; // stloc.s 4 - // TODO stloc indx (not short form) - arg = 1; // starg.s arg - // TODO starg arg (not short form) return arg + l4; } @@ -909,28 +859,6 @@ public Type LoadToken() public void Branch(int a, int b, Exception e) { - // TODO - // beq - // bge, bge.s - // bge.un, bge.un.s - // bgt, bgt.s - // bgt.un, bgt.un.s - // ble, ble.s - // ble.un, ble.un.s - // blt, blt.s - // blt.un, blt.un.s - // bne, bne.s - // bne.un, bne.un.s - // br (not short form) - // brfalse (not short form) - // brnull.s - // brnull (not short form) - // brzero.s - // brzero (not short form) - // brtrue (not short form) - // brinst.s - // brinst (not short form) - goto Label; // br.s Label: int x; @@ -974,17 +902,69 @@ public void ExceptionHandlingTryCatchSpecific(int x) } - public void ExceptionHandlingTryCatchFilter(int x) + public void ExceptionHandlingMultipleFilter(int x) { try { var y = 1 / x; } + catch (EntryPointNotFoundException e) when (e.Message.Contains("")) + { + Console.WriteLine(e.Message); + } catch (Exception ex) when (ex.Message.Contains("by zero")) { Console.WriteLine(ex.Message); } } + + public void ExceptionHandlingFilterCatch(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) when (e.Message.Contains("")) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + public void ExceptionHandlingCatchFilter(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) when (ex.Message.Contains("")) + { + Console.WriteLine(ex.Message); + } + } + + public void ExceptionHandlingMultipleCatchs(int x) + { + try + { + var y = 1 / x; + } + catch (EntryPointNotFoundException e) + { + Console.WriteLine(e.Message); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } } } @@ -1017,7 +997,7 @@ public class AnnotatedClass [ExcludeFromCodeCoverage, Obsolete("Method is obsolete", true)] [AttributeWithObjectParam("something")] - [AttributeWithTypeParam(typeof(Nested.ClassContainingNestedTypes.NestedClass))] + [AttributeWithTypeParam(typeof(ClassContainingNestedTypes.NestedClass))] public void Method() { } diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 65e437db..e38129d0 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -9,8 +9,6 @@ namespace ExamplesEXE { public static class MainClass { - // TODO pedump --verify all Console/bin/Debug/ExamplesEXE\(generated\).exe - // TODO pedump --verify all Console/bin/Debug/Examples\(generated\).dll // IMPORTANT ExamplesEXE has Examples as reference so it's important to copy de latest Examples.dll to the Console/bin/debug directory public static void Main(string[] args) { @@ -37,7 +35,7 @@ public static void Main(string[] args) Console.WriteLine(methodBodyExamples.StoreValue(100)); methodBodyExamples.ExceptionHandlingTryCatchSpecific(0); methodBodyExamples.ExceptionHandlingTryCatch(0); - methodBodyExamples.ExceptionHandlingTryCatchFilter(0); + methodBodyExamples.ExceptionHandlingMultipleFilter(0); Console.WriteLine(methodBodyExamples.LoadField()); Console.WriteLine(methodBodyExamples.StoreField()); methodBodyExamples.Calls(sc, e => 5); @@ -75,10 +73,6 @@ public static void Main(string[] args) Console.WriteLine(structWithProperties.DoublePropertyWithAutoImplementedGetSet); structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet = new DerivedClass(); Console.WriteLine(structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet); - - /* FIXME Try when that example is fixed - methodBodyExamples.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); - */ } } diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index 7ef501c1..ace07fae 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; +using System.Collections.Generic; using System.Linq; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -16,10 +14,6 @@ public static T FirstOr(this IEnumerable enumerable, T defaultValue) return first.Equals(default(T)) ? defaultValue : first; } - public static bool IsOneOf(this Enum value, params Enum[] values) => ImmutableList.Create(values).Contains(value); - - public static bool IsOneOf(this IType type, params IType[] types) => ImmutableList.Create(types).Contains(type); - public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.EntityHandle methodReference) { encoder.OpCode(SRM.ILOpCode.Callvirt); @@ -28,7 +22,7 @@ public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.Enti // The next available slot in the corresponding table. If nothing is defined in the module then use row number 1 for the corresponding table public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; - + public static bool IsGenericInstantiation(this IBasicType type) => type.GenericType != null; public static bool IsGenericInstantiation(this IMethodReference method) => method.GenericMethod != null; diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 1b92590f..252e3c7b 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -533,7 +533,8 @@ loadInstruction.Operand is Constant constant && { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u4); } - else if (loadArrayElementInstruction.Array.ElementsType.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int64) || + loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt64)) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i8); } From bd9579a3fcee249404087f32eac3709256c9b5a9 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 14 Aug 2020 07:55:32 -0300 Subject: [PATCH 213/256] undo code-generator changes --- Examples/Examples.cs | 151 +----------------- ExamplesEXE/ExamplesEXE.cs | 10 -- MetadataGenerator/Extensions.cs | 6 +- .../Methods/Body/MethodBodyGenerator.cs | 90 ++++++----- .../Body/MethodLocalsSignatureGenerator.cs | 1 - 5 files changed, 54 insertions(+), 204 deletions(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 437ead01..70f1c222 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -3,11 +3,11 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection.Metadata; -using System.Runtime.ConstrainedExecution; using Classes; using Enums; using Hierarchy; using Interfaces; +using Nested; using Nested.NestedNamespace.NestedNestedNamesace; using NUnit.Framework; using Structs; @@ -167,7 +167,6 @@ public virtual void VirtualMethod() public abstract void AbstractMethod(); } - // TODO var arggs, optional parameters, named arguments, public class ClassWithMoreComplexFieldsAndParametersOrReturnTypes { public string[] stringArrayField; @@ -487,8 +486,6 @@ public class Generic where H : class, new() where I : List where J : List - // where K : unmanaged FIXME framework read not implemented - // where L : D FIXME framework read is not working { public C genericClassTypeField; public Dictionary genericField; @@ -624,7 +621,6 @@ public void Nothing2() { } - // TODO more generic method calls examples public int Calls(SimpleClass simpleClass, Func func) { Console.WriteLine("A method call"); // static @@ -636,21 +632,7 @@ public int Calls(SimpleClass simpleClass, Func func) var result = func(1); result += l.Count; - // TODO calli (indirect) - - // FIXME - // not working when reading dll - //var g = new Generics.Generic(); - //g.PrintGeneric("hola"); - //g.PrintGeneric(1); - // - Nothing2(); - // FIXME - //not working when reading dll - //Nothing2>(); - //Nothing2.NestedClassThatAddsNewGenericParameters.NestedNestedClassThatDoesNotAddNewGenericParameters>(); - // return result; } @@ -702,14 +684,10 @@ public int Convert(object o) int x4 = (int) x1; // conv.i4 x1 = (long) d; // conv.i8 float f = (float) d; // conv.r4 - //TODO conv.r8 byte x5 = (byte) x1; // conv.u1 ushort x6 = (ushort) x1; // conv.u2 uint x7 = (uint) x1; // conv.u4 var x8 = (ulong) d; // conv.u8 - // TODO conv.i - // TODO conv.u - // TODO conv.r.un string s = (string) (object) "asd"; // castclass $class var x = (int[]) (object) new int[] { }; @@ -719,8 +697,6 @@ public int Convert(object o) object l = 1; // box int int i = (int) l; // unbox.any int - // TODO unbox (unbox ptr) - return i + x6 + s.Length + l.ToString().Length + o.ToString().Length; } @@ -755,7 +731,6 @@ public string LoadArgument(int arg1, string arg2, bool arg3, int arg4) var i2 = arg2; // ldarg.2 var i3 = arg3; // ldarg.3 var i4 = arg4; // ldarg.s $value - // TODO ldarg $value (see ecma) return arg2 + arg1 + i4 + i0; } @@ -773,7 +748,6 @@ public int LoadLocal() var y2 = x2; // ldloc.2 var y3 = x3; // ldloc.3 var y4 = x4; // ldloc.s $index (=4) - // TODO ldloc $index (see ecma) return x0 + x1 + y4 + y2; } @@ -783,9 +757,7 @@ public void LoadAddress(int x) unsafe { var p = default(int*); // ldloca.s 0 + initobj int* - // TODO ldloca $argNum var q = &x; // ldarga.s 0 - // TODO ldarga $argNum Console.WriteLine(*q); } @@ -797,62 +769,6 @@ public void LoadPointer() Action y = null; // ldnull } - public string LoadIndirect(ref int g) - { - unsafe - { - sbyte a_1 = sbyte.MinValue; - byte a_2 = byte.MinValue; - short b_1 = short.MinValue; - ushort b_2 = ushort.MinValue; - int c_1 = int.MinValue; - uint c_2 = uint.MinValue; - long d = long.MinValue; - float e = float.MinValue; - double f = double.MinValue; - IntPtr h = default; - - var x1 = *&a_1; // ldind.i1 - var x2 = *&a_2; // ldind.u1 - var x3 = *&b_1; // ldind.i2 - var x4 = *&b_2; // ldind.u2 - var x5 = *&c_1; // ldind.i4 - var x6 = *&c_2; // ldind.u4 - var x7 = *&d; // ldind.i8 (ldind.u8 is alias for ldind.i8) - var x8 = *&e; // ldind.r4 - var x9 = *&f; // ldind.r8 - var x10 = *&h; // ldind.i - var x11 = g; // ldind.ref - - return a_1 + c_2.ToString() + x4 + x11 + g.ToString().Length; - } - } - - public double StoreIndirect( - out sbyte outByte, - out short outShort, - out int outInt, - out long outLong, - out float outFloat, - out double outDouble, - out IntPtr outIntPtr, - out SimpleClass outClass - ) - { - IntPtr h = default; - - outByte = 1; // stind.i1 - outShort = 2; // stind.i2 - outInt = 3; // stind.i4 - outLong = 4; // stind.i8 (stind.u8 is alias for stind.i8) - outFloat = 5; // stind.r4 - outDouble = 6; // stind.r8 - outIntPtr = h; // stind.i - outClass = new SimpleClass(1, ""); // stind.ref - - return outByte + outDouble + outClass.readOnlyIntField; - } - public bool Compare(int b, int x) { var a = b == 2; // ceq @@ -886,17 +802,6 @@ public int LoadArray(Exception[] x, int[] q) var k = (new double[] {9})[0]; // ldelem.r8 var l = new EmptyStruct[] {new EmptyStruct()}[0]; // ldelem typeTok - // TODO ldelem.i ??? - // - // FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? - // unsafe - // { - // fixed (int* p = &q[0]) // ldelema $type - // { - // } - // } - - var m = (new int[] {1, 2, 3}).Length; // ldlen return m + k.ToString(CultureInfo.InvariantCulture).Length + c + a.Message.Length + q.Length; @@ -909,15 +814,6 @@ public string LoadField() var c = new ClassWithMoreComplexFieldsAndParametersOrReturnTypes().b; // ldfld class $field var d = SimpleClass.staticLongField; // ldsfld - //FIXME framework read not working. Something not implemented? Maybe avoid fixed keyword? - // unsafe - // { - // fixed (int* d = &(new Classes.SimpleClass(1, "b")).readOnlyIntField) // ldflda int32 $field - // { } - // } - // TODO ldsflda - - return c.GetType().ToString() + b + d; } @@ -938,10 +834,7 @@ public int StoreValue(int arg) l2 = 1; // stloc.2 l3 = 1; // stloc.3 l4 = 1; // stloc.s 4 - // TODO stloc indx (not short form) - arg = 1; // starg.s arg - // TODO starg arg (not short form) return arg + l4; } @@ -966,28 +859,6 @@ public Type LoadToken() public void Branch(int a, int b, Exception e) { - // TODO - // beq - // bge, bge.s - // bge.un, bge.un.s - // bgt, bgt.s - // bgt.un, bgt.un.s - // ble, ble.s - // ble.un, ble.un.s - // blt, blt.s - // blt.un, blt.un.s - // bne, bne.s - // bne.un, bne.un.s - // br (not short form) - // brfalse (not short form) - // brnull.s - // brnull (not short form) - // brzero.s - // brzero (not short form) - // brtrue (not short form) - // brinst.s - // brinst (not short form) - goto Label; // br.s Label: int x; @@ -1094,24 +965,6 @@ public void ExceptionHandlingMultipleCatchs(int x) Console.WriteLine(ex.Message); } } - - /* FIXME finally end label is wrong in the model (one more that it should be, that label does not exist)? this example results in an - FIXME unmarked label. The IL though is generated correctly - public void ExceptionHandlingTryCatchFinally(Exception e) - { - try - { - throw e; - } - catch - { - throw; // rethrow - } - finally - { - Console.WriteLine("finally"); - } - }*/ } } @@ -1144,7 +997,7 @@ public class AnnotatedClass [ExcludeFromCodeCoverage, Obsolete("Method is obsolete", true)] [AttributeWithObjectParam("something")] - [AttributeWithTypeParam(typeof(Nested.ClassContainingNestedTypes.NestedClass))] + [AttributeWithTypeParam(typeof(ClassContainingNestedTypes.NestedClass))] public void Method() { } diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index af57c01b..e38129d0 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -9,8 +9,6 @@ namespace ExamplesEXE { public static class MainClass { - // TODO pedump --verify all Console/bin/Debug/ExamplesEXE\(generated\).exe - // TODO pedump --verify all Console/bin/Debug/Examples\(generated\).dll // IMPORTANT ExamplesEXE has Examples as reference so it's important to copy de latest Examples.dll to the Console/bin/debug directory public static void Main(string[] args) { @@ -44,10 +42,6 @@ public static void Main(string[] args) Console.WriteLine(methodBodyExamples.Nothing(new object())); Console.WriteLine(methodBodyExamples.Alloc()); methodBodyExamples.LoadAddress(4); - Console.WriteLine(methodBodyExamples.LoadIndirect(ref g)); - Console.WriteLine(methodBodyExamples.StoreIndirect(out sbyte b, out short q, out int i, out long l, out float f, out double d, - out IntPtr ip, - out SimpleClass s)); Console.WriteLine(methodBodyExamples.LoadToken()); Console.WriteLine(sc.ReceivesArraysAndReturnsIntArray(new[] {""}, new[] {new Exception()})); unsafe @@ -79,10 +73,6 @@ public static void Main(string[] args) Console.WriteLine(structWithProperties.DoublePropertyWithAutoImplementedGetSet); structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet = new DerivedClass(); Console.WriteLine(structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet); - - /* FIXME Try when that example is fixed - methodBodyExamples.ExceptionHandlingTryCatchFinally(new AggregateException("Intentionally not catched exception")); - */ } } diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index beed73a2..ace07fae 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; +using System.Collections.Generic; using System.Linq; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -24,7 +22,7 @@ public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.Enti // The next available slot in the corresponding table. If nothing is defined in the module then use row number 1 for the corresponding table public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; - + public static bool IsGenericInstantiation(this IBasicType type) => type.GenericType != null; public static bool IsGenericInstantiation(this IMethodReference method) => method.GenericMethod != null; diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 9d06f568..252e3c7b 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using MetadataGenerator.Metadata; -using Model; using Model.Bytecode; using Model.ThreeAddressCode.Values; using Model.Types; @@ -28,8 +27,13 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) var labelToEncoderOffset = new Dictionary(); var switchInstructionsPlaceHolders = new List(); - foreach (var instruction in body.Instructions) + var ignoreInstructions = new HashSet(); + + for (var i = 0; i < body.Instructions.Count; i++) { + if (ignoreInstructions.Contains(i)) continue; + + var instruction = body.Instructions[i]; labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); @@ -96,7 +100,23 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Shr_un : SRM.ILOpCode.Shr); break; case BasicOperation.Eq: - instructionEncoder.OpCode(SRM.ILOpCode.Ceq); + var previousInstructionIsLoadNull = + body.Instructions[i - 1] is LoadInstruction loadInstruction && + loadInstruction.Operand is Constant constant && + constant.Value == null; + var nexInstructionIsNeg = body.Instructions[i + 1] is BasicInstruction bi && bi.Operation == BasicOperation.Neg; + if (previousInstructionIsLoadNull && nexInstructionIsNeg) + { + // cgt_un is used as a compare-not-equal with null. + // load null - compare eq - negate => ldnull - cgt_un + instructionEncoder.OpCode(SRM.ILOpCode.Cgt_un); + ignoreInstructions.Add(i + 1); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Ceq); + } + break; case BasicOperation.Lt: instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Clt_un : SRM.ILOpCode.Clt); @@ -195,6 +215,7 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) throw new UnhandledCase(); } + instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(branchInstruction.Target)); break; @@ -423,44 +444,32 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) } case LoadOperation.Value: { - if (((Constant) loadInstruction.Operand).Value == null) + switch ((loadInstruction.Operand as Constant).Value) { - instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); + case null: + instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); + break; + case string value: + instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); + break; + case int value: + instructionEncoder.LoadConstantI4(value); + break; + case long value: + instructionEncoder.LoadConstantI8(value); + break; + case float value: + instructionEncoder.LoadConstantR4(value); + break; + case double value: + instructionEncoder.LoadConstantR8(value); + break; + case bool value: + instructionEncoder.LoadConstantI4(value ? 1 : 0); + break; + default: + throw new UnhandledCase(); } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.String)) - { - var value = (string) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); - } - - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int8, PlatformTypes.UInt8)) - { - var value = (int) (loadInstruction.Operand as Constant).Value; - instructionEncoder.OpCode(SRM.ILOpCode.Ldc_i4_s); - instructionEncoder.Token(value); - } - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int16, PlatformTypes.Int32, PlatformTypes.UInt16, - PlatformTypes.UInt32)) - { - var value = (int) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantI4(value); - } - else if (loadInstruction.Operand.Type.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) - { - var value = (long) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantI8(value); - } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float32)) - { - var value = (float) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantR4(value); - } - else if (loadInstruction.Operand.Type.Equals(PlatformTypes.Float64)) - { - var value = (double) (loadInstruction.Operand as Constant).Value; - instructionEncoder.LoadConstantR8(value); - } - else throw new UnhandledCase(); break; } @@ -524,7 +533,8 @@ public ECMA335.InstructionEncoder Generate(MethodBody body) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u4); } - else if (loadArrayElementInstruction.Array.ElementsType.IsOneOf(PlatformTypes.Int64, PlatformTypes.UInt64)) + else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int64) || + loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt64)) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i8); } diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs index f8c8d9ea..988921bb 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using MetadataGenerator.Metadata; using Model.ThreeAddressCode.Values; -using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; From bb19b74bfb4f9e7672f19c09a12006aedbc0df20 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 16 Aug 2020 16:46:27 -0300 Subject: [PATCH 214/256] refactor: use visitor --- .../Methods/Body/MethodBodyGenerator.cs | 1386 +++++++++-------- .../Generators/Methods/MethodGenerator.cs | 4 +- 2 files changed, 709 insertions(+), 681 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 252e3c7b..4b46857d 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using MetadataGenerator.Metadata; +using Model; using Model.Bytecode; +using Model.Bytecode.Visitor; using Model.ThreeAddressCode.Values; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -9,797 +11,825 @@ namespace MetadataGenerator.Generators.Methods.Body { - internal class MethodBodyGenerator + internal class MethodBodyGenerator : IInstructionVisitor { private readonly MetadataContainer metadataContainer; - - public MethodBodyGenerator(MetadataContainer metadataContainer) + private readonly ECMA335.InstructionEncoder instructionEncoder; + private readonly MethodBodyControlFlowGenerator controlFlowGenerator; + private readonly List switchInstructionsPlaceHolders; + private readonly ISet ignoredInstructions; + private readonly MethodBody body; + private int Index { get; set; } + + public MethodBodyGenerator(MetadataContainer metadataContainer, MethodBody body) { this.metadataContainer = metadataContainer; + this.body = body; + instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), new ECMA335.ControlFlowBuilder()); + controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); + switchInstructionsPlaceHolders = new List(); + ignoredInstructions = new HashSet(); } - public ECMA335.InstructionEncoder Generate(MethodBody body) + public ECMA335.InstructionEncoder Generate() { - var instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), new ECMA335.ControlFlowBuilder()); - var controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); controlFlowGenerator.DefineNeededBranchLabels(body.Instructions); var labelToEncoderOffset = new Dictionary(); - var switchInstructionsPlaceHolders = new List(); - - var ignoreInstructions = new HashSet(); - for (var i = 0; i < body.Instructions.Count; i++) + for (Index = 0; Index < body.Instructions.Count; Index++) { - if (ignoreInstructions.Contains(i)) continue; - - var instruction = body.Instructions[i]; + var instruction = (Instruction) body.Instructions[Index]; labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); - switch (instruction) + if (!ignoredInstructions.Contains(Index)) { - case BasicInstruction basicInstruction: - switch (basicInstruction.Operation) - { - case BasicOperation.Nop: - instructionEncoder.OpCode(SRM.ILOpCode.Nop); - break; - case BasicOperation.Add: - if (basicInstruction.OverflowCheck) - { - instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Add_ovf_un : SRM.ILOpCode.Add_ovf); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Add); - } - - break; - case BasicOperation.Sub: - if (basicInstruction.OverflowCheck) - { - instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Sub_ovf_un : SRM.ILOpCode.Sub_ovf); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Sub); - } - - break; - case BasicOperation.Mul: - if (basicInstruction.OverflowCheck) - { - instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Mul_ovf_un : SRM.ILOpCode.Mul_ovf); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Mul); - } - - break; - case BasicOperation.Div: - instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Div_un : SRM.ILOpCode.Div); - break; - case BasicOperation.Rem: - instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Rem_un : SRM.ILOpCode.Rem); - break; - case BasicOperation.And: - instructionEncoder.OpCode(SRM.ILOpCode.And); - break; - case BasicOperation.Or: - instructionEncoder.OpCode(SRM.ILOpCode.Or); - break; - case BasicOperation.Xor: - instructionEncoder.OpCode(SRM.ILOpCode.Xor); - break; - case BasicOperation.Shl: - instructionEncoder.OpCode(SRM.ILOpCode.Shl); - break; - case BasicOperation.Shr: - instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Shr_un : SRM.ILOpCode.Shr); - break; - case BasicOperation.Eq: - var previousInstructionIsLoadNull = - body.Instructions[i - 1] is LoadInstruction loadInstruction && - loadInstruction.Operand is Constant constant && - constant.Value == null; - var nexInstructionIsNeg = body.Instructions[i + 1] is BasicInstruction bi && bi.Operation == BasicOperation.Neg; - if (previousInstructionIsLoadNull && nexInstructionIsNeg) - { - // cgt_un is used as a compare-not-equal with null. - // load null - compare eq - negate => ldnull - cgt_un - instructionEncoder.OpCode(SRM.ILOpCode.Cgt_un); - ignoreInstructions.Add(i + 1); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Ceq); - } - - break; - case BasicOperation.Lt: - instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Clt_un : SRM.ILOpCode.Clt); - break; - case BasicOperation.Gt: - instructionEncoder.OpCode(basicInstruction.UnsignedOperands ? SRM.ILOpCode.Cgt_un : SRM.ILOpCode.Cgt); - break; - case BasicOperation.Throw: - instructionEncoder.OpCode(SRM.ILOpCode.Throw); - break; - case BasicOperation.Rethrow: - instructionEncoder.OpCode(SRM.ILOpCode.Rethrow); - break; - case BasicOperation.Not: - instructionEncoder.OpCode(SRM.ILOpCode.Not); - break; - case BasicOperation.Neg: - instructionEncoder.OpCode(SRM.ILOpCode.Neg); - break; - case BasicOperation.Pop: - instructionEncoder.OpCode(SRM.ILOpCode.Pop); - break; - case BasicOperation.Dup: - instructionEncoder.OpCode(SRM.ILOpCode.Dup); - break; - case BasicOperation.EndFinally: - instructionEncoder.OpCode(SRM.ILOpCode.Endfinally); - break; - case BasicOperation.EndFilter: - instructionEncoder.OpCode(SRM.ILOpCode.Endfilter); - break; - case BasicOperation.LocalAllocation: - instructionEncoder.OpCode(SRM.ILOpCode.Localloc); - break; - case BasicOperation.InitBlock: - instructionEncoder.OpCode(SRM.ILOpCode.Initblk); - break; - case BasicOperation.CopyBlock: - instructionEncoder.OpCode(SRM.ILOpCode.Cpblk); - break; - case BasicOperation.LoadArrayLength: - instructionEncoder.OpCode(SRM.ILOpCode.Ldlen); - break; - case BasicOperation.Breakpoint: - instructionEncoder.OpCode(SRM.ILOpCode.Break); - break; - case BasicOperation.Return: - instructionEncoder.OpCode(SRM.ILOpCode.Ret); - break; - default: - throw new UnhandledCase(); - } + instruction.Accept(this); + } + } - break; - case BranchInstruction branchInstruction: + foreach (var switchInstructionPlaceholder in switchInstructionsPlaceHolders) + { + switchInstructionPlaceholder.FillWithRealTargets(labelToEncoderOffset); + } + + return instructionEncoder; + } + + public void Visit(IInstructionContainer container) + { + } + + public void Visit(Instruction instruction) + { + } + + public void Visit(InitObjInstruction instruction) + { + instructionEncoder.OpCode(SRM.ILOpCode.Initobj); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Type)); + } + + public void Visit(BasicInstruction instruction) + { + switch (instruction.Operation) + { + case BasicOperation.Nop: + instructionEncoder.OpCode(SRM.ILOpCode.Nop); + break; + case BasicOperation.Add: + if (instruction.OverflowCheck) { - SRM.ILOpCode opCode; - // targets of branch instructions reference other instructions (labels) in the body. But this labels are not going to be - // the same as the ones in the final CIL (the ones that instructionEncoder generates) because the instructions in the model - // do not know about the size they will occupy in CIL. Due to this, it is not possible to know if the branches could be cil - // short forms or not. So regular forms are used in all cases. This does not change functionality, it just means that the - // generated CIL will not be optimal in size. - switch (branchInstruction.Operation) - { - case BranchOperation.False: - opCode = SRM.ILOpCode.Brfalse; - break; - case BranchOperation.True: - opCode = SRM.ILOpCode.Brtrue; - break; - case BranchOperation.Eq: - opCode = SRM.ILOpCode.Beq; - break; - case BranchOperation.Neq: - opCode = SRM.ILOpCode.Bne_un; - break; - case BranchOperation.Lt: - opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Blt_un : SRM.ILOpCode.Blt; - break; - case BranchOperation.Le: - opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Ble_un : SRM.ILOpCode.Ble; - break; - case BranchOperation.Gt: - opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Bgt_un : SRM.ILOpCode.Bgt; - break; - case BranchOperation.Ge: - opCode = branchInstruction.UnsignedOperands ? SRM.ILOpCode.Bge_un : SRM.ILOpCode.Bge; - break; - case BranchOperation.Branch: - opCode = SRM.ILOpCode.Br; - break; - case BranchOperation.Leave: - opCode = SRM.ILOpCode.Leave; - break; - default: - throw new UnhandledCase(); - } - - - instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(branchInstruction.Target)); + instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Add_ovf_un : SRM.ILOpCode.Add_ovf); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Add); + } - break; + break; + case BasicOperation.Sub: + if (instruction.OverflowCheck) + { + instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Sub_ovf_un : SRM.ILOpCode.Sub_ovf); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Sub); } - case ConvertInstruction convertInstruction: - switch (convertInstruction.Operation) - { - case ConvertOperation.Conv: - if (convertInstruction.ConversionType.Equals(PlatformTypes.Int8)) - { - if (convertInstruction.OverflowCheck) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands - ? SRM.ILOpCode.Conv_ovf_i1_un - : SRM.ILOpCode.Conv_ovf_i1); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i1); - } - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt8)) - { - if (convertInstruction.OverflowCheck) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands - ? SRM.ILOpCode.Conv_ovf_u1_un - : SRM.ILOpCode.Conv_ovf_u1); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u1); - } - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int16)) - { - if (convertInstruction.OverflowCheck) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands - ? SRM.ILOpCode.Conv_ovf_i2_un - : SRM.ILOpCode.Conv_ovf_i2); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i2); - } - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt16)) - { - if (convertInstruction.OverflowCheck) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands - ? SRM.ILOpCode.Conv_ovf_u2_un - : SRM.ILOpCode.Conv_ovf_u2); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u2); - } - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int32)) - { - if (convertInstruction.OverflowCheck) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands - ? SRM.ILOpCode.Conv_ovf_i4_un - : SRM.ILOpCode.Conv_ovf_i4); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i4); - } - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt32)) - { - if (convertInstruction.OverflowCheck) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands - ? SRM.ILOpCode.Conv_ovf_u4_un - : SRM.ILOpCode.Conv_ovf_u4); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u4); - } - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.Int64)) - { - if (convertInstruction.OverflowCheck) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands - ? SRM.ILOpCode.Conv_ovf_i8_un - : SRM.ILOpCode.Conv_ovf_i8); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); - } - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.UInt64)) - { - if (convertInstruction.OverflowCheck) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands - ? SRM.ILOpCode.Conv_ovf_u8_un - : SRM.ILOpCode.Conv_ovf_u8); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u8); - } - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.Float32)) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands ? SRM.ILOpCode.Conv_r_un : SRM.ILOpCode.Conv_r4); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.Float64)) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands ? SRM.ILOpCode.Conv_r_un : SRM.ILOpCode.Conv_r8); - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.IntPtr)) - { - if (convertInstruction.OverflowCheck) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands - ? SRM.ILOpCode.Conv_ovf_i_un - : SRM.ILOpCode.Conv_ovf_i); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_i); - } - } - else if (convertInstruction.ConversionType.Equals(PlatformTypes.UIntPtr)) - { - if (convertInstruction.OverflowCheck) - { - instructionEncoder.OpCode(convertInstruction.UnsignedOperands - ? SRM.ILOpCode.Conv_ovf_u_un - : SRM.ILOpCode.Conv_ovf_u); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Conv_u); - } - } - else throw new UnhandledCase(); - - break; - case ConvertOperation.Cast: - instructionEncoder.OpCode(SRM.ILOpCode.Castclass); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(convertInstruction.ConversionType)); - break; - case ConvertOperation.IsInst: - instructionEncoder.OpCode(SRM.ILOpCode.Isinst); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(convertInstruction.ConversionType)); - break; - case ConvertOperation.Box: - instructionEncoder.OpCode(SRM.ILOpCode.Box); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(convertInstruction.ConversionType)); - break; - case ConvertOperation.Unbox: - instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(convertInstruction.ConversionType)); - break; - case ConvertOperation.UnboxPtr: - instructionEncoder.OpCode(SRM.ILOpCode.Unbox); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(convertInstruction.ConversionType)); - break; - default: - throw new UnhandledCase(); - } + break; + case BasicOperation.Mul: + if (instruction.OverflowCheck) + { + instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Mul_ovf_un : SRM.ILOpCode.Mul_ovf); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Mul); + } - break; - case MethodCallInstruction methodCallInstruction: - switch (methodCallInstruction.Operation) - { - case MethodCallOperation.Virtual: - instructionEncoder.CallVirtual(metadataContainer.MetadataResolver.HandleOf(methodCallInstruction.Method)); - break; - case MethodCallOperation.Static: - case MethodCallOperation.Jump: - instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(methodCallInstruction.Method)); - break; - default: - throw new UnhandledCase(); - } + break; + case BasicOperation.Div: + instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Div_un : SRM.ILOpCode.Div); + break; + case BasicOperation.Rem: + instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Rem_un : SRM.ILOpCode.Rem); + break; + case BasicOperation.And: + instructionEncoder.OpCode(SRM.ILOpCode.And); + break; + case BasicOperation.Or: + instructionEncoder.OpCode(SRM.ILOpCode.Or); + break; + case BasicOperation.Xor: + instructionEncoder.OpCode(SRM.ILOpCode.Xor); + break; + case BasicOperation.Shl: + instructionEncoder.OpCode(SRM.ILOpCode.Shl); + break; + case BasicOperation.Shr: + instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Shr_un : SRM.ILOpCode.Shr); + break; + case BasicOperation.Eq: + instructionEncoder.OpCode(SRM.ILOpCode.Ceq); + break; + case BasicOperation.Lt: + instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Clt_un : SRM.ILOpCode.Clt); + break; + case BasicOperation.Gt: + instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Cgt_un : SRM.ILOpCode.Cgt); + break; + case BasicOperation.Throw: + instructionEncoder.OpCode(SRM.ILOpCode.Throw); + break; + case BasicOperation.Rethrow: + instructionEncoder.OpCode(SRM.ILOpCode.Rethrow); + break; + case BasicOperation.Not: + instructionEncoder.OpCode(SRM.ILOpCode.Not); + break; + case BasicOperation.Neg: + instructionEncoder.OpCode(SRM.ILOpCode.Neg); + break; + case BasicOperation.Pop: + instructionEncoder.OpCode(SRM.ILOpCode.Pop); + break; + case BasicOperation.Dup: + instructionEncoder.OpCode(SRM.ILOpCode.Dup); + break; + case BasicOperation.EndFinally: + instructionEncoder.OpCode(SRM.ILOpCode.Endfinally); + break; + case BasicOperation.EndFilter: + instructionEncoder.OpCode(SRM.ILOpCode.Endfilter); + break; + case BasicOperation.LocalAllocation: + instructionEncoder.OpCode(SRM.ILOpCode.Localloc); + break; + case BasicOperation.InitBlock: + instructionEncoder.OpCode(SRM.ILOpCode.Initblk); + break; + case BasicOperation.CopyBlock: + instructionEncoder.OpCode(SRM.ILOpCode.Cpblk); + break; + case BasicOperation.LoadArrayLength: + instructionEncoder.OpCode(SRM.ILOpCode.Ldlen); + break; + case BasicOperation.Breakpoint: + instructionEncoder.OpCode(SRM.ILOpCode.Break); + break; + case BasicOperation.Return: + instructionEncoder.OpCode(SRM.ILOpCode.Ret); + break; + default: + throw new UnhandledCase(); + } + } - break; - case LoadInstruction loadInstruction: + public void Visit(ConstrainedInstruction instruction) + { + instructionEncoder.OpCode(SRM.ILOpCode.Constrained); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ThisType)); + } + + public void Visit(LoadInstruction instruction) + { + switch (instruction.Operation) + { + case LoadOperation.Address: + { + var variable = (IVariable) instruction.Operand; + if (variable.IsParameter) { - switch (loadInstruction.Operation) - { - case LoadOperation.Address: - { - var variable = (IVariable) loadInstruction.Operand; - if (variable.IsParameter) - { - var index = body.Parameters.IndexOf(variable); - instructionEncoder.LoadArgumentAddress(index); - } - else - { - var index = body.LocalVariables.IndexOf(variable); - instructionEncoder.LoadLocalAddress(index); - } - - break; - } - case LoadOperation.Content: - { - var variable = (IVariable) loadInstruction.Operand; - if (variable.IsParameter) - { - var index = body.Parameters.IndexOf(variable); - instructionEncoder.LoadArgument(index); - } - else - { - var index = body.LocalVariables.IndexOf(variable); - instructionEncoder.LoadLocal(index); - } - - break; - } - case LoadOperation.Value: - { - switch ((loadInstruction.Operand as Constant).Value) - { - case null: - instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); - break; - case string value: - instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); - break; - case int value: - instructionEncoder.LoadConstantI4(value); - break; - case long value: - instructionEncoder.LoadConstantI8(value); - break; - case float value: - instructionEncoder.LoadConstantR4(value); - break; - case double value: - instructionEncoder.LoadConstantR8(value); - break; - case bool value: - instructionEncoder.LoadConstantI4(value ? 1 : 0); - break; - default: - throw new UnhandledCase(); - } - - break; - } - default: - throw new UnhandledCase(); - } + var index = body.Parameters.IndexOf(variable); + instructionEncoder.LoadArgumentAddress(index); + } + else + { + var index = body.LocalVariables.IndexOf(variable); + instructionEncoder.LoadLocalAddress(index); + } - break; + break; + } + case LoadOperation.Content: + { + var variable = (IVariable) instruction.Operand; + if (variable.IsParameter) + { + var index = body.Parameters.IndexOf(variable); + instructionEncoder.LoadArgument(index); + } + else + { + var index = body.LocalVariables.IndexOf(variable); + instructionEncoder.LoadLocal(index); } - case LoadFieldInstruction loadFieldInstruction: - switch (loadFieldInstruction.Operation) - { - case LoadFieldOperation.Content: - instructionEncoder.OpCode(loadFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Ldsfld : SRM.ILOpCode.Ldfld); - break; - case LoadFieldOperation.Address: - instructionEncoder.OpCode(loadFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Ldsflda : SRM.ILOpCode.Ldflda); - break; - default: - throw new UnhandledCase(); - } - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(loadFieldInstruction.Field)); - break; - case LoadArrayElementInstruction loadArrayElementInstruction: + break; + } + case LoadOperation.Value: + { + switch (((Constant) instruction.Operand).Value) { - if (loadArrayElementInstruction.Method != null) - { - instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(loadArrayElementInstruction.Method)); - } - else - { - switch (loadArrayElementInstruction.Operation) + case null: + instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); + + if ( + body.Instructions.Count > Index + 2 && + body.Instructions[Index + 1] is BasicInstruction i1 && i1.Operation == BasicOperation.Eq && + body.Instructions[Index + 2] is BasicInstruction i2 && i2.Operation == BasicOperation.Neg + ) { - case LoadArrayElementOperation.Content: - if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i1); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt8)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u1); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int16)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i2); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt16)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u2); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i4); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u4); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int64) || - loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.UInt64)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i8); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_r4); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float64)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_r8); - } - else if (loadArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Object)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_ref); - } - else - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); - instructionEncoder.Token( - metadataContainer.MetadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); - } - - break; - case LoadArrayElementOperation.Address: - instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); - instructionEncoder.Token( - metadataContainer.MetadataResolver.HandleOf(loadArrayElementInstruction.Array.ElementsType)); - break; - - default: - throw new UnhandledCase(); + // cgt_un is used as a compare-not-equal with null. + // load null - compare eq - negate => ldnull - cgt_un + instructionEncoder.OpCode(SRM.ILOpCode.Cgt_un); + + // skip processing next 2 instructions + ignoredInstructions.Add(Index + 1); + ignoredInstructions.Add(Index + 2); } - } - break; + break; + case string value: + instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); + break; + case int value: + instructionEncoder.LoadConstantI4(value); + break; + case long value: + instructionEncoder.LoadConstantI8(value); + break; + case float value: + instructionEncoder.LoadConstantR4(value); + break; + case double value: + instructionEncoder.LoadConstantR8(value); + break; + case bool value: + instructionEncoder.LoadConstantI4(value ? 1 : 0); + break; + default: + throw new UnhandledCase(); } - case LoadMethodAddressInstruction loadMethodAddressInstruction: - instructionEncoder.OpCode(loadMethodAddressInstruction.Method.IsVirtual ? SRM.ILOpCode.Ldvirtftn : SRM.ILOpCode.Ldftn); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(loadMethodAddressInstruction.Method)); - break; - case CreateArrayInstruction createArrayInstruction: - if (createArrayInstruction.Type.IsVector) + + break; + } + default: + throw new UnhandledCase(); + } + } + + public void Visit(LoadIndirectInstruction instruction) + { + if (instruction.Type.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i1); + } + else if (instruction.Type.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i2); + } + else if (instruction.Type.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i4); + } + else if (instruction.Type.Equals(PlatformTypes.Int64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i8); + } + else if (instruction.Type.Equals(PlatformTypes.UInt8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_u1); + } + else if (instruction.Type.Equals(PlatformTypes.UInt16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_u2); + } + else if (instruction.Type.Equals(PlatformTypes.UInt32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_u4); + } + else if (instruction.Type.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_r4); + } + else if (instruction.Type.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_r8); + } + else if (instruction.Type.Equals(PlatformTypes.IntPtr)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i); + } + else if (instruction.Type.Equals(PlatformTypes.Object)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldind_ref); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldobj); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Type)); + } + } + + public void Visit(LoadFieldInstruction instruction) + { + switch (instruction.Operation) + { + case LoadFieldOperation.Content: + instructionEncoder.OpCode(instruction.Field.IsStatic ? SRM.ILOpCode.Ldsfld : SRM.ILOpCode.Ldfld); + break; + case LoadFieldOperation.Address: + instructionEncoder.OpCode(instruction.Field.IsStatic ? SRM.ILOpCode.Ldsflda : SRM.ILOpCode.Ldflda); + break; + default: + throw new UnhandledCase(); + } + + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Field)); + } + + public void Visit(LoadMethodAddressInstruction instruction) + { + instructionEncoder.OpCode(instruction.Method.IsVirtual ? SRM.ILOpCode.Ldvirtftn : SRM.ILOpCode.Ldftn); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + } + + public void Visit(StoreIndirectInstruction instruction) + { + if (instruction.Type.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_i1); + } + else if (instruction.Type.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_i2); + } + else if (instruction.Type.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_i4); + } + else if (instruction.Type.Equals(PlatformTypes.Int64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_i8); + } + else if (instruction.Type.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_r4); + } + else if (instruction.Type.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_r8); + } + else if (instruction.Type.Equals(PlatformTypes.IntPtr)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_i); + } + else if (instruction.Type.Equals(PlatformTypes.Object)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stind_ref); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Stobj); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Type)); + } + } + + public void Visit(StoreInstruction instruction) + { + var target = instruction.Target; + if (target.IsParameter) + { + var index = body.Parameters.IndexOf(target); + instructionEncoder.StoreArgument(index); + } + else + { + var index = body.LocalVariables.IndexOf(target); + instructionEncoder.StoreLocal(index); + } + } + + public void Visit(StoreFieldInstruction instruction) + { + instructionEncoder.OpCode(instruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Field)); + } + + public void Visit(ConvertInstruction instruction) + { + switch (instruction.Operation) + { + case ConvertOperation.Conv: + if (instruction.ConversionType.Equals(PlatformTypes.Int8)) + { + if (instruction.OverflowCheck) { - instructionEncoder.OpCode(SRM.ILOpCode.Newarr); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(createArrayInstruction.Type.ElementsType)); + instructionEncoder.OpCode(instruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_i1_un + : SRM.ILOpCode.Conv_ovf_i1); } else { - var method = metadataContainer.MetadataResolver.HandleOf(createArrayInstruction.Constructor); - instructionEncoder.OpCode(SRM.ILOpCode.Newobj); - instructionEncoder.Token(method); + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i1); } - - break; - case CreateObjectInstruction createObjectInstruction: - { - var method = metadataContainer.MetadataResolver.HandleOf(createObjectInstruction.Constructor); - instructionEncoder.OpCode(SRM.ILOpCode.Newobj); - instructionEncoder.Token(method); - break; } - case StoreInstruction storeInstruction: + else if (instruction.ConversionType.Equals(PlatformTypes.UInt8)) { - var target = storeInstruction.Target; - if (target.IsParameter) + if (instruction.OverflowCheck) { - var index = body.Parameters.IndexOf(target); - instructionEncoder.StoreArgument(index); + instructionEncoder.OpCode(instruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_u1_un + : SRM.ILOpCode.Conv_ovf_u1); } else { - var index = body.LocalVariables.IndexOf(target); - instructionEncoder.StoreLocal(index); + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u1); } - - break; } - case StoreFieldInstruction storeFieldInstruction: - instructionEncoder.OpCode(storeFieldInstruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(storeFieldInstruction.Field)); - break; - case SwitchInstruction switchInstruction: + else if (instruction.ConversionType.Equals(PlatformTypes.Int16)) { - // switch is encoded as OpCode NumberOfTargets target1, target2, .... - // the targets in SwitchInstruction are labels that refer to the Instructions in the method body - // but when encoded they must be be offsets relative to the instructionEncoder offsets (real Cil offsets) - // this offsets can't be determined until the whole body is generated so a space is reserved for the targets and filled up later - var targetsCount = switchInstruction.Targets.Count; - instructionEncoder.OpCode(SRM.ILOpCode.Switch); - instructionEncoder.Token(targetsCount); - var targetsReserveBytes = instructionEncoder.CodeBuilder.ReserveBytes(sizeof(int) * targetsCount); - var switchInstructionPlaceholder = new SwitchInstructionPlaceholder( - instructionEncoder.Offset, - targetsReserveBytes, - switchInstruction.Targets); - switchInstructionsPlaceHolders.Add(switchInstructionPlaceholder); - break; - } - case SizeofInstruction sizeofInstruction: - instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(sizeofInstruction.MeasuredType)); - break; - case LoadTokenInstruction loadTokenInstruction: - instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(loadTokenInstruction.Token)); - break; - case IndirectMethodCallInstruction indirectMethodCallInstruction: - var methodSignature = metadataContainer.MetadataResolver.HandleOf(indirectMethodCallInstruction.Function); - instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); - break; - case StoreArrayElementInstruction storeArrayElementInstruction: - if (storeArrayElementInstruction.Method != null) - { - instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(storeArrayElementInstruction.Method)); - } - else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int8)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i1); - } - else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int16)) + if (instruction.OverflowCheck) { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i2); + instructionEncoder.OpCode(instruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_i2_un + : SRM.ILOpCode.Conv_ovf_i2); } - else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int32)) + else { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i4); + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i2); } - else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Int64)) + } + else if (instruction.ConversionType.Equals(PlatformTypes.UInt16)) + { + if (instruction.OverflowCheck) { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i8); + instructionEncoder.OpCode(instruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_u2_un + : SRM.ILOpCode.Conv_ovf_u2); } - else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float32)) + else { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_r4); + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u2); } - else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Float64)) + } + else if (instruction.ConversionType.Equals(PlatformTypes.Int32)) + { + if (instruction.OverflowCheck) { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_r8); + instructionEncoder.OpCode(instruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_i4_un + : SRM.ILOpCode.Conv_ovf_i4); } - else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) + else { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i); + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i4); } - else if (storeArrayElementInstruction.Array.ElementsType.Equals(PlatformTypes.Object)) + } + else if (instruction.ConversionType.Equals(PlatformTypes.UInt32)) + { + if (instruction.OverflowCheck) { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_ref); + instructionEncoder.OpCode(instruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_u4_un + : SRM.ILOpCode.Conv_ovf_u4); } else { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(storeArrayElementInstruction.Array.ElementsType)); + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u4); } - - break; - case InitObjInstruction initObjInstruction: - instructionEncoder.OpCode(SRM.ILOpCode.Initobj); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(initObjInstruction.Type)); - break; - case ConstrainedInstruction constrainedInstruction: - instructionEncoder.OpCode(SRM.ILOpCode.Constrained); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(constrainedInstruction.ThisType)); - break; - case LoadIndirectInstruction loadIndirectInstruction: - if (loadIndirectInstruction.Type.Equals(PlatformTypes.Int8)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i1); - } - else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Int16)) + } + else if (instruction.ConversionType.Equals(PlatformTypes.Int64)) + { + if (instruction.OverflowCheck) { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i2); + instructionEncoder.OpCode(instruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_i8_un + : SRM.ILOpCode.Conv_ovf_i8); } - else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Int32)) + else { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i4); + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i8); } - else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Int64)) + } + else if (instruction.ConversionType.Equals(PlatformTypes.UInt64)) + { + if (instruction.OverflowCheck) { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i8); + instructionEncoder.OpCode(instruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_u8_un + : SRM.ILOpCode.Conv_ovf_u8); } - else if (loadIndirectInstruction.Type.Equals(PlatformTypes.UInt8)) + else { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_u1); + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u8); } - else if (loadIndirectInstruction.Type.Equals(PlatformTypes.UInt16)) + } + else if (instruction.ConversionType.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Conv_r_un : SRM.ILOpCode.Conv_r4); + } + else if (instruction.ConversionType.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Conv_r_un : SRM.ILOpCode.Conv_r8); + } + else if (instruction.ConversionType.Equals(PlatformTypes.IntPtr)) + { + if (instruction.OverflowCheck) { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_u2); + instructionEncoder.OpCode(instruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_i_un + : SRM.ILOpCode.Conv_ovf_i); } - else if (loadIndirectInstruction.Type.Equals(PlatformTypes.UInt32)) + else { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_u4); + instructionEncoder.OpCode(SRM.ILOpCode.Conv_i); } - else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Float32)) + } + else if (instruction.ConversionType.Equals(PlatformTypes.UIntPtr)) + { + if (instruction.OverflowCheck) { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_r4); + instructionEncoder.OpCode(instruction.UnsignedOperands + ? SRM.ILOpCode.Conv_ovf_u_un + : SRM.ILOpCode.Conv_ovf_u); } - else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Float64)) + else { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_r8); + instructionEncoder.OpCode(SRM.ILOpCode.Conv_u); } - else if (loadIndirectInstruction.Type.Equals(PlatformTypes.IntPtr)) + } + else throw new UnhandledCase(); + + break; + case ConvertOperation.Cast: + instructionEncoder.OpCode(SRM.ILOpCode.Castclass); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ConversionType)); + break; + case ConvertOperation.IsInst: + instructionEncoder.OpCode(SRM.ILOpCode.Isinst); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ConversionType)); + break; + case ConvertOperation.Box: + instructionEncoder.OpCode(SRM.ILOpCode.Box); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ConversionType)); + break; + case ConvertOperation.Unbox: + instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ConversionType)); + break; + case ConvertOperation.UnboxPtr: + instructionEncoder.OpCode(SRM.ILOpCode.Unbox); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ConversionType)); + break; + default: + throw new UnhandledCase(); + } + } + + public void Visit(BranchInstruction instruction) + { + SRM.ILOpCode opCode; + // targets of branch instructions reference other instructions (labels) in the body. But this labels are not going to be + // the same as the ones in the final CIL (the ones that instructionEncoder generates) because the instructions in the model + // do not know about the size they will occupy in CIL. Due to this, it is not possible to know if the branches could be cil + // short forms or not. So regular forms are used in all cases. This does not change functionality, it just means that the + // generated CIL will not be optimal in size. + switch (instruction.Operation) + { + case BranchOperation.False: + opCode = SRM.ILOpCode.Brfalse; + break; + case BranchOperation.True: + opCode = SRM.ILOpCode.Brtrue; + break; + case BranchOperation.Eq: + opCode = SRM.ILOpCode.Beq; + break; + case BranchOperation.Neq: + opCode = SRM.ILOpCode.Bne_un; + break; + case BranchOperation.Lt: + opCode = instruction.UnsignedOperands ? SRM.ILOpCode.Blt_un : SRM.ILOpCode.Blt; + break; + case BranchOperation.Le: + opCode = instruction.UnsignedOperands ? SRM.ILOpCode.Ble_un : SRM.ILOpCode.Ble; + break; + case BranchOperation.Gt: + opCode = instruction.UnsignedOperands ? SRM.ILOpCode.Bgt_un : SRM.ILOpCode.Bgt; + break; + case BranchOperation.Ge: + opCode = instruction.UnsignedOperands ? SRM.ILOpCode.Bge_un : SRM.ILOpCode.Bge; + break; + case BranchOperation.Branch: + opCode = SRM.ILOpCode.Br; + break; + case BranchOperation.Leave: + opCode = SRM.ILOpCode.Leave; + break; + default: + throw new UnhandledCase(); + } + + instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(instruction.Target)); + } + + public void Visit(SwitchInstruction instruction) + { + // switch is encoded as OpCode NumberOfTargets target1, target2, .... + // the targets in SwitchInstruction are labels that refer to the Instructions in the method body + // but when encoded they must be be offsets relative to the instructionEncoder offsets (real Cil offsets) + // this offsets can't be determined until the whole body is generated so a space is reserved for the targets and filled up later + var targetsCount = instruction.Targets.Count; + instructionEncoder.OpCode(SRM.ILOpCode.Switch); + instructionEncoder.Token(targetsCount); + var targetsReserveBytes = instructionEncoder.CodeBuilder.ReserveBytes(sizeof(int) * targetsCount); + var switchInstructionPlaceholder = new SwitchInstructionPlaceholder( + instructionEncoder.Offset, + targetsReserveBytes, + instruction.Targets); + switchInstructionsPlaceHolders.Add(switchInstructionPlaceholder); + } + + public void Visit(SizeofInstruction instruction) + { + instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.MeasuredType)); + } + + public void Visit(LoadTokenInstruction instruction) + { + instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Token)); + } + + public void Visit(MethodCallInstruction instruction) + { + switch (instruction.Operation) + { + case MethodCallOperation.Virtual: + instructionEncoder.CallVirtual(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + break; + case MethodCallOperation.Static: + case MethodCallOperation.Jump: + instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + break; + default: + throw new UnhandledCase(); + } + } + + public void Visit(IndirectMethodCallInstruction instruction) + { + var methodSignature = metadataContainer.MetadataResolver.HandleOf(instruction.Function); + instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); + } + + public void Visit(CreateObjectInstruction instruction) + { + var method = metadataContainer.MetadataResolver.HandleOf(instruction.Constructor); + instructionEncoder.OpCode(SRM.ILOpCode.Newobj); + instructionEncoder.Token(method); + } + + public void Visit(CreateArrayInstruction instruction) + { + if (instruction.Type.IsVector) + { + instructionEncoder.OpCode(SRM.ILOpCode.Newarr); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Type.ElementsType)); + } + else + { + var method = metadataContainer.MetadataResolver.HandleOf(instruction.Constructor); + instructionEncoder.OpCode(SRM.ILOpCode.Newobj); + instructionEncoder.Token(method); + } + } + + public void Visit(LoadArrayElementInstruction instruction) + { + if (instruction.Method != null) + { + instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + } + else + { + switch (instruction.Operation) + { + case LoadArrayElementOperation.Content: + if (instruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_i); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i); } - else if (loadIndirectInstruction.Type.Equals(PlatformTypes.Object)) + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int8)) { - instructionEncoder.OpCode(SRM.ILOpCode.Ldind_ref); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i1); } - else + else if (instruction.Array.ElementsType.Equals(PlatformTypes.UInt8)) { - instructionEncoder.OpCode(SRM.ILOpCode.Ldobj); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(loadIndirectInstruction.Type)); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u1); } - - break; - case StoreIndirectInstruction storeIndirectInstruction: - if (storeIndirectInstruction.Type.Equals(PlatformTypes.Int8)) + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int16)) { - instructionEncoder.OpCode(SRM.ILOpCode.Stind_i1); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i2); } - else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Int16)) + else if (instruction.Array.ElementsType.Equals(PlatformTypes.UInt16)) { - instructionEncoder.OpCode(SRM.ILOpCode.Stind_i2); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u2); } - else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Int32)) + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int32)) { - instructionEncoder.OpCode(SRM.ILOpCode.Stind_i4); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i4); } - else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Int64)) + else if (instruction.Array.ElementsType.Equals(PlatformTypes.UInt32)) { - instructionEncoder.OpCode(SRM.ILOpCode.Stind_i8); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_u4); } - else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Float32)) + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int64) || + instruction.Array.ElementsType.Equals(PlatformTypes.UInt64)) { - instructionEncoder.OpCode(SRM.ILOpCode.Stind_r4); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_i8); } - else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Float64)) + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Float32)) { - instructionEncoder.OpCode(SRM.ILOpCode.Stind_r8); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_r4); } - else if (storeIndirectInstruction.Type.Equals(PlatformTypes.IntPtr)) + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Float64)) { - instructionEncoder.OpCode(SRM.ILOpCode.Stind_i); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_r8); } - else if (storeIndirectInstruction.Type.Equals(PlatformTypes.Object)) + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Object)) { - instructionEncoder.OpCode(SRM.ILOpCode.Stind_ref); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem_ref); } else { - instructionEncoder.OpCode(SRM.ILOpCode.Stobj); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(storeIndirectInstruction.Type)); + instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); + instructionEncoder.Token( + metadataContainer.MetadataResolver.HandleOf(instruction.Array.ElementsType)); } break; + case LoadArrayElementOperation.Address: + instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); + instructionEncoder.Token( + metadataContainer.MetadataResolver.HandleOf(instruction.Array.ElementsType)); + break; + default: throw new UnhandledCase(); } } + } - foreach (var switchInstructionPlaceholder in switchInstructionsPlaceHolders) + public void Visit(StoreArrayElementInstruction instruction) + { + if (instruction.Method != null) { - switchInstructionPlaceholder.FillWithRealTargets(labelToEncoderOffset); + instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i1); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i2); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i4); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i8); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_r4); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_r8); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Object)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_ref); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Array.ElementsType)); } - - return instructionEncoder; } private class SwitchInstructionPlaceholder diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 5d1b8d94..c87faf90 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -12,7 +12,6 @@ internal class MethodGenerator { private readonly MetadataContainer metadataContainer; private readonly MethodSignatureGenerator methodSignatureGenerator; - private readonly MethodBodyGenerator methodBodyGenerator; private readonly MethodLocalsSignatureGenerator methodLocalsSignatureGenerator; private readonly MethodParametersGenerator methodParametersGenerator; private readonly CustomAttributeGenerator customAttributeGenerator; @@ -21,7 +20,6 @@ public MethodGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); - methodBodyGenerator = new MethodBodyGenerator(metadataContainer); methodLocalsSignatureGenerator = new MethodLocalsSignatureGenerator(metadataContainer); methodParametersGenerator = new MethodParametersGenerator(metadataContainer); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); @@ -40,7 +38,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) // programatically then the maxStack is gonna be missing var maxStack = method.Body.MaxStack; methodBodyOffset = metadataContainer.MethodBodyStream.AddMethodBody( - instructionEncoder: methodBodyGenerator.Generate(method.Body), + instructionEncoder: new MethodBodyGenerator(metadataContainer, method.Body).Generate(), localVariablesSignature: methodLocalsSignatureGenerator.GenerateSignatureFor(method.Body.LocalVariables), maxStack: maxStack); } From e8ac43fe0b6e646a827da7e850fc95b343602975 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 17 Aug 2020 15:24:01 -0300 Subject: [PATCH 215/256] refactor: use visitor --- Backend/Analyses/TypeInferenceAnalysis.cs | 4 - Backend/Transformations/Assembly/Assembler.cs | 854 +++++++++--------- Backend/Transformations/Disassembler.cs | 79 +- Model/Bytecode/Instructions.cs | 15 +- .../Visitor/InstructionVisitor.cs | 8 +- 5 files changed, 477 insertions(+), 483 deletions(-) diff --git a/Backend/Analyses/TypeInferenceAnalysis.cs b/Backend/Analyses/TypeInferenceAnalysis.cs index e6a661a8..b4a1a98f 100644 --- a/Backend/Analyses/TypeInferenceAnalysis.cs +++ b/Backend/Analyses/TypeInferenceAnalysis.cs @@ -349,10 +349,6 @@ public override void Visit(FilterInstruction instruction) { instruction.Result.Type = instruction.ExceptionType; } - - - - // FIXME hay varias instrucciones que no estan aca implementadas en este visitor, faltara agregarlas? } #endregion diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 7acafb6e..7048468b 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -23,10 +23,15 @@ namespace Backend.Transformations.Assembly { - public class Assembler + 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)) @@ -35,6 +40,9 @@ public Assembler(MethodDefinition method) } this.method = method; + translatedInstructions = new List(); + exceptionInformationBuilder = new ExceptionInformationBuilder(); + ignoredInstructions = new HashSet(); } public MethodBody Execute() @@ -43,551 +51,503 @@ public MethodBody Execute() body.MaxStack = 20; // FIXME calcular (ver StackSize) body.Parameters.AddRange(method.Body.Parameters); + // FIXME esto esta bien? porque las local variables se actualizan. La unica diferencia con eso era el this creo + // no habira que en todo poner las locals variables mas el this si es que esta? - if (method.Body.Instructions.Count > 0) + for (Index = 0; Index < method.Body.Instructions.Count; Index++) { - var instructionTranslator = new InstructionTranslator(method.Body); - instructionTranslator.Visit(method.Body); - - body.ExceptionInformation.AddRange(instructionTranslator.exceptionInformationBuilder.Build()); - body.Instructions.AddRange(instructionTranslator.translatedInstructions); - - body.UpdateVariables(); + 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; } - private class InstructionTranslator : InstructionVisitor + // abstract + public void Visit(IInstructionContainer container) { - // FIXMe hay que ver si no es mas prolijo quiza que sean del y que se las pase para que las rellene, mas que que este las tenga public - public readonly IList translatedInstructions = new List(); - public readonly ExceptionInformationBuilder exceptionInformationBuilder = new ExceptionInformationBuilder(); - - public readonly StackSize stackSize; -/* - FIXME - Tema maxStack. quiza convenga validar con edgar como hacerlo. Porque ya veo que quiza hay que usar el CFG en vez de recorrer asi para calcularlo - ver como lo calcula en el dissasembler (eso de stack size at entry y demas) - */ + } - private readonly MethodBody bodyToProcess; - private readonly IDictionary ignoreInstruction = new Dictionary(); + public void Visit(Instruction instruction) + { + } - public InstructionTranslator(MethodBody bodyToProcess) - { - this.bodyToProcess = bodyToProcess; - stackSize = new StackSize(); - } + public void Visit(DefinitionInstruction instruction) + { + } - public override bool ShouldVisit(Instruction instruction) - { - var shouldProcessInstruction = !ignoreInstruction.TryGetValue(bodyToProcess.Instructions.IndexOf(instruction), out _); - return shouldProcessInstruction; - } + public void Visit(BranchInstruction instruction) + { + } + public void Visit(ExceptionalBranchInstruction instruction) + { + } + // - // FIXME hace falta esta realmente? - public override void Visit(PopInstruction instruction) + public void Visit(BinaryInstruction instruction) + { + if (instruction.Operation == BinaryOperation.Neq) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Pop) {Label = instruction.Label}; + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Eq) + { + Label = instruction.Label, + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands + }; translatedInstructions.Add(basicInstruction); - } - public override void Visit(BinaryInstruction instruction) - { - if (instruction.Operation == BinaryOperation.Neq) + basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Neg) { - 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 + "'", - 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); - } + Label = instruction.Label + "º", // ensure unique label + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands + }; + translatedInstructions.Add(basicInstruction); } - - public override void Visit(UnaryInstruction instruction) + else { var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, OperationHelper.ToBasicOperation(instruction.Operation)) { - Label = instruction.Label + Label = instruction.Label, + OverflowCheck = instruction.OverflowCheck, + UnsignedOperands = instruction.UnsignedOperands }; translatedInstructions.Add(basicInstruction); } + } - public override void Visit(LoadInstruction instruction) + public void Visit(UnaryInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, OperationHelper.ToBasicOperation(instruction.Operation)) { - 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 Exception(); // TODO - } - - 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 Exception(); // TODO - } - } - else - { - bytecodeInstruction = new Bytecode.StoreInstruction(instruction.Offset, (LocalVariable) instruction.Result); - } - - bytecodeInstruction.Label = instruction.Label; - translatedInstructions.Add(bytecodeInstruction); - } + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } - public override void Visit(StoreInstruction instruction) + public void Visit(LoadInstruction instruction) + { + Bytecode.Instruction bytecodeInstruction; + if (instruction.Result is TemporalVariable) { - Bytecode.Instruction storeInstruction; - switch (instruction.Result) + switch (instruction.Operand) { - case ArrayElementAccess arrayElementAccess: - { - storeInstruction = new Bytecode.StoreArrayElementInstruction(instruction.Offset, (ArrayType) arrayElementAccess.Array.Type) - { - Method = arrayElementAccess.Method - }; + 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: - { - storeInstruction = new Bytecode.StoreIndirectInstruction(instruction.Offset, dereference.Type); + 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: - storeInstruction = new Bytecode.StoreFieldInstruction(instruction.Offset, instanceFieldAccess.Field); + bytecodeInstruction = new Bytecode.LoadFieldInstruction( + instruction.Offset, + Bytecode.LoadFieldOperation.Content, + instanceFieldAccess.Field); break; case StaticFieldAccess staticFieldAccess: - storeInstruction = new Bytecode.StoreFieldInstruction(instruction.Offset, staticFieldAccess.Field); + 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 Exception(); // TODO msg + throw new CaseNotHandledException(); } - - storeInstruction.Label = instruction.Label; - translatedInstructions.Add(storeInstruction); } - - public override void Visit(NopInstruction instruction) + else { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop) - { - Label = instruction.Label - }; - translatedInstructions.Add(basicInstruction); + bytecodeInstruction = new Bytecode.StoreInstruction(instruction.Offset, (LocalVariable) instruction.Result); } - public override void Visit(BreakpointInstruction instruction) - { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Breakpoint) - { - Label = instruction.Label - }; - translatedInstructions.Add(basicInstruction); - } + bytecodeInstruction.Label = instruction.Label; + translatedInstructions.Add(bytecodeInstruction); + } - public override void Visit(TryInstruction instruction) + public void Visit(StoreInstruction instruction) + { + Bytecode.Instruction storeInstruction; + switch (instruction.Result) { - // try with multiple handlers is modelled as multiple consecutive try instructions with different handlers. - var instructionIndex = bodyToProcess.Instructions.IndexOf(instruction); - var previousInstructionIsTry = instructionIndex > 0 && bodyToProcess.Instructions[instructionIndex - 1] is TryInstruction; - if (previousInstructionIsTry) - { - exceptionInformationBuilder.IncrementCurrentProtectedBlockExpectedHandlers(); - } - else - { - // try starts at the instruction following the try instruction. - var label = ""; - for (var i = instructionIndex + 1; i < bodyToProcess.Instructions.Count; i++) + case ArrayElementAccess arrayElementAccess: + storeInstruction = new Bytecode.StoreArrayElementInstruction(instruction.Offset, (ArrayType) arrayElementAccess.Array.Type) { - var currentInstruction = bodyToProcess.Instructions[i]; - if (!(currentInstruction is TryInstruction)) - { - label = currentInstruction.Label; - break; - } - } - - exceptionInformationBuilder.BeginProtectedBlockAt(label); - } - } - - public override void Visit(FaultInstruction instruction) - { - // FIXME comment, esta duplicado en todos ademas. Hay una form amas eficiente de hacer esto?. Quiza si no uso el visitor, puedo recorrerlas - // en orden e ir pasando tambien el indice de la instruccion que estoy procesando. Si hago eso, lo de ignore insturctions - // no hace falta que este en el visitor. La realidad es que necesito indices asi que el visitor mucho no me sirve - var index = bodyToProcess.Instructions.IndexOf(instruction); - var label = bodyToProcess.Instructions[index + 1].Label; - exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(label, ExceptionHandlerBlockKind.Fault); - } - - public override void Visit(FinallyInstruction instruction) - { - var index = bodyToProcess.Instructions.IndexOf(instruction); - var label = bodyToProcess.Instructions[index + 1].Label; - exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock(label, ExceptionHandlerBlockKind.Finally); - } - + 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 override void Visit(FilterInstruction instruction) + public void Visit(NopInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Nop) { - var index = bodyToProcess.Instructions.IndexOf(instruction); - var label = bodyToProcess.Instructions[index + 1].Label; - exceptionInformationBuilder.AddFilterHandlerToCurrentProtectedBlock(label, instruction.kind, instruction.ExceptionType); - } + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } - public override void Visit(CatchInstruction instruction) + public void Visit(BreakpointInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Breakpoint) { - var index = bodyToProcess.Instructions.IndexOf(instruction); - var label = bodyToProcess.Instructions[index + 1].Label; - exceptionInformationBuilder.AddHandlerToCurrentProtectedBlock( - label, - ExceptionHandlerBlockKind.Catch, - instruction.ExceptionType); - } + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } - public override void Visit(ThrowInstruction instruction) + 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) { - 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 (!bodyToProcess.Instructions.Last().Equals(instruction)) // FIXME medio choto esto - { - var index = bodyToProcess.Instructions.IndexOf(instruction); - var label = bodyToProcess.Instructions[index + 1].Label; - exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(label); // block ends after instruction - } + exceptionInformationBuilder.IncrementCurrentProtectedBlockExpectedHandlers(); } - - public override void Visit(UnconditionalBranchInstruction instruction) + else { - var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); - Bytecode.Instruction bytecodeInstruction; - switch (instruction.Operation) + // try starts at the instruction following the try instruction. + var label = ""; + for (var i = Index + 1; i < method.Body.Instructions.Count; i++) { - case UnconditionalBranchOperation.Leave: - { - bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Leave, target); - var index = bodyToProcess.Instructions.IndexOf(instruction); - var label = bodyToProcess.Instructions[index + 1].Label; - exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(label); // block ends after instruction - - break; - } - case UnconditionalBranchOperation.Branch: - { - bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Branch, target); - break; - } - case UnconditionalBranchOperation.EndFinally: - { - bytecodeInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.EndFinally); - // no more handlers after finally - var index = bodyToProcess.Instructions.IndexOf(instruction); - var label = bodyToProcess.Instructions[index + 1].Label; - exceptionInformationBuilder.EndCurrentProtectedBlockAt(label); // block ends after instruction - break; - } - case UnconditionalBranchOperation.EndFilter: + var currentInstruction = method.Body.Instructions[i]; + if (!(currentInstruction is TryInstruction)) { - // 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); + label = currentInstruction.Label; break; } - default: throw instruction.Operation.ToUnknownValueException(); } - bytecodeInstruction.Label = instruction.Label; - translatedInstructions.Add(bytecodeInstruction); + exceptionInformationBuilder.BeginProtectedBlockAt(label); } + } - public override 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(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 override void Visit(ReturnInstruction instruction) + 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 basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Return) - { - Label = instruction.Label - }; - translatedInstructions.Add(basicInstruction); + var label = method.Body.Instructions[Index + 1].Label; + exceptionInformationBuilder.EndCurrentProtectedBlockIfAppliesAt(label); // block ends after instruction } + } - public override void Visit(ConditionalBranchInstruction instruction) + public void Visit(UnconditionalBranchInstruction instruction) + { + Bytecode.Instruction bytecodeInstruction; + switch (instruction.Operation) { - var branchOperation = OperationHelper.ToBranchOperation(instruction.Operation); - if (instruction.RightOperand is Constant constant) + case UnconditionalBranchOperation.Leave: { - var loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant) - { - Label = instruction.Label + "'" - }; - translatedInstructions.Add(loadInstruction); - } + 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 - var target = Convert.ToUInt32(instruction.Target.Substring(2), 16); - var branchInstruction = new Bytecode.BranchInstruction( - instruction.Offset, - branchOperation, - target) + break; + } + case UnconditionalBranchOperation.Branch: + bytecodeInstruction = new Bytecode.BranchInstruction(instruction.Offset, Bytecode.BranchOperation.Branch, instruction.Target); + break; + case UnconditionalBranchOperation.EndFinally: { - Label = instruction.Label - }; - translatedInstructions.Add(branchInstruction); + 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(); } - public override void Visit(SwitchInstruction instruction) + 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) { - var targets = instruction.Targets - .Select(target => Convert.ToUInt32(target.Substring(2), 16)) - .ToList(); - var switchInstruction = new Bytecode.SwitchInstruction(instruction.Offset, targets) - { - Label = instruction.Label - }; - translatedInstructions.Add(switchInstruction); - } + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } - public override void Visit(SizeofInstruction instruction) + public void Visit(ConditionalBranchInstruction instruction) + { + var branchOperation = OperationHelper.ToBranchOperation(instruction.Operation); + if (instruction.RightOperand is Constant constant) { - var sizeofInstruction = new Bytecode.SizeofInstruction(instruction.Offset, instruction.MeasuredType) + var loadInstruction = new Bytecode.LoadInstruction(instruction.Offset, Bytecode.LoadOperation.Value, constant) { - Label = instruction.Label + Label = instruction.Label + "º" // ensure unique label }; - translatedInstructions.Add(sizeofInstruction); + translatedInstructions.Add(loadInstruction); } + var branchInstruction = new Bytecode.BranchInstruction(instruction.Offset, branchOperation, instruction.Target) + { + Label = instruction.Label + }; + translatedInstructions.Add(branchInstruction); + } - public override void Visit(LoadTokenInstruction instruction) + public void Visit(SwitchInstruction instruction) + { + var switchInstruction = new Bytecode.SwitchInstruction(instruction.Offset, instruction.Targets) { - var loadTokenInstruction = new Bytecode.LoadTokenInstruction(instruction.Offset, instruction.Token) - { - Label = instruction.Label - }; - translatedInstructions.Add(loadTokenInstruction); - } + Label = instruction.Label + }; + translatedInstructions.Add(switchInstruction); + } - public override void Visit(MethodCallInstruction instruction) + public void Visit(SizeofInstruction instruction) + { + var sizeofInstruction = new Bytecode.SizeofInstruction(instruction.Offset, instruction.MeasuredType) { - var methodCallInstruction = new Bytecode.MethodCallInstruction( - instruction.Offset, - OperationHelper.ToMethodCallOperation(instruction.Operation), - instruction.Method - ) - { - Label = instruction.Label - }; - translatedInstructions.Add(methodCallInstruction); - } + Label = instruction.Label + }; + translatedInstructions.Add(sizeofInstruction); + } - public override void Visit(IndirectMethodCallInstruction instruction) + public void Visit(LoadTokenInstruction instruction) + { + var loadTokenInstruction = new Bytecode.LoadTokenInstruction(instruction.Offset, instruction.Token) { - var indirectMethodCallInstruction = new Bytecode.IndirectMethodCallInstruction(instruction.Offset, instruction.Function) - { - Label = instruction.Label - }; - translatedInstructions.Add(indirectMethodCallInstruction); - } + 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 override void Visit(CreateObjectInstruction instruction) + public void Visit(IndirectMethodCallInstruction instruction) + { + var indirectMethodCallInstruction = new Bytecode.IndirectMethodCallInstruction(instruction.Offset, instruction.Function) { - var index = bodyToProcess.Instructions.IndexOf(instruction); - var methodCallInstruction = (MethodCallInstruction) bodyToProcess.Instructions[index + 1]; - ignoreInstruction.Add(index + 1, true); // method call - ignoreInstruction.Add(index + 2, true); // load + Label = instruction.Label + }; + translatedInstructions.Add(indirectMethodCallInstruction); + } - var createObjectInstruction = new Bytecode.CreateObjectInstruction(instruction.Offset, methodCallInstruction.Method) - { - Label = instruction.Label - }; - translatedInstructions.Add(createObjectInstruction); - } + 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 - public override void Visit(CopyMemoryInstruction instruction) + var createObjectInstruction = new Bytecode.CreateObjectInstruction(instruction.Offset, methodCallInstruction.Method) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyBlock) - { - Label = instruction.Label - }; - translatedInstructions.Add(basicInstruction); - } + Label = instruction.Label + }; + translatedInstructions.Add(createObjectInstruction); + } - public override void Visit(LocalAllocationInstruction instruction) + public void Visit(CopyMemoryInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyBlock) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LocalAllocation) - { - Label = instruction.Label - }; - translatedInstructions.Add(basicInstruction); - } + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } - public override void Visit(InitializeMemoryInstruction instruction) + public void Visit(LocalAllocationInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.LocalAllocation) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.InitBlock) - { - Label = instruction.Label - }; - translatedInstructions.Add(basicInstruction); - } + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } - public override void Visit(InitializeObjectInstruction instruction) + public void Visit(InitializeMemoryInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.InitBlock) { - var type = ((PointerType) instruction.TargetAddress.Type).TargetType; - var initObjInstruction = new Bytecode.InitObjInstruction(instruction.Offset, type) - { - Label = instruction.Label - }; - translatedInstructions.Add(initObjInstruction); - } + Label = instruction.Label + }; + translatedInstructions.Add(basicInstruction); + } - public override void Visit(CopyObjectInstruction instruction) + public void Visit(InitializeObjectInstruction instruction) + { + var type = ((PointerType) instruction.TargetAddress.Type).TargetType; + var initObjInstruction = new Bytecode.InitObjInstruction(instruction.Offset, type) { - var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyObject) - { - Label = instruction.Label - }; - translatedInstructions.Add(basicInstruction); - } + Label = instruction.Label + }; + translatedInstructions.Add(initObjInstruction); + } - public override void Visit(CreateArrayInstruction instruction) + public void Visit(CopyObjectInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.CopyObject) { - 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); - } + 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 override void Visit(PhiInstruction instruction) => throw new Exception(); + public void Visit(PhiInstruction instruction) => throw new CaseNotHandledException(); - public override void Visit(ConstrainedInstruction instruction) + public void Visit(ConstrainedInstruction instruction) + { + var constrainedInstruction = new Bytecode.ConstrainedInstruction(instruction.Offset, instruction.ThisType) { - var constrainedInstruction = new Bytecode.ConstrainedInstruction(instruction.Offset, instruction.ThisType) - { - Label = instruction.Label - }; - translatedInstructions.Add(constrainedInstruction); - } + Label = instruction.Label + }; + translatedInstructions.Add(constrainedInstruction); + } + + public void Visit(PopInstruction instruction) + { + var basicInstruction = new Bytecode.BasicInstruction(instruction.Offset, Bytecode.BasicOperation.Pop); + translatedInstructions.Add(basicInstruction); } // FIXME se podria ir calculando. Pero ahi hay que ir contando segun la instruccion (si suma o vacia el stack). Es esta la mejor forma? @@ -622,5 +582,9 @@ public void Clear() currentStackSize = 0; } } + + private class CaseNotHandledException : Exception + { + } } } \ No newline at end of file diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 3748b419..95ed4e26 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -98,6 +98,8 @@ public TemporalVariable Top() private class InstructionTranslator : InstructionVisitor { + public const string NextInstructionLabelPlaceHolder = "{nextInstructionLabelPlaceHolder}"; + private MethodBody body; private OperandStack stack; private IType returnType; @@ -240,7 +242,8 @@ private void ProcessEmptyOperation(Bytecode.BasicInstruction op) private void ProcessPop(Bytecode.BasicInstruction op) { stack.Pop(); - body.Instructions.Add(new Tac.PopInstruction(op.Offset)); + var instruction = new Tac.PopInstruction(op.Offset); + body.Instructions.Add(instruction); } private void ProcessDup(Bytecode.BasicInstruction op) @@ -255,8 +258,12 @@ private void ProcessEndFinally(Bytecode.BasicInstruction op) { stack.Clear(); - // jump target is always next instruction. This relies on CIL instruction size which is 1 byte - var instruction = new Tac.UnconditionalBranchInstruction(op.Offset, op.Offset+1, Tac.UnconditionalBranchOperation.EndFinally); + // 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 @@ -282,8 +289,12 @@ private void ProcessEndFilter(Bytecode.BasicInstruction op) { stack.Clear(); - // jump target is always next instruction. This relies on CIL instruction size which is 2 byte - var instruction = new Tac.UnconditionalBranchInstruction(op.Offset, op.Offset+2, Tac.UnconditionalBranchOperation.EndFilter); + // 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); } @@ -542,10 +553,11 @@ private void ProcessLoadArrayElement(Bytecode.LoadArrayElementInstruction op) } var array = stack.Pop(); + indices.Reverse(); - var source = new ArrayElementAccess(array, indices) { Method = op.Method}; var dest = stack.Push(); + var source = new ArrayElementAccess(array, indices) { Method = op.Method}; var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -564,9 +576,10 @@ private void ProcessLoadArrayElementAddress(Bytecode.LoadArrayElementInstruction indices.Reverse(); + var dest = stack.Push(); + var access = new ArrayElementAccess(array, indices) { Method = op.Method};; var source = new Reference(access); - var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -583,7 +596,9 @@ public override void Visit(Bytecode.StoreArrayElementInstruction op) } var array = stack.Pop(); + indices.Reverse(); + var dest = new ArrayElementAccess(array, indices) { Method = op.Method}; var instruction = new Tac.StoreInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); @@ -598,7 +613,7 @@ public override void Visit(Bytecode.CreateObjectInstruction op) var arguments = new List(); - foreach (var parameter in op.Constructor.Parameters) + foreach (var par in op.Constructor.Parameters) { var arg = stack.Pop(); arguments.Add(arg); @@ -618,13 +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 + 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 + instruction.Label += "ºº"; // ensure unique label body.Instructions.Add(instruction); stack.DecrementCapacity(); @@ -636,7 +651,7 @@ public override void Visit(Bytecode.IndirectMethodCallInstruction op) var arguments = new List(); IVariable result = null; - foreach (var parameter in op.Function.Parameters) + foreach (var par in op.Function.Parameters) { var arg = stack.Pop(); arguments.Add(arg); @@ -702,8 +717,8 @@ private void ProcessLoadFieldAddress(Bytecode.LoadFieldInstruction op) private void ProcessLoadStaticField(Bytecode.LoadFieldInstruction op) { - var source = new StaticFieldAccess(op.Field); var dest = stack.Push(); + var source = new StaticFieldAccess(op.Field); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -711,17 +726,17 @@ private void ProcessLoadStaticField(Bytecode.LoadFieldInstruction op) private void ProcessLoadInstanceField(Bytecode.LoadFieldInstruction op) { var obj = stack.Pop(); - var source = new InstanceFieldAccess(obj, op.Field); var dest = stack.Push(); + var source = new InstanceFieldAccess(obj, op.Field); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } private void ProcessLoadStaticFieldAddress(Bytecode.LoadFieldInstruction op) { + var dest = stack.Push(); var access = new StaticFieldAccess(op.Field); var source = new Reference(access); - var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -729,17 +744,17 @@ private void ProcessLoadStaticFieldAddress(Bytecode.LoadFieldInstruction op) private void ProcessLoadInstanceFieldAddress(Bytecode.LoadFieldInstruction op) { var obj = stack.Pop(); + var dest = stack.Push(); var access = new InstanceFieldAccess(obj, op.Field); var source = new Reference(access); - var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } public override void Visit(Bytecode.LoadIndirectInstruction op) { var address = stack.Pop(); - var source = new Dereference(address); var dest = stack.Push(); + var source = new Dereference(address); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -779,9 +794,9 @@ private void ProcessLoadVariable(Bytecode.LoadInstruction op) private void ProcessLoadVariableAddress(Bytecode.LoadInstruction op) { + var dest = stack.Push(); var operand = (IVariable)op.Operand; var source = new Reference(operand); - var dest = stack.Push(); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -804,8 +819,8 @@ public override void Visit(Bytecode.LoadMethodAddressInstruction op) public void ProcessLoadStaticMethodAddress(Bytecode.LoadMethodAddressInstruction op) { - var source = new StaticMethodReference(op.Method); var dest = stack.Push(); + var source = new StaticMethodReference(op.Method); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -813,8 +828,8 @@ public void ProcessLoadStaticMethodAddress(Bytecode.LoadMethodAddressInstruction public void ProcessLoadVirtualMethodAddress(Bytecode.LoadMethodAddressInstruction op) { var obj = stack.Pop(); - var source = new VirtualMethodReference(obj, op.Method); var dest = stack.Push(); + var source = new VirtualMethodReference(obj, op.Method); var instruction = new Tac.LoadInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); } @@ -832,7 +847,7 @@ public override void Visit(Bytecode.MethodCallInstruction op) var arguments = new List(); IVariable result = null; - foreach (var parameter in op.Method.Parameters) + foreach (var par in op.Method.Parameters) { var arg = stack.Pop(); arguments.Add(arg); @@ -921,9 +936,10 @@ public override void Visit(Bytecode.SwitchInstruction op) body.Instructions.Add(instruction); } - public override void Visit(Bytecode.ConstrainedInstruction instruction) + public override void Visit(Bytecode.ConstrainedInstruction op) { - body.Instructions.Add(new Tac.ConstrainedInstruction(instruction.Offset, instruction.ThisType)); + var instruction = new Tac.ConstrainedInstruction(op.Offset, op.ThisType); + body.Instructions.Add(instruction); } } @@ -1003,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(); @@ -1041,7 +1068,7 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) if (exceptionHandlersStart.ContainsKey(operation.Label)) { var handlerBlocks = exceptionHandlersStart[operation.Label]; - var labelSuffix = "'"; + var labelSuffix = "º"; // ensure unique label foreach (var block in handlerBlocks) { Tac.Instruction instruction; @@ -1053,6 +1080,8 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) break; case ExceptionHandlerBlockKind.Filter: + + // fixme revisar esta parte agregada. El clear hace falta? la diferencia de los filters asi esta bien? stack.Clear(); var filterException = stack.Push(); // Push the exception into the stack var filterBlock = (FilterExceptionHandler) block; @@ -1063,6 +1092,8 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) break; case ExceptionHandlerBlockKind.Catch: + + // fixme este clear va? stack.Clear(); var catchException = stack.Push(); // Push the exception into the stack var catchBlock = block as CatchExceptionHandler; @@ -1083,7 +1114,7 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) instruction.Label = operation.Label + labelSuffix; body.Instructions.Add(instruction); - labelSuffix += "'"; + labelSuffix += "º"; } } } diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index 75cbf01e..728299c2 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -213,10 +213,14 @@ public class BranchInstruction : Instruction public string Target { get; set; } public bool UnsignedOperands { get; set; } - public BranchInstruction(uint label, BranchOperation operation, uint target) + public BranchInstruction(uint label, BranchOperation operation, uint target) + : this(label, operation, $"L_{target:X4}") + { + } + public BranchInstruction(uint label, BranchOperation operation, string target) : base(label) { - this.Target = string.Format("L_{0:X4}", target); + this.Target = target; this.Operation = operation; } @@ -237,9 +241,14 @@ public class SwitchInstruction : Instruction public IList Targets { get; private set; } public SwitchInstruction(uint label, IEnumerable targets) + : this(label, targets.Select(target => $"L_{target:X4}").ToList()) + { + } + + public SwitchInstruction(uint label, IEnumerable targets) : base(label) { - this.Targets = targets.Select(target => string.Format("L_{0:X4}", target)).ToList(); + this.Targets = targets.ToList(); } public override void Accept(IInstructionVisitor visitor) diff --git a/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs b/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs index b0daf076..6c067d37 100644 --- a/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs +++ b/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs @@ -15,11 +15,7 @@ public virtual void Visit(IInstructionContainer container) foreach (var instruction in container.Instructions) { var tacInstruction = instruction as Instruction; - if (ShouldVisit(tacInstruction)) - { - tacInstruction.Accept(this); - } - + tacInstruction.Accept(this); } } @@ -58,7 +54,5 @@ public virtual void Visit(CreateArrayInstruction instruction) { } public virtual void Visit(PhiInstruction instruction) { } public virtual void Visit(ConstrainedInstruction instruction) { } public virtual void Visit(PopInstruction instruction) { } - - public virtual bool ShouldVisit(Instruction instruction) => true; } } From 3091cabd0d876856dbf4bdbcab5094dd0856def9 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 17 Aug 2020 17:12:44 -0300 Subject: [PATCH 216/256] fix stack size --- Backend/Transformations/Disassembler.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 95ed4e26..656f2bf1 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -1003,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!"); @@ -1080,9 +1080,6 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) break; case ExceptionHandlerBlockKind.Filter: - - // fixme revisar esta parte agregada. El clear hace falta? la diferencia de los filters asi esta bien? - stack.Clear(); var filterException = stack.Push(); // Push the exception into the stack var filterBlock = (FilterExceptionHandler) block; var kind = operation.Label.Equals(filterBlock.FilterStart) @@ -1092,9 +1089,6 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) break; case ExceptionHandlerBlockKind.Catch: - - // fixme este clear va? - stack.Clear(); var catchException = stack.Push(); // Push the exception into the stack var catchBlock = block as CatchExceptionHandler; instruction = new Tac.CatchInstruction(operation.Offset, catchException, catchBlock.ExceptionType); From f80b1c59a232c3c21d3dc08520b4c431e0e0f738 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 18 Aug 2020 08:28:45 -0300 Subject: [PATCH 217/256] instrumentation and generation tests --- Backend/Transformations/Assembly/Assembler.cs | 3 - Console/Program.cs | 169 +++++++++++++++--- Examples/Examples.cs | 1 + ExamplesEXE/ExamplesEXE.cs | 79 +------- .../Generators/Methods/MethodGenerator.cs | 29 +-- 5 files changed, 148 insertions(+), 133 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 7048468b..b8a8bc0e 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -48,11 +48,8 @@ public Assembler(MethodDefinition method) public MethodBody Execute() { var body = new MethodBody(MethodBodyKind.Bytecode); - body.MaxStack = 20; // FIXME calcular (ver StackSize) body.Parameters.AddRange(method.Body.Parameters); - // FIXME esto esta bien? porque las local variables se actualizan. La unica diferencia con eso era el this creo - // no habira que en todo poner las locals variables mas el this si es que esta? for (Index = 0; Index < method.Body.Instructions.Count; Index++) { diff --git a/Console/Program.cs b/Console/Program.cs index 7310e8c2..17c21aee 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -13,6 +13,8 @@ using Backend.Transformations; using Backend.Utils; using Backend.Model; +using Backend.Transformations.Assembly; +using Model.ThreeAddressCode.Values; using Tac = Model.ThreeAddressCode.Instructions; using Bytecode = Model.Bytecode; @@ -365,9 +367,62 @@ private static void RunInterPointsToTests() ok = effectsResult.TryGetValue(method, out effectsInfo); } } - - private static void DisassembleAndThenAssemble(string input) + + private static void HelloWorldAssembly() { + var mscorlib = new AssemblyReference("mscorlib") + { + Version = new Version("4.0.0.0"), + Culture = "", + PublicKey = new byte[0] + }; + var assembly = new Assembly("SampleAssembly", AssemblyKind.EXE) + { + Version = new Version("1.0.0.0"), + PublicKey = new byte[0], + Culture = "", + References = {mscorlib} + }; + var namezpace = new Namespace("MainNamespace") {ContainingAssembly = assembly}; + assembly.RootNamespace = namezpace; + var type = new TypeDefinition("MainType", TypeKind.ReferenceType, TypeDefinitionKind.Class) + { + ContainingAssembly = assembly, + ContainingNamespace = namezpace, + Visibility = VisibilityKind.Public, + IsStatic = true, + Base = new BasicType("Object", TypeKind.ReferenceType) + { + ContainingAssembly = mscorlib, + ContainingNamespace = "System", + } + }; + namezpace.Types.Add(type); + var method = new MethodDefinition("Main", PlatformTypes.Void) + { + Visibility = VisibilityKind.Public, + ContainingType = type, + IsStatic = true, + Body = new MethodBody(MethodBodyKind.Bytecode) + { + MaxStack = 1, + Instructions = + { + new Bytecode.BasicInstruction(0, Bytecode.BasicOperation.Nop), + new Bytecode.LoadInstruction(1, Bytecode.LoadOperation.Value, new Constant("Hello World!")), + new Bytecode.MethodCallInstruction(2, Bytecode.MethodCallOperation.Static, ConsoleWriteLineMethodReference()), + new Bytecode.BasicInstruction(3, Bytecode.BasicOperation.Return) + } + } + }; + type.Methods.Add(method); + var generator = new MetadataGenerator.Generator(); + generator.Generate(assembly); + } + + private static void TacInstrumentation() + { + var input = "../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"; var host = new Host(); PlatformTypes.Resolve(host); @@ -375,29 +430,32 @@ private static void DisassembleAndThenAssemble(string input) System.Console.WriteLine($"Reading {input}"); var loader = new MetadataProvider.Loader(host); loader.LoadAssembly(input); - - /* var allDefinedMethods = from a in host.Assemblies + + var main = (from a in host.Assemblies from t in a.RootNamespace.GetAllTypes() from m in t.Members.OfType() - where m.HasBody - select m; + where m.Name.Equals("Main") + select m).First(); - foreach (var method in allDefinedMethods) - { - var tac = new Backend.Transformations.Disassembler(method).Execute(); - method.Body = tac; - - var cfanalysis = new ControlFlowAnalysis(method.Body); - var cfg = cfanalysis.GenerateExceptionalControlFlow(); + var tac = new Backend.Transformations.Disassembler(main).Execute(); + main.Body = tac; + + AddLogAtIndex(0, "entering main", main.Body); + AddLogAtIndex(tac.Instructions.Count - 1, "exiting main", main.Body); - var webAnalysis = new WebAnalysis(cfg); - webAnalysis.Analyze(); - webAnalysis.Transform(); - method.Body.UpdateVariables(); + var cfanalysis = new ControlFlowAnalysis(main.Body); + var cfg = cfanalysis.GenerateExceptionalControlFlow(); - var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); - typeInferenceAnalysis.Analyze(); - }*/ + var webAnalysis = new WebAnalysis(cfg); + webAnalysis.Analyze(); + webAnalysis.Transform(); + main.Body.UpdateVariables(); + + var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, main.ReturnType); + typeInferenceAnalysis.Analyze(); + + var bytecode = new Backend.Transformations.Assembly.Assembler(main).Execute(); + main.Body = bytecode; var generator = new MetadataGenerator.Generator(); @@ -406,9 +464,53 @@ where m.HasBody generator.Generate(assembly); } } - - static void Main(string[] args) + + private static void AddLogAtIndex(int index, string message, MethodBody body) + { + var result = new TemporalVariable("$s", 0); + var loadInstruction = new Tac.LoadInstruction(0, result, new Constant(message)) + { + Label = body.Instructions[index].Label + "º" + }; + var methodCallInstruction = new Tac.MethodCallInstruction( + 0, + null, + Tac.MethodCallOperation.Static, + ConsoleWriteLineMethodReference(), + new List {result}) + { + Label = loadInstruction.Label + "º" + }; + + var instructions = + body.Instructions.Take(index) + .Concat(new List {loadInstruction, methodCallInstruction}) + .Concat(body.Instructions.Skip(index)) + .ToList(); + + body.Instructions.Clear(); + body.Instructions.AddRange(instructions); + } + + private static MethodReference ConsoleWriteLineMethodReference() + { + var writeLineMethod = new MethodReference("WriteLine", PlatformTypes.Void) + { + Parameters = {new MethodParameter(0, "value", PlatformTypes.String)}, + IsStatic = true + }; + var consoleType = new BasicType("Console", TypeKind.ReferenceType) + { + ContainingAssembly = new AssemblyReference("mscorlib") {Version = new Version("4.0.0.0")}, + ContainingNamespace = "System" + }; + writeLineMethod.ContainingType = consoleType; + return writeLineMethod; + } + + private static void DisassembleAndThenAssemble() { + // FIXME PROBAR generar y correr tests (+pedump) CONVIRTIENDO Y SIN CONVERTIR a tac var inputs = new[] { new[] {"../../../Examples/bin/Debug/Examples.dll"}, @@ -436,13 +538,30 @@ static void Main(string[] args) } }; - foreach (var input in inputs) + foreach (var file in inputs.SelectMany(i => i)) { - foreach (var file in input) + var host = new Host(); + + PlatformTypes.Resolve(host); + + System.Console.WriteLine($"Reading {file}"); + var loader = new MetadataProvider.Loader(host); + loader.LoadAssembly(file); + + var generator = new MetadataGenerator.Generator(); + + foreach (var assembly in host.Assemblies) { - DisassembleAndThenAssemble(file); + generator.Generate(assembly); } } + } + + static void Main(string[] args) + { + //DisassembleAndThenAssemble(); + //TacInstrumentation(); + HelloWorldAssembly(); System.Console.WriteLine("Done!"); } diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 70f1c222..370076da 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1052,6 +1052,7 @@ public void Test() [Test] public void AnotherTest() { + // Console.WriteLine("begining of method"); Assert.AreEqual(1, 1); } } diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index e38129d0..c8dc390b 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -1,85 +1,10 @@ -using System; -using Classes; -using Hierarchy; -using MethodBody; -using Properties; -using Structs; - -namespace ExamplesEXE +namespace ExamplesEXE { public static class MainClass { - // IMPORTANT ExamplesEXE has Examples as reference so it's important to copy de latest Examples.dll to the Console/bin/debug directory public static void Main(string[] args) { - var methodBodyExamples = new MethodBodyExamples(); - var g = 5; - var sc = new SimpleClass(3, "a"); - - Console.WriteLine(methodBodyExamples.Arithmetics(1, 2)); - Console.WriteLine(methodBodyExamples.Compare(6, 90)); - methodBodyExamples.Branch(1, 2, new Exception()); - Console.WriteLine(methodBodyExamples.Convert(new Exception())); - methodBodyExamples.Empty(); - Console.WriteLine(methodBodyExamples.Logic(true, false)); - methodBodyExamples.Nothing2(); - Console.WriteLine(methodBodyExamples.BitwiseOperations(235)); - methodBodyExamples.HelloWorld(); - Console.WriteLine(methodBodyExamples.LoadArgument(1, "2", true, 4)); - Console.WriteLine(methodBodyExamples.LoadConstant()); - Console.WriteLine(methodBodyExamples.LoadLocal()); - methodBodyExamples.LoadPointer(); - Console.WriteLine(methodBodyExamples.ReturnsArg(10)); - Console.WriteLine(methodBodyExamples.ReturnsOne()); - Console.WriteLine(methodBodyExamples.SizeOf()); - Console.WriteLine(methodBodyExamples.StoreValue(100)); - methodBodyExamples.ExceptionHandlingTryCatchSpecific(0); - methodBodyExamples.ExceptionHandlingTryCatch(0); - methodBodyExamples.ExceptionHandlingMultipleFilter(0); - Console.WriteLine(methodBodyExamples.LoadField()); - Console.WriteLine(methodBodyExamples.StoreField()); - methodBodyExamples.Calls(sc, e => 5); - Console.WriteLine(methodBodyExamples.Nothing(new object())); - Console.WriteLine(methodBodyExamples.Alloc()); - methodBodyExamples.LoadAddress(4); - Console.WriteLine(methodBodyExamples.LoadToken()); - Console.WriteLine(sc.ReceivesArraysAndReturnsIntArray(new[] {""}, new[] {new Exception()})); - unsafe - { - Console.WriteLine(methodBodyExamples.Create()); - } - - Console.WriteLine(methodBodyExamples.Arrays(new[] {new EmptyStruct()})); - Console.WriteLine(methodBodyExamples.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); - methodBodyExamples.Calls(sc, e => 5); - - var classWithProperties = new ClassWithProperties(); - classWithProperties.IntPropertyWithBackingField = 2; - Console.WriteLine(classWithProperties.IntPropertyWithBackingField); - Console.WriteLine(classWithProperties.StringPropertyWithBackingField); - classWithProperties.DoublePropertyWithAutoImplementedGetSet = 1.4; - Console.WriteLine(classWithProperties.DoublePropertyWithAutoImplementedGetSet); - Console.WriteLine(classWithProperties.BytePropertyWithAutoImplementedGetAndDefaultValue); - Console.WriteLine(classWithProperties.ExceptionPropertyWithAutoImplementedGetSetAndDefaultValue); - classWithProperties.ExceptionPropertyWithAutoImplementedGetSetAndDefaultValue = null; - Console.WriteLine(classWithProperties.ExceptionPropertyWithAutoImplementedGetSetAndDefaultValue); - classWithProperties.DerivedClassPropertyWithAutoImplementedGetSet = new DerivedClass(); - Console.WriteLine(classWithProperties.DerivedClassPropertyWithAutoImplementedGetSet); - - var structWithProperties = new StructWithProperties(); - structWithProperties.IntPropertyWithBackingField = 2; - Console.WriteLine(structWithProperties.IntPropertyWithBackingField); - structWithProperties.DoublePropertyWithAutoImplementedGetSet = 1.4; - Console.WriteLine(structWithProperties.DoublePropertyWithAutoImplementedGetSet); - structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet = new DerivedClass(); - Console.WriteLine(structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet); - } - } - - public class MethodBodyExamples : ContainingClass - { - public override void NoBody() - { + var x = 1; } } } \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 09db17fe..0eb539a3 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -1,14 +1,7 @@ -using System.Linq; -using Backend.Analyses; -using Backend.Transformations.Assembly; -using MetadataGenerator.Generators.Methods.Body; +using MetadataGenerator.Generators.Methods.Body; using MetadataGenerator.Metadata; -using Model.Bytecode; -using Model.ThreeAddressCode.Instructions; using Model.Types; using static MetadataGenerator.Metadata.AttributesProvider; -using BranchInstruction = Model.Bytecode.BranchInstruction; -using BranchOperation = Model.Bytecode.BranchOperation; using ECMA335 = System.Reflection.Metadata.Ecma335; using SR = System.Reflection; using SRM = System.Reflection.Metadata; @@ -41,26 +34,6 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var methodBodyOffset = -1; if (method.HasBody) { - // FIXME PROBAR generar y correr tests (+pedump) CONVIRTIENDO Y SIN CONVERTIR - - // FIXME undo this. Just for testing assembler. - var tac = new Backend.Transformations.Disassembler(method).Execute(); - method.Body = tac; - - var cfanalysis = new ControlFlowAnalysis(method.Body); - var cfg = cfanalysis.GenerateExceptionalControlFlow(); - - var webAnalysis = new WebAnalysis(cfg); - webAnalysis.Analyze(); - webAnalysis.Transform(); - method.Body.UpdateVariables(); - - var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); - typeInferenceAnalysis.Analyze(); - - var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); - method.Body = bytecode; - // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated // programatically then the maxStamck is gonna be missing var maxStack = method.Body.MaxStack; From 2e52856f59a642bf9c5545f9f28d247e31f7acd6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 19 Aug 2020 08:23:14 -0300 Subject: [PATCH 218/256] optimization test --- Console/Program.cs | 67 +++++++++++++++++++++++++++++++++- ExamplesEXE/ExamplesEXE.cs | 9 +++++ ExamplesEXE/ExamplesEXE.csproj | 6 --- 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index 17c21aee..2cdcb536 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -557,11 +557,76 @@ private static void DisassembleAndThenAssemble() } } + private static void RemoveUnusedMethodFromSimpleExecutable() + { + var input = "../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"; + + var host = new Host(); + + PlatformTypes.Resolve(host); + + System.Console.WriteLine($"Reading {input}"); + var loader = new MetadataProvider.Loader(host); + loader.LoadAssembly(input); + + var allDefinedMethods = (from a in host.Assemblies + from t in a.RootNamespace.GetAllTypes() + from m in t.Members.OfType() + select m).ToList(); + + // convert bodies to typed tac + foreach (var method in allDefinedMethods) + { + var tac = new Backend.Transformations.Disassembler(method).Execute(); + method.Body = tac; + + var cfanalysis = new ControlFlowAnalysis(method.Body); + var cfg = cfanalysis.GenerateExceptionalControlFlow(); + + var webAnalysis = new WebAnalysis(cfg); + webAnalysis.Analyze(); + webAnalysis.Transform(); + method.Body.UpdateVariables(); + + var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); + typeInferenceAnalysis.Analyze(); + } + + // run call graph analysis + var classHierarchy = new ClassHierarchy(); + classHierarchy.Analyze(host); + var classHierarchyAnalysis = new ClassHierarchyAnalysis(classHierarchy); + var roots = host.GetRootMethods(); + var callGraph = classHierarchyAnalysis.Analyze(host, roots); + + // convert back to bytecode for generation + foreach (var method in allDefinedMethods) + { + var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); + method.Body = bytecode; + } + + // remove unsued method + var unusedMethod = allDefinedMethods.Except(callGraph.Methods).First(); + var type = (TypeDefinition) unusedMethod.ContainingType; + var onlyUsedMethods = type.Methods.Where(method => !method.Equals(unusedMethod)).ToList(); + type.Methods.Clear(); + type.Methods.AddRange(onlyUsedMethods); + + // generate + var generator = new MetadataGenerator.Generator(); + foreach (var assembly in host.Assemblies) + { + generator.Generate(assembly); + } + } + static void Main(string[] args) { //DisassembleAndThenAssemble(); //TacInstrumentation(); - HelloWorldAssembly(); + // HelloWorldAssembly(); + RemoveUnusedMethodFromSimpleExecutable(); System.Console.WriteLine("Done!"); } diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index c8dc390b..3db313a6 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -5,6 +5,15 @@ public static class MainClass public static void Main(string[] args) { var x = 1; + UsedMethod(); + } + + private static void UsedMethod() + { + } + + private static void UnusedMethod() + { } } } \ No newline at end of file diff --git a/ExamplesEXE/ExamplesEXE.csproj b/ExamplesEXE/ExamplesEXE.csproj index a07dfa89..cf40c7ad 100644 --- a/ExamplesEXE/ExamplesEXE.csproj +++ b/ExamplesEXE/ExamplesEXE.csproj @@ -34,11 +34,5 @@ - - - {73254DAD-0794-4BFA-A894-A24B79A006D0} - Examples - - \ No newline at end of file From 7d89e0b617739c5266fdd45d138017f906e8c7d8 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Fri, 21 Aug 2020 08:09:21 -0300 Subject: [PATCH 219/256] remove unused code --- Backend/Transformations/Assembly/Assembler.cs | 35 +------------------ 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index b8a8bc0e..098f31ee 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -48,7 +48,7 @@ public Assembler(MethodDefinition method) public MethodBody Execute() { var body = new MethodBody(MethodBodyKind.Bytecode); - body.MaxStack = 20; // FIXME calcular (ver StackSize) + body.MaxStack = 20; // FIXME calcular body.Parameters.AddRange(method.Body.Parameters); for (Index = 0; Index < method.Body.Instructions.Count; Index++) @@ -547,39 +547,6 @@ public void Visit(PopInstruction instruction) translatedInstructions.Add(basicInstruction); } - // FIXME se podria ir calculando. Pero ahi hay que ir contando segun la instruccion (si suma o vacia el stack). Es esta la mejor forma? - private class StackSize - { - private uint currentStackSize; - public uint MaxStackSize { get; private set; } - - public StackSize() - { - currentStackSize = 0; - MaxStackSize = 0; - } - - public void Increment() - { - currentStackSize += 1; - if (currentStackSize > MaxStackSize) - { - MaxStackSize = currentStackSize; - } - } - - public void Decrement() - { - if (currentStackSize == 0) throw new Exception("Current stack size is 0"); - currentStackSize -= 1; - } - - public void Clear() - { - currentStackSize = 0; - } - } - private class CaseNotHandledException : Exception { } From bb4ab8857dbd73ffb06e46b67611e4a1d3c75bd6 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 22 Aug 2020 15:47:57 -0300 Subject: [PATCH 220/256] draft --- .../Methods/Body/MethodBodyGenerator.cs | 220 ++++++++++++++---- .../Generators/Methods/MethodGenerator.cs | 6 +- 2 files changed, 183 insertions(+), 43 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 4b46857d..1123a2cf 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using MetadataGenerator.Metadata; using Model; using Model.Bytecode; @@ -19,6 +20,7 @@ internal class MethodBodyGenerator : IInstructionVisitor private readonly List switchInstructionsPlaceHolders; private readonly ISet ignoredInstructions; private readonly MethodBody body; + private readonly StackSize stackSize; private int Index { get; set; } public MethodBodyGenerator(MetadataContainer metadataContainer, MethodBody body) @@ -29,9 +31,10 @@ public MethodBodyGenerator(MetadataContainer metadataContainer, MethodBody body) controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); switchInstructionsPlaceHolders = new List(); ignoredInstructions = new HashSet(); + stackSize = new StackSize(); } - public ECMA335.InstructionEncoder Generate() + public ECMA335.InstructionEncoder Generate(out int maxStack) { controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); controlFlowGenerator.DefineNeededBranchLabels(body.Instructions); @@ -43,6 +46,23 @@ public ECMA335.InstructionEncoder Generate() labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); + if (body.ExceptionInformation.Any(block => + { + switch (block.Handler) + { + case FilterExceptionHandler filterExceptionHandler: + return filterExceptionHandler.FilterStart.Equals(instruction.Label) || + filterExceptionHandler.Start.Equals(instruction.Label); + case CatchExceptionHandler catchExceptionHandler: + return catchExceptionHandler.Start.Equals(instruction.Label); + default: + return false; + } + })) + { + stackSize.Increment(); + } + if (!ignoredInstructions.Contains(Index)) { instruction.Accept(this); @@ -54,6 +74,8 @@ public ECMA335.InstructionEncoder Generate() switchInstructionPlaceholder.FillWithRealTargets(labelToEncoderOffset); } + // FIXME revienta + maxStack = stackSize.MaxStackSize; return instructionEncoder; } @@ -69,6 +91,7 @@ public void Visit(InitObjInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Initobj); instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Type)); + stackSize.Decrement(); } public void Visit(BasicInstruction instruction) @@ -88,6 +111,8 @@ public void Visit(BasicInstruction instruction) instructionEncoder.OpCode(SRM.ILOpCode.Add); } + stackSize.Decrement(); + break; case BasicOperation.Sub: if (instruction.OverflowCheck) @@ -99,6 +124,7 @@ public void Visit(BasicInstruction instruction) instructionEncoder.OpCode(SRM.ILOpCode.Sub); } + stackSize.Decrement(); break; case BasicOperation.Mul: if (instruction.OverflowCheck) @@ -110,42 +136,55 @@ public void Visit(BasicInstruction instruction) instructionEncoder.OpCode(SRM.ILOpCode.Mul); } + stackSize.Decrement(); break; case BasicOperation.Div: instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Div_un : SRM.ILOpCode.Div); + stackSize.Decrement(); break; case BasicOperation.Rem: instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Rem_un : SRM.ILOpCode.Rem); + stackSize.Decrement(); break; case BasicOperation.And: instructionEncoder.OpCode(SRM.ILOpCode.And); + stackSize.Decrement(); break; case BasicOperation.Or: instructionEncoder.OpCode(SRM.ILOpCode.Or); + stackSize.Decrement(); break; case BasicOperation.Xor: instructionEncoder.OpCode(SRM.ILOpCode.Xor); + stackSize.Decrement(); break; case BasicOperation.Shl: instructionEncoder.OpCode(SRM.ILOpCode.Shl); + stackSize.Decrement(); break; case BasicOperation.Shr: instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Shr_un : SRM.ILOpCode.Shr); + stackSize.Decrement(); break; case BasicOperation.Eq: instructionEncoder.OpCode(SRM.ILOpCode.Ceq); + stackSize.Decrement(); break; case BasicOperation.Lt: instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Clt_un : SRM.ILOpCode.Clt); + stackSize.Decrement(); break; case BasicOperation.Gt: instructionEncoder.OpCode(instruction.UnsignedOperands ? SRM.ILOpCode.Cgt_un : SRM.ILOpCode.Cgt); + stackSize.Decrement(); break; case BasicOperation.Throw: instructionEncoder.OpCode(SRM.ILOpCode.Throw); + stackSize.Clear(); break; case BasicOperation.Rethrow: instructionEncoder.OpCode(SRM.ILOpCode.Rethrow); + stackSize.Clear(); break; case BasicOperation.Not: instructionEncoder.OpCode(SRM.ILOpCode.Not); @@ -155,24 +194,30 @@ public void Visit(BasicInstruction instruction) break; case BasicOperation.Pop: instructionEncoder.OpCode(SRM.ILOpCode.Pop); + stackSize.Decrement(); break; case BasicOperation.Dup: instructionEncoder.OpCode(SRM.ILOpCode.Dup); + stackSize.Increment(); break; case BasicOperation.EndFinally: instructionEncoder.OpCode(SRM.ILOpCode.Endfinally); + stackSize.Clear(); break; case BasicOperation.EndFilter: instructionEncoder.OpCode(SRM.ILOpCode.Endfilter); + stackSize.Clear(); break; case BasicOperation.LocalAllocation: instructionEncoder.OpCode(SRM.ILOpCode.Localloc); break; case BasicOperation.InitBlock: instructionEncoder.OpCode(SRM.ILOpCode.Initblk); + stackSize.Decrement(3); break; case BasicOperation.CopyBlock: instructionEncoder.OpCode(SRM.ILOpCode.Cpblk); + stackSize.Decrement(3); break; case BasicOperation.LoadArrayLength: instructionEncoder.OpCode(SRM.ILOpCode.Ldlen); @@ -212,6 +257,8 @@ public void Visit(LoadInstruction instruction) instructionEncoder.LoadLocalAddress(index); } + stackSize.Increment(); + break; } case LoadOperation.Content: @@ -228,6 +275,8 @@ public void Visit(LoadInstruction instruction) instructionEncoder.LoadLocal(index); } + stackSize.Increment(); + break; } case LoadOperation.Value: @@ -236,6 +285,7 @@ public void Visit(LoadInstruction instruction) { case null: instructionEncoder.OpCode(SRM.ILOpCode.Ldnull); + stackSize.Increment(); if ( body.Instructions.Count > Index + 2 && @@ -246,6 +296,7 @@ public void Visit(LoadInstruction instruction) // cgt_un is used as a compare-not-equal with null. // load null - compare eq - negate => ldnull - cgt_un instructionEncoder.OpCode(SRM.ILOpCode.Cgt_un); + stackSize.Decrement(); // skip processing next 2 instructions ignoredInstructions.Add(Index + 1); @@ -255,21 +306,27 @@ public void Visit(LoadInstruction instruction) break; case string value: instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); + stackSize.Increment(); break; case int value: instructionEncoder.LoadConstantI4(value); + stackSize.Increment(); break; case long value: instructionEncoder.LoadConstantI8(value); + stackSize.Increment(); break; case float value: instructionEncoder.LoadConstantR4(value); + stackSize.Increment(); break; case double value: instructionEncoder.LoadConstantR8(value); + stackSize.Increment(); break; case bool value: instructionEncoder.LoadConstantI4(value ? 1 : 0); + stackSize.Increment(); break; default: throw new UnhandledCase(); @@ -337,25 +394,35 @@ public void Visit(LoadIndirectInstruction instruction) public void Visit(LoadFieldInstruction instruction) { + var isStatic = instruction.Field.IsStatic; switch (instruction.Operation) { case LoadFieldOperation.Content: - instructionEncoder.OpCode(instruction.Field.IsStatic ? SRM.ILOpCode.Ldsfld : SRM.ILOpCode.Ldfld); + instructionEncoder.OpCode(isStatic ? SRM.ILOpCode.Ldsfld : SRM.ILOpCode.Ldfld); break; case LoadFieldOperation.Address: - instructionEncoder.OpCode(instruction.Field.IsStatic ? SRM.ILOpCode.Ldsflda : SRM.ILOpCode.Ldflda); + instructionEncoder.OpCode(isStatic ? SRM.ILOpCode.Ldsflda : SRM.ILOpCode.Ldflda); break; default: throw new UnhandledCase(); } instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Field)); + if (isStatic) + { + stackSize.Increment(); + } } public void Visit(LoadMethodAddressInstruction instruction) { - instructionEncoder.OpCode(instruction.Method.IsVirtual ? SRM.ILOpCode.Ldvirtftn : SRM.ILOpCode.Ldftn); + var isVirtual = instruction.Method.IsVirtual; + instructionEncoder.OpCode(isVirtual ? SRM.ILOpCode.Ldvirtftn : SRM.ILOpCode.Ldftn); instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + if (!isVirtual) + { + stackSize.Increment(); + } } public void Visit(StoreIndirectInstruction instruction) @@ -397,6 +464,8 @@ public void Visit(StoreIndirectInstruction instruction) instructionEncoder.OpCode(SRM.ILOpCode.Stobj); instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Type)); } + + stackSize.Decrement(2); } public void Visit(StoreInstruction instruction) @@ -412,12 +481,16 @@ public void Visit(StoreInstruction instruction) var index = body.LocalVariables.IndexOf(target); instructionEncoder.StoreLocal(index); } + + stackSize.Decrement(); } public void Visit(StoreFieldInstruction instruction) { - instructionEncoder.OpCode(instruction.Field.IsStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); + var isStatic = instruction.Field.IsStatic; + instructionEncoder.OpCode(isStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Field)); + stackSize.Decrement(isStatic ? 1 : 2); } public void Visit(ConvertInstruction instruction) @@ -609,27 +682,34 @@ public void Visit(BranchInstruction instruction) break; case BranchOperation.Eq: opCode = SRM.ILOpCode.Beq; + stackSize.Decrement(2); break; case BranchOperation.Neq: opCode = SRM.ILOpCode.Bne_un; + stackSize.Decrement(2); break; case BranchOperation.Lt: opCode = instruction.UnsignedOperands ? SRM.ILOpCode.Blt_un : SRM.ILOpCode.Blt; + stackSize.Decrement(2); break; case BranchOperation.Le: opCode = instruction.UnsignedOperands ? SRM.ILOpCode.Ble_un : SRM.ILOpCode.Ble; + stackSize.Decrement(2); break; case BranchOperation.Gt: opCode = instruction.UnsignedOperands ? SRM.ILOpCode.Bgt_un : SRM.ILOpCode.Bgt; + stackSize.Decrement(2); break; case BranchOperation.Ge: opCode = instruction.UnsignedOperands ? SRM.ILOpCode.Bge_un : SRM.ILOpCode.Bge; + stackSize.Decrement(2); break; case BranchOperation.Branch: opCode = SRM.ILOpCode.Br; break; case BranchOperation.Leave: opCode = SRM.ILOpCode.Leave; + stackSize.Clear(); break; default: throw new UnhandledCase(); @@ -653,18 +733,21 @@ public void Visit(SwitchInstruction instruction) targetsReserveBytes, instruction.Targets); switchInstructionsPlaceHolders.Add(switchInstructionPlaceholder); + stackSize.Decrement(); } public void Visit(SizeofInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.MeasuredType)); + stackSize.Increment(); } public void Visit(LoadTokenInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Token)); + stackSize.Increment(); } public void Visit(MethodCallInstruction instruction) @@ -673,20 +756,32 @@ public void Visit(MethodCallInstruction instruction) { case MethodCallOperation.Virtual: instructionEncoder.CallVirtual(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + stackSize.Decrement(instruction.Method.Parameters.Count + 1); break; case MethodCallOperation.Static: case MethodCallOperation.Jump: instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + stackSize.Decrement(instruction.Method.Parameters.Count); break; default: throw new UnhandledCase(); } + + if (!instruction.Method.ReturnType.Equals(PlatformTypes.Void)) + { + stackSize.Increment(); + } } public void Visit(IndirectMethodCallInstruction instruction) { var methodSignature = metadataContainer.MetadataResolver.HandleOf(instruction.Function); instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); + stackSize.Decrement(instruction.Function.Parameters.Count + 1); + if (!instruction.Function.ReturnType.Equals(PlatformTypes.Void)) + { + stackSize.Increment(); + } } public void Visit(CreateObjectInstruction instruction) @@ -694,6 +789,8 @@ public void Visit(CreateObjectInstruction instruction) var method = metadataContainer.MetadataResolver.HandleOf(instruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); + stackSize.Decrement(instruction.Constructor.Parameters.Count); + stackSize.Increment(); } public void Visit(CreateArrayInstruction instruction) @@ -708,6 +805,8 @@ public void Visit(CreateArrayInstruction instruction) var method = metadataContainer.MetadataResolver.HandleOf(instruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); + stackSize.Decrement(instruction.Constructor.Parameters.Count); + stackSize.Increment(); } } @@ -716,6 +815,8 @@ public void Visit(LoadArrayElementInstruction instruction) if (instruction.Method != null) { instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + stackSize.Decrement(instruction.Method.Parameters.Count); + stackSize.Increment(); // FIXME creo que esto es porque en este caso se usa un metodo Get(); } else { @@ -784,6 +885,8 @@ public void Visit(LoadArrayElementInstruction instruction) default: throw new UnhandledCase(); } + + stackSize.Decrement(); } } @@ -792,43 +895,50 @@ public void Visit(StoreArrayElementInstruction instruction) if (instruction.Method != null) { instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); - } - else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int8)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i1); - } - else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int16)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i2); - } - else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i4); - } - else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int64)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i8); - } - else if (instruction.Array.ElementsType.Equals(PlatformTypes.Float32)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_r4); - } - else if (instruction.Array.ElementsType.Equals(PlatformTypes.Float64)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_r8); - } - else if (instruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i); - } - else if (instruction.Array.ElementsType.Equals(PlatformTypes.Object)) - { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem_ref); + stackSize.Decrement(instruction.Method.Parameters.Count); + // FIXME y aca no iria increment porque es un Set() } else { - instructionEncoder.OpCode(SRM.ILOpCode.Stelem); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Array.ElementsType)); + if (instruction.Array.ElementsType.Equals(PlatformTypes.Int8)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i1); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int16)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i2); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i4); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Int64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i8); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Float32)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_r4); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Float64)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_r8); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.IntPtr)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_i); + } + else if (instruction.Array.ElementsType.Equals(PlatformTypes.Object)) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem_ref); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Stelem); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Array.ElementsType)); + } + + stackSize.Decrement(3); } } @@ -857,6 +967,38 @@ public void FillWithRealTargets(IDictionary labelToEncoderOffset) } } } + + private class StackSize + { + private int currentStackSize; + public int MaxStackSize { get; private set; } + + public StackSize() + { + currentStackSize = 0; + MaxStackSize = 0; + } + + public void Increment() + { + currentStackSize += 1; + if (currentStackSize > MaxStackSize) + { + MaxStackSize = currentStackSize; + } + } + + public void Decrement(int times = 1) + { + if (currentStackSize < times) throw new Exception("Stack size cannot be less than 0"); + currentStackSize -= times; + } + + public void Clear() + { + currentStackSize = 0; + } + } } internal class UnhandledCase : Exception diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index c87faf90..db70eb4a 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -34,11 +34,9 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var methodBodyOffset = -1; if (method.HasBody) { - // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated - // programatically then the maxStack is gonna be missing - var maxStack = method.Body.MaxStack; + var instructionEncoder = new MethodBodyGenerator(metadataContainer, method.Body).Generate(out var maxStack); methodBodyOffset = metadataContainer.MethodBodyStream.AddMethodBody( - instructionEncoder: new MethodBodyGenerator(metadataContainer, method.Body).Generate(), + instructionEncoder: instructionEncoder, localVariablesSignature: methodLocalsSignatureGenerator.GenerateSignatureFor(method.Body.LocalVariables), maxStack: maxStack); } From 532fe457db5d3fb757bf7a0fbc50ded372b8bad0 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 22 Aug 2020 15:53:09 -0300 Subject: [PATCH 221/256] comment --- .../Generators/Methods/Body/MethodBodyGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 1123a2cf..9179cd38 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -46,7 +46,7 @@ public ECMA335.InstructionEncoder Generate(out int maxStack) labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); - if (body.ExceptionInformation.Any(block => + if (body.ExceptionInformation.Any(block => // FIXME metodo aparte { switch (block.Handler) { From c87bcfd9585618bf06b00626877bc1d9a12385a5 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 22 Aug 2020 16:40:47 -0300 Subject: [PATCH 222/256] remove proxy and unused code --- .../Generators/Methods/MethodGenerator.cs | 2 +- MetadataProvider/AssemblyExtractor.cs | 29 +------------------ Model/Extensions.cs | 17 ----------- Model/ThreeAddressCode/Instructions.cs | 1 - Model/Types/Types.cs | 1 - 5 files changed, 2 insertions(+), 48 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 0eb539a3..c87faf90 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -35,7 +35,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) if (method.HasBody) { // FIXME maxStack should be computed from instructions. When a dll is read, the maxStack will be available (Model) but if code is generated - // programatically then the maxStamck is gonna be missing + // programatically then the maxStack is gonna be missing var maxStack = method.Body.MaxStack; methodBodyOffset = metadataContainer.MethodBodyStream.AddMethodBody( instructionEncoder: new MethodBodyGenerator(metadataContainer, method.Body).Generate(), diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index e7c73c07..d4e104f5 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1375,38 +1375,11 @@ private IMethodReference GetMethodReference(SRM.MethodSpecificationHandle handle CreateGenericParameterReferences(GenericParameterKind.Method, genericArguments.Length); var method = GetMethodReference(methodspec.Method); - method = new MethodInstantiationProxy(method, genericArguments); + method = method.Instantiate(genericArguments); BindGenericParameterReferences(GenericParameterKind.Method, method); return method; } - - // TODO make copies of collections - private class MethodInstantiationProxy : IMethodReference - { - public IBasicType ContainingType => method.ContainingType; - public ISet Attributes => method.Attributes; - public int GenericParameterCount => method.GenericParameterCount; - public IType ReturnType => method.ReturnType; - public string Name => method.Name; - public string GenericName => method.GenericName; - public IList Parameters => method.Parameters; - public IList GenericArguments => genericArguments; - public IMethodReference GenericMethod => method; - public MethodDefinition ResolvedMethod => throw new NotImplementedException(); - public bool IsStatic => method.IsStatic; - public bool IsVirtual => method.IsVirtual; - - private readonly IMethodReference method; - private readonly IList genericArguments; - - public MethodInstantiationProxy(IMethodReference method, IEnumerable genericArguments) - { - this.method = method; - this.genericArguments = new List(); - this.genericArguments.AddRange(genericArguments); - } - } private IMethodReference GetMethodReference(SRM.EntityHandle handle) { diff --git a/Model/Extensions.cs b/Model/Extensions.cs index 4dad3866..50475a80 100644 --- a/Model/Extensions.cs +++ b/Model/Extensions.cs @@ -570,22 +570,5 @@ public static TypeKind ToTypeKind(this TypeDefinitionKind kind) default: throw kind.ToUnknownValueException(); } } - - public static bool IsIntType(this IType type) => - new[] - { - PlatformTypes.Int8, - PlatformTypes.UInt8, - PlatformTypes.Int16, - PlatformTypes.UInt16, - PlatformTypes.Int32, - PlatformTypes.UInt32, - PlatformTypes.Int64, - PlatformTypes.UInt64 - }.Contains(type); - - public static bool IsFloatType(this IType type) => new[] {PlatformTypes.Float32, PlatformTypes.Float64}.Contains(type); - - public static bool IsOneOf(this IType type, params IType[] types) => types.Contains(type); } } diff --git a/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index 39c1d6d7..138cfdd0 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -72,7 +72,6 @@ public enum MethodCallOperation Jump } - // FIXME names public enum FilterInstructionKind { FilterSection, diff --git a/Model/Types/Types.cs b/Model/Types/Types.cs index f1bb4fde..2279fd08 100644 --- a/Model/Types/Types.cs +++ b/Model/Types/Types.cs @@ -75,7 +75,6 @@ public static class PlatformTypes public static readonly BasicType PureAttribute = New("mscorlib", "System.Diagnostics.Contracts", "PureAttribute", TypeKind.ReferenceType); public static readonly BasicType ICollection = New("mscorlib", "System.Collections", "ICollection", TypeKind.ReferenceType); - public static readonly BasicType List = New("mscorlib", "System.Collections.Generic", "List", TypeKind.ReferenceType); public static readonly BasicType IEnumerable = New("mscorlib", "System.Collections", "IEnumerable", TypeKind.ReferenceType); public static readonly BasicType IEnumerator = New("mscorlib", "System.Collections", "IEnumerator", TypeKind.ReferenceType); public static readonly BasicType GenericICollection = New("mscorlib", "System.Collections.Generic", "ICollection", TypeKind.ReferenceType, 1); From 5c27c62d3c10b014a5bc371e503eb8803c7081c4 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 22 Aug 2020 17:07:26 -0300 Subject: [PATCH 223/256] fix method instantiation problem --- MetadataProvider/AssemblyExtractor.cs | 5 ++++- Model/Types/TypeDefinitions.cs | 29 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index f058f90f..ae625ebf 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1307,7 +1307,10 @@ private IMethodReference GetMethodReference(SRM.MethodSpecificationHandle handle CreateGenericParameterReferences(GenericParameterKind.Method, genericArguments.Length); var method = GetMethodReference(methodspec.Method); - method = method.Instantiate(genericArguments); + // method might have not been extracted yet so some properties might be missing (ex: returnType, isStatic, etc). + // a proxy is used instead so when the method is actually extracted, this instantiated one is also complete. Otherwise the instantiated + // one will have null in some of its properties. + method = new MethodInstantiationProxy(method, genericArguments); BindGenericParameterReferences(GenericParameterKind.Method, method); return method; diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 752a3540..e17d7a7e 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -587,6 +587,35 @@ public override string ToString() return result.ToString(); } } + + public class MethodInstantiationProxy : IMethodReference + { + public IBasicType ContainingType => method.ContainingType; + public ISet Attributes => method.Attributes; + public int GenericParameterCount => method.GenericParameterCount; + public IType ReturnType => method.ReturnType; + public string Name => method.Name; + public string GenericName => method.GenericName; + public IList Parameters => method.Parameters; + public IList GenericArguments => genericArguments; + public IMethodReference GenericMethod => method; + + public MethodDefinition ResolvedMethod => + throw new InvalidOperationException("Use Resolve method to bind this reference with some host."); + + public bool IsStatic => method.IsStatic; + public bool IsVirtual => method.IsVirtual; + + private readonly IMethodReference method; + private readonly IList genericArguments; + + public MethodInstantiationProxy(IMethodReference method, IEnumerable genericArguments) + { + this.method = method; + this.genericArguments = new List(); + this.genericArguments.AddRange(genericArguments); + } + } public enum TypeDefinitionKind { From 29a56ee90f5634e824e365f49e3d2c2c39f685cf Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 22 Aug 2020 17:28:38 -0300 Subject: [PATCH 224/256] comment --- MetadataProvider/AssemblyExtractor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index ae625ebf..9a500c8c 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -1307,9 +1307,9 @@ private IMethodReference GetMethodReference(SRM.MethodSpecificationHandle handle CreateGenericParameterReferences(GenericParameterKind.Method, genericArguments.Length); var method = GetMethodReference(methodspec.Method); - // method might have not been extracted yet so some properties might be missing (ex: returnType, isStatic, etc). - // a proxy is used instead so when the method is actually extracted, this instantiated one is also complete. Otherwise the instantiated - // one will have null in some of its properties. + // method might have not been extracted yet so some fields might be missing (ex: returnType, isStatic, etc). + // a proxy is used instead so when the method is actually extracted, this instantiated one is updated as well. + // Otherwise the instantiated one would have some null fields. method = new MethodInstantiationProxy(method, genericArguments); BindGenericParameterReferences(GenericParameterKind.Method, method); From 3eb80d9561b9d4fb504a154409845f3e59d143bf Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 22 Aug 2020 18:02:41 -0300 Subject: [PATCH 225/256] fix --- .../Methods/Body/MethodBodyGenerator.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index 9179cd38..f448ce3f 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -46,19 +46,7 @@ public ECMA335.InstructionEncoder Generate(out int maxStack) labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); - if (body.ExceptionInformation.Any(block => // FIXME metodo aparte - { - switch (block.Handler) - { - case FilterExceptionHandler filterExceptionHandler: - return filterExceptionHandler.FilterStart.Equals(instruction.Label) || - filterExceptionHandler.Start.Equals(instruction.Label); - case CatchExceptionHandler catchExceptionHandler: - return catchExceptionHandler.Start.Equals(instruction.Label); - default: - return false; - } - })) + if (ExceptionHandlerStartsAt(instruction.Label)) { stackSize.Increment(); } @@ -74,7 +62,6 @@ public ECMA335.InstructionEncoder Generate(out int maxStack) switchInstructionPlaceholder.FillWithRealTargets(labelToEncoderOffset); } - // FIXME revienta maxStack = stackSize.MaxStackSize; return instructionEncoder; } @@ -942,6 +929,19 @@ public void Visit(StoreArrayElementInstruction instruction) } } + private bool ExceptionHandlerStartsAt(string label) => body.ExceptionInformation.Any(block => + { + switch (block.Handler) + { + case FilterExceptionHandler filterExceptionHandler: + return filterExceptionHandler.FilterStart.Equals(label) || filterExceptionHandler.Start.Equals(label); + case CatchExceptionHandler catchExceptionHandler: + return catchExceptionHandler.Start.Equals(label); + default: + return false; + } + }); + private class SwitchInstructionPlaceholder { private readonly int nextInstructionEncoderOffset; From b597c47433cc3fc0593c51fa276574556a3a2a43 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 22 Aug 2020 18:08:08 -0300 Subject: [PATCH 226/256] comments and rename --- .../Generators/Methods/Body/MethodBodyGenerator.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index f448ce3f..e98320e3 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -46,7 +46,7 @@ public ECMA335.InstructionEncoder Generate(out int maxStack) labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); - if (ExceptionHandlerStartsAt(instruction.Label)) + if (FilterOrCatchStartAt(instruction.Label)) { stackSize.Increment(); } @@ -803,7 +803,7 @@ public void Visit(LoadArrayElementInstruction instruction) { instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); - stackSize.Increment(); // FIXME creo que esto es porque en este caso se usa un metodo Get(); + stackSize.Increment(); } else { @@ -883,7 +883,6 @@ public void Visit(StoreArrayElementInstruction instruction) { instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); - // FIXME y aca no iria increment porque es un Set() } else { @@ -929,7 +928,7 @@ public void Visit(StoreArrayElementInstruction instruction) } } - private bool ExceptionHandlerStartsAt(string label) => body.ExceptionInformation.Any(block => + private bool FilterOrCatchStartAt(string label) => body.ExceptionInformation.Any(block => { switch (block.Handler) { From bddf7e2c5f4713d97f06a0562303e153b9cf7b5e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Aug 2020 15:15:56 -0300 Subject: [PATCH 227/256] remove comment --- Examples/Examples.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Examples/Examples.cs b/Examples/Examples.cs index 370076da..70f1c222 100644 --- a/Examples/Examples.cs +++ b/Examples/Examples.cs @@ -1052,7 +1052,6 @@ public void Test() [Test] public void AnotherTest() { - // Console.WriteLine("begining of method"); Assert.AreEqual(1, 1); } } From 65e8cf182d275711a059339be4166887b6f9f81f Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Aug 2020 15:18:12 -0300 Subject: [PATCH 228/256] simplify examplesExe --- ExamplesEXE/ExamplesEXE.cs | 80 +++------------------------------- ExamplesEXE/ExamplesEXE.csproj | 6 --- 2 files changed, 7 insertions(+), 79 deletions(-) diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index e38129d0..3db313a6 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -1,84 +1,18 @@ -using System; -using Classes; -using Hierarchy; -using MethodBody; -using Properties; -using Structs; - -namespace ExamplesEXE +namespace ExamplesEXE { public static class MainClass { - // IMPORTANT ExamplesEXE has Examples as reference so it's important to copy de latest Examples.dll to the Console/bin/debug directory public static void Main(string[] args) { - var methodBodyExamples = new MethodBodyExamples(); - var g = 5; - var sc = new SimpleClass(3, "a"); - - Console.WriteLine(methodBodyExamples.Arithmetics(1, 2)); - Console.WriteLine(methodBodyExamples.Compare(6, 90)); - methodBodyExamples.Branch(1, 2, new Exception()); - Console.WriteLine(methodBodyExamples.Convert(new Exception())); - methodBodyExamples.Empty(); - Console.WriteLine(methodBodyExamples.Logic(true, false)); - methodBodyExamples.Nothing2(); - Console.WriteLine(methodBodyExamples.BitwiseOperations(235)); - methodBodyExamples.HelloWorld(); - Console.WriteLine(methodBodyExamples.LoadArgument(1, "2", true, 4)); - Console.WriteLine(methodBodyExamples.LoadConstant()); - Console.WriteLine(methodBodyExamples.LoadLocal()); - methodBodyExamples.LoadPointer(); - Console.WriteLine(methodBodyExamples.ReturnsArg(10)); - Console.WriteLine(methodBodyExamples.ReturnsOne()); - Console.WriteLine(methodBodyExamples.SizeOf()); - Console.WriteLine(methodBodyExamples.StoreValue(100)); - methodBodyExamples.ExceptionHandlingTryCatchSpecific(0); - methodBodyExamples.ExceptionHandlingTryCatch(0); - methodBodyExamples.ExceptionHandlingMultipleFilter(0); - Console.WriteLine(methodBodyExamples.LoadField()); - Console.WriteLine(methodBodyExamples.StoreField()); - methodBodyExamples.Calls(sc, e => 5); - Console.WriteLine(methodBodyExamples.Nothing(new object())); - Console.WriteLine(methodBodyExamples.Alloc()); - methodBodyExamples.LoadAddress(4); - Console.WriteLine(methodBodyExamples.LoadToken()); - Console.WriteLine(sc.ReceivesArraysAndReturnsIntArray(new[] {""}, new[] {new Exception()})); - unsafe - { - Console.WriteLine(methodBodyExamples.Create()); - } - - Console.WriteLine(methodBodyExamples.Arrays(new[] {new EmptyStruct()})); - Console.WriteLine(methodBodyExamples.LoadArray(new[] {new Exception("m1"), new Exception("m2")}, new int[5])); - methodBodyExamples.Calls(sc, e => 5); - - var classWithProperties = new ClassWithProperties(); - classWithProperties.IntPropertyWithBackingField = 2; - Console.WriteLine(classWithProperties.IntPropertyWithBackingField); - Console.WriteLine(classWithProperties.StringPropertyWithBackingField); - classWithProperties.DoublePropertyWithAutoImplementedGetSet = 1.4; - Console.WriteLine(classWithProperties.DoublePropertyWithAutoImplementedGetSet); - Console.WriteLine(classWithProperties.BytePropertyWithAutoImplementedGetAndDefaultValue); - Console.WriteLine(classWithProperties.ExceptionPropertyWithAutoImplementedGetSetAndDefaultValue); - classWithProperties.ExceptionPropertyWithAutoImplementedGetSetAndDefaultValue = null; - Console.WriteLine(classWithProperties.ExceptionPropertyWithAutoImplementedGetSetAndDefaultValue); - classWithProperties.DerivedClassPropertyWithAutoImplementedGetSet = new DerivedClass(); - Console.WriteLine(classWithProperties.DerivedClassPropertyWithAutoImplementedGetSet); + var x = 1; + UsedMethod(); + } - var structWithProperties = new StructWithProperties(); - structWithProperties.IntPropertyWithBackingField = 2; - Console.WriteLine(structWithProperties.IntPropertyWithBackingField); - structWithProperties.DoublePropertyWithAutoImplementedGetSet = 1.4; - Console.WriteLine(structWithProperties.DoublePropertyWithAutoImplementedGetSet); - structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet = new DerivedClass(); - Console.WriteLine(structWithProperties.DerivedClassPropertyWithAutoImplementedGetSet); + private static void UsedMethod() + { } - } - public class MethodBodyExamples : ContainingClass - { - public override void NoBody() + private static void UnusedMethod() { } } diff --git a/ExamplesEXE/ExamplesEXE.csproj b/ExamplesEXE/ExamplesEXE.csproj index a07dfa89..cf40c7ad 100644 --- a/ExamplesEXE/ExamplesEXE.csproj +++ b/ExamplesEXE/ExamplesEXE.csproj @@ -34,11 +34,5 @@ - - - {73254DAD-0794-4BFA-A894-A24B79A006D0} - Examples - - \ No newline at end of file From d78121f5592cda8a5e105c8bd066d0a43f85c843 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Aug 2020 15:21:17 -0300 Subject: [PATCH 229/256] remove unnecesary dependency --- MetadataGenerator/MetadataGenerator.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 8c8c0f41..b0f0c9ff 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -46,10 +46,6 @@ - - {45c7b613-e32d-43e8-8030-932d509602eb} - Backend - {F08216AD-E55C-44B1-A253-AB8B024B7597} Model From 116e3dcec75fa1793f804df717e7e63e65f87aeb Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Aug 2020 15:57:40 -0300 Subject: [PATCH 230/256] add some constructor overloads needed for tac to bytecode translation --- Model/Bytecode/Instructions.cs | 14 ++++++++-- Model/ExceptionHandlers.cs | 51 ++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index bb12534e..06230d5d 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -199,9 +199,14 @@ public class BranchInstruction : Instruction public bool UnsignedOperands { get; set; } public BranchInstruction(uint label, BranchOperation operation, uint target) + : this(label, operation, $"L_{target:X4}") + { + } + + public BranchInstruction(uint label, BranchOperation operation, string target) : base(label) { - this.Target = string.Format("L_{0:X4}", target); + this.Target = target; this.Operation = operation; } @@ -222,9 +227,14 @@ public class SwitchInstruction : Instruction public IList Targets { get; private set; } public SwitchInstruction(uint label, IEnumerable targets) + : this(label, targets.Select(target => $"L_{target:X4}").ToList()) + { + } + + public SwitchInstruction(uint label, IEnumerable targets) : base(label) { - this.Targets = targets.Select(target => string.Format("L_{0:X4}", target)).ToList(); + this.Targets = targets.ToList(); } public override void Accept(IInstructionVisitor visitor) diff --git a/Model/ExceptionHandlers.cs b/Model/ExceptionHandlers.cs index c7b4be2d..0658a2f9 100644 --- a/Model/ExceptionHandlers.cs +++ b/Model/ExceptionHandlers.cs @@ -35,11 +35,15 @@ public class ProtectedBlock : IExceptionHandlerBlock public string End { get; set; } public IExceptionHandler Handler { get; set; } - public ProtectedBlock(uint start, uint end) + public ProtectedBlock(uint start, uint end) : this($"L_{start:X4}", $"L_{end:X4}") + { + } + + public ProtectedBlock(string start, string end) { this.Kind = ExceptionHandlerBlockKind.Try; - this.Start = string.Format("L_{0:X4}", start); - this.End = string.Format("L_{0:X4}", end); + this.Start = start; + this.End = end; } public override string ToString() @@ -57,11 +61,16 @@ public class FilterExceptionHandler : IExceptionHandler public IType ExceptionType { get; set; } public FilterExceptionHandler(uint filterStart, uint start, uint end, IType exceptionType) + : this($"L_{filterStart:X4}", $"L_{start:X4}", $"L_{end:X4}", exceptionType) + { + } + + public FilterExceptionHandler(string filterStart, string start, string end, IType exceptionType) { this.Kind = ExceptionHandlerBlockKind.Filter; - this.FilterStart = string.Format("L_{0:X4}", filterStart); - this.Start = string.Format("L_{0:X4}", start); - this.End = string.Format("L_{0:X4}", end); + this.FilterStart = filterStart; + this.Start = start; + this.End = end; this.ExceptionType = exceptionType; } @@ -78,11 +87,15 @@ public class CatchExceptionHandler : IExceptionHandler public string End { get; set; } public IType ExceptionType { get; set; } - public CatchExceptionHandler(uint start, uint end, IType exceptionType) + public CatchExceptionHandler(uint start, uint end, IType exceptionType) : this($"L_{start:X4}", $"L_{end:X4}", exceptionType) + { + } + + public CatchExceptionHandler(string start, string end, IType exceptionType) { this.Kind = ExceptionHandlerBlockKind.Catch; - this.Start = string.Format("L_{0:X4}", start); - this.End = string.Format("L_{0:X4}", end); + this.Start = start; + this.End = end; this.ExceptionType = exceptionType; } @@ -98,11 +111,15 @@ public class FaultExceptionHandler : IExceptionHandler public string Start { get; set; } public string End { get; set; } - public FaultExceptionHandler(uint start, uint end) + public FaultExceptionHandler(uint start, uint end) : this($"L_{start:X4}", $"L_{end:X4}") + { + } + + public FaultExceptionHandler(string start, string end) { this.Kind = ExceptionHandlerBlockKind.Fault; - this.Start = string.Format("L_{0:X4}", start); - this.End = string.Format("L_{0:X4}", end); + this.Start = start; + this.End = end; } public override string ToString() @@ -117,11 +134,15 @@ public class FinallyExceptionHandler : IExceptionHandler public string Start { get; set; } public string End { get; set; } - public FinallyExceptionHandler(uint start, uint end) + public FinallyExceptionHandler(uint start, uint end) : this($"L_{start:X4}", $"L_{end:X4}") + { + } + + public FinallyExceptionHandler(string start, string end) { this.Kind = ExceptionHandlerBlockKind.Finally; - this.Start = string.Format("L_{0:X4}", start); - this.End = string.Format("L_{0:X4}", end); + this.Start = start; + this.End = end; } public override string ToString() From 8c1b12b6cb799ab7caa51307ecd43e70cfb49ef0 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Aug 2020 16:13:32 -0300 Subject: [PATCH 231/256] fix whitespaces --- Model/Bytecode/Instructions.cs | 5 +++-- Model/ExceptionHandlers.cs | 10 ++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index 728299c2..7c83302b 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -213,10 +213,11 @@ public class BranchInstruction : Instruction public string Target { get; set; } public bool UnsignedOperands { get; set; } - public BranchInstruction(uint label, BranchOperation operation, uint target) + public BranchInstruction(uint label, BranchOperation operation, uint target) : this(label, operation, $"L_{target:X4}") { } + public BranchInstruction(uint label, BranchOperation operation, string target) : base(label) { @@ -244,7 +245,7 @@ public SwitchInstruction(uint label, IEnumerable targets) : this(label, targets.Select(target => $"L_{target:X4}").ToList()) { } - + public SwitchInstruction(uint label, IEnumerable targets) : base(label) { diff --git a/Model/ExceptionHandlers.cs b/Model/ExceptionHandlers.cs index f8cf0904..70d54645 100644 --- a/Model/ExceptionHandlers.cs +++ b/Model/ExceptionHandlers.cs @@ -35,7 +35,7 @@ public class ProtectedBlock : IExceptionHandlerBlock public string End { get; set; } public IExceptionHandler Handler { get; set; } - public ProtectedBlock(uint start, uint end): this($"L_{start:X4}", $"L_{end:X4}") + public ProtectedBlock(uint start, uint end) : this($"L_{start:X4}", $"L_{end:X4}") { } @@ -88,9 +88,9 @@ public class CatchExceptionHandler : IExceptionHandler public IType ExceptionType { get; set; } public CatchExceptionHandler(uint start, uint end, IType exceptionType) : this($"L_{start:X4}", $"L_{end:X4}", exceptionType) - { + { } - + public CatchExceptionHandler(string start, string end, IType exceptionType) { this.Kind = ExceptionHandlerBlockKind.Catch; @@ -99,7 +99,6 @@ public CatchExceptionHandler(string start, string end, IType exceptionType) this.ExceptionType = exceptionType; } - public override string ToString() { return string.Format("catch {0} handler {1} to {2}", this.ExceptionType, this.Start, this.End); @@ -123,7 +122,6 @@ public FaultExceptionHandler(string start, string end) this.End = end; } - public override string ToString() { return string.Format("fault handler {0} to {1}", this.Start, this.End); @@ -139,7 +137,7 @@ public class FinallyExceptionHandler : IExceptionHandler public FinallyExceptionHandler(uint start, uint end) : this($"L_{start:X4}", $"L_{end:X4}") { } - + public FinallyExceptionHandler(string start, string end) { this.Kind = ExceptionHandlerBlockKind.Finally; From 1ae23da71d06e00294d1fdcc4f4b3ed2264be267 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Aug 2020 16:14:58 -0300 Subject: [PATCH 232/256] fix whitespaces --- Model/Bytecode/Instructions.cs | 2 +- Model/ExceptionHandlers.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Model/Bytecode/Instructions.cs b/Model/Bytecode/Instructions.cs index 7c83302b..c12f74e9 100644 --- a/Model/Bytecode/Instructions.cs +++ b/Model/Bytecode/Instructions.cs @@ -217,7 +217,7 @@ public BranchInstruction(uint label, BranchOperation operation, uint target) : this(label, operation, $"L_{target:X4}") { } - + public BranchInstruction(uint label, BranchOperation operation, string target) : base(label) { diff --git a/Model/ExceptionHandlers.cs b/Model/ExceptionHandlers.cs index 70d54645..0658a2f9 100644 --- a/Model/ExceptionHandlers.cs +++ b/Model/ExceptionHandlers.cs @@ -114,7 +114,7 @@ public class FaultExceptionHandler : IExceptionHandler public FaultExceptionHandler(uint start, uint end) : this($"L_{start:X4}", $"L_{end:X4}") { } - + public FaultExceptionHandler(string start, string end) { this.Kind = ExceptionHandlerBlockKind.Fault; From be0c86157cdf79fbe7fb057e5d25a55f8e65f6be Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Aug 2020 17:25:03 -0300 Subject: [PATCH 233/256] fix type of this parameter in generic method body --- MetadataProvider/AssemblyExtractor.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..9bb007be 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -626,6 +626,12 @@ private void ExtractParameters(IList parameters) if (!currentMethod.IsStatic) { IType type = currentMethod.ContainingType; + + if (currentMethod.ContainingType.GenericParameters.Count > 0) + { + // within a generic method body, "this" is not the generic type itself but its instantiation + type = currentMethod.ContainingType.Instantiate(currentMethod.ContainingType.GenericParameters); + } if (type.TypeKind == TypeKind.ValueType) { From 56aca9b886661a93eed6ef7b1651326fbe0fe82c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Aug 2020 17:39:52 -0300 Subject: [PATCH 234/256] fix merge --- MetadataProvider/AssemblyExtractor.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 346a0232..a8acad41 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -678,12 +678,6 @@ private void ExtractParameters(IList parameters) { IType type = currentMethod.ContainingType; - if (currentMethod.ContainingType.GenericParameters.Count > 0) - { - // within a generic method body, "this" is not the generic type itself but its instantiation - type = currentMethod.ContainingType.Instantiate(currentMethod.ContainingType.GenericParameters); - } - if (currentMethod.ContainingType.GenericParameters.Count > 0) { // within a generic method body, "this" is not the generic type itself but its instantiation From 651ef30b592e1a4d9d3bb0d143d951bfbcf9cdf1 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 23 Aug 2020 17:40:23 -0300 Subject: [PATCH 235/256] fix merge --- MetadataProvider/AssemblyExtractor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index a8acad41..e3f048e7 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -683,7 +683,7 @@ private void ExtractParameters(IList parameters) // within a generic method body, "this" is not the generic type itself but its instantiation type = currentMethod.ContainingType.Instantiate(currentMethod.ContainingType.GenericParameters); } - + if (type.TypeKind == TypeKind.ValueType) { type = signatureTypeProvider.GetByReferenceType(type); From baba985ccd5d76b5a1b94bdd2dac70ecf1a78d02 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 24 Aug 2020 19:28:06 -0300 Subject: [PATCH 236/256] more tests --- Console/Program.cs | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index 2cdcb536..5a07a795 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -508,9 +508,8 @@ private static MethodReference ConsoleWriteLineMethodReference() return writeLineMethod; } - private static void DisassembleAndThenAssemble() + private static void ReadAndGenerateDll(bool transformToTacAndBackToBytecode) { - // FIXME PROBAR generar y correr tests (+pedump) CONVIRTIENDO Y SIN CONVERTIR a tac var inputs = new[] { new[] {"../../../Examples/bin/Debug/Examples.dll"}, @@ -548,6 +547,35 @@ private static void DisassembleAndThenAssemble() var loader = new MetadataProvider.Loader(host); loader.LoadAssembly(file); + if (transformToTacAndBackToBytecode) + { + var allDefinedMethods = (from a in host.Assemblies + from t in a.RootNamespace.GetAllTypes() + from m in t.Members.OfType() + where m.HasBody + select m).ToList(); + + foreach (var method in allDefinedMethods) + { + var tac = new Backend.Transformations.Disassembler(method).Execute(); + method.Body = tac; + + var cfanalysis = new ControlFlowAnalysis(method.Body); + var cfg = cfanalysis.GenerateExceptionalControlFlow(); + + var webAnalysis = new WebAnalysis(cfg); + webAnalysis.Analyze(); + webAnalysis.Transform(); + method.Body.UpdateVariables(); + + var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); + typeInferenceAnalysis.Analyze(); + + var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); + method.Body = bytecode; + } + } + var generator = new MetadataGenerator.Generator(); foreach (var assembly in host.Assemblies) @@ -623,9 +651,10 @@ from m in t.Members.OfType() static void Main(string[] args) { - //DisassembleAndThenAssemble(); - //TacInstrumentation(); - // HelloWorldAssembly(); +// ReadAndGenerateDll(false); +// ReadAndGenerateDll(true); +// TacInstrumentation(); +// HelloWorldAssembly(); RemoveUnusedMethodFromSimpleExecutable(); System.Console.WriteLine("Done!"); From 9a0e327ae85e18935fb52762347f56bbd6ef80fb Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 24 Aug 2020 20:16:58 -0300 Subject: [PATCH 237/256] fix type inferer --- Backend/Analyses/TypeInferenceAnalysis.cs | 22 ++++++++++++---------- Console/Program.cs | 10 +++++----- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Backend/Analyses/TypeInferenceAnalysis.cs b/Backend/Analyses/TypeInferenceAnalysis.cs index b4a1a98f..9ec8ef12 100644 --- a/Backend/Analyses/TypeInferenceAnalysis.cs +++ b/Backend/Analyses/TypeInferenceAnalysis.cs @@ -56,26 +56,28 @@ public override void Visit(MethodCallInstruction instruction) { if (instruction.HasResult) { - - if (instruction.Method.ReturnType is GenericParameterReference genericParameterReference) + 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: - instruction.Result.Type = (genericParameterReference.GenericContainer as IBasicType).GenericArguments[genericParameterReference.Index]; + genericArguments = ((IBasicType) genericParameterReference.GenericContainer).GenericArguments; break; case GenericParameterKind.Method: - instruction.Result.Type = (genericParameterReference.GenericContainer as IMethodReference).GenericArguments[genericParameterReference.Index]; + genericArguments = ((IMethodReference) genericParameterReference.GenericContainer).GenericArguments; break; default: - throw new ArgumentOutOfRangeException(); + throw genericParameterReference.Kind.ToUnknownValueException(); + } + if (genericArguments.Count > 0) + { + instruction.Result.Type = genericArguments[genericParameterReference.Index]; } } - else - { - instruction.Result.Type = instruction.Method.ReturnType; - } - } // Skip implicit "this" parameter. diff --git a/Console/Program.cs b/Console/Program.cs index 5a07a795..e7fef15f 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -651,11 +651,11 @@ from m in t.Members.OfType() static void Main(string[] args) { -// ReadAndGenerateDll(false); -// ReadAndGenerateDll(true); -// TacInstrumentation(); -// HelloWorldAssembly(); - RemoveUnusedMethodFromSimpleExecutable(); + // ReadAndGenerateDll(false); + ReadAndGenerateDll(true); + // TacInstrumentation(); + // HelloWorldAssembly(); + // RemoveUnusedMethodFromSimpleExecutable(); System.Console.WriteLine("Done!"); } From 7e15be5bef74a562943253a764ef9ffd1b540847 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Mon, 24 Aug 2020 20:26:43 -0300 Subject: [PATCH 238/256] retrieve generic parameter instantiated type --- Backend/Analyses/TypeInferenceAnalysis.cs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Backend/Analyses/TypeInferenceAnalysis.cs b/Backend/Analyses/TypeInferenceAnalysis.cs index b25cde66..d8a79ff9 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. From 48d360affd0e562314354bccd12bce58bd59b678 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 26 Aug 2020 07:40:54 -0300 Subject: [PATCH 239/256] whitespaces --- Backend/Transformations/Disassembler.cs | 14 ++++++++------ Model/ThreeAddressCode/Instructions.cs | 2 +- Model/ThreeAddressCode/Operands.cs | 3 +-- .../ThreeAddressCode/Visitor/InstructionVisitor.cs | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Backend/Transformations/Disassembler.cs b/Backend/Transformations/Disassembler.cs index 656f2bf1..3b26b1ae 100644 --- a/Backend/Transformations/Disassembler.cs +++ b/Backend/Transformations/Disassembler.cs @@ -553,7 +553,7 @@ private void ProcessLoadArrayElement(Bytecode.LoadArrayElementInstruction op) } var array = stack.Pop(); - + indices.Reverse(); var dest = stack.Push(); @@ -596,9 +596,9 @@ public override void Visit(Bytecode.StoreArrayElementInstruction op) } var array = stack.Pop(); - + indices.Reverse(); - + var dest = new ArrayElementAccess(array, indices) { Method = op.Method}; var instruction = new Tac.StoreInstruction(op.Offset, dest, source); body.Instructions.Add(instruction); @@ -1034,7 +1034,7 @@ public MethodBody Execute() //body.LocalVariables.AddRange(stack.Variables); body.UpdateVariables(); } - + return body; } @@ -1080,7 +1080,8 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) break; case ExceptionHandlerBlockKind.Filter: - var filterException = stack.Push(); // Push the exception into the stack + // Push the exception into the stack + var filterException = stack.Push(); var filterBlock = (FilterExceptionHandler) block; var kind = operation.Label.Equals(filterBlock.FilterStart) ? Tac.FilterInstructionKind.FilterSection @@ -1089,7 +1090,8 @@ private void ProcessExceptionHandling(MethodBody body, IInstruction operation) break; case ExceptionHandlerBlockKind.Catch: - var catchException = stack.Push(); // Push the exception into the stack + // Push the exception into the stack + var catchException = stack.Push(); var catchBlock = block as CatchExceptionHandler; instruction = new Tac.CatchInstruction(operation.Offset, catchException, catchBlock.ExceptionType); break; diff --git a/Model/ThreeAddressCode/Instructions.cs b/Model/ThreeAddressCode/Instructions.cs index 138cfdd0..5d8b3699 100644 --- a/Model/ThreeAddressCode/Instructions.cs +++ b/Model/ThreeAddressCode/Instructions.cs @@ -859,7 +859,7 @@ public override string ToString() public class SwitchInstruction : Instruction { public IVariable Operand { get; set; } - public IList Targets { get; set; } + public IList Targets { get; private set; } public SwitchInstruction(uint offset, IVariable operand, IEnumerable targets) : base(offset) diff --git a/Model/ThreeAddressCode/Operands.cs b/Model/ThreeAddressCode/Operands.cs index 767d0e82..31317532 100644 --- a/Model/ThreeAddressCode/Operands.cs +++ b/Model/ThreeAddressCode/Operands.cs @@ -325,7 +325,7 @@ public override bool Equals(object obj) var other = obj as LocalVariable; return other != null && - this.Name.Equals(other.Name); + this.Name.Equals(other.Name); } public override int GetHashCode() @@ -784,7 +784,6 @@ public class ArrayElementAccess : IAssignableValue, IReferenceable, IExpression { public IVariable Array { get; set; } public IList Indices { get; set; } - public IMethodReference Method { get; set; } public ArrayElementAccess(IVariable array, IEnumerable indices) { diff --git a/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs b/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs index 6c067d37..43781331 100644 --- a/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs +++ b/Model/ThreeAddressCode/Visitor/InstructionVisitor.cs @@ -15,7 +15,7 @@ public virtual void Visit(IInstructionContainer container) foreach (var instruction in container.Instructions) { var tacInstruction = instruction as Instruction; - tacInstruction.Accept(this); + tacInstruction.Accept(this); } } From 4871b186cb72f6dd0f89f4d4cb19c87af93178bb Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 26 Aug 2020 08:49:23 -0300 Subject: [PATCH 240/256] remove comments --- Backend/Transformations/Assembly/Assembler.cs | 1 - .../Methods/Body/MethodBodyControlFlowGenerator.cs | 1 - .../Methods/Body/MethodLocalsSignatureGenerator.cs | 1 - MetadataGenerator/Generators/Methods/MethodGenerator.cs | 6 ++---- .../Generators/Methods/MethodSignatureGenerator.cs | 1 - MetadataGenerator/Metadata/MetadataContainer.cs | 3 --- MetadataGenerator/Metadata/MetadataResolver.cs | 4 ---- 7 files changed, 2 insertions(+), 15 deletions(-) diff --git a/Backend/Transformations/Assembly/Assembler.cs b/Backend/Transformations/Assembly/Assembler.cs index 098f31ee..08077523 100644 --- a/Backend/Transformations/Assembly/Assembler.cs +++ b/Backend/Transformations/Assembly/Assembler.cs @@ -48,7 +48,6 @@ public Assembler(MethodDefinition method) public MethodBody Execute() { var body = new MethodBody(MethodBodyKind.Bytecode); - body.MaxStack = 20; // FIXME calcular body.Parameters.AddRange(method.Body.Parameters); for (Index = 0; Index < method.Body.Instructions.Count; Index++) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index 9468bdb1..b8053ea5 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -30,7 +30,6 @@ public ECMA335.LabelHandle LabelHandleFor(string label) return labelHandle; } - // FIXME name, quiza hacer tmb con las exception information asi es mas prolijo? y despues en el labelHandle solo levantarla y nunca crearla public void DefineNeededBranchLabels(IList instructions) { foreach (var instruction in instructions) diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs index 988921bb..e0093f59 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs @@ -24,7 +24,6 @@ public SRM.StandaloneSignatureHandle GenerateSignatureFor(IList local var encoder = new ECMA335.BlobEncoder(signature).LocalVariableSignature(localVariables.Count); foreach (var localVariable in localVariables) { - // TODO pinned is achieved by the fixed keyword and this is not in the model metadataContainer.MetadataResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); } diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index db70eb4a..00483d0c 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -42,10 +42,8 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) } var methodImplementationAttributes = - SR.MethodImplAttributes.IL | - (!method.HasBody && !method.IsAbstract // FIXME Could also be PinvokeImpl or InternalCall in some special cases - ? SR.MethodImplAttributes.Runtime - : SR.MethodImplAttributes.Managed); + SR.MethodImplAttributes.IL | + (!method.HasBody && !method.IsAbstract ? SR.MethodImplAttributes.Runtime : SR.MethodImplAttributes.Managed); var methodDefinitionHandle = metadataContainer.MetadataBuilder.AddMethodDefinition( attributes: GetMethodAttributesFor(method), diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 60ca7040..28870681 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -57,7 +57,6 @@ private SRM.BlobBuilder GenerateMethodSignature( } else { - // TODO isByRef param. ref in return type is not in the model var encoder = returnTypeEncoder.Type(); metadataContainer.MetadataResolver.Encode(returnType, encoder); } diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/Metadata/MetadataContainer.cs index 1d7612c6..4a1fc8b2 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/Metadata/MetadataContainer.cs @@ -105,9 +105,6 @@ public void GenerateInterfaceImplementations() => .ForEach(row => MetadataBuilder.AddInterfaceImplementation(row.Type, row.ImplementedInterface)); #region Rows - - // FIXME hacen falta los equality members? Deberian mirar todos los campos? - private class InterfaceImplementationRow { public readonly SRM.TypeDefinitionHandle Type; diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/Metadata/MetadataResolver.cs index 9d6e363f..7c9c5932 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/Metadata/MetadataResolver.cs @@ -11,10 +11,6 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -// TODO revisar si esas keys que pongo en los getOrAdd (al ser mas precisas) estan funcionando o hacen que siempre se agregue uno nuevo -// TODO para esto comparar sin guardar ninguna cuanto da el conteo de las tablas y guardando despues. -// TODO ver si conviene usar blobhandle, byteArray de la signature u otro. Evaluarlo tabla por tabla, quiza algunas andan bien y otras no -// TODO mas alla de la eficiencia, algunas tablas no admiten duplicados por lo que si no rompe por eso es que algunas esta usando. namespace MetadataGenerator.Metadata { internal class MetadataResolver From 4963545746efd99bb1c49915141c404c8334f06e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 29 Aug 2020 21:09:52 -0300 Subject: [PATCH 241/256] rename enum --- CCIProvider/AssemblyTraverser.cs | 4 ++-- MetadataProvider/AssemblyExtractor.cs | 4 ++-- Model/Assembly.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CCIProvider/AssemblyTraverser.cs b/CCIProvider/AssemblyTraverser.cs index a83f6933..e9730d28 100644 --- a/CCIProvider/AssemblyTraverser.cs +++ b/CCIProvider/AssemblyTraverser.cs @@ -40,8 +40,8 @@ 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; + case Cci.ModuleKind.WindowsApplication: return AssemblyKind.Exe; + case Cci.ModuleKind.DynamicallyLinkedLibrary: return AssemblyKind.Dll; default: throw new Exception($"Assembly kind {cciAssembly.Kind} not supported"); } } diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index b145874d..b8b17d98 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -174,8 +174,8 @@ public FieldDefinition GetDefinedField(SRM.FieldDefinitionHandle handle) private AssemblyKind AssemblyKindFrom(SRPE.PEHeaders headers) { - if (headers.IsDll) return AssemblyKind.DLL; - if (headers.IsExe || headers.IsConsoleApplication) return AssemblyKind.EXE; + if (headers.IsDll) return AssemblyKind.Dll; + if (headers.IsExe || headers.IsConsoleApplication) return AssemblyKind.Exe; else throw new Exception("Assembly kind not supported"); } diff --git a/Model/Assembly.cs b/Model/Assembly.cs index 5cd23ac2..d21501c8 100644 --- a/Model/Assembly.cs +++ b/Model/Assembly.cs @@ -46,8 +46,8 @@ public override bool Equals(object obj) public enum AssemblyKind { - EXE, - DLL + Exe, + Dll } public class Assembly : IAssemblyReference From 2e217bff84f7183d0af13f745268d9845dceaed4 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 29 Aug 2020 21:38:33 -0300 Subject: [PATCH 242/256] refactor --- Console/Program.cs | 2 +- .../{Metadata => }/AttributesProvider.cs | 104 ++++++++---------- MetadataGenerator/Extensions.cs | 8 -- MetadataGenerator/Generator.cs | 9 +- .../Generators/AssemblyGenerator.cs | 3 +- .../Generators/CustomAttributeGenerator.cs | 1 - .../Generators/Fields/FieldGenerator.cs | 5 +- .../Fields/FieldSignatureGenerator.cs | 3 +- .../Body/MethodBodyControlFlowGenerator.cs | 1 - .../Methods/Body/MethodBodyGenerator.cs | 4 +- .../Body/MethodLocalsSignatureGenerator.cs | 1 - .../Generators/Methods/MethodGenerator.cs | 5 +- .../Methods/MethodParametersGenerator.cs | 5 +- .../Methods/MethodSignatureGenerator.cs | 1 - .../Generators/NamespaceGenerator.cs | 1 - .../Generators/PropertyGenerator.cs | 1 - MetadataGenerator/Generators/TypeGenerator.cs | 8 +- .../{Metadata => }/MetadataContainer.cs | 19 ++-- MetadataGenerator/MetadataGenerator.csproj | 7 +- .../{Metadata => }/MetadataResolver.cs | 2 +- Model/IGenerator.cs | 2 +- 21 files changed, 79 insertions(+), 113 deletions(-) rename MetadataGenerator/{Metadata => }/AttributesProvider.cs (67%) rename MetadataGenerator/{Metadata => }/MetadataContainer.cs (94%) rename MetadataGenerator/{Metadata => }/MetadataResolver.cs (99%) diff --git a/Console/Program.cs b/Console/Program.cs index e7fef15f..cc949ae6 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -376,7 +376,7 @@ private static void HelloWorldAssembly() Culture = "", PublicKey = new byte[0] }; - var assembly = new Assembly("SampleAssembly", AssemblyKind.EXE) + var assembly = new Assembly("SampleAssembly", AssemblyKind.Exe) { Version = new Version("1.0.0.0"), PublicKey = new byte[0], diff --git a/MetadataGenerator/Metadata/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs similarity index 67% rename from MetadataGenerator/Metadata/AttributesProvider.cs rename to MetadataGenerator/AttributesProvider.cs index 2c0582d6..585d62cd 100644 --- a/MetadataGenerator/Metadata/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -1,13 +1,12 @@ -using System; -using System.Reflection; +using System.Reflection; using Model; using Model.Types; -namespace MetadataGenerator.Metadata +namespace MetadataGenerator { public static class AttributesProvider { - public static TypeAttributes GetTypeAttributesFor(TypeDefinition typeDefinition) + public static TypeAttributes AttributesFor(TypeDefinition typeDefinition) { switch (typeDefinition.Kind) { @@ -16,54 +15,43 @@ public static TypeAttributes GetTypeAttributesFor(TypeDefinition typeDefinition) case TypeDefinitionKind.Interface: return InterfaceTypeAttributes(); case TypeDefinitionKind.Struct: return StructTypeAttributes(typeDefinition); case TypeDefinitionKind.Delegate: return DelegateTypeAttributes(typeDefinition); - default: throw new Exception($"TypeDefinition {typeDefinition.Name} not supported"); + default: throw typeDefinition.Kind.ToUnknownValueException(); } } - private static TypeAttributes DelegateTypeAttributes(TypeDefinition typeDefinition) - { - return TypeAttributes.Class | - TypeAttributes.Sealed | - (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | - VisibilityAttributesFor(typeDefinition); - } - - private static TypeAttributes StructTypeAttributes(TypeDefinition typeDefinition) - { - return TypeAttributes.Class | - VisibilityAttributesFor(typeDefinition) | - LayoutAttributesFor(typeDefinition.LayoutInformation) | - (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | - TypeAttributes.Sealed | - (typeDefinition.BeforeFieldInit ? TypeAttributes.BeforeFieldInit : 0); - } - - private static TypeAttributes EnumTypeAttributes(TypeDefinition typeDefinition) - { - return TypeAttributes.Class | - VisibilityAttributesFor(typeDefinition) | - (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | - TypeAttributes.Sealed; - } - - private static TypeAttributes ClassTypeAttributes(TypeDefinition typeDefinition) - { - return TypeAttributes.Class | - (typeDefinition.BeforeFieldInit ? TypeAttributes.BeforeFieldInit : 0) | - (typeDefinition.IsAbstract ? TypeAttributes.Abstract : 0) | - (typeDefinition.IsSealed ? TypeAttributes.Sealed : 0) | - (typeDefinition.IsStatic ? TypeAttributes.Abstract | TypeAttributes.Sealed : 0) | - (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | - LayoutAttributesFor(typeDefinition.LayoutInformation) | - VisibilityAttributesFor(typeDefinition); - } - - private static TypeAttributes InterfaceTypeAttributes() - { - return TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; - } - - public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) + private static TypeAttributes DelegateTypeAttributes(TypeDefinition typeDefinition) => + TypeAttributes.Class | + TypeAttributes.Sealed | + (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | + VisibilityAttributesFor(typeDefinition); + + private static TypeAttributes StructTypeAttributes(TypeDefinition typeDefinition) => + TypeAttributes.Class | + VisibilityAttributesFor(typeDefinition) | + LayoutAttributesFor(typeDefinition.LayoutInformation) | + (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | + TypeAttributes.Sealed | + (typeDefinition.BeforeFieldInit ? TypeAttributes.BeforeFieldInit : 0); + + private static TypeAttributes EnumTypeAttributes(TypeDefinition typeDefinition) => + TypeAttributes.Class | + VisibilityAttributesFor(typeDefinition) | + (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | + TypeAttributes.Sealed; + + private static TypeAttributes ClassTypeAttributes(TypeDefinition typeDefinition) => + TypeAttributes.Class | + (typeDefinition.BeforeFieldInit ? TypeAttributes.BeforeFieldInit : 0) | + (typeDefinition.IsAbstract ? TypeAttributes.Abstract : 0) | + (typeDefinition.IsSealed ? TypeAttributes.Sealed : 0) | + (typeDefinition.IsStatic ? TypeAttributes.Abstract | TypeAttributes.Sealed : 0) | + (typeDefinition.Serializable ? TypeAttributes.Serializable : 0) | + LayoutAttributesFor(typeDefinition.LayoutInformation) | + VisibilityAttributesFor(typeDefinition); + + private static TypeAttributes InterfaceTypeAttributes() => TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; + + public static FieldAttributes AttributesFor(FieldDefinition field) { var fieldAttributes = (field.IsStatic ? FieldAttributes.Static : 0) | @@ -97,7 +85,7 @@ public static FieldAttributes GetFieldAttributesFor(FieldDefinition field) return fieldAttributes; } - public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) + public static MethodAttributes AttributesFor(MethodDefinition method) { var methodAttributes = MethodAttributes.HideBySig | @@ -129,7 +117,7 @@ public static MethodAttributes GetMethodAttributesFor(MethodDefinition method) return methodAttributes; } - public static ParameterAttributes GetParameterAttributesFor(MethodParameter parameter) + public static ParameterAttributes AttributesFor(MethodParameter parameter) { var attributes = parameter.HasDefaultValue ? ParameterAttributes.HasDefault : 0; switch (parameter.Kind) @@ -155,9 +143,9 @@ public static ParameterAttributes GetParameterAttributesFor(MethodParameter para return attributes; } - public static GenericParameterAttributes GetGenericParameterAttributesFor(GenericParameter genericParameter) + public static GenericParameterAttributes AttributesFor(GenericParameter genericParameter) { - GenericParameterAttributes attributes = GenericParameterAttributes.None; + var attributes = GenericParameterAttributes.None; if (genericParameter.DefaultConstructorConstraint) { attributes |= GenericParameterAttributes.DefaultConstructorConstraint; @@ -190,18 +178,14 @@ private static TypeAttributes VisibilityAttributesFor(TypeDefinition typeDefinit { if (typeDefinition.ContainingType != null) { - return VisibilityKind.Public.Equals(typeDefinition.Visibility) - ? TypeAttributes.NestedPublic - : TypeAttributes.NestedPrivate; + return VisibilityKind.Public == typeDefinition.Visibility ? TypeAttributes.NestedPublic : TypeAttributes.NestedPrivate; } else { - return VisibilityKind.Public.Equals(typeDefinition.Visibility) - ? TypeAttributes.Public - : TypeAttributes.NotPublic; + return VisibilityKind.Public == typeDefinition.Visibility ? TypeAttributes.Public : TypeAttributes.NotPublic; } } - + private static TypeAttributes LayoutAttributesFor(LayoutInformation layoutInformation) { switch (layoutInformation.Kind) diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index ace07fae..f3894ceb 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -14,19 +14,11 @@ public static T FirstOr(this IEnumerable enumerable, T defaultValue) return first.Equals(default(T)) ? defaultValue : first; } - public static void CallVirtual(this ECMA335.InstructionEncoder encoder, SRM.EntityHandle methodReference) - { - encoder.OpCode(SRM.ILOpCode.Callvirt); - encoder.Token(methodReference); - } - // The next available slot in the corresponding table. If nothing is defined in the module then use row number 1 for the corresponding table public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; public static bool IsGenericInstantiation(this IBasicType type) => type.GenericType != null; public static bool IsGenericInstantiation(this IMethodReference method) => method.GenericMethod != null; - - public static bool IsGenericType(this IBasicType type) => type.GenericType == null && type.GenericParameterCount > 0; } } \ No newline at end of file diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index a722d1f8..a385bc0f 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -2,6 +2,7 @@ using System.IO; using MetadataGenerator.Generators; using Model; +using static Model.AssemblyKind; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; using SRPE = System.Reflection.PortableExecutable; @@ -12,16 +13,14 @@ public class Generator : IGenerator { public void Generate(Assembly assembly) { - var extension = assembly.Kind == AssemblyKind.EXE ? "exe" : "dll"; + var extension = assembly.Kind == Exe ? "exe" : "dll"; var fileName = $"./{assembly.Name}.{extension}"; Console.WriteLine($"Generating Console/bin/debug/{fileName.Substring(2)}"); using (var peStream = File.OpenWrite(fileName)) { var metadataContainer = AssemblyGenerator.Generate(assembly); var peHeaderBuilder = new SRPE.PEHeaderBuilder( - imageCharacteristics: assembly.Kind == AssemblyKind.EXE - ? SRPE.Characteristics.ExecutableImage - : SRPE.Characteristics.Dll + imageCharacteristics: assembly.Kind == Exe ? SRPE.Characteristics.ExecutableImage : SRPE.Characteristics.Dll ); var peBlob = new SRM.BlobBuilder(); new SRPE.ManagedPEBuilder( @@ -29,7 +28,7 @@ public void Generate(Assembly assembly) metadataRootBuilder: new ECMA335.MetadataRootBuilder(metadataContainer.MetadataBuilder), ilStream: metadataContainer.MethodBodyStream.Builder, mappedFieldData: metadataContainer.MappedFieldData, - entryPoint: assembly.Kind.Equals(AssemblyKind.EXE) ? metadataContainer.MainMethodHandle : default, + entryPoint: assembly.Kind == Exe ? metadataContainer.MainMethodHandle : default, flags: SRPE.CorFlags.ILOnly | SRPE.CorFlags.StrongNameSigned ).Serialize(peBlob); peBlob.WriteContentTo(peStream); diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generators/AssemblyGenerator.cs index 0d9dcd54..d783cd2b 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generators/AssemblyGenerator.cs @@ -1,5 +1,4 @@ using System; -using MetadataGenerator.Metadata; using Model; using SR = System.Reflection; @@ -22,7 +21,7 @@ public static MetadataContainer Generate(Assembly assembly) hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1 ); - var moduleName = $"{assembly.Name}.{(assembly.Kind == AssemblyKind.EXE ? "exe" : "dll")}"; + var moduleName = $"{assembly.Name}.{(assembly.Kind == AssemblyKind.Exe ? "exe" : "dll")}"; metadataContainer.ModuleHandle = metadataBuilder.AddModule( generation: 0, moduleName: metadataBuilder.GetOrAddString(moduleName), diff --git a/MetadataGenerator/Generators/CustomAttributeGenerator.cs b/MetadataGenerator/Generators/CustomAttributeGenerator.cs index ef6597e7..c70fe5d6 100644 --- a/MetadataGenerator/Generators/CustomAttributeGenerator.cs +++ b/MetadataGenerator/Generators/CustomAttributeGenerator.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Immutable; -using MetadataGenerator.Metadata; using Model; using Model.ThreeAddressCode.Values; using Model.Types; diff --git a/MetadataGenerator/Generators/Fields/FieldGenerator.cs b/MetadataGenerator/Generators/Fields/FieldGenerator.cs index 49207087..89988250 100644 --- a/MetadataGenerator/Generators/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldGenerator.cs @@ -1,7 +1,6 @@ using System.Reflection.PortableExecutable; -using MetadataGenerator.Metadata; using Model.Types; -using static MetadataGenerator.Metadata.AttributesProvider; +using static MetadataGenerator.AttributesProvider; using SRM = System.Reflection.Metadata; namespace MetadataGenerator.Generators.Fields @@ -23,7 +22,7 @@ public SRM.FieldDefinitionHandle Generate(FieldDefinition field) { var fieldSignature = fieldSignatureGenerator.GenerateSignatureOf(field); var fieldDefinitionHandle = metadataContainer.MetadataBuilder.AddFieldDefinition( - attributes: GetFieldAttributesFor(field), + attributes: AttributesFor(field), name: metadataContainer.MetadataBuilder.GetOrAddString(field.Name), signature: metadataContainer.MetadataBuilder.GetOrAddBlob(fieldSignature)); diff --git a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs index b2bf7c03..a60cc6ee 100644 --- a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs @@ -1,5 +1,4 @@ -using MetadataGenerator.Metadata; -using Model.Types; +using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs index b8053ea5..b7fc5ec8 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using MetadataGenerator.Metadata; using Model; using Model.Bytecode; using ECMA335 = System.Reflection.Metadata.Ecma335; diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs index e98320e3..f7bd8866 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using MetadataGenerator.Metadata; using Model; using Model.Bytecode; using Model.Bytecode.Visitor; @@ -742,7 +741,8 @@ public void Visit(MethodCallInstruction instruction) switch (instruction.Operation) { case MethodCallOperation.Virtual: - instructionEncoder.CallVirtual(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + instructionEncoder.OpCode(SRM.ILOpCode.Callvirt); + instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count + 1); break; case MethodCallOperation.Static: diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs index e0093f59..9219dff9 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using MetadataGenerator.Metadata; using Model.ThreeAddressCode.Values; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generators/Methods/MethodGenerator.cs index 00483d0c..3f67da3f 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodGenerator.cs @@ -1,7 +1,6 @@ using MetadataGenerator.Generators.Methods.Body; -using MetadataGenerator.Metadata; using Model.Types; -using static MetadataGenerator.Metadata.AttributesProvider; +using static MetadataGenerator.AttributesProvider; using ECMA335 = System.Reflection.Metadata.Ecma335; using SR = System.Reflection; using SRM = System.Reflection.Metadata; @@ -46,7 +45,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) (!method.HasBody && !method.IsAbstract ? SR.MethodImplAttributes.Runtime : SR.MethodImplAttributes.Managed); var methodDefinitionHandle = metadataContainer.MetadataBuilder.AddMethodDefinition( - attributes: GetMethodAttributesFor(method), + attributes: AttributesFor(method), implAttributes: methodImplementationAttributes, name: metadataContainer.MetadataBuilder.GetOrAddString(method.Name), signature: metadataContainer.MetadataBuilder.GetOrAddBlob(methodSignature), diff --git a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs b/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs index dfd7e296..bdd77271 100644 --- a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs @@ -1,10 +1,9 @@ using System.Collections.Generic; -using MetadataGenerator.Metadata; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SR = System.Reflection; using SRM = System.Reflection.Metadata; -using static MetadataGenerator.Metadata.AttributesProvider; +using static MetadataGenerator.AttributesProvider; namespace MetadataGenerator.Generators.Methods { @@ -23,7 +22,7 @@ internal MethodParametersGenerator(MetadataContainer metadataContainer) foreach (var parameter in methodParameters) { var parameterHandle = metadataContainer.MetadataBuilder.AddParameter( - attributes: GetParameterAttributesFor(parameter), + attributes: AttributesFor(parameter), name: metadataContainer.MetadataBuilder.GetOrAddString(parameter.Name), sequenceNumber: parameter.Index); if (parameter.HasDefaultValue) diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs index 28870681..bf71a6d8 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using MetadataGenerator.Metadata; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; diff --git a/MetadataGenerator/Generators/NamespaceGenerator.cs b/MetadataGenerator/Generators/NamespaceGenerator.cs index a475184f..3cbc86fc 100644 --- a/MetadataGenerator/Generators/NamespaceGenerator.cs +++ b/MetadataGenerator/Generators/NamespaceGenerator.cs @@ -1,5 +1,4 @@ using System.Linq; -using MetadataGenerator.Metadata; using Model; using Model.Types; using SRM = System.Reflection.Metadata; diff --git a/MetadataGenerator/Generators/PropertyGenerator.cs b/MetadataGenerator/Generators/PropertyGenerator.cs index 58cf8425..e4de145c 100644 --- a/MetadataGenerator/Generators/PropertyGenerator.cs +++ b/MetadataGenerator/Generators/PropertyGenerator.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using MetadataGenerator.Metadata; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SR = System.Reflection; diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generators/TypeGenerator.cs index 730bec1d..0bd8417f 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generators/TypeGenerator.cs @@ -3,9 +3,8 @@ using MetadataGenerator.Generators.Fields; using MetadataGenerator.Generators.Methods; using MetadataGenerator.Generators.Methods.Body; -using MetadataGenerator.Metadata; using Model.Types; -using static MetadataGenerator.Metadata.AttributesProvider; +using static MetadataGenerator.AttributesProvider; using ECMA335 = System.Reflection.Metadata.Ecma335; using SR = System.Reflection; using SRM = System.Reflection.Metadata; @@ -59,7 +58,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) var nextFieldDefinitionHandle = ECMA335.MetadataTokens.FieldDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.Field)); var nextMethodDefinitionHandle = ECMA335.MetadataTokens.MethodDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.MethodDef)); var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( - attributes: GetTypeAttributesFor(type), + attributes: AttributesFor(type), @namespace: metadataBuilder.GetOrAddString(type.ContainingNamespace.FullName), name: metadataBuilder.GetOrAddString(TypeNameOf(type)), baseType: type.Base != null ? metadataContainer.MetadataResolver.HandleOf(type.Base) : default, @@ -133,7 +132,8 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) public static string TypeNameOf(IBasicType type) { var typeName = type.Name; - if (type.IsGenericType()) + var isGenericType = type.GenericType == null && type.GenericParameterCount > 0; + if (isGenericType) { if (type.ContainingType != null) { diff --git a/MetadataGenerator/Metadata/MetadataContainer.cs b/MetadataGenerator/MetadataContainer.cs similarity index 94% rename from MetadataGenerator/Metadata/MetadataContainer.cs rename to MetadataGenerator/MetadataContainer.cs index 4a1fc8b2..15ff665f 100644 --- a/MetadataGenerator/Metadata/MetadataContainer.cs +++ b/MetadataGenerator/MetadataContainer.cs @@ -2,14 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using Model; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -using static MetadataGenerator.Metadata.AttributesProvider; +using static MetadataGenerator.AttributesProvider; using Assembly = Model.Assembly; -namespace MetadataGenerator.Metadata +namespace MetadataGenerator { internal class MetadataContainer { @@ -19,9 +18,9 @@ internal class MetadataContainer public readonly SRM.BlobBuilder MappedFieldData; private SRM.MethodDefinitionHandle? mainMethodHandle; private SRM.ModuleDefinitionHandle? moduleHandle; - private readonly ISet genericParameterRows = new HashSet(); - private readonly ISet nestedTypeRows = new HashSet(); - private readonly ISet interfaceImplementationRows = new HashSet(); + private readonly ISet genericParameterRows; + private readonly ISet nestedTypeRows; + private readonly ISet interfaceImplementationRows; public SRM.MethodDefinitionHandle MainMethodHandle { @@ -49,6 +48,9 @@ public MetadataContainer(Assembly assembly) MethodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); MetadataResolver = new MetadataResolver(this, assembly); MappedFieldData = new SRM.BlobBuilder(); + genericParameterRows = new HashSet(); + nestedTypeRows = new HashSet(); + interfaceImplementationRows = new HashSet(); } public void RegisterGenericParameter(SRM.TypeDefinitionHandle parent, GenericParameter genericParameter) => @@ -60,10 +62,10 @@ public void RegisterGenericParameter(SRM.MethodDefinitionHandle parent, GenericP private void DoRegisterGenericParameter(SRM.EntityHandle parent, GenericParameter genericParameter) => genericParameterRows.Add(new GenericParamRow( parent, - GetGenericParameterAttributesFor(genericParameter), + AttributesFor(genericParameter), MetadataBuilder.GetOrAddString(genericParameter.Name), genericParameter.Index, - genericParameter.Constraints.Select(type => MetadataResolver.HandleOf(type)).ToSet() + Model.Extensions.ToSet(genericParameter.Constraints.Select(type => MetadataResolver.HandleOf(type))) )); public void GenerateGenericParameters() => @@ -105,6 +107,7 @@ public void GenerateInterfaceImplementations() => .ForEach(row => MetadataBuilder.AddInterfaceImplementation(row.Type, row.ImplementedInterface)); #region Rows + private class InterfaceImplementationRow { public readonly SRM.TypeDefinitionHandle Type; diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index b0f0c9ff..0db47607 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -26,6 +26,7 @@ + @@ -36,14 +37,13 @@ - - - + + @@ -63,7 +63,6 @@ - diff --git a/MetadataGenerator/Metadata/MetadataResolver.cs b/MetadataGenerator/MetadataResolver.cs similarity index 99% rename from MetadataGenerator/Metadata/MetadataResolver.cs rename to MetadataGenerator/MetadataResolver.cs index 7c9c5932..8d1ef69d 100644 --- a/MetadataGenerator/Metadata/MetadataResolver.cs +++ b/MetadataGenerator/MetadataResolver.cs @@ -11,7 +11,7 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Metadata +namespace MetadataGenerator { internal class MetadataResolver { diff --git a/Model/IGenerator.cs b/Model/IGenerator.cs index d7e3ae42..7ada7ccd 100644 --- a/Model/IGenerator.cs +++ b/Model/IGenerator.cs @@ -4,4 +4,4 @@ public interface IGenerator { void Generate(Assembly assembly); } -} +} \ No newline at end of file From 90561701ee61cd6853f166a71c2b51e039e1a87c Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 30 Aug 2020 14:53:20 -0300 Subject: [PATCH 243/256] refactor --- Console/Program.cs | 5 +- MetadataGenerator/AttributesProvider.cs | 2 +- .../AssemblyGenerator.cs | 26 +-- .../CustomAttributeGenerator.cs | 6 +- .../Fields/FieldGenerator.cs | 4 +- .../Fields/FieldSignatureGenerator.cs | 2 +- .../Generation/GenericParameterGenerator.cs | 85 +++++++ .../Body/MethodBodyControlFlowGenerator.cs | 2 +- .../Methods/Body/MethodBodyGenerator.cs | 3 +- .../Body/MethodLocalsSignatureGenerator.cs | 2 +- .../Methods/MethodGenerator.cs | 6 +- .../Methods/MethodParametersGenerator.cs | 4 +- .../Methods/MethodSignatureGenerator.cs | 2 +- .../Generation/ModuleGenerator.cs | 30 +++ .../NamespaceGenerator.cs | 7 +- .../PropertyGenerator.cs | 5 +- .../Types/InterfaceImplementationGenerator.cs | 30 +++ .../Generation/Types/NestedTypeGenerator.cs | 29 +++ .../Types}/TypeGenerator.cs | 60 ++--- MetadataGenerator/Generator.cs | 2 +- MetadataGenerator/MetadataContainer.cs | 214 +----------------- MetadataGenerator/MetadataGenerator.csproj | 38 ++-- MetadataGenerator/MetadataResolver.cs | 8 +- 23 files changed, 279 insertions(+), 293 deletions(-) rename MetadataGenerator/{Generators => Generation}/AssemblyGenerator.cs (57%) rename MetadataGenerator/{Generators => Generation}/CustomAttributeGenerator.cs (98%) rename MetadataGenerator/{Generators => Generation}/Fields/FieldGenerator.cs (95%) rename MetadataGenerator/{Generators => Generation}/Fields/FieldSignatureGenerator.cs (93%) create mode 100644 MetadataGenerator/Generation/GenericParameterGenerator.cs rename MetadataGenerator/{Generators => Generation}/Methods/Body/MethodBodyControlFlowGenerator.cs (98%) rename MetadataGenerator/{Generators => Generation}/Methods/Body/MethodBodyGenerator.cs (99%) rename MetadataGenerator/{Generators => Generation}/Methods/Body/MethodLocalsSignatureGenerator.cs (96%) rename MetadataGenerator/{Generators => Generation}/Methods/MethodGenerator.cs (95%) rename MetadataGenerator/{Generators => Generation}/Methods/MethodParametersGenerator.cs (91%) rename MetadataGenerator/{Generators => Generation}/Methods/MethodSignatureGenerator.cs (98%) create mode 100644 MetadataGenerator/Generation/ModuleGenerator.cs rename MetadataGenerator/{Generators => Generation}/NamespaceGenerator.cs (81%) rename MetadataGenerator/{Generators => Generation}/PropertyGenerator.cs (93%) create mode 100644 MetadataGenerator/Generation/Types/InterfaceImplementationGenerator.cs create mode 100644 MetadataGenerator/Generation/Types/NestedTypeGenerator.cs rename MetadataGenerator/{Generators => Generation/Types}/TypeGenerator.cs (75%) diff --git a/Console/Program.cs b/Console/Program.cs index cc949ae6..820bca8a 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -456,7 +456,6 @@ where m.Name.Equals("Main") var bytecode = new Backend.Transformations.Assembly.Assembler(main).Execute(); main.Body = bytecode; - var generator = new MetadataGenerator.Generator(); foreach (var assembly in host.Assemblies) @@ -651,8 +650,8 @@ from m in t.Members.OfType() static void Main(string[] args) { - // ReadAndGenerateDll(false); - ReadAndGenerateDll(true); + ReadAndGenerateDll(false); + // ReadAndGenerateDll(true); // TacInstrumentation(); // HelloWorldAssembly(); // RemoveUnusedMethodFromSimpleExecutable(); diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/AttributesProvider.cs index 585d62cd..ccf28f80 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/AttributesProvider.cs @@ -4,7 +4,7 @@ namespace MetadataGenerator { - public static class AttributesProvider + internal static class AttributesProvider { public static TypeAttributes AttributesFor(TypeDefinition typeDefinition) { diff --git a/MetadataGenerator/Generators/AssemblyGenerator.cs b/MetadataGenerator/Generation/AssemblyGenerator.cs similarity index 57% rename from MetadataGenerator/Generators/AssemblyGenerator.cs rename to MetadataGenerator/Generation/AssemblyGenerator.cs index d783cd2b..ca8a76ae 100644 --- a/MetadataGenerator/Generators/AssemblyGenerator.cs +++ b/MetadataGenerator/Generation/AssemblyGenerator.cs @@ -1,8 +1,8 @@ -using System; -using Model; +using MetadataGenerator.Generation.Types; +using Assembly = Model.Assembly; using SR = System.Reflection; -namespace MetadataGenerator.Generators +namespace MetadataGenerator.Generation { internal static class AssemblyGenerator { @@ -10,25 +10,19 @@ public static MetadataContainer Generate(Assembly assembly) { var metadataContainer = new MetadataContainer(assembly); var namespaceGenerator = new NamespaceGenerator(metadataContainer); + var moduleGenerator = new ModuleGenerator(metadataContainer); var metadataBuilder = metadataContainer.MetadataBuilder; metadataBuilder.AddAssembly( name: metadataBuilder.GetOrAddString(assembly.Name), version: assembly.Version, - culture: metadataContainer.MetadataBuilder.GetOrAddString(assembly.Culture), - publicKey: metadataContainer.MetadataBuilder.GetOrAddBlob(assembly.PublicKey), + culture: metadataBuilder.GetOrAddString(assembly.Culture), + publicKey: metadataBuilder.GetOrAddBlob(assembly.PublicKey), flags: SR.AssemblyFlags.PublicKey, hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1 ); - var moduleName = $"{assembly.Name}.{(assembly.Kind == AssemblyKind.Exe ? "exe" : "dll")}"; - metadataContainer.ModuleHandle = metadataBuilder.AddModule( - generation: 0, - moduleName: metadataBuilder.GetOrAddString(moduleName), - mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), - encId: default, - encBaseId: default); - + moduleGenerator.GenerateModuleFor(assembly); namespaceGenerator.Generate(assembly.RootNamespace); /* @@ -36,9 +30,9 @@ public static MetadataContainer Generate(Assembly assembly) * particular order, the info needed to load this tables is stored during type/method generation but not added to the MetadataBuilder * until now where they can be previously sorted */ - metadataContainer.GenerateInterfaceImplementations(); - metadataContainer.GenerateGenericParameters(); - metadataContainer.GenerateNestedTypes(); + InterfaceImplementationGenerator.GenerateInterfaceImplementations(metadataContainer); + GenericParameterGenerator.GenerateGenericParameters(metadataContainer); + NestedTypeGenerator.GenerateNestedTypes(metadataContainer); return metadataContainer; } diff --git a/MetadataGenerator/Generators/CustomAttributeGenerator.cs b/MetadataGenerator/Generation/CustomAttributeGenerator.cs similarity index 98% rename from MetadataGenerator/Generators/CustomAttributeGenerator.cs rename to MetadataGenerator/Generation/CustomAttributeGenerator.cs index c70fe5d6..60718b6d 100644 --- a/MetadataGenerator/Generators/CustomAttributeGenerator.cs +++ b/MetadataGenerator/Generation/CustomAttributeGenerator.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Immutable; using Model; -using Model.ThreeAddressCode.Values; using Model.Types; +using Constant = Model.ThreeAddressCode.Values.Constant; +using CustomAttribute = Model.Types.CustomAttribute; using ECMA335 = System.Reflection.Metadata.Ecma335; -using SR = System.Reflection; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators +namespace MetadataGenerator.Generation { internal class CustomAttributeGenerator { diff --git a/MetadataGenerator/Generators/Fields/FieldGenerator.cs b/MetadataGenerator/Generation/Fields/FieldGenerator.cs similarity index 95% rename from MetadataGenerator/Generators/Fields/FieldGenerator.cs rename to MetadataGenerator/Generation/Fields/FieldGenerator.cs index 89988250..2444f9c8 100644 --- a/MetadataGenerator/Generators/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generation/Fields/FieldGenerator.cs @@ -1,9 +1,9 @@ using System.Reflection.PortableExecutable; -using Model.Types; using static MetadataGenerator.AttributesProvider; +using FieldDefinition = Model.Types.FieldDefinition; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators.Fields +namespace MetadataGenerator.Generation.Fields { internal class FieldGenerator { diff --git a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs b/MetadataGenerator/Generation/Fields/FieldSignatureGenerator.cs similarity index 93% rename from MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs rename to MetadataGenerator/Generation/Fields/FieldSignatureGenerator.cs index a60cc6ee..df29378f 100644 --- a/MetadataGenerator/Generators/Fields/FieldSignatureGenerator.cs +++ b/MetadataGenerator/Generation/Fields/FieldSignatureGenerator.cs @@ -2,7 +2,7 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators.Fields +namespace MetadataGenerator.Generation.Fields { internal class FieldSignatureGenerator { diff --git a/MetadataGenerator/Generation/GenericParameterGenerator.cs b/MetadataGenerator/Generation/GenericParameterGenerator.cs new file mode 100644 index 00000000..768b4a51 --- /dev/null +++ b/MetadataGenerator/Generation/GenericParameterGenerator.cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Model; +using Model.Types; +using static MetadataGenerator.AttributesProvider; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generation +{ + internal static class GenericParameterGenerator + { + // GenericParam Table (0x2A) + public static void GenerateGenericParameters(MetadataContainer metadataContainer) => + metadataContainer + .GenericParameterEntries + .Select(entry => + { + var genericParameter = entry.GenericParameter; + var constraints = genericParameter.Constraints + .Select(type => metadataContainer.MetadataResolver.HandleOf(type)) + .ToSet(); + return new GenericParamRow( + entry.Parent, + AttributesFor(genericParameter), + metadataContainer.MetadataBuilder.GetOrAddString(genericParameter.Name), + genericParameter.Index, + constraints + ); + }) + .OrderBy(row => ECMA335.CodedIndex.TypeOrMethodDef(row.Parent)) + .ThenBy(row => row.Index) + .ToList() + .ForEach(row => + { + var genericParameterHandle = metadataContainer.MetadataBuilder.AddGenericParameter( + row.Parent, + row.Attributes, + row.Name, + row.Index + ); + + foreach (var constraint in row.Constraints) + { + metadataContainer.MetadataBuilder.AddGenericParameterConstraint(genericParameterHandle, constraint); + } + }); + + private class GenericParamRow + { + public readonly SRM.EntityHandle Parent; + public readonly GenericParameterAttributes Attributes; + public readonly SRM.StringHandle Name; + public readonly ushort Index; + public readonly ISet Constraints; + + public GenericParamRow( + SRM.EntityHandle parent, + GenericParameterAttributes attributes, + SRM.StringHandle name, + ushort index, + ISet constraints) + { + Parent = parent; + Attributes = attributes; + Name = name; + Index = index; + Constraints = constraints; + } + } + + public class GenericParameterEntry + { + public readonly SRM.EntityHandle Parent; + public readonly GenericParameter GenericParameter; + + public GenericParameterEntry(SRM.EntityHandle parent, GenericParameter genericParameter) + { + Parent = parent; + GenericParameter = genericParameter; + } + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlowGenerator.cs similarity index 98% rename from MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs rename to MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlowGenerator.cs index b7fc5ec8..a4f6a953 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlowGenerator.cs @@ -3,7 +3,7 @@ using Model.Bytecode; using ECMA335 = System.Reflection.Metadata.Ecma335; -namespace MetadataGenerator.Generators.Methods.Body +namespace MetadataGenerator.Generation.Methods.Body { internal class MethodBodyControlFlowGenerator { diff --git a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyGenerator.cs similarity index 99% rename from MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs rename to MetadataGenerator/Generation/Methods/Body/MethodBodyGenerator.cs index f7bd8866..97840c52 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyGenerator.cs @@ -6,10 +6,11 @@ using Model.Bytecode.Visitor; using Model.ThreeAddressCode.Values; using Model.Types; +using Constant = Model.ThreeAddressCode.Values.Constant; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators.Methods.Body +namespace MetadataGenerator.Generation.Methods.Body { internal class MethodBodyGenerator : IInstructionVisitor { diff --git a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs b/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureGenerator.cs similarity index 96% rename from MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs rename to MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureGenerator.cs index 9219dff9..f965da58 100644 --- a/MetadataGenerator/Generators/Methods/Body/MethodLocalsSignatureGenerator.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureGenerator.cs @@ -3,7 +3,7 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators.Methods.Body +namespace MetadataGenerator.Generation.Methods.Body { internal class MethodLocalsSignatureGenerator { diff --git a/MetadataGenerator/Generators/Methods/MethodGenerator.cs b/MetadataGenerator/Generation/Methods/MethodGenerator.cs similarity index 95% rename from MetadataGenerator/Generators/Methods/MethodGenerator.cs rename to MetadataGenerator/Generation/Methods/MethodGenerator.cs index 3f67da3f..8676a74c 100644 --- a/MetadataGenerator/Generators/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodGenerator.cs @@ -1,11 +1,11 @@ -using MetadataGenerator.Generators.Methods.Body; -using Model.Types; +using MetadataGenerator.Generation.Methods.Body; using static MetadataGenerator.AttributesProvider; using ECMA335 = System.Reflection.Metadata.Ecma335; +using MethodDefinition = Model.Types.MethodDefinition; using SR = System.Reflection; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators.Methods +namespace MetadataGenerator.Generation.Methods { internal class MethodGenerator { diff --git a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs b/MetadataGenerator/Generation/Methods/MethodParametersGenerator.cs similarity index 91% rename from MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs rename to MetadataGenerator/Generation/Methods/MethodParametersGenerator.cs index bdd77271..1c30cd94 100644 --- a/MetadataGenerator/Generators/Methods/MethodParametersGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodParametersGenerator.cs @@ -1,11 +1,9 @@ using System.Collections.Generic; using Model.Types; -using ECMA335 = System.Reflection.Metadata.Ecma335; -using SR = System.Reflection; using SRM = System.Reflection.Metadata; using static MetadataGenerator.AttributesProvider; -namespace MetadataGenerator.Generators.Methods +namespace MetadataGenerator.Generation.Methods { internal class MethodParametersGenerator { diff --git a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generation/Methods/MethodSignatureGenerator.cs similarity index 98% rename from MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs rename to MetadataGenerator/Generation/Methods/MethodSignatureGenerator.cs index bf71a6d8..4089049c 100644 --- a/MetadataGenerator/Generators/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodSignatureGenerator.cs @@ -3,7 +3,7 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators.Methods +namespace MetadataGenerator.Generation.Methods { internal class MethodSignatureGenerator { diff --git a/MetadataGenerator/Generation/ModuleGenerator.cs b/MetadataGenerator/Generation/ModuleGenerator.cs new file mode 100644 index 00000000..7d554a14 --- /dev/null +++ b/MetadataGenerator/Generation/ModuleGenerator.cs @@ -0,0 +1,30 @@ +using System; +using Model; + +namespace MetadataGenerator.Generation +{ + internal class ModuleGenerator + { + private readonly MetadataContainer metadataContainer; + + public ModuleGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public void GenerateModuleFor(Assembly assembly) + { + var extension = assembly.Kind == AssemblyKind.Exe ? "exe" : "dll"; + var moduleName = $"{assembly.Name}.{extension}"; + var metadataBuilder = metadataContainer.MetadataBuilder; + + // Module Table (0x00) + metadataContainer.ModuleHandle = metadataBuilder.AddModule( + generation: 0, + moduleName: metadataBuilder.GetOrAddString(moduleName), + mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), + encId: default, + encBaseId: default); + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/NamespaceGenerator.cs b/MetadataGenerator/Generation/NamespaceGenerator.cs similarity index 81% rename from MetadataGenerator/Generators/NamespaceGenerator.cs rename to MetadataGenerator/Generation/NamespaceGenerator.cs index 3cbc86fc..836457aa 100644 --- a/MetadataGenerator/Generators/NamespaceGenerator.cs +++ b/MetadataGenerator/Generation/NamespaceGenerator.cs @@ -1,9 +1,11 @@ using System.Linq; +using MetadataGenerator.Generation.Types; using Model; using Model.Types; +using static MetadataGenerator.Generation.Types.NestedTypeGenerator; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators +namespace MetadataGenerator.Generation { internal class NamespaceGenerator { @@ -32,11 +34,10 @@ public void Generate(Namespace namezpace) private SRM.TypeDefinitionHandle GenerateTypes(TypeDefinition type) { var nestedTypes = type.Types.Select(GenerateTypes).ToList(); - var typeDefinitionHandle = typeGenerator.Generate(type); foreach (var nestedType in nestedTypes) { - metadataContainer.RegisterNestedType(nestedType, typeDefinitionHandle); + metadataContainer.NestedTypeEntries.Add(new NestedTypeEntry(nestedType, typeDefinitionHandle)); } return typeDefinitionHandle; diff --git a/MetadataGenerator/Generators/PropertyGenerator.cs b/MetadataGenerator/Generation/PropertyGenerator.cs similarity index 93% rename from MetadataGenerator/Generators/PropertyGenerator.cs rename to MetadataGenerator/Generation/PropertyGenerator.cs index e4de145c..88affe4f 100644 --- a/MetadataGenerator/Generators/PropertyGenerator.cs +++ b/MetadataGenerator/Generation/PropertyGenerator.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; -using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; +using MethodDefinition = Model.Types.MethodDefinition; +using PropertyDefinition = Model.Types.PropertyDefinition; using SR = System.Reflection; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators +namespace MetadataGenerator.Generation { internal class PropertyGenerator { diff --git a/MetadataGenerator/Generation/Types/InterfaceImplementationGenerator.cs b/MetadataGenerator/Generation/Types/InterfaceImplementationGenerator.cs new file mode 100644 index 00000000..ba1c3285 --- /dev/null +++ b/MetadataGenerator/Generation/Types/InterfaceImplementationGenerator.cs @@ -0,0 +1,30 @@ +using System.Linq; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generation.Types +{ + internal static class InterfaceImplementationGenerator + { + // InterfaceImpl Table (0x09) + public static void GenerateInterfaceImplementations(MetadataContainer metadataContainer) => + metadataContainer + .InterfaceImplementationEntries + .OrderBy(entry => ECMA335.CodedIndex.TypeDefOrRef(entry.Type)) + .ThenBy(entry => ECMA335.CodedIndex.TypeDefOrRefOrSpec(entry.ImplementedInterface)) + .ToList() + .ForEach(entry => metadataContainer.MetadataBuilder.AddInterfaceImplementation(entry.Type, entry.ImplementedInterface)); + + public class InterfaceImplementationEntry + { + public readonly SRM.TypeDefinitionHandle Type; + public readonly SRM.EntityHandle ImplementedInterface; + + public InterfaceImplementationEntry(SRM.TypeDefinitionHandle type, SRM.EntityHandle implementedInterface) + { + Type = type; + ImplementedInterface = implementedInterface; + } + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generation/Types/NestedTypeGenerator.cs b/MetadataGenerator/Generation/Types/NestedTypeGenerator.cs new file mode 100644 index 00000000..33520c36 --- /dev/null +++ b/MetadataGenerator/Generation/Types/NestedTypeGenerator.cs @@ -0,0 +1,29 @@ +using System.Linq; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generation.Types +{ + internal static class NestedTypeGenerator + { + // NestedClass Table (0x29) + public static void GenerateNestedTypes(MetadataContainer metadataContainer) => + metadataContainer + .NestedTypeEntries + .OrderBy(entry => ECMA335.CodedIndex.TypeDefOrRef(entry.Type)) + .ToList() + .ForEach(entry => metadataContainer.MetadataBuilder.AddNestedType(entry.Type, entry.EnclosingType)); + + public class NestedTypeEntry + { + public readonly SRM.TypeDefinitionHandle Type; + public readonly SRM.TypeDefinitionHandle EnclosingType; + + public NestedTypeEntry(SRM.TypeDefinitionHandle type, SRM.TypeDefinitionHandle enclosingType) + { + Type = type; + EnclosingType = enclosingType; + } + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generators/TypeGenerator.cs b/MetadataGenerator/Generation/Types/TypeGenerator.cs similarity index 75% rename from MetadataGenerator/Generators/TypeGenerator.cs rename to MetadataGenerator/Generation/Types/TypeGenerator.cs index 0bd8417f..2b62a262 100644 --- a/MetadataGenerator/Generators/TypeGenerator.cs +++ b/MetadataGenerator/Generation/Types/TypeGenerator.cs @@ -1,15 +1,16 @@ using System.Collections.Generic; using System.Linq; -using MetadataGenerator.Generators.Fields; -using MetadataGenerator.Generators.Methods; -using MetadataGenerator.Generators.Methods.Body; +using MetadataGenerator.Generation.Fields; +using MetadataGenerator.Generation.Methods; +using MetadataGenerator.Generation.Methods.Body; using Model.Types; using static MetadataGenerator.AttributesProvider; +using static MetadataGenerator.Generation.GenericParameterGenerator; +using static MetadataGenerator.Generation.Types.InterfaceImplementationGenerator; using ECMA335 = System.Reflection.Metadata.Ecma335; -using SR = System.Reflection; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generators +namespace MetadataGenerator.Generation.Types { internal class TypeGenerator { @@ -31,74 +32,79 @@ public TypeGenerator(MetadataContainer metadataContainer) public SRM.TypeDefinitionHandle Generate(TypeDefinition type) { var methodDefinitionHandles = new List(); - var metadataBuilder = metadataContainer.MetadataBuilder; - var fieldDefinitionHandles = type.Fields.Select(field => fieldGenerator.Generate(field)).ToList(); var methodDefToHandle = new Dictionary(); var methodOverrides = new List(); + var metadataBuilder = metadataContainer.MetadataBuilder; + var metadataResolver = metadataContainer.MetadataResolver; + + var fieldDefinitionHandles = type + .Fields + .Select(field => fieldGenerator.Generate(field)) + .ToList(); foreach (var method in type.Methods) { - var methodHandle = methodGenerator.Generate(method); - methodDefinitionHandles.Add(methodHandle); + var methodDefinitionHandle = methodGenerator.Generate(method); + methodDefinitionHandles.Add(methodDefinitionHandle); if (method.OverridenMethod != null) { - methodOverrides.Add(new MethodOverride( - methodHandle, - metadataContainer.MetadataResolver.HandleOf(method.OverridenMethod))); + methodOverrides.Add( + new MethodOverride(methodDefinitionHandle, metadataResolver.HandleOf(method.OverridenMethod))); } if (method.Name.Equals("Main")) { - metadataContainer.MainMethodHandle = methodHandle; + metadataContainer.MainMethodHandle = methodDefinitionHandle; } - methodDefToHandle.Add(method, methodHandle); + methodDefToHandle.Add(method, methodDefinitionHandle); } var nextFieldDefinitionHandle = ECMA335.MetadataTokens.FieldDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.Field)); var nextMethodDefinitionHandle = ECMA335.MetadataTokens.MethodDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.MethodDef)); + // TypeDef Table (0x02) var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( attributes: AttributesFor(type), @namespace: metadataBuilder.GetOrAddString(type.ContainingNamespace.FullName), name: metadataBuilder.GetOrAddString(TypeNameOf(type)), - baseType: type.Base != null ? metadataContainer.MetadataResolver.HandleOf(type.Base) : default, + baseType: type.Base != null ? metadataResolver.HandleOf(type.Base) : default, fieldList: fieldDefinitionHandles.FirstOr(nextFieldDefinitionHandle), methodList: methodDefinitionHandles.FirstOr(nextMethodDefinitionHandle)); - var firstPropertyDefinitionHandle = type.PropertyDefinitions + var propertyDefinitionHandles = type.PropertyDefinitions .Select(property => propertyGenerator.Generate(property, methodDefToHandle)) - .ToList() - .FirstOrDefault(); + .ToList(); - if (!firstPropertyDefinitionHandle.IsNil) + if (propertyDefinitionHandles.Count > 0) { - metadataContainer.MetadataBuilder.AddPropertyMap(typeDefinitionHandle, firstPropertyDefinitionHandle); + // PropertyMap Table (0x15) + metadataBuilder.AddPropertyMap(typeDefinitionHandle, propertyDefinitionHandles.First()); } foreach (var interfaze in type.Interfaces) { - metadataContainer.RegisterInterfaceImplementation(typeDefinitionHandle, metadataContainer.MetadataResolver.HandleOf(interfaze)); + metadataContainer.InterfaceImplementationEntries.Add(new InterfaceImplementationEntry( + typeDefinitionHandle, + metadataResolver.HandleOf(interfaze))); } - // generate class generic parameters (Class) foreach (var genericParameter in type.GenericParameters) { - metadataContainer.RegisterGenericParameter(typeDefinitionHandle, genericParameter); + metadataContainer.GenericParameterEntries.Add(new GenericParameterEntry(typeDefinitionHandle, genericParameter)); } - // generate method generic parameters (public T method(T param)) for (var i = 0; i < type.Methods.Count; i++) { var method = type.Methods[i]; foreach (var genericParameter in method.GenericParameters) { - metadataContainer.RegisterGenericParameter(methodDefinitionHandles[i], genericParameter); + metadataContainer.GenericParameterEntries.Add(new GenericParameterEntry(methodDefinitionHandles[i], genericParameter)); } } foreach (var methodOverride in methodOverrides) { - metadataContainer.MetadataBuilder.AddMethodImplementation( + metadataBuilder.AddMethodImplementation( typeDefinitionHandle, methodOverride.methodImplementation, methodOverride.overridenMethod @@ -107,7 +113,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) if (type.LayoutInformation.SpecifiesSizes()) { - metadataContainer.MetadataBuilder.AddTypeLayout( + metadataBuilder.AddTypeLayout( typeDefinitionHandle, (ushort) type.LayoutInformation.PackingSize, (uint) type.LayoutInformation.ClassSize); diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index a385bc0f..427e8f4f 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -1,6 +1,6 @@ using System; using System.IO; -using MetadataGenerator.Generators; +using MetadataGenerator.Generation; using Model; using static Model.AssemblyKind; using ECMA335 = System.Reflection.Metadata.Ecma335; diff --git a/MetadataGenerator/MetadataContainer.cs b/MetadataGenerator/MetadataContainer.cs index 15ff665f..579158f1 100644 --- a/MetadataGenerator/MetadataContainer.cs +++ b/MetadataGenerator/MetadataContainer.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Model.Types; +using Model; +using static MetadataGenerator.Generation.GenericParameterGenerator; +using static MetadataGenerator.Generation.Types.InterfaceImplementationGenerator; +using static MetadataGenerator.Generation.Types.NestedTypeGenerator; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -using static MetadataGenerator.AttributesProvider; -using Assembly = Model.Assembly; namespace MetadataGenerator { @@ -16,18 +15,18 @@ internal class MetadataContainer public readonly MetadataResolver MetadataResolver; public readonly ECMA335.MethodBodyStreamEncoder MethodBodyStream; public readonly SRM.BlobBuilder MappedFieldData; + public readonly ISet GenericParameterEntries; + public readonly ISet InterfaceImplementationEntries; + public readonly ISet NestedTypeEntries; private SRM.MethodDefinitionHandle? mainMethodHandle; private SRM.ModuleDefinitionHandle? moduleHandle; - private readonly ISet genericParameterRows; - private readonly ISet nestedTypeRows; - private readonly ISet interfaceImplementationRows; public SRM.MethodDefinitionHandle MainMethodHandle { get => mainMethodHandle ?? throw new Exception("Main method handle was not set"); set { - if (mainMethodHandle != null) throw new Exception("Assembly has more than one main method"); + if (mainMethodHandle != null) throw new Exception("Main method was already set"); mainMethodHandle = value; } } @@ -48,200 +47,9 @@ public MetadataContainer(Assembly assembly) MethodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); MetadataResolver = new MetadataResolver(this, assembly); MappedFieldData = new SRM.BlobBuilder(); - genericParameterRows = new HashSet(); - nestedTypeRows = new HashSet(); - interfaceImplementationRows = new HashSet(); + GenericParameterEntries = new HashSet(); + InterfaceImplementationEntries = new HashSet(); + NestedTypeEntries = new HashSet(); } - - public void RegisterGenericParameter(SRM.TypeDefinitionHandle parent, GenericParameter genericParameter) => - DoRegisterGenericParameter(parent, genericParameter); - - public void RegisterGenericParameter(SRM.MethodDefinitionHandle parent, GenericParameter genericParameter) => - DoRegisterGenericParameter(parent, genericParameter); - - private void DoRegisterGenericParameter(SRM.EntityHandle parent, GenericParameter genericParameter) => - genericParameterRows.Add(new GenericParamRow( - parent, - AttributesFor(genericParameter), - MetadataBuilder.GetOrAddString(genericParameter.Name), - genericParameter.Index, - Model.Extensions.ToSet(genericParameter.Constraints.Select(type => MetadataResolver.HandleOf(type))) - )); - - public void GenerateGenericParameters() => - genericParameterRows - .OrderBy(row => ECMA335.CodedIndex.TypeOrMethodDef(row.Parent)) - .ThenBy(row => row.Index) - .ToList() - .ForEach(row => - { - var genericParameterHandle = MetadataBuilder.AddGenericParameter( - row.Parent, - row.Attributes, - row.Name, - row.Index - ); - foreach (var constraint in row.Constraints) - { - MetadataBuilder.AddGenericParameterConstraint(genericParameterHandle, constraint); - } - }); - - public void RegisterNestedType(SRM.TypeDefinitionHandle type, SRM.TypeDefinitionHandle enclosingType) => - nestedTypeRows.Add(new NestedTypeRow(type, enclosingType)); - - public void GenerateNestedTypes() => - nestedTypeRows - .OrderBy(row => ECMA335.CodedIndex.TypeDefOrRef(row.Type)) - .ToList() - .ForEach(row => MetadataBuilder.AddNestedType(row.Type, row.EnclosingType)); - - public void RegisterInterfaceImplementation(SRM.TypeDefinitionHandle type, SRM.EntityHandle implementedInterface) => - interfaceImplementationRows.Add(new InterfaceImplementationRow(type, implementedInterface)); - - public void GenerateInterfaceImplementations() => - interfaceImplementationRows - .OrderBy(row => ECMA335.CodedIndex.TypeDefOrRef(row.Type)) - .ThenBy(row => ECMA335.CodedIndex.TypeDefOrRefOrSpec(row.ImplementedInterface)) - .ToList() - .ForEach(row => MetadataBuilder.AddInterfaceImplementation(row.Type, row.ImplementedInterface)); - - #region Rows - - private class InterfaceImplementationRow - { - public readonly SRM.TypeDefinitionHandle Type; - public readonly SRM.EntityHandle ImplementedInterface; - - public InterfaceImplementationRow(SRM.TypeDefinitionHandle type, SRM.EntityHandle implementedInterface) - { - Type = type; - ImplementedInterface = implementedInterface; - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - var other = (InterfaceImplementationRow) obj; - return Type.Equals(other.Type) && ImplementedInterface.Equals(other.ImplementedInterface); - } - - public override int GetHashCode() - { - unchecked - { - return (Type.GetHashCode() * 397) ^ ImplementedInterface.GetHashCode(); - } - } - - public static bool operator ==(InterfaceImplementationRow left, InterfaceImplementationRow right) - { - return Equals(left, right); - } - - public static bool operator !=(InterfaceImplementationRow left, InterfaceImplementationRow right) - { - return !Equals(left, right); - } - } - - private class GenericParamRow - { - public readonly SRM.EntityHandle Parent; - public readonly GenericParameterAttributes Attributes; - public readonly SRM.StringHandle Name; - public readonly ushort Index; - public readonly ISet Constraints; - - public GenericParamRow( - SRM.EntityHandle parent, - GenericParameterAttributes attributes, - SRM.StringHandle name, - ushort index, - ISet constraints) - { - Parent = parent; - Attributes = attributes; - Name = name; - Index = index; - Constraints = constraints; - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - GenericParamRow other = (GenericParamRow) obj; - return Parent.Equals(other.Parent) && Attributes == other.Attributes && Name.Equals(other.Name) && Index == other.Index && - Equals(Constraints, other.Constraints); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = Parent.GetHashCode(); - hashCode = (hashCode * 397) ^ (int) Attributes; - hashCode = (hashCode * 397) ^ Name.GetHashCode(); - hashCode = (hashCode * 397) ^ Index.GetHashCode(); - hashCode = (hashCode * 397) ^ (Constraints != null ? Constraints.GetHashCode() : 0); - return hashCode; - } - } - - public static bool operator ==(GenericParamRow left, GenericParamRow right) - { - return Equals(left, right); - } - - public static bool operator !=(GenericParamRow left, GenericParamRow right) - { - return !Equals(left, right); - } - } - - private class NestedTypeRow - { - public readonly SRM.TypeDefinitionHandle Type; - public readonly SRM.TypeDefinitionHandle EnclosingType; - - public NestedTypeRow(SRM.TypeDefinitionHandle type, SRM.TypeDefinitionHandle enclosingType) - { - Type = type; - EnclosingType = enclosingType; - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - var other = (NestedTypeRow) obj; - return Type.Equals(other.Type) && EnclosingType.Equals(other.EnclosingType); - } - - public override int GetHashCode() - { - unchecked - { - return (Type.GetHashCode() * 397) ^ EnclosingType.GetHashCode(); - } - } - - public static bool operator ==(NestedTypeRow left, NestedTypeRow right) - { - return Equals(left, right); - } - - public static bool operator !=(NestedTypeRow left, NestedTypeRow right) - { - return !Equals(left, right); - } - } - - #endregion } } \ No newline at end of file diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 0db47607..a897d604 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -28,21 +28,25 @@ + + + - - - - - - - - + + + + + + + + + - - - - - + + + + + @@ -61,10 +65,10 @@ - - - - + + + + \ No newline at end of file diff --git a/MetadataGenerator/MetadataResolver.cs b/MetadataGenerator/MetadataResolver.cs index 8d1ef69d..2ea1ff21 100644 --- a/MetadataGenerator/MetadataResolver.cs +++ b/MetadataGenerator/MetadataResolver.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using MetadataGenerator.Generators.Fields; -using MetadataGenerator.Generators.Methods; -using MetadataGenerator.Generators.Methods.Body; +using MetadataGenerator.Generation.Fields; +using MetadataGenerator.Generation.Methods; +using MetadataGenerator.Generation.Methods.Body; using Model; using Model.Types; using static System.Linq.Enumerable; -using static MetadataGenerator.Generators.TypeGenerator; +using static MetadataGenerator.Generation.Types.TypeGenerator; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; From a7bb1f602bb04f5d4b6c8ba39e44df50b93815cd Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 30 Aug 2020 16:57:30 -0300 Subject: [PATCH 244/256] refactor --- .../Generation/Fields/FieldGenerator.cs | 31 ++++++++---- .../Fields/FieldSignatureEncoder.cs | 23 +++++++++ .../Fields/FieldSignatureGenerator.cs | 23 --------- ...dBodyGenerator.cs => MethodBodyEncoder.cs} | 6 +-- .../Body/MethodLocalsSignatureEncoder.cs | 32 +++++++++++++ .../Body/MethodLocalsSignatureGenerator.cs | 35 -------------- .../Generation/Methods/MethodGenerator.cs | 48 ++++++++++++------- .../Methods/MethodParameterGenerator.cs | 31 ++++++++++++ .../Methods/MethodParametersGenerator.cs | 40 ---------------- ...Generator.cs => MethodSignatureEncoder.cs} | 33 ++++++------- .../Generation/Types/TypeGenerator.cs | 7 +-- MetadataGenerator/MetadataGenerator.csproj | 10 ++-- MetadataGenerator/MetadataResolver.cs | 16 +++---- 13 files changed, 175 insertions(+), 160 deletions(-) create mode 100644 MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs delete mode 100644 MetadataGenerator/Generation/Fields/FieldSignatureGenerator.cs rename MetadataGenerator/Generation/Methods/Body/{MethodBodyGenerator.cs => MethodBodyEncoder.cs} (99%) create mode 100644 MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs delete mode 100644 MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureGenerator.cs create mode 100644 MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs delete mode 100644 MetadataGenerator/Generation/Methods/MethodParametersGenerator.cs rename MetadataGenerator/Generation/Methods/{MethodSignatureGenerator.cs => MethodSignatureEncoder.cs} (65%) diff --git a/MetadataGenerator/Generation/Fields/FieldGenerator.cs b/MetadataGenerator/Generation/Fields/FieldGenerator.cs index 2444f9c8..a2ca84a0 100644 --- a/MetadataGenerator/Generation/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generation/Fields/FieldGenerator.cs @@ -1,6 +1,6 @@ using System.Reflection.PortableExecutable; +using Model.Types; using static MetadataGenerator.AttributesProvider; -using FieldDefinition = Model.Types.FieldDefinition; using SRM = System.Reflection.Metadata; namespace MetadataGenerator.Generation.Fields @@ -8,34 +8,47 @@ namespace MetadataGenerator.Generation.Fields internal class FieldGenerator { private readonly MetadataContainer metadataContainer; - private readonly FieldSignatureGenerator fieldSignatureGenerator; + private readonly FieldSignatureEncoder fieldSignatureEncoder; private readonly CustomAttributeGenerator customAttributeGenerator; public FieldGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; - fieldSignatureGenerator = new FieldSignatureGenerator(metadataContainer); + fieldSignatureEncoder = new FieldSignatureEncoder(metadataContainer.MetadataResolver); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } public SRM.FieldDefinitionHandle Generate(FieldDefinition field) { - var fieldSignature = fieldSignatureGenerator.GenerateSignatureOf(field); - var fieldDefinitionHandle = metadataContainer.MetadataBuilder.AddFieldDefinition( + var metadataBuilder = metadataContainer.MetadataBuilder; + var fieldSignature = fieldSignatureEncoder.EncodeSignatureOf(field); + + // Field Table (0x04) + var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( attributes: AttributesFor(field), - name: metadataContainer.MetadataBuilder.GetOrAddString(field.Name), - signature: metadataContainer.MetadataBuilder.GetOrAddBlob(fieldSignature)); + name: metadataBuilder.GetOrAddString(field.Name), + signature: metadataBuilder.GetOrAddBlob(fieldSignature)); + // add initial value if (field.SpecifiesRelativeVirtualAddress) { + /* + * Static fields can define their initial value as a constant stored in the PE File. The value is declared using the .data directive, + * represented as a bytearray and labeled so it can be referenced later. + * + * Initialization of a static array field is an example of this. The field itself does not hold the initial value. + * A special type is created () that has a field that references the value declared with .data. + * It is then used in the constructor of the class that has the static array field to initialize it. + * + */ var offset = metadataContainer.MappedFieldData.Count; metadataContainer.MappedFieldData.WriteBytes((byte[]) field.Value.Value); metadataContainer.MappedFieldData.Align(ManagedPEBuilder.MappedFieldDataAlignment); - metadataContainer.MetadataBuilder.AddFieldRelativeVirtualAddress(fieldDefinitionHandle, offset); + metadataBuilder.AddFieldRelativeVirtualAddress(fieldDefinitionHandle, offset); } else if (field.Value != null) { - metadataContainer.MetadataBuilder.AddConstant(fieldDefinitionHandle, field.Value.Value); + metadataBuilder.AddConstant(fieldDefinitionHandle, field.Value.Value); } foreach (var customAttribute in field.Attributes) diff --git a/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs b/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs new file mode 100644 index 00000000..d46d50ef --- /dev/null +++ b/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs @@ -0,0 +1,23 @@ +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generation.Fields +{ + internal class FieldSignatureEncoder + { + private readonly MetadataResolver metadataResolver; + + public FieldSignatureEncoder(MetadataResolver metadataResolver) + { + this.metadataResolver = metadataResolver; + } + + public SRM.BlobBuilder EncodeSignatureOf(IFieldReference field) + { + var fieldSignature = new SRM.BlobBuilder(); + metadataResolver.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); + return fieldSignature; + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generation/Fields/FieldSignatureGenerator.cs b/MetadataGenerator/Generation/Fields/FieldSignatureGenerator.cs deleted file mode 100644 index df29378f..00000000 --- a/MetadataGenerator/Generation/Fields/FieldSignatureGenerator.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Model.Types; -using ECMA335 = System.Reflection.Metadata.Ecma335; -using SRM = System.Reflection.Metadata; - -namespace MetadataGenerator.Generation.Fields -{ - internal class FieldSignatureGenerator - { - private readonly MetadataContainer metadataContainer; - - public FieldSignatureGenerator(MetadataContainer metadataContainer) - { - this.metadataContainer = metadataContainer; - } - - public SRM.BlobBuilder GenerateSignatureOf(IFieldReference field) - { - var fieldSignature = new SRM.BlobBuilder(); - metadataContainer.MetadataResolver.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); - return fieldSignature; - } - } -} \ No newline at end of file diff --git a/MetadataGenerator/Generation/Methods/Body/MethodBodyGenerator.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs similarity index 99% rename from MetadataGenerator/Generation/Methods/Body/MethodBodyGenerator.cs rename to MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs index 97840c52..18336712 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodBodyGenerator.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs @@ -12,7 +12,7 @@ namespace MetadataGenerator.Generation.Methods.Body { - internal class MethodBodyGenerator : IInstructionVisitor + internal class MethodBodyEncoder : IInstructionVisitor { private readonly MetadataContainer metadataContainer; private readonly ECMA335.InstructionEncoder instructionEncoder; @@ -23,7 +23,7 @@ internal class MethodBodyGenerator : IInstructionVisitor private readonly StackSize stackSize; private int Index { get; set; } - public MethodBodyGenerator(MetadataContainer metadataContainer, MethodBody body) + public MethodBodyEncoder(MetadataContainer metadataContainer, MethodBody body) { this.metadataContainer = metadataContainer; this.body = body; @@ -34,7 +34,7 @@ public MethodBodyGenerator(MetadataContainer metadataContainer, MethodBody body) stackSize = new StackSize(); } - public ECMA335.InstructionEncoder Generate(out int maxStack) + public ECMA335.InstructionEncoder Encode(out int maxStack) { controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); controlFlowGenerator.DefineNeededBranchLabels(body.Instructions); diff --git a/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs b/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs new file mode 100644 index 00000000..6fc8228b --- /dev/null +++ b/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using Model.ThreeAddressCode.Values; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generation.Methods.Body +{ + internal class MethodLocalsSignatureEncoder + { + private readonly MetadataResolver metadataResolver; + + public MethodLocalsSignatureEncoder(MetadataResolver metadataResolver) + { + this.metadataResolver = metadataResolver; + } + + public SRM.BlobBuilder EncodeSignatureOf(IList localVariables) + { + if (localVariables.Count == 0) throw new Exception("No local variables to generate signature for"); + + var signature = new SRM.BlobBuilder(); + var encoder = new ECMA335.BlobEncoder(signature).LocalVariableSignature(localVariables.Count); + foreach (var localVariable in localVariables) + { + metadataResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); + } + + return signature; + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureGenerator.cs b/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureGenerator.cs deleted file mode 100644 index f965da58..00000000 --- a/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureGenerator.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using Model.ThreeAddressCode.Values; -using ECMA335 = System.Reflection.Metadata.Ecma335; -using SRM = System.Reflection.Metadata; - -namespace MetadataGenerator.Generation.Methods.Body -{ - internal class MethodLocalsSignatureGenerator - { - private readonly MetadataContainer metadataContainer; - - public MethodLocalsSignatureGenerator(MetadataContainer metadataContainer) - { - this.metadataContainer = metadataContainer; - } - - public SRM.StandaloneSignatureHandle GenerateSignatureFor(IList localVariables) - { - SRM.StandaloneSignatureHandle localVariablesSignature = default; - if (localVariables.Count > 0) - { - var signature = new SRM.BlobBuilder(); - var encoder = new ECMA335.BlobEncoder(signature).LocalVariableSignature(localVariables.Count); - foreach (var localVariable in localVariables) - { - metadataContainer.MetadataResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); - } - - localVariablesSignature = metadataContainer.MetadataResolver.GetOrAddStandaloneSignature(signature); - } - - return localVariablesSignature; - } - } -} \ No newline at end of file diff --git a/MetadataGenerator/Generation/Methods/MethodGenerator.cs b/MetadataGenerator/Generation/Methods/MethodGenerator.cs index 8676a74c..16b99e55 100644 --- a/MetadataGenerator/Generation/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodGenerator.cs @@ -1,7 +1,8 @@ -using MetadataGenerator.Generation.Methods.Body; +using System.Linq; +using MetadataGenerator.Generation.Methods.Body; +using Model.Types; using static MetadataGenerator.AttributesProvider; using ECMA335 = System.Reflection.Metadata.Ecma335; -using MethodDefinition = Model.Types.MethodDefinition; using SR = System.Reflection; using SRM = System.Reflection.Metadata; @@ -10,53 +11,68 @@ namespace MetadataGenerator.Generation.Methods internal class MethodGenerator { private readonly MetadataContainer metadataContainer; - private readonly MethodSignatureGenerator methodSignatureGenerator; - private readonly MethodLocalsSignatureGenerator methodLocalsSignatureGenerator; - private readonly MethodParametersGenerator methodParametersGenerator; + private readonly MethodSignatureEncoder methodSignatureEncoder; + private readonly MethodLocalsSignatureEncoder methodLocalsSignatureEncoder; + private readonly MethodParameterGenerator methodParameterGenerator; private readonly CustomAttributeGenerator customAttributeGenerator; public MethodGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; - methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); - methodLocalsSignatureGenerator = new MethodLocalsSignatureGenerator(metadataContainer); - methodParametersGenerator = new MethodParametersGenerator(metadataContainer); + methodSignatureEncoder = new MethodSignatureEncoder(metadataContainer.MetadataResolver); + methodLocalsSignatureEncoder = new MethodLocalsSignatureEncoder(metadataContainer.MetadataResolver); + methodParameterGenerator = new MethodParameterGenerator(metadataContainer); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } public SRM.MethodDefinitionHandle Generate(MethodDefinition method) { - var parameters = methodParametersGenerator.Generate(method.Parameters) - ?? ECMA335.MetadataTokens.ParameterHandle(metadataContainer.MetadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); - var methodSignature = methodSignatureGenerator.GenerateSignatureOf(method); - + var methodParameterHandles = method + .Parameters + .Select(parameter => methodParameterGenerator.Generate(parameter)) + .ToList(); + var methodSignature = methodSignatureEncoder.EncodeSignatureOf(method); var methodBodyOffset = -1; if (method.HasBody) { - var instructionEncoder = new MethodBodyGenerator(metadataContainer, method.Body).Generate(out var maxStack); + SRM.StandaloneSignatureHandle localVariablesSignature = default; + if (method.Body.LocalVariables.Count > 0) + { + var signature = methodLocalsSignatureEncoder.EncodeSignatureOf(method.Body.LocalVariables); + localVariablesSignature = metadataContainer.MetadataResolver.GetOrAddStandaloneSignature(signature); + } + + var instructionEncoder = new MethodBodyEncoder(metadataContainer, method.Body).Encode(out var maxStack); methodBodyOffset = metadataContainer.MethodBodyStream.AddMethodBody( instructionEncoder: instructionEncoder, - localVariablesSignature: methodLocalsSignatureGenerator.GenerateSignatureFor(method.Body.LocalVariables), + localVariablesSignature: localVariablesSignature, maxStack: maxStack); } var methodImplementationAttributes = - SR.MethodImplAttributes.IL | + SR.MethodImplAttributes.IL | (!method.HasBody && !method.IsAbstract ? SR.MethodImplAttributes.Runtime : SR.MethodImplAttributes.Managed); + var nextParameterHandle = ECMA335.MetadataTokens.ParameterHandle(metadataContainer.MetadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); + // MethodDef Table (0x06) var methodDefinitionHandle = metadataContainer.MetadataBuilder.AddMethodDefinition( attributes: AttributesFor(method), implAttributes: methodImplementationAttributes, name: metadataContainer.MetadataBuilder.GetOrAddString(method.Name), signature: metadataContainer.MetadataBuilder.GetOrAddBlob(methodSignature), bodyOffset: methodBodyOffset, - parameterList: parameters); + parameterList: methodParameterHandles.FirstOr(nextParameterHandle)); foreach (var customAttribute in method.Attributes) { customAttributeGenerator.Generate(methodDefinitionHandle, customAttribute); } + if (method.Name.Equals("Main")) + { + metadataContainer.MainMethodHandle = methodDefinitionHandle; + } + return methodDefinitionHandle; } } diff --git a/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs b/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs new file mode 100644 index 00000000..09b49afa --- /dev/null +++ b/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs @@ -0,0 +1,31 @@ +using Model.Types; +using SRM = System.Reflection.Metadata; +using static MetadataGenerator.AttributesProvider; + +namespace MetadataGenerator.Generation.Methods +{ + internal class MethodParameterGenerator + { + private readonly MetadataContainer metadataContainer; + + internal MethodParameterGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public SRM.ParameterHandle Generate(MethodParameter methodParameter) + { + // Param Table (0x08) + var parameterHandle = metadataContainer.MetadataBuilder.AddParameter( + attributes: AttributesFor(methodParameter), + name: metadataContainer.MetadataBuilder.GetOrAddString(methodParameter.Name), + sequenceNumber: methodParameter.Index); + if (methodParameter.HasDefaultValue) + { + metadataContainer.MetadataBuilder.AddConstant(parameterHandle, methodParameter.DefaultValue.Value); + } + + return parameterHandle; + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generation/Methods/MethodParametersGenerator.cs b/MetadataGenerator/Generation/Methods/MethodParametersGenerator.cs deleted file mode 100644 index 1c30cd94..00000000 --- a/MetadataGenerator/Generation/Methods/MethodParametersGenerator.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Collections.Generic; -using Model.Types; -using SRM = System.Reflection.Metadata; -using static MetadataGenerator.AttributesProvider; - -namespace MetadataGenerator.Generation.Methods -{ - internal class MethodParametersGenerator - { - private readonly MetadataContainer metadataContainer; - - internal MethodParametersGenerator(MetadataContainer metadataContainer) - { - this.metadataContainer = metadataContainer; - } - - public SRM.ParameterHandle? Generate(IList methodParameters) - { - SRM.ParameterHandle? firstParameterHandle = null; - foreach (var parameter in methodParameters) - { - var parameterHandle = metadataContainer.MetadataBuilder.AddParameter( - attributes: AttributesFor(parameter), - name: metadataContainer.MetadataBuilder.GetOrAddString(parameter.Name), - sequenceNumber: parameter.Index); - if (parameter.HasDefaultValue) - { - metadataContainer.MetadataBuilder.AddConstant(parameterHandle, parameter.DefaultValue.Value); - } - - if (!firstParameterHandle.HasValue) - { - firstParameterHandle = parameterHandle; - } - } - - return firstParameterHandle; - } - } -} \ No newline at end of file diff --git a/MetadataGenerator/Generation/Methods/MethodSignatureGenerator.cs b/MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs similarity index 65% rename from MetadataGenerator/Generation/Methods/MethodSignatureGenerator.cs rename to MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs index 4089049c..211fce1b 100644 --- a/MetadataGenerator/Generation/Methods/MethodSignatureGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs @@ -5,16 +5,16 @@ namespace MetadataGenerator.Generation.Methods { - internal class MethodSignatureGenerator + internal class MethodSignatureEncoder { - private readonly MetadataContainer metadataContainer; + private readonly MetadataResolver metadataResolver; - public MethodSignatureGenerator(MetadataContainer metadataContainer) + public MethodSignatureEncoder(MetadataResolver metadataResolver) { - this.metadataContainer = metadataContainer; + this.metadataResolver = metadataResolver; } - public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) + public SRM.BlobBuilder EncodeSignatureOf(IMethodReference method) { if (method.IsGenericInstantiation()) { @@ -22,29 +22,29 @@ public SRM.BlobBuilder GenerateSignatureOf(IMethodReference method) var encoder = new ECMA335.BlobEncoder(signature).MethodSpecificationSignature(method.GenericArguments.Count); foreach (var genericArg in method.GenericArguments) { - metadataContainer.MetadataResolver.Encode(genericArg, encoder.AddArgument()); + metadataResolver.Encode(genericArg, encoder.AddArgument()); } return signature; } else { - return GenerateMethodSignature(method.IsStatic, method.GenericParameterCount, method.Parameters, method.ReturnType); + return EncodeSignature(method.IsStatic, method.GenericParameterCount, method.Parameters, method.ReturnType); } } - // 0 because FunctionPointerType does not have that property (there's a comment in that class) - public SRM.BlobBuilder GenerateSignatureOf(FunctionPointerType method) => - GenerateMethodSignature(method.IsStatic, 0, method.Parameters, method.ReturnType); + // 0 because FunctionPointerType does not have that property + public SRM.BlobBuilder EncodeSignatureOf(FunctionPointerType method) => + EncodeSignature(method.IsStatic, 0, method.Parameters, method.ReturnType); - private SRM.BlobBuilder GenerateMethodSignature( + private SRM.BlobBuilder EncodeSignature( bool isStatic, int genericParameterCount, IList parameters, IType returnType) { - var methodSignature = new SRM.BlobBuilder(); - new ECMA335.BlobEncoder(methodSignature) + var signature = new SRM.BlobBuilder(); + new ECMA335.BlobEncoder(signature) .MethodSignature(isInstanceMethod: !isStatic, genericParameterCount: genericParameterCount) .Parameters( parameters.Count, @@ -57,7 +57,7 @@ private SRM.BlobBuilder GenerateMethodSignature( else { var encoder = returnTypeEncoder.Type(); - metadataContainer.MetadataResolver.Encode(returnType, encoder); + metadataResolver.Encode(returnType, encoder); } }, parametersEncoder => @@ -73,10 +73,11 @@ private SRM.BlobBuilder GenerateMethodSignature( } var encoder = parametersEncoder.AddParameter().Type(isByRef); - metadataContainer.MetadataResolver.Encode(type, encoder); + metadataResolver.Encode(type, encoder); } }); - return methodSignature; + + return signature; } } } \ No newline at end of file diff --git a/MetadataGenerator/Generation/Types/TypeGenerator.cs b/MetadataGenerator/Generation/Types/TypeGenerator.cs index 2b62a262..2babeca6 100644 --- a/MetadataGenerator/Generation/Types/TypeGenerator.cs +++ b/MetadataGenerator/Generation/Types/TypeGenerator.cs @@ -52,11 +52,6 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) new MethodOverride(methodDefinitionHandle, metadataResolver.HandleOf(method.OverridenMethod))); } - if (method.Name.Equals("Main")) - { - metadataContainer.MainMethodHandle = methodDefinitionHandle; - } - methodDefToHandle.Add(method, methodDefinitionHandle); } @@ -102,6 +97,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) } } + // FIXME se puede llevar a otro lado esto? foreach (var methodOverride in methodOverrides) { metadataBuilder.AddMethodImplementation( @@ -113,6 +109,7 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) if (type.LayoutInformation.SpecifiesSizes()) { + // ClassLayout Table (0x0F) metadataBuilder.AddTypeLayout( typeDefinitionHandle, (ushort) type.LayoutInformation.PackingSize, diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index a897d604..e2eda873 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -36,16 +36,16 @@ - - + + - - - + + + diff --git a/MetadataGenerator/MetadataResolver.cs b/MetadataGenerator/MetadataResolver.cs index 2ea1ff21..789eff2b 100644 --- a/MetadataGenerator/MetadataResolver.cs +++ b/MetadataGenerator/MetadataResolver.cs @@ -32,8 +32,8 @@ internal class MetadataResolver private readonly IDictionary standaloneSignatureReferences = new Dictionary(); - private readonly FieldSignatureGenerator fieldSignatureGenerator; - private readonly MethodSignatureGenerator methodSignatureGenerator; + private readonly FieldSignatureEncoder fieldSignatureEncoder; + private readonly MethodSignatureEncoder methodSignatureEncoder; public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) { @@ -52,8 +52,8 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) ); } - fieldSignatureGenerator = new FieldSignatureGenerator(metadataContainer); - methodSignatureGenerator = new MethodSignatureGenerator(metadataContainer); + fieldSignatureEncoder = new FieldSignatureEncoder(this); + methodSignatureEncoder = new MethodSignatureEncoder(this); } public SRM.EntityHandle HandleOf(IMetadataReference metadataReference) @@ -62,17 +62,17 @@ public SRM.EntityHandle HandleOf(IMetadataReference metadataReference) { case IFieldReference field: { - var signature = fieldSignatureGenerator.GenerateSignatureOf(field); + var signature = fieldSignatureEncoder.EncodeSignatureOf(field); return GetOrAddFieldReference(field, signature); } case IMethodReference method: { - var signature = methodSignatureGenerator.GenerateSignatureOf(method); + var signature = methodSignatureEncoder.EncodeSignatureOf(method); return GetOrAddMethodReference(method, signature); } case FunctionPointerType functionPointer: { - var signature = methodSignatureGenerator.GenerateSignatureOf(functionPointer); + var signature = methodSignatureEncoder.EncodeSignatureOf(functionPointer); return GetOrAddStandaloneSignature(signature); } case IType type: @@ -138,7 +138,7 @@ private SRM.TypeSpecificationHandle GetOrAddTypeSpecificationFor(IType type) private SRM.MethodSpecificationHandle GetOrAddMethodSpecificationFor(IMethodReference method, SRM.BlobBuilder signature) { - var genericMethodSignature = methodSignatureGenerator.GenerateSignatureOf(method.GenericMethod); + var genericMethodSignature = methodSignatureEncoder.EncodeSignatureOf(method.GenericMethod); var key = new Tuple( $"{method.GenericMethod.ContainingType.GetFullName()}.{method.GenericName}", genericMethodSignature.ToArray() From e24113db3872b15442ee60dc95cc482fc41ad687 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 30 Aug 2020 19:34:03 -0300 Subject: [PATCH 245/256] more refactors. Packages and more classes --- .../Generation/AssemblyGenerator.cs | 8 +- .../{ => Generation}/AttributesProvider.cs | 2 +- .../CustomAttributeGenerator.cs | 26 ++++ .../CustomAttributesSignatureEncoder.cs} | 43 ++---- .../Generation/Fields/FieldGenerator.cs | 18 ++- .../Generation/GenericParameterGenerator.cs | 2 +- .../{ => Generation}/MetadataContainer.cs | 2 +- .../{ => Generation}/MetadataResolver.cs | 13 +- ...wGenerator.cs => MethodBodyControlFlow.cs} | 48 ++++--- .../Methods/Body/MethodBodyEncoder.cs | 125 +++++++++--------- .../Generation/Methods/MethodGenerator.cs | 5 +- .../Methods/MethodParameterGenerator.cs | 2 +- .../{ => Properties}/PropertyGenerator.cs | 22 +-- .../Properties/PropertySignatureEncoder.cs | 28 ++++ .../Generation/Types/TypeGenerator.cs | 25 ++-- MetadataGenerator/MetadataGenerator.csproj | 14 +- 16 files changed, 215 insertions(+), 168 deletions(-) rename MetadataGenerator/{ => Generation}/AttributesProvider.cs (99%) create mode 100644 MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs rename MetadataGenerator/Generation/{CustomAttributeGenerator.cs => CustomAttributes/CustomAttributesSignatureEncoder.cs} (84%) rename MetadataGenerator/{ => Generation}/MetadataContainer.cs (98%) rename MetadataGenerator/{ => Generation}/MetadataResolver.cs (97%) rename MetadataGenerator/Generation/Methods/Body/{MethodBodyControlFlowGenerator.cs => MethodBodyControlFlow.cs} (53%) rename MetadataGenerator/Generation/{ => Properties}/PropertyGenerator.cs (73%) create mode 100644 MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs diff --git a/MetadataGenerator/Generation/AssemblyGenerator.cs b/MetadataGenerator/Generation/AssemblyGenerator.cs index ca8a76ae..e462707e 100644 --- a/MetadataGenerator/Generation/AssemblyGenerator.cs +++ b/MetadataGenerator/Generation/AssemblyGenerator.cs @@ -25,11 +25,9 @@ public static MetadataContainer Generate(Assembly assembly) moduleGenerator.GenerateModuleFor(assembly); namespaceGenerator.Generate(assembly.RootNamespace); - /* - * Some tables must be sorted by one or more of their columns. Since the dll's methods and types don't follow a - * particular order, the info needed to load this tables is stored during type/method generation but not added to the MetadataBuilder - * until now where they can be previously sorted - */ + // Some tables must be sorted by one or more of their columns. Since the dll's methods and types don't follow a + // particular order, the info needed to load this tables is stored during type/method generation but not added to the MetadataBuilder + // until now where they can be previously sorted InterfaceImplementationGenerator.GenerateInterfaceImplementations(metadataContainer); GenericParameterGenerator.GenerateGenericParameters(metadataContainer); NestedTypeGenerator.GenerateNestedTypes(metadataContainer); diff --git a/MetadataGenerator/AttributesProvider.cs b/MetadataGenerator/Generation/AttributesProvider.cs similarity index 99% rename from MetadataGenerator/AttributesProvider.cs rename to MetadataGenerator/Generation/AttributesProvider.cs index ccf28f80..84d6c1f1 100644 --- a/MetadataGenerator/AttributesProvider.cs +++ b/MetadataGenerator/Generation/AttributesProvider.cs @@ -2,7 +2,7 @@ using Model; using Model.Types; -namespace MetadataGenerator +namespace MetadataGenerator.Generation { internal static class AttributesProvider { diff --git a/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs b/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs new file mode 100644 index 00000000..3f076873 --- /dev/null +++ b/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs @@ -0,0 +1,26 @@ +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generation.CustomAttributes +{ + internal class CustomAttributeGenerator + { + private readonly MetadataContainer metadataContainer; + + public CustomAttributeGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + + public void Generate(SRM.EntityHandle owner, CustomAttribute customAttribute) + { + var signature = CustomAttributesSignatureEncoder.EncodeSignatureOf(customAttribute); + // CustomAttribute Table (0x0C) + metadataContainer.MetadataBuilder.AddCustomAttribute( + owner, + metadataContainer.MetadataResolver.HandleOf(customAttribute.Constructor), + metadataContainer.MetadataBuilder.GetOrAddBlob(signature)); + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generation/CustomAttributeGenerator.cs b/MetadataGenerator/Generation/CustomAttributes/CustomAttributesSignatureEncoder.cs similarity index 84% rename from MetadataGenerator/Generation/CustomAttributeGenerator.cs rename to MetadataGenerator/Generation/CustomAttributes/CustomAttributesSignatureEncoder.cs index 60718b6d..a380dee1 100644 --- a/MetadataGenerator/Generation/CustomAttributeGenerator.cs +++ b/MetadataGenerator/Generation/CustomAttributes/CustomAttributesSignatureEncoder.cs @@ -1,27 +1,19 @@ using System; using System.Collections.Immutable; using Model; +using Model.ThreeAddressCode.Values; using Model.Types; -using Constant = Model.ThreeAddressCode.Values.Constant; -using CustomAttribute = Model.Types.CustomAttribute; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generation +namespace MetadataGenerator.Generation.CustomAttributes { - internal class CustomAttributeGenerator + public static class CustomAttributesSignatureEncoder { - private readonly MetadataContainer metadataContainer; - - public CustomAttributeGenerator(MetadataContainer metadataContainer) - { - this.metadataContainer = metadataContainer; - } - - public void Generate(SRM.EntityHandle owner, CustomAttribute customAttribute) + public static SRM.BlobBuilder EncodeSignatureOf(CustomAttribute customAttribute) { - var customAttributeEncodedValue = new SRM.BlobBuilder(); - new ECMA335.BlobEncoder(customAttributeEncodedValue) + var signature = new SRM.BlobBuilder(); + new ECMA335.BlobEncoder(signature) .CustomAttributeSignature( fixedArgumentsEncoder => { @@ -47,16 +39,11 @@ public void Generate(SRM.EntityHandle owner, CustomAttribute customAttribute) namedArgumentsEncoder.Count(0); }); - metadataContainer.MetadataBuilder.AddCustomAttribute( - owner, - metadataContainer.MetadataResolver.HandleOf(customAttribute.Constructor), - metadataContainer.MetadataBuilder.GetOrAddBlob(customAttributeEncodedValue)); + return signature; } - /* - * Encodes vector (only SZArray are permitted as arguments of a custom attribute constructor) - * The constructor can have this value as an object, object[] or type[]. In the first two cases, the type needs to be encoded as well. - */ + // Encodes vector (only SZArray are permitted as arguments of a custom attribute constructor) + // The constructor can have this value as an object, object[] or type[]. In the first two cases, the type needs to be encoded as well. private static void EncodeVector(CustomAttribute customAttribute, Constant argument, ECMA335.LiteralEncoder encoder) { var type = ((ArrayType) argument.Type).ElementsType; @@ -115,10 +102,8 @@ private static void EncodeVector(CustomAttribute customAttribute, Constant argum } } - /* - * Encode types. Types are represented by their serialized name (namespace.type or namespace.type+anotherType if nested) - * If this parameter has type object in the customAttribute constructor, then its real type also needs to be encoded. - */ + // Encode types. Types are represented by their serialized name (namespace.type or namespace.type+anotherType if nested) + // If this parameter has type object in the customAttribute constructor, then its real type also needs to be encoded. private static void EncodeComplexValue(CustomAttribute customAttribute, Constant argument, ECMA335.LiteralEncoder encoder) { var serializedTypeName = ((IBasicType) argument.Value).Name; @@ -134,10 +119,8 @@ private static void EncodeComplexValue(CustomAttribute customAttribute, Constant } } - /* - * Simple values: bool (as byte), char, float32, float64, int8, int16, int32, int64, unsigned int8, unsigned int16, unsigned int32,unsigned int64, enums (integer value) - * If this parameter has type object in the customAttribute constructor, then its real type also needs to be encoded. - */ + // Simple values: bool (as byte), char, float32, float64, int8, int16, int32, int64, unsigned int8, unsigned int16, unsigned int32,unsigned int64, enums (integer value) + // If this parameter has type object in the customAttribute constructor, then its real type also needs to be encoded. private static void EncodeSimpleValue(CustomAttribute customAttribute, Constant argument, ECMA335.LiteralEncoder encoder) { var type = argument.Type; diff --git a/MetadataGenerator/Generation/Fields/FieldGenerator.cs b/MetadataGenerator/Generation/Fields/FieldGenerator.cs index a2ca84a0..355f127b 100644 --- a/MetadataGenerator/Generation/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generation/Fields/FieldGenerator.cs @@ -1,6 +1,7 @@ using System.Reflection.PortableExecutable; +using MetadataGenerator.Generation.CustomAttributes; using Model.Types; -using static MetadataGenerator.AttributesProvider; +using static MetadataGenerator.Generation.AttributesProvider; using SRM = System.Reflection.Metadata; namespace MetadataGenerator.Generation.Fields @@ -32,15 +33,12 @@ public SRM.FieldDefinitionHandle Generate(FieldDefinition field) // add initial value if (field.SpecifiesRelativeVirtualAddress) { - /* - * Static fields can define their initial value as a constant stored in the PE File. The value is declared using the .data directive, - * represented as a bytearray and labeled so it can be referenced later. - * - * Initialization of a static array field is an example of this. The field itself does not hold the initial value. - * A special type is created () that has a field that references the value declared with .data. - * It is then used in the constructor of the class that has the static array field to initialize it. - * - */ + // Static fields can define their initial value as a constant stored in the PE File. The value is declared using the .data directive, + // represented as a bytearray and labeled so it can be referenced later. + // + // Initialization of a static array field is an example of this. The field itself does not hold the initial value. + // A special type is created () that has a field that references the value declared with .data. + // It is then used in the constructor of the class that has the static array field to initialize it. var offset = metadataContainer.MappedFieldData.Count; metadataContainer.MappedFieldData.WriteBytes((byte[]) field.Value.Value); metadataContainer.MappedFieldData.Align(ManagedPEBuilder.MappedFieldDataAlignment); diff --git a/MetadataGenerator/Generation/GenericParameterGenerator.cs b/MetadataGenerator/Generation/GenericParameterGenerator.cs index 768b4a51..4749deb1 100644 --- a/MetadataGenerator/Generation/GenericParameterGenerator.cs +++ b/MetadataGenerator/Generation/GenericParameterGenerator.cs @@ -3,7 +3,7 @@ using System.Reflection; using Model; using Model.Types; -using static MetadataGenerator.AttributesProvider; +using static MetadataGenerator.Generation.AttributesProvider; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; diff --git a/MetadataGenerator/MetadataContainer.cs b/MetadataGenerator/Generation/MetadataContainer.cs similarity index 98% rename from MetadataGenerator/MetadataContainer.cs rename to MetadataGenerator/Generation/MetadataContainer.cs index 579158f1..c2ec41ee 100644 --- a/MetadataGenerator/MetadataContainer.cs +++ b/MetadataGenerator/Generation/MetadataContainer.cs @@ -7,7 +7,7 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator +namespace MetadataGenerator.Generation { internal class MetadataContainer { diff --git a/MetadataGenerator/MetadataResolver.cs b/MetadataGenerator/Generation/MetadataResolver.cs similarity index 97% rename from MetadataGenerator/MetadataResolver.cs rename to MetadataGenerator/Generation/MetadataResolver.cs index 789eff2b..956ed8d1 100644 --- a/MetadataGenerator/MetadataResolver.cs +++ b/MetadataGenerator/Generation/MetadataResolver.cs @@ -3,7 +3,6 @@ using System.Collections.Immutable; using MetadataGenerator.Generation.Fields; using MetadataGenerator.Generation.Methods; -using MetadataGenerator.Generation.Methods.Body; using Model; using Model.Types; using static System.Linq.Enumerable; @@ -11,7 +10,7 @@ using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator +namespace MetadataGenerator.Generation { internal class MetadataResolver { @@ -56,6 +55,8 @@ public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) methodSignatureEncoder = new MethodSignatureEncoder(this); } + public SRM.UserStringHandle UserStringHandleOf(string value) => metadataContainer.MetadataBuilder.GetOrAddUserString(value); + public SRM.EntityHandle HandleOf(IMetadataReference metadataReference) { switch (metadataReference) @@ -285,10 +286,8 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), arrayShapeEncoder => { - /** - * This assumes that all dimensions have 0 as lower bound and none declare sizes. - * Lower bounds and sizes are not modelled. - */ + // This assumes that all dimensions have 0 as lower bound and none declare sizes. + // Lower bounds and sizes are not modelled. var lowerBounds = Repeat(0, (int) arrayType.Rank).ToImmutableArray(); var sizes = ImmutableArray.Empty; arrayShapeEncoder.Shape((int) arrayType.Rank, sizes, lowerBounds); @@ -328,7 +327,7 @@ public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) encoder.GenericMethodTypeParameter(genericParameter.Index); break; default: - throw new UnhandledCase(); + throw genericParameter.Kind.ToUnknownValueException(); } break; diff --git a/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlowGenerator.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs similarity index 53% rename from MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlowGenerator.cs rename to MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs index a4f6a953..088fa064 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlowGenerator.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs @@ -1,22 +1,27 @@ using System.Collections.Generic; using Model; -using Model.Bytecode; using ECMA335 = System.Reflection.Metadata.Ecma335; namespace MetadataGenerator.Generation.Methods.Body { - internal class MethodBodyControlFlowGenerator + // Control flow is tracked by using SRM.LabelHandle. This allows us to reference instructions in the method body that are targets of + // branch instructions or part of exception regions. This LabelHandles point a specific part of the InstructionEncoder which translates + // to the encoded instruction. Since we can target an instruction that is further away in the body, not encoded yet, LabelHandles are defined + // with a placeholder target, and then marked when we actually process the target instruction. + internal class MethodBodyControlFlow { - private readonly IDictionary labelHandles = new Dictionary(); private readonly ECMA335.InstructionEncoder instructionEncoder; - private readonly MetadataContainer metadataContainer; + private readonly MetadataResolver metadataResolver; + private readonly IDictionary labelHandles; - public MethodBodyControlFlowGenerator(ECMA335.InstructionEncoder instructionEncoder, MetadataContainer metadataContainer) + public MethodBodyControlFlow(ECMA335.InstructionEncoder instructionEncoder, MetadataResolver metadataResolver) { this.instructionEncoder = instructionEncoder; - this.metadataContainer = metadataContainer; + this.metadataResolver = metadataResolver; + labelHandles = new Dictionary(); } + // get LabelHandle associated with label or define a new one. public ECMA335.LabelHandle LabelHandleFor(string label) { label = label.ToLower(); @@ -29,18 +34,17 @@ public ECMA335.LabelHandle LabelHandleFor(string label) return labelHandle; } - public void DefineNeededBranchLabels(IList instructions) + // Defines needed LabelHandles for branch instructions + public void ProcessBranchTargets(IList targets) { - foreach (var instruction in instructions) + foreach (var target in targets) { - if (instruction is BranchInstruction branchInstruction) - { - LabelHandleFor(branchInstruction.Target); - } + LabelHandleFor(target); } } - public void MarkCurrentLabelIfNeeded(string label) + // if there is an associated LabelHandle then mark it with its real position in the InstructionEncoder + public void MarkLabelIfNeeded(string label) { if (labelHandles.TryGetValue(label.ToLower(), out var labelHandle)) { @@ -61,20 +65,30 @@ public void ProcessExceptionInformation(IList exceptionInformati switch (protectedBlock.Handler.Kind) { case ExceptionHandlerBlockKind.Filter: - var filterStart = LabelHandleFor(((FilterExceptionHandler) protectedBlock.Handler).FilterStart); + { + var handler = (FilterExceptionHandler) protectedBlock.Handler; + var filterStart = LabelHandleFor(handler.FilterStart); controlFlowBuilder.AddFilterRegion(tryStart, tryEnd, handlerStart, handlerEnd, filterStart); break; + } case ExceptionHandlerBlockKind.Catch: - var catchType = ((CatchExceptionHandler) protectedBlock.Handler).ExceptionType; - controlFlowBuilder.AddCatchRegion(tryStart, tryEnd, handlerStart, handlerEnd, - metadataContainer.MetadataResolver.HandleOf(catchType)); + { + var handler = (CatchExceptionHandler) protectedBlock.Handler; + controlFlowBuilder.AddCatchRegion( + tryStart, + tryEnd, + handlerStart, + handlerEnd, + metadataResolver.HandleOf(handler.ExceptionType)); break; + } case ExceptionHandlerBlockKind.Fault: controlFlowBuilder.AddFaultRegion(tryStart, tryEnd, handlerStart, handlerEnd); break; case ExceptionHandlerBlockKind.Finally: controlFlowBuilder.AddFinallyRegion(tryStart, tryEnd, handlerStart, handlerEnd); break; + default: throw protectedBlock.Handler.Kind.ToUnknownValueException(); } } } diff --git a/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs index 18336712..377d789a 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs @@ -6,7 +6,6 @@ using Model.Bytecode.Visitor; using Model.ThreeAddressCode.Values; using Model.Types; -using Constant = Model.ThreeAddressCode.Values.Constant; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -14,44 +13,47 @@ namespace MetadataGenerator.Generation.Methods.Body { internal class MethodBodyEncoder : IInstructionVisitor { - private readonly MetadataContainer metadataContainer; + private readonly MetadataResolver metadataResolver; private readonly ECMA335.InstructionEncoder instructionEncoder; - private readonly MethodBodyControlFlowGenerator controlFlowGenerator; + private readonly MethodBodyControlFlow methodBodyControlFlow; private readonly List switchInstructionsPlaceHolders; - private readonly ISet ignoredInstructions; + private readonly ISet skippedIndices; private readonly MethodBody body; private readonly StackSize stackSize; private int Index { get; set; } - public MethodBodyEncoder(MetadataContainer metadataContainer, MethodBody body) + public MethodBodyEncoder(MetadataResolver metadataResolver, MethodBody body) { - this.metadataContainer = metadataContainer; + this.metadataResolver = metadataResolver; this.body = body; instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), new ECMA335.ControlFlowBuilder()); - controlFlowGenerator = new MethodBodyControlFlowGenerator(instructionEncoder, metadataContainer); + methodBodyControlFlow = new MethodBodyControlFlow(instructionEncoder, metadataResolver); switchInstructionsPlaceHolders = new List(); - ignoredInstructions = new HashSet(); + skippedIndices = new HashSet(); stackSize = new StackSize(); } + // Encodes instructions using SRM InstructionEncoder. Also calculates needed MaxStack since this value might not be present (programatically + // generated dll) or incorrect (if changes were made to the method body or if it was converted to TAC and back again). public ECMA335.InstructionEncoder Encode(out int maxStack) { - controlFlowGenerator.ProcessExceptionInformation(body.ExceptionInformation); - controlFlowGenerator.DefineNeededBranchLabels(body.Instructions); - var labelToEncoderOffset = new Dictionary(); + var branchTargets = body.Instructions.OfType().Select(i => i.Target).ToList(); + methodBodyControlFlow.ProcessExceptionInformation(body.ExceptionInformation); + methodBodyControlFlow.ProcessBranchTargets(branchTargets); + var labelToInstructionEncoderOffset = new Dictionary(); for (Index = 0; Index < body.Instructions.Count; Index++) { var instruction = (Instruction) body.Instructions[Index]; - labelToEncoderOffset[instruction.Label] = instructionEncoder.Offset; - controlFlowGenerator.MarkCurrentLabelIfNeeded(instruction.Label); + labelToInstructionEncoderOffset[instruction.Label] = instructionEncoder.Offset; + methodBodyControlFlow.MarkLabelIfNeeded(instruction.Label); if (FilterOrCatchStartAt(instruction.Label)) { stackSize.Increment(); } - if (!ignoredInstructions.Contains(Index)) + if (!skippedIndices.Contains(Index)) { instruction.Accept(this); } @@ -59,7 +61,7 @@ public ECMA335.InstructionEncoder Encode(out int maxStack) foreach (var switchInstructionPlaceholder in switchInstructionsPlaceHolders) { - switchInstructionPlaceholder.FillWithRealTargets(labelToEncoderOffset); + switchInstructionPlaceholder.FillWithRealTargets(labelToInstructionEncoderOffset); } maxStack = stackSize.MaxStackSize; @@ -77,7 +79,7 @@ public void Visit(Instruction instruction) public void Visit(InitObjInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Initobj); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Type)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.Type)); stackSize.Decrement(); } @@ -216,14 +218,14 @@ public void Visit(BasicInstruction instruction) instructionEncoder.OpCode(SRM.ILOpCode.Ret); break; default: - throw new UnhandledCase(); + throw instruction.Operation.ToUnknownValueException(); } } public void Visit(ConstrainedInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Constrained); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ThisType)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.ThisType)); } public void Visit(LoadInstruction instruction) @@ -286,13 +288,13 @@ public void Visit(LoadInstruction instruction) stackSize.Decrement(); // skip processing next 2 instructions - ignoredInstructions.Add(Index + 1); - ignoredInstructions.Add(Index + 2); + skippedIndices.Add(Index + 1); + skippedIndices.Add(Index + 2); } break; case string value: - instructionEncoder.LoadString(metadataContainer.MetadataBuilder.GetOrAddUserString(value)); + instructionEncoder.LoadString(metadataResolver.UserStringHandleOf(value)); stackSize.Increment(); break; case int value: @@ -316,13 +318,13 @@ public void Visit(LoadInstruction instruction) stackSize.Increment(); break; default: - throw new UnhandledCase(); + throw new Exception(); } break; } default: - throw new UnhandledCase(); + throw instruction.Operation.ToUnknownValueException(); } } @@ -375,7 +377,7 @@ public void Visit(LoadIndirectInstruction instruction) else { instructionEncoder.OpCode(SRM.ILOpCode.Ldobj); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Type)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.Type)); } } @@ -391,10 +393,10 @@ public void Visit(LoadFieldInstruction instruction) instructionEncoder.OpCode(isStatic ? SRM.ILOpCode.Ldsflda : SRM.ILOpCode.Ldflda); break; default: - throw new UnhandledCase(); + throw instruction.Operation.ToUnknownValueException(); } - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Field)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.Field)); if (isStatic) { stackSize.Increment(); @@ -405,7 +407,7 @@ public void Visit(LoadMethodAddressInstruction instruction) { var isVirtual = instruction.Method.IsVirtual; instructionEncoder.OpCode(isVirtual ? SRM.ILOpCode.Ldvirtftn : SRM.ILOpCode.Ldftn); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.Method)); if (!isVirtual) { stackSize.Increment(); @@ -449,7 +451,7 @@ public void Visit(StoreIndirectInstruction instruction) else { instructionEncoder.OpCode(SRM.ILOpCode.Stobj); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Type)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.Type)); } stackSize.Decrement(2); @@ -476,7 +478,7 @@ public void Visit(StoreFieldInstruction instruction) { var isStatic = instruction.Field.IsStatic; instructionEncoder.OpCode(isStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Field)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.Field)); stackSize.Decrement(isStatic ? 1 : 2); } @@ -623,31 +625,31 @@ public void Visit(ConvertInstruction instruction) instructionEncoder.OpCode(SRM.ILOpCode.Conv_u); } } - else throw new UnhandledCase(); + else throw new Exception(); break; case ConvertOperation.Cast: instructionEncoder.OpCode(SRM.ILOpCode.Castclass); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.IsInst: instructionEncoder.OpCode(SRM.ILOpCode.Isinst); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.Box: instructionEncoder.OpCode(SRM.ILOpCode.Box); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.Unbox: instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.UnboxPtr: instructionEncoder.OpCode(SRM.ILOpCode.Unbox); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.ConversionType)); break; default: - throw new UnhandledCase(); + throw instruction.Operation.ToUnknownValueException(); } } @@ -699,18 +701,19 @@ public void Visit(BranchInstruction instruction) stackSize.Clear(); break; default: - throw new UnhandledCase(); + throw instruction.Operation.ToUnknownValueException(); } - instructionEncoder.Branch(opCode, controlFlowGenerator.LabelHandleFor(instruction.Target)); + instructionEncoder.Branch(opCode, methodBodyControlFlow.LabelHandleFor(instruction.Target)); } public void Visit(SwitchInstruction instruction) { // switch is encoded as OpCode NumberOfTargets target1, target2, .... - // the targets in SwitchInstruction are labels that refer to the Instructions in the method body - // but when encoded they must be be offsets relative to the instructionEncoder offsets (real Cil offsets) - // this offsets can't be determined until the whole body is generated so a space is reserved for the targets and filled up later + // the targets in SwitchInstruction are labels that refer to the Instructions in the method body but when encoded they must be be offsets + // relative to the instructionEncoder offsets (real Cil offsets). This offsets can't be determined until the whole body is generated so a + // space is reserved for the targets and filled up later. Although this is almost the same as branch targets, SRM does not allow + // LabelHandles to be used for this and does not provide an alternative. var targetsCount = instruction.Targets.Count; instructionEncoder.OpCode(SRM.ILOpCode.Switch); instructionEncoder.Token(targetsCount); @@ -726,14 +729,14 @@ public void Visit(SwitchInstruction instruction) public void Visit(SizeofInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.MeasuredType)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.MeasuredType)); stackSize.Increment(); } public void Visit(LoadTokenInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Token)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.Token)); stackSize.Increment(); } @@ -743,16 +746,16 @@ public void Visit(MethodCallInstruction instruction) { case MethodCallOperation.Virtual: instructionEncoder.OpCode(SRM.ILOpCode.Callvirt); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count + 1); break; case MethodCallOperation.Static: case MethodCallOperation.Jump: - instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + instructionEncoder.Call(metadataResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); break; default: - throw new UnhandledCase(); + throw instruction.Operation.ToUnknownValueException(); } if (!instruction.Method.ReturnType.Equals(PlatformTypes.Void)) @@ -763,7 +766,7 @@ public void Visit(MethodCallInstruction instruction) public void Visit(IndirectMethodCallInstruction instruction) { - var methodSignature = metadataContainer.MetadataResolver.HandleOf(instruction.Function); + var methodSignature = metadataResolver.HandleOf(instruction.Function); instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); stackSize.Decrement(instruction.Function.Parameters.Count + 1); if (!instruction.Function.ReturnType.Equals(PlatformTypes.Void)) @@ -774,7 +777,7 @@ public void Visit(IndirectMethodCallInstruction instruction) public void Visit(CreateObjectInstruction instruction) { - var method = metadataContainer.MetadataResolver.HandleOf(instruction.Constructor); + var method = metadataResolver.HandleOf(instruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); stackSize.Decrement(instruction.Constructor.Parameters.Count); @@ -786,11 +789,11 @@ public void Visit(CreateArrayInstruction instruction) if (instruction.Type.IsVector) { instructionEncoder.OpCode(SRM.ILOpCode.Newarr); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Type.ElementsType)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.Type.ElementsType)); } else { - var method = metadataContainer.MetadataResolver.HandleOf(instruction.Constructor); + var method = metadataResolver.HandleOf(instruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); stackSize.Decrement(instruction.Constructor.Parameters.Count); @@ -802,7 +805,7 @@ public void Visit(LoadArrayElementInstruction instruction) { if (instruction.Method != null) { - instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + instructionEncoder.Call(metadataResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); stackSize.Increment(); } @@ -860,18 +863,18 @@ public void Visit(LoadArrayElementInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); instructionEncoder.Token( - metadataContainer.MetadataResolver.HandleOf(instruction.Array.ElementsType)); + metadataResolver.HandleOf(instruction.Array.ElementsType)); } break; case LoadArrayElementOperation.Address: instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); instructionEncoder.Token( - metadataContainer.MetadataResolver.HandleOf(instruction.Array.ElementsType)); + metadataResolver.HandleOf(instruction.Array.ElementsType)); break; default: - throw new UnhandledCase(); + throw instruction.Operation.ToUnknownValueException(); } stackSize.Decrement(); @@ -882,7 +885,7 @@ public void Visit(StoreArrayElementInstruction instruction) { if (instruction.Method != null) { - instructionEncoder.Call(metadataContainer.MetadataResolver.HandleOf(instruction.Method)); + instructionEncoder.Call(metadataResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); } else @@ -922,7 +925,7 @@ public void Visit(StoreArrayElementInstruction instruction) else { instructionEncoder.OpCode(SRM.ILOpCode.Stelem); - instructionEncoder.Token(metadataContainer.MetadataResolver.HandleOf(instruction.Array.ElementsType)); + instructionEncoder.Token(metadataResolver.HandleOf(instruction.Array.ElementsType)); } stackSize.Decrement(3); @@ -955,14 +958,14 @@ public SwitchInstructionPlaceholder(int nextInstructionEncoderOffset, SRM.Blob b this.targets = targets; } - // labelToEncoderOffset is the translation of method body labels to the real cil offsets after generation - public void FillWithRealTargets(IDictionary labelToEncoderOffset) + // labelToInstructionEncoderOffset is the translation of method body labels to the real cil offsets after generation + public void FillWithRealTargets(IDictionary labelToInstructionEncoderOffset) { var writer = new SRM.BlobWriter(blob); foreach (var target in targets) { // switch targets are offsets relative to the beginning of the next instruction. - var offset = labelToEncoderOffset[target] - nextInstructionEncoderOffset; + var offset = labelToInstructionEncoderOffset[target] - nextInstructionEncoderOffset; writer.WriteInt32(offset); } } @@ -1000,8 +1003,4 @@ public void Clear() } } } - - internal class UnhandledCase : Exception - { - } } \ No newline at end of file diff --git a/MetadataGenerator/Generation/Methods/MethodGenerator.cs b/MetadataGenerator/Generation/Methods/MethodGenerator.cs index 16b99e55..9c8aeccc 100644 --- a/MetadataGenerator/Generation/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodGenerator.cs @@ -1,7 +1,8 @@ using System.Linq; +using MetadataGenerator.Generation.CustomAttributes; using MetadataGenerator.Generation.Methods.Body; using Model.Types; -using static MetadataGenerator.AttributesProvider; +using static MetadataGenerator.Generation.AttributesProvider; using ECMA335 = System.Reflection.Metadata.Ecma335; using SR = System.Reflection; using SRM = System.Reflection.Metadata; @@ -42,7 +43,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) localVariablesSignature = metadataContainer.MetadataResolver.GetOrAddStandaloneSignature(signature); } - var instructionEncoder = new MethodBodyEncoder(metadataContainer, method.Body).Encode(out var maxStack); + var instructionEncoder = new MethodBodyEncoder(metadataContainer.MetadataResolver, method.Body).Encode(out var maxStack); methodBodyOffset = metadataContainer.MethodBodyStream.AddMethodBody( instructionEncoder: instructionEncoder, localVariablesSignature: localVariablesSignature, diff --git a/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs b/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs index 09b49afa..a4736fd4 100644 --- a/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs @@ -1,6 +1,6 @@ using Model.Types; using SRM = System.Reflection.Metadata; -using static MetadataGenerator.AttributesProvider; +using static MetadataGenerator.Generation.AttributesProvider; namespace MetadataGenerator.Generation.Methods { diff --git a/MetadataGenerator/Generation/PropertyGenerator.cs b/MetadataGenerator/Generation/Properties/PropertyGenerator.cs similarity index 73% rename from MetadataGenerator/Generation/PropertyGenerator.cs rename to MetadataGenerator/Generation/Properties/PropertyGenerator.cs index 88affe4f..a84bc3b9 100644 --- a/MetadataGenerator/Generation/PropertyGenerator.cs +++ b/MetadataGenerator/Generation/Properties/PropertyGenerator.cs @@ -1,35 +1,33 @@ using System.Collections.Generic; +using MetadataGenerator.Generation.CustomAttributes; +using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; -using MethodDefinition = Model.Types.MethodDefinition; -using PropertyDefinition = Model.Types.PropertyDefinition; using SR = System.Reflection; using SRM = System.Reflection.Metadata; -namespace MetadataGenerator.Generation +namespace MetadataGenerator.Generation.Properties { internal class PropertyGenerator { private readonly MetadataContainer metadataContainer; + private readonly PropertySignatureEncoder propertySignatureEncoder; private readonly CustomAttributeGenerator customAttributeGenerator; public PropertyGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; + propertySignatureEncoder = new PropertySignatureEncoder(metadataContainer.MetadataResolver); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } + // Properties can have getters or setters which are methods defined within the class. + // methodDefHandleOf is the association of methods to their handles. public SRM.PropertyDefinitionHandle Generate( PropertyDefinition property, IDictionary methodDefHandleOf) { - var signature = new SRM.BlobBuilder(); - new ECMA335.BlobEncoder(signature) - .PropertySignature(isInstanceProperty: !property.IsStatic) - .Parameters( - parameterCount: 0, - returnType: returnTypeEncoder => metadataContainer.MetadataResolver.Encode(property.PropertyType, returnTypeEncoder.Type()), - parameters: parametersEncoder => { }); - + var signature = propertySignatureEncoder.EncodeSignatureOf(property); + // Property Table (0x17) var propertyDefinitionHandle = metadataContainer.MetadataBuilder.AddProperty( attributes: SR.PropertyAttributes.None, name: metadataContainer.MetadataBuilder.GetOrAddString(property.Name), @@ -37,6 +35,7 @@ public SRM.PropertyDefinitionHandle Generate( if (property.Getter != null) { + // MethodSemantics Table (0x18) metadataContainer.MetadataBuilder.AddMethodSemantics( propertyDefinitionHandle, SR.MethodSemanticsAttributes.Getter, @@ -45,6 +44,7 @@ public SRM.PropertyDefinitionHandle Generate( if (property.Setter != null) { + // MethodSemantics Table (0x18) metadataContainer.MetadataBuilder.AddMethodSemantics( propertyDefinitionHandle, SR.MethodSemanticsAttributes.Setter, diff --git a/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs b/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs new file mode 100644 index 00000000..e185e83c --- /dev/null +++ b/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs @@ -0,0 +1,28 @@ +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generation.Properties +{ + internal class PropertySignatureEncoder + { + private readonly MetadataResolver metadataResolver; + + public PropertySignatureEncoder(MetadataResolver metadataResolver) + { + this.metadataResolver = metadataResolver; + } + + public SRM.BlobBuilder EncodeSignatureOf(PropertyDefinition property) + { + var signature = new SRM.BlobBuilder(); + new ECMA335.BlobEncoder(signature) + .PropertySignature(isInstanceProperty: !property.IsStatic) + .Parameters( + parameterCount: 0, + returnType: returnTypeEncoder => metadataResolver.Encode(property.PropertyType, returnTypeEncoder.Type()), + parameters: parametersEncoder => { }); + return signature; + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generation/Types/TypeGenerator.cs b/MetadataGenerator/Generation/Types/TypeGenerator.cs index 2babeca6..b92fc16a 100644 --- a/MetadataGenerator/Generation/Types/TypeGenerator.cs +++ b/MetadataGenerator/Generation/Types/TypeGenerator.cs @@ -1,10 +1,12 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; +using MetadataGenerator.Generation.CustomAttributes; using MetadataGenerator.Generation.Fields; using MetadataGenerator.Generation.Methods; -using MetadataGenerator.Generation.Methods.Body; +using MetadataGenerator.Generation.Properties; using Model.Types; -using static MetadataGenerator.AttributesProvider; +using static MetadataGenerator.Generation.AttributesProvider; using static MetadataGenerator.Generation.GenericParameterGenerator; using static MetadataGenerator.Generation.Types.InterfaceImplementationGenerator; using ECMA335 = System.Reflection.Metadata.Ecma335; @@ -97,7 +99,6 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) } } - // FIXME se puede llevar a otro lado esto? foreach (var methodOverride in methodOverrides) { metadataBuilder.AddMethodImplementation( @@ -124,14 +125,12 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) return typeDefinitionHandle; } - /** - * CLS-compliant generic type names are encoded using the format “name[`arity]”, where […] indicates that the grave accent character “`” and - * arity together are optional. The encoded name shall follow these rules: - * - name shall be an ID that does not contain the “`” character. - * - arity is specified as an unsigned decimal number without leading zeros or spaces. - * - For a normal generic type, arity is the number of type parameters declared on the type. - * - For a nested generic type, arity is the number of newly introduced type parameters. - */ + // CLS-compliant generic type names are encoded using the format “name[`arity]”, where […] indicates that the grave accent character “`” and + // arity together are optional. The encoded name shall follow these rules: + // - name shall be an ID that does not contain the “`” character. + // - arity is specified as an unsigned decimal number without leading zeros or spaces. + // - For a normal generic type, arity is the number of type parameters declared on the type. + // - For a nested generic type, arity is the number of newly introduced type parameters. public static string TypeNameOf(IBasicType type) { var typeName = type.Name; @@ -146,7 +145,7 @@ IList GenericParametersNamesOf(IBasicType iBasicType) { case BasicType bt: return bt.GenericArguments.Select(elem => ((IBasicType) elem).Name).ToList(); case TypeDefinition td: return td.GenericParameters.Select(elem => elem.Name).ToList(); - default: throw new UnhandledCase(); + default: throw new Exception("Not supported"); } } diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index e2eda873..29f51f60 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -26,28 +26,30 @@ - + + + + + + + - - - - - + From 2664030ec117a5c746b4e8716ed39f5b7f350185 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 30 Aug 2020 19:42:23 -0300 Subject: [PATCH 246/256] remove comment --- Console/Program.cs | 2 +- MetadataGenerator/Generation/MetadataResolver.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index 820bca8a..2b5a8c1a 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -633,7 +633,7 @@ from m in t.Members.OfType() method.Body = bytecode; } - // remove unsued method + // remove unused method var unusedMethod = allDefinedMethods.Except(callGraph.Methods).First(); var type = (TypeDefinition) unusedMethod.ContainingType; var onlyUsedMethods = type.Methods.Where(method => !method.Equals(unusedMethod)).ToList(); diff --git a/MetadataGenerator/Generation/MetadataResolver.cs b/MetadataGenerator/Generation/MetadataResolver.cs index 956ed8d1..37200464 100644 --- a/MetadataGenerator/Generation/MetadataResolver.cs +++ b/MetadataGenerator/Generation/MetadataResolver.cs @@ -228,9 +228,7 @@ private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field, return memberReferenceHandle; } - - // SignatureTypeEncoder is a struct but it is not necessary to pass it by reference since - // it operates on its Builder (BlobBuilder) which is a class (that means the builder reference is always the same) + public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) { if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); From bbc94ad76f7961564bdfb289291dba31bc0bc20f Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 4 Oct 2020 22:59:06 -0300 Subject: [PATCH 247/256] more interesting Program examples --- Console/Program.cs | 366 ++++++++++++++++++++++++++++++--------------- 1 file changed, 248 insertions(+), 118 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index 2b5a8c1a..f07e7bb2 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -368,7 +368,7 @@ private static void RunInterPointsToTests() } } - private static void HelloWorldAssembly() + private static void ProgramaticallyGeneratedAssembly() { var mscorlib = new AssemblyReference("mscorlib") { @@ -376,53 +376,170 @@ private static void HelloWorldAssembly() Culture = "", PublicKey = new byte[0] }; - var assembly = new Assembly("SampleAssembly", AssemblyKind.Exe) + var assembly = new Assembly("ProgramaticallyGeneratedAssembly", AssemblyKind.Exe) { Version = new Version("1.0.0.0"), PublicKey = new byte[0], Culture = "", References = {mscorlib} }; - var namezpace = new Namespace("MainNamespace") {ContainingAssembly = assembly}; - assembly.RootNamespace = namezpace; - var type = new TypeDefinition("MainType", TypeKind.ReferenceType, TypeDefinitionKind.Class) + var rootNamespace = new Namespace("") {ContainingAssembly = assembly}; + rootNamespace.Types.Add(new TypeDefinition("", TypeKind.ReferenceType, TypeDefinitionKind.Class) { ContainingAssembly = assembly, - ContainingNamespace = namezpace, + ContainingNamespace = rootNamespace, + Visibility = VisibilityKind.Private + }); + assembly.RootNamespace = rootNamespace; + + var objectType = new BasicType("Object", TypeKind.ReferenceType) + { + ContainingAssembly = mscorlib, + ContainingNamespace = "System", + }; + var objectConstructorMethod = new MethodReference(".ctor", PlatformTypes.Void) + { + ContainingType = objectType + }; + + var languagesNamespace = new Namespace("Languages") {ContainingAssembly = assembly, ContainingNamespace = rootNamespace}; + rootNamespace.Namespaces.Add(languagesNamespace); + var englishType = new TypeDefinition("English", TypeKind.ReferenceType, TypeDefinitionKind.Class) + { + ContainingAssembly = assembly, + ContainingNamespace = languagesNamespace, Visibility = VisibilityKind.Public, - IsStatic = true, - Base = new BasicType("Object", TypeKind.ReferenceType) + IsStatic = false, + Base = objectType + }; + var englishGreetMethod = new MethodDefinition("Greet", PlatformTypes.String) + { + Visibility = VisibilityKind.Public, + ContainingType = englishType, + IsStatic = false, + Body = new MethodBody(MethodBodyKind.Bytecode) { - ContainingAssembly = mscorlib, - ContainingNamespace = "System", + Instructions = + { + new Bytecode.LoadInstruction(0, Bytecode.LoadOperation.Value, new Constant("¡Hello!")), + new Bytecode.BasicInstruction(1, Bytecode.BasicOperation.Return) + } } }; - namezpace.Types.Add(type); - var method = new MethodDefinition("Main", PlatformTypes.Void) + + var thisVariable = new LocalVariable("this", true); + var englishTypeConstructor = new MethodDefinition(".ctor", PlatformTypes.Void) { + SpecialName = true, + RuntimeSpecialName = true, Visibility = VisibilityKind.Public, - ContainingType = type, + ContainingType = englishType, + IsStatic = false, + Body = new MethodBody(MethodBodyKind.Bytecode) + { + Parameters = {thisVariable}, + Instructions = + { + new Bytecode.LoadInstruction(0, Bytecode.LoadOperation.Content, thisVariable), + new Bytecode.MethodCallInstruction(1, Bytecode.MethodCallOperation.Jump, objectConstructorMethod), + new Bytecode.BasicInstruction(2, Bytecode.BasicOperation.Nop), + new Bytecode.BasicInstruction(3, Bytecode.BasicOperation.Return) + } + } + }; + englishType.Methods.Add(englishTypeConstructor); + englishType.Methods.Add(englishGreetMethod); + languagesNamespace.Types.Add(englishType); + + var spanishType = new TypeDefinition("Spanish", TypeKind.ReferenceType, TypeDefinitionKind.Class) + { + ContainingAssembly = assembly, + ContainingNamespace = languagesNamespace, + Visibility = VisibilityKind.Public, + IsStatic = false, + Base = objectType + }; + var spanishGreetMethod = new MethodDefinition("Greet", PlatformTypes.String) + { + Visibility = VisibilityKind.Public, + ContainingType = spanishType, + IsStatic = false, + Body = new MethodBody(MethodBodyKind.Bytecode) + { + Instructions = + { + new Bytecode.LoadInstruction(0, Bytecode.LoadOperation.Value, new Constant("¡Hola!")), + new Bytecode.BasicInstruction(1, Bytecode.BasicOperation.Return) + } + } + }; + var spanishTypeConstructor = new MethodDefinition(".ctor", PlatformTypes.Void) + { + SpecialName = true, + RuntimeSpecialName = true, + Visibility = VisibilityKind.Public, + ContainingType = spanishType, + IsStatic = false, + Body = new MethodBody(MethodBodyKind.Bytecode) + { + Parameters = {thisVariable}, + Instructions = + { + new Bytecode.LoadInstruction(0, Bytecode.LoadOperation.Content, thisVariable), + new Bytecode.MethodCallInstruction(1, Bytecode.MethodCallOperation.Jump, objectConstructorMethod), + new Bytecode.BasicInstruction(2, Bytecode.BasicOperation.Nop), + new Bytecode.BasicInstruction(3, Bytecode.BasicOperation.Return) + } + } + }; + spanishType.Methods.Add(spanishGreetMethod); + spanishType.Methods.Add(spanishTypeConstructor); + languagesNamespace.Types.Add(spanishType); + + var consoleNamespace = new Namespace("Console") {ContainingAssembly = assembly, ContainingNamespace = rootNamespace}; + rootNamespace.Namespaces.Add(consoleNamespace); + var programType = new TypeDefinition("Program", TypeKind.ReferenceType, TypeDefinitionKind.Class) + { + ContainingAssembly = assembly, + ContainingNamespace = consoleNamespace, + Visibility = VisibilityKind.Public, + IsStatic = true, + Base = objectType + }; + consoleNamespace.Types.Add(programType); + + var mainMethod = new MethodDefinition("Main", PlatformTypes.Void) + { + Visibility = VisibilityKind.Public, + ContainingType = programType, IsStatic = true, Body = new MethodBody(MethodBodyKind.Bytecode) { - MaxStack = 1, Instructions = { new Bytecode.BasicInstruction(0, Bytecode.BasicOperation.Nop), - new Bytecode.LoadInstruction(1, Bytecode.LoadOperation.Value, new Constant("Hello World!")), - new Bytecode.MethodCallInstruction(2, Bytecode.MethodCallOperation.Static, ConsoleWriteLineMethodReference()), - new Bytecode.BasicInstruction(3, Bytecode.BasicOperation.Return) + new Bytecode.CreateObjectInstruction(1, englishTypeConstructor), + new Bytecode.MethodCallInstruction(2, Bytecode.MethodCallOperation.Jump, englishGreetMethod), + new Bytecode.MethodCallInstruction(3, Bytecode.MethodCallOperation.Static, ConsoleWriteLineMethodReference()), + new Bytecode.BasicInstruction(4, Bytecode.BasicOperation.Nop), + new Bytecode.CreateObjectInstruction(5, spanishTypeConstructor), + new Bytecode.MethodCallInstruction(6, Bytecode.MethodCallOperation.Jump, spanishGreetMethod), + new Bytecode.MethodCallInstruction(7, Bytecode.MethodCallOperation.Static, ConsoleWriteLineMethodReference()), + new Bytecode.BasicInstruction(8, Bytecode.BasicOperation.Nop), + new Bytecode.BasicInstruction(9, Bytecode.BasicOperation.Return) } } }; - type.Methods.Add(method); + programType.Methods.Add(mainMethod); + var generator = new MetadataGenerator.Generator(); generator.Generate(assembly); } - private static void TacInstrumentation() + // Each method body is translated to TAC and modified by adding a log at the beginning of the method. Then it is translated back + // to Bytecode and generated + private static void TacInstrumentation() => DoWithLibs(input => { - var input = "../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"; var host = new Host(); PlatformTypes.Resolve(host); @@ -431,45 +548,48 @@ private static void TacInstrumentation() var loader = new MetadataProvider.Loader(host); loader.LoadAssembly(input); - var main = (from a in host.Assemblies + var allDefinedMethods = (from a in host.Assemblies from t in a.RootNamespace.GetAllTypes() from m in t.Members.OfType() - where m.Name.Equals("Main") - select m).First(); + where m.HasBody + select m).ToList(); + + foreach (var method in allDefinedMethods) + { + var tac = new Backend.Transformations.Disassembler(method).Execute(); + method.Body = tac; - var tac = new Backend.Transformations.Disassembler(main).Execute(); - main.Body = tac; + AddLogAtMethodEntry($"Entering method: {method.Name}", method.Body); - AddLogAtIndex(0, "entering main", main.Body); - AddLogAtIndex(tac.Instructions.Count - 1, "exiting main", main.Body); + var cfanalysis = new ControlFlowAnalysis(method.Body); + var cfg = cfanalysis.GenerateExceptionalControlFlow(); - var cfanalysis = new ControlFlowAnalysis(main.Body); - var cfg = cfanalysis.GenerateExceptionalControlFlow(); + var webAnalysis = new WebAnalysis(cfg); + webAnalysis.Analyze(); + webAnalysis.Transform(); + method.Body.UpdateVariables(); - var webAnalysis = new WebAnalysis(cfg); - webAnalysis.Analyze(); - webAnalysis.Transform(); - main.Body.UpdateVariables(); + var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); + typeInferenceAnalysis.Analyze(); - var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, main.ReturnType); - typeInferenceAnalysis.Analyze(); + var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); + method.Body = bytecode; + } - var bytecode = new Backend.Transformations.Assembly.Assembler(main).Execute(); - main.Body = bytecode; var generator = new MetadataGenerator.Generator(); foreach (var assembly in host.Assemblies) { generator.Generate(assembly); } - } + }); - private static void AddLogAtIndex(int index, string message, MethodBody body) + private static void AddLogAtMethodEntry(string message, MethodBody body) { var result = new TemporalVariable("$s", 0); var loadInstruction = new Tac.LoadInstruction(0, result, new Constant(message)) { - Label = body.Instructions[index].Label + "º" + Label = body.Instructions.First().Label + "º" }; var methodCallInstruction = new Tac.MethodCallInstruction( 0, @@ -481,11 +601,9 @@ private static void AddLogAtIndex(int index, string message, MethodBody body) Label = loadInstruction.Label + "º" }; - var instructions = - body.Instructions.Take(index) - .Concat(new List {loadInstruction, methodCallInstruction}) - .Concat(body.Instructions.Skip(index)) - .ToList(); + var instructions = new List {loadInstruction, methodCallInstruction} + .Concat(body.Instructions) + .ToList(); body.Instructions.Clear(); body.Instructions.AddRange(instructions); @@ -507,83 +625,54 @@ private static MethodReference ConsoleWriteLineMethodReference() return writeLineMethod; } - private static void ReadAndGenerateDll(bool transformToTacAndBackToBytecode) + private static void ReadAndGenerateDll(bool transformToTacAndBackToBytecode) => DoWithLibs(file => { - var inputs = new[] - { - new[] {"../../../Examples/bin/Debug/Examples.dll"}, - new[] - { - "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll", - "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll" - }, - new[] - { - "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll", - "../../../../DSA/DSA/DSAUnitTests/bin/Debug/net45/DSAUnitTests.dll" - }, - new[] - { - "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.dll", - "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.Tests.dll" - }, - new[] - { - "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll", - "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Async.dll", - "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll", - "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll" - } - }; + var host = new Host(); - foreach (var file in inputs.SelectMany(i => i)) - { - var host = new Host(); + PlatformTypes.Resolve(host); - PlatformTypes.Resolve(host); + System.Console.WriteLine($"Reading {file}"); + var loader = new MetadataProvider.Loader(host); + loader.LoadAssembly(file); - System.Console.WriteLine($"Reading {file}"); - var loader = new MetadataProvider.Loader(host); - loader.LoadAssembly(file); + if (transformToTacAndBackToBytecode) + { + var allDefinedMethods = (from a in host.Assemblies + from t in a.RootNamespace.GetAllTypes() + from m in t.Members.OfType() + where m.HasBody + select m).ToList(); - if (transformToTacAndBackToBytecode) + foreach (var method in allDefinedMethods) { - var allDefinedMethods = (from a in host.Assemblies - from t in a.RootNamespace.GetAllTypes() - from m in t.Members.OfType() - where m.HasBody - select m).ToList(); + var tac = new Backend.Transformations.Disassembler(method).Execute(); + method.Body = tac; - foreach (var method in allDefinedMethods) - { - var tac = new Backend.Transformations.Disassembler(method).Execute(); - method.Body = tac; - - var cfanalysis = new ControlFlowAnalysis(method.Body); - var cfg = cfanalysis.GenerateExceptionalControlFlow(); - - var webAnalysis = new WebAnalysis(cfg); - webAnalysis.Analyze(); - webAnalysis.Transform(); - method.Body.UpdateVariables(); - - var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); - typeInferenceAnalysis.Analyze(); - - var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); - method.Body = bytecode; - } - } + var cfanalysis = new ControlFlowAnalysis(method.Body); + var cfg = cfanalysis.GenerateExceptionalControlFlow(); - var generator = new MetadataGenerator.Generator(); + var webAnalysis = new WebAnalysis(cfg); + webAnalysis.Analyze(); + webAnalysis.Transform(); + method.Body.UpdateVariables(); - foreach (var assembly in host.Assemblies) - { - generator.Generate(assembly); + var typeInferenceAnalysis = new TypeInferenceAnalysis(cfg, method.ReturnType); + typeInferenceAnalysis.Analyze(); + + var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); + method.Body = bytecode; } } - } + var generator = new MetadataGenerator.Generator(); + + foreach (var assembly in host.Assemblies) + { + generator.Generate(assembly); + } + }); + + // TODO hacerlo generico y ver como darle sentido para los casos de estudio (ya que al ser libs van a tener metodos que no se usan). private static void RemoveUnusedMethodFromSimpleExecutable() { var input = "../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"; @@ -634,11 +723,16 @@ from m in t.Members.OfType() } // remove unused method - var unusedMethod = allDefinedMethods.Except(callGraph.Methods).First(); - var type = (TypeDefinition) unusedMethod.ContainingType; - var onlyUsedMethods = type.Methods.Where(method => !method.Equals(unusedMethod)).ToList(); - type.Methods.Clear(); - type.Methods.AddRange(onlyUsedMethods); + var unusedPrivateMethods = allDefinedMethods + .Except(callGraph.Methods.Cast()) + .Where(method => method.Visibility == VisibilityKind.Private) + .ToList(); + foreach (var unusedMethods in unusedPrivateMethods) + { + unusedMethods.ContainingType.Methods.Remove(unusedMethods); + } + + System.Console.WriteLine($"File: {input} - Unused methods removed: {unusedPrivateMethods.Count}"); // generate var generator = new MetadataGenerator.Generator(); @@ -648,12 +742,48 @@ from m in t.Members.OfType() } } + private static void DoWithLibs(Action operation) + { + var inputs = new[] + { + new[] {"../../../Examples/bin/Debug/Examples.dll"}, + new[] + { + "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser/bin/Debug/net45/TinyCsvParser.dll", + "../../../../TinyCsvParser/TinyCsvParser/TinyCsvParser.Test/bin/Debug/net45/TinyCsvParser.Test.dll" + }, + new[] + { + "../../../../DSA/DSA/DSA/bin/Debug/net45/DSA.dll", + "../../../../DSA/DSA/DSAUnitTests/bin/Debug/net45/DSAUnitTests.dll" + }, + new[] + { + "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.dll", + "../../../../Fleck/src/Fleck.Tests/bin/Debug/net45/Fleck.Tests.dll" + }, + new[] + { + "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.dll", + "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Async.dll", + "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Tests.dll", + "../../../../Optional/src/Optional.Tests/bin/Debug/net45/Optional.Utilities.dll" + } + }; + + foreach (var file in inputs.SelectMany(i => i)) + { + operation.Invoke(file); + } + + } + static void Main(string[] args) { - ReadAndGenerateDll(false); - // ReadAndGenerateDll(true); + // ReadAndGenerateDll(transformToTacAndBackToBytecode: false); + // ReadAndGenerateDll(transformToTacAndBackToBytecode: true); // TacInstrumentation(); - // HelloWorldAssembly(); + // ProgramaticallyGeneratedAssembly(); // RemoveUnusedMethodFromSimpleExecutable(); System.Console.WriteLine("Done!"); From aa9c64f9e1d2db149846374e51c6407e567d4826 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 17 Oct 2020 20:42:46 -0300 Subject: [PATCH 248/256] refactor --- Console/Program.cs | 2 +- .../Generation/AssemblyGenerator.cs | 1 + .../CustomAttributeGenerator.cs | 2 +- .../Generation/Fields/FieldGenerator.cs | 2 +- .../Fields/FieldSignatureEncoder.cs | 8 +- .../Generation/GenericParameterGenerator.cs | 2 +- .../Generation/HandleResolver.cs | 449 ++++++++++++++++++ .../Generation/MetadataContainer.cs | 29 +- .../Generation/MetadataResolver.cs | 339 ------------- .../Methods/Body/MethodBodyControlFlow.cs | 8 +- .../Methods/Body/MethodBodyEncoder.cs | 60 +-- .../Body/MethodLocalsSignatureEncoder.cs | 8 +- .../Generation/Methods/MethodGenerator.cs | 22 +- .../Methods/MethodSignatureEncoder.cs | 12 +- .../Generation/ModuleGenerator.cs | 2 +- .../Properties/PropertyGenerator.cs | 2 +- .../Properties/PropertySignatureEncoder.cs | 8 +- .../Generation/Types/TypeGenerator.cs | 65 +-- .../Generation/Types/TypeSignatureEncoder.cs | 23 + MetadataGenerator/Generator.cs | 2 +- MetadataGenerator/MetadataGenerator.csproj | 3 +- 21 files changed, 570 insertions(+), 479 deletions(-) create mode 100644 MetadataGenerator/Generation/HandleResolver.cs delete mode 100644 MetadataGenerator/Generation/MetadataResolver.cs create mode 100644 MetadataGenerator/Generation/Types/TypeSignatureEncoder.cs diff --git a/Console/Program.cs b/Console/Program.cs index f07e7bb2..ba29552f 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -780,7 +780,7 @@ private static void DoWithLibs(Action operation) static void Main(string[] args) { - // ReadAndGenerateDll(transformToTacAndBackToBytecode: false); + ReadAndGenerateDll(transformToTacAndBackToBytecode: false); // ReadAndGenerateDll(transformToTacAndBackToBytecode: true); // TacInstrumentation(); // ProgramaticallyGeneratedAssembly(); diff --git a/MetadataGenerator/Generation/AssemblyGenerator.cs b/MetadataGenerator/Generation/AssemblyGenerator.cs index e462707e..59645fd8 100644 --- a/MetadataGenerator/Generation/AssemblyGenerator.cs +++ b/MetadataGenerator/Generation/AssemblyGenerator.cs @@ -13,6 +13,7 @@ public static MetadataContainer Generate(Assembly assembly) var moduleGenerator = new ModuleGenerator(metadataContainer); var metadataBuilder = metadataContainer.MetadataBuilder; + // Assembly Table (0x20) metadataBuilder.AddAssembly( name: metadataBuilder.GetOrAddString(assembly.Name), version: assembly.Version, diff --git a/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs b/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs index 3f076873..8f356b37 100644 --- a/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs +++ b/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs @@ -19,7 +19,7 @@ public void Generate(SRM.EntityHandle owner, CustomAttribute customAttribute) // CustomAttribute Table (0x0C) metadataContainer.MetadataBuilder.AddCustomAttribute( owner, - metadataContainer.MetadataResolver.HandleOf(customAttribute.Constructor), + metadataContainer.HandleResolver.HandleOf(customAttribute.Constructor), metadataContainer.MetadataBuilder.GetOrAddBlob(signature)); } } diff --git a/MetadataGenerator/Generation/Fields/FieldGenerator.cs b/MetadataGenerator/Generation/Fields/FieldGenerator.cs index 355f127b..baab1675 100644 --- a/MetadataGenerator/Generation/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generation/Fields/FieldGenerator.cs @@ -15,7 +15,7 @@ internal class FieldGenerator public FieldGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; - fieldSignatureEncoder = new FieldSignatureEncoder(metadataContainer.MetadataResolver); + fieldSignatureEncoder = new FieldSignatureEncoder(metadataContainer.HandleResolver); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } diff --git a/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs b/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs index d46d50ef..9aa06ebc 100644 --- a/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs +++ b/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs @@ -6,17 +6,17 @@ namespace MetadataGenerator.Generation.Fields { internal class FieldSignatureEncoder { - private readonly MetadataResolver metadataResolver; + private readonly HandleResolver _handleResolver; - public FieldSignatureEncoder(MetadataResolver metadataResolver) + public FieldSignatureEncoder(HandleResolver handleResolver) { - this.metadataResolver = metadataResolver; + this._handleResolver = handleResolver; } public SRM.BlobBuilder EncodeSignatureOf(IFieldReference field) { var fieldSignature = new SRM.BlobBuilder(); - metadataResolver.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); + _handleResolver.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); return fieldSignature; } } diff --git a/MetadataGenerator/Generation/GenericParameterGenerator.cs b/MetadataGenerator/Generation/GenericParameterGenerator.cs index 4749deb1..896f734c 100644 --- a/MetadataGenerator/Generation/GenericParameterGenerator.cs +++ b/MetadataGenerator/Generation/GenericParameterGenerator.cs @@ -19,7 +19,7 @@ public static void GenerateGenericParameters(MetadataContainer metadataContainer { var genericParameter = entry.GenericParameter; var constraints = genericParameter.Constraints - .Select(type => metadataContainer.MetadataResolver.HandleOf(type)) + .Select(type => metadataContainer.HandleResolver.HandleOf(type)) .ToSet(); return new GenericParamRow( entry.Parent, diff --git a/MetadataGenerator/Generation/HandleResolver.cs b/MetadataGenerator/Generation/HandleResolver.cs new file mode 100644 index 00000000..09cd41a1 --- /dev/null +++ b/MetadataGenerator/Generation/HandleResolver.cs @@ -0,0 +1,449 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection; +using MetadataGenerator.Generation.Fields; +using MetadataGenerator.Generation.Methods; +using MetadataGenerator.Generation.Methods.Body; +using MetadataGenerator.Generation.Types; +using Model; +using Model.ThreeAddressCode.Values; +using Model.Types; +using static System.Linq.Enumerable; +using static MetadataGenerator.Generation.Types.TypeGenerator; +using Assembly = Model.Assembly; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generation +{ + internal class HandleResolver + { + private readonly Assembly assembly; + private readonly MetadataContainer metadataContainer; + private readonly FieldSignatureEncoder fieldSignatureEncoder; + private readonly MethodSignatureEncoder methodSignatureEncoder; + private readonly MethodLocalsSignatureEncoder methodLocalsSignatureEncoder; + private readonly TypeSignatureEncoder typeSignatureEncoder; + + #region handles + + // module + private SRM.ModuleDefinitionHandle? moduleHandle; + + public SRM.ModuleDefinitionHandle ModuleHandle + { + get => moduleHandle ?? throw new Exception("Module handle was not set"); + set + { + if (moduleHandle != null) throw new Exception("Multiple modules not supported"); + moduleHandle = value; + } + } + // + + // assembly + private readonly IDictionary, + SRM.AssemblyReferenceHandle> assemblyRefHandles; + + private Tuple + RefKeyFor(IAssemblyReference assemblyReference) + { + var matchedAssemblyReference = assembly.References.First(assembly => assembly.Name == assemblyReference.Name); + var name = metadataContainer.MetadataBuilder.GetOrAddString(matchedAssemblyReference.Name); + var version = matchedAssemblyReference.Version; + var culture = metadataContainer.MetadataBuilder.GetOrAddString(matchedAssemblyReference.Culture); + var publicKey = metadataContainer.MetadataBuilder.GetOrAddBlob(matchedAssemblyReference.PublicKey); + AssemblyFlags flags = default; + SRM.BlobHandle hashValue = default; + return new Tuple( + name, + version, + culture, + publicKey, + flags, + hashValue + ); + } + // + + // type + private readonly IDictionary, SRM.TypeReferenceHandle> typeRefHandles; + + private Tuple RefKeyFor(IBasicType type) + { + SRM.EntityHandle resolutionScope; + if (type.ContainingType == null) + { + resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) + ? ModuleHandle + : (SRM.EntityHandle) GetOrAddAssemblyReference(type.ContainingAssembly); + } + else + { + resolutionScope = GetOrAddTypeReference(type.ContainingType); + } + + var key = new Tuple( + resolutionScope, + metadataContainer.MetadataBuilder.GetOrAddString(type.ContainingNamespace), + metadataContainer.MetadataBuilder.GetOrAddString(TypeNameOf(type)) + ); + return key; + } + + private readonly IDictionary typeSpecHandles; + + private SRM.BlobHandle SpecKeyFor(IType type) + { + var signature = typeSignatureEncoder.EncodeSignatureOf(type); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); + var key = blobHandle; + return key; + } + // + + //field + private readonly IDictionary, SRM.MemberReferenceHandle> fieldRefHandles; + + private Tuple RefKeyFor(IFieldReference field) + { + var signature = fieldSignatureEncoder.EncodeSignatureOf(field); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); + var parent = HandleOf(field.ContainingType); + var key = new Tuple( + parent, + metadataContainer.MetadataBuilder.GetOrAddString(field.Name), + blobHandle + ); + return key; + } + + // + + // method + private readonly IDictionary, SRM.MemberReferenceHandle> methodRefHandles; + + private Tuple RefKeyFor(IMethodReference method) + { + var signature = methodSignatureEncoder.EncodeSignatureOf(method); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); + var parent = + method.ContainingType is ArrayTypeWrapper arrayTypeWrapper + ? HandleOf(arrayTypeWrapper.Type) + : HandleOf(method.ContainingType); + var key = new Tuple( + parent, + metadataContainer.MetadataBuilder.GetOrAddString(method.Name), + blobHandle + ); + return key; + } + + private readonly IDictionary, SRM.MethodSpecificationHandle> methodSpecHandles; + + + private Tuple SpecKeyFor(IMethodReference method) + { + var signature = methodSignatureEncoder.EncodeSignatureOf(method); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); + var genericMethodHandle = HandleOf(method.GenericMethod); + var key = new Tuple(genericMethodHandle, blobHandle); + return key; + } + // + + // other + private readonly IDictionary variablesSignatureHandles; + + private SRM.BlobHandle StandaloneSigKeyFor(IList localVariables) + { + var signature = methodLocalsSignatureEncoder.EncodeSignatureOf(localVariables); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); + var key = blobHandle; + return key; + } + + private SRM.MethodDefinitionHandle? mainMethodHandle; + + public SRM.MethodDefinitionHandle MainMethodHandle + { + get => mainMethodHandle ?? throw new Exception("Main method handle was not set"); + set + { + if (mainMethodHandle != null) throw new Exception("Main method was already set"); + mainMethodHandle = value; + } + } + // + + #endregion + + + public HandleResolver(MetadataContainer metadataContainer, Assembly assembly) + { + this.metadataContainer = metadataContainer; + this.assembly = assembly; + assemblyRefHandles = + new Dictionary, + SRM.AssemblyReferenceHandle>(); + variablesSignatureHandles = new Dictionary(); + variablesSignatureHandles = new Dictionary(); + methodSpecHandles = new Dictionary, SRM.MethodSpecificationHandle>(); + typeSpecHandles = new Dictionary(); + fieldRefHandles = new Dictionary, SRM.MemberReferenceHandle>(); + methodRefHandles = new Dictionary, SRM.MemberReferenceHandle>(); + typeRefHandles = new Dictionary, SRM.TypeReferenceHandle>(); + fieldSignatureEncoder = new FieldSignatureEncoder(this); + methodSignatureEncoder = new MethodSignatureEncoder(this); + methodLocalsSignatureEncoder = new MethodLocalsSignatureEncoder(this); + typeSignatureEncoder = new TypeSignatureEncoder(this); + } + + public SRM.UserStringHandle UserStringHandleOf(string value) => metadataContainer.MetadataBuilder.GetOrAddUserString(value); + + public SRM.StandaloneSignatureHandle HandleOf(IList localVariables) + { + var key = StandaloneSigKeyFor(localVariables); + if (!variablesSignatureHandles.TryGetValue(key, out var variableSignatureHandle)) + { + // StandAloneSig Table (0x11) + variableSignatureHandle = metadataContainer.MetadataBuilder.AddStandaloneSignature(signature: key); + variablesSignatureHandles[key] = variableSignatureHandle; + } + + return variableSignatureHandle; + } + + public SRM.EntityHandle HandleOf(IMetadataReference metadataReference) + { + switch (metadataReference) + { + case IFieldReference field: + return GetOrAddFieldReference(field); + case IMethodReference method: + return method.IsGenericInstantiation() + ? GetOrAddMethodSpecification(method) + : GetOrAddMethodReference(method); + case IType type: + switch (type) + { + case IType iType when iType is ArrayType + || iType is PointerType + || iType is IGenericParameterReference + || iType is IBasicType basicType && basicType.IsGenericInstantiation(): + return GetOrAddTypeSpecification(iType); + case IBasicType basicType: + return GetOrAddTypeReference(basicType); + default: + throw new Exception($"type {type} not yet supported"); + } + default: + throw new Exception($"Metadata {metadataReference} reference not supported"); + } + } + + private SRM.AssemblyReferenceHandle GetOrAddAssemblyReference(IAssemblyReference assemblyReference) + { + var key = RefKeyFor(assemblyReference); + if (!assemblyRefHandles.TryGetValue(key, out var assemblyRefHandle)) + { + // AssemblyRef Table (0x23) + assemblyRefHandle = metadataContainer.MetadataBuilder.AddAssemblyReference( + name: key.Item1, + version: key.Item2, + culture: key.Item3, + publicKeyOrToken: key.Item4, + flags: key.Item5, + hashValue: key.Item6 + ); + assemblyRefHandles.Add(key, assemblyRefHandle); + } + + return assemblyRefHandle; + } + + private SRM.EntityHandle GetOrAddTypeReference(IBasicType type) + { + var key = RefKeyFor(type); + if (!typeRefHandles.TryGetValue(key, out var typeRefHandle)) + { + // TypeRef Table (0x01) + typeRefHandle = metadataContainer.MetadataBuilder.AddTypeReference( + resolutionScope: key.Item1, + @namespace: key.Item2, + name: key.Item3); + typeRefHandles.Add(key, typeRefHandle); + } + + return typeRefHandle; + } + + private SRM.TypeSpecificationHandle GetOrAddTypeSpecification(IType type) + { + var key = SpecKeyFor(type); + if (!typeSpecHandles.TryGetValue(key, out var typeSpecHandle)) + { + // TypeSpec Table (0x1B) + typeSpecHandle = metadataContainer.MetadataBuilder.AddTypeSpecification(signature: key); + typeSpecHandles.Add(key, typeSpecHandle); + } + + return typeSpecHandle; + } + + private SRM.MethodSpecificationHandle GetOrAddMethodSpecification(IMethodReference method) + { + var key = SpecKeyFor(method); + if (!methodSpecHandles.TryGetValue(key, out var methodSpecHandle)) + { + // MethodSpec Table (0x2B) + methodSpecHandle = metadataContainer.MetadataBuilder.AddMethodSpecification( + method: key.Item1, + instantiation: key.Item2); + methodSpecHandles.Add(key, methodSpecHandle); + } + + return methodSpecHandle; + } + + private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method) + { + var key = RefKeyFor(method); + if (!methodRefHandles.TryGetValue(key, out var methodRefHandle)) + { + // MemberRef Table (0x0A) + methodRefHandle = metadataContainer.MetadataBuilder.AddMemberReference( + parent: key.Item1, + name: key.Item2, + signature: key.Item3); + methodRefHandles.Add(key, methodRefHandle); + } + + return methodRefHandle; + } + + private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field) + { + var key = RefKeyFor(field); + if (!fieldRefHandles.TryGetValue(key, out var fieldRefHandle)) + { + // MemberRef Table (0x0A) + fieldRefHandle = metadataContainer.MetadataBuilder.AddMemberReference( + parent: key.Item1, + name: key.Item2, + signature: key.Item3); + fieldRefHandles.Add(key, fieldRefHandle); + } + + return fieldRefHandle; + } + + public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) + { + if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); + else if (type.Equals(PlatformTypes.Byte)) encoder.Byte(); + else if (type.Equals(PlatformTypes.SByte)) encoder.SByte(); + else if (type.Equals(PlatformTypes.Char)) encoder.Char(); + else if (type.Equals(PlatformTypes.Double)) encoder.Double(); + else if (type.Equals(PlatformTypes.Int16)) encoder.Int16(); + else if (type.Equals(PlatformTypes.UInt16)) encoder.UInt16(); + else if (type.Equals(PlatformTypes.Int32)) encoder.Int32(); + else if (type.Equals(PlatformTypes.UInt32)) encoder.UInt32(); + else if (type.Equals(PlatformTypes.Int64)) encoder.Int64(); + else if (type.Equals(PlatformTypes.UInt64)) encoder.UInt64(); + else if (type.Equals(PlatformTypes.String)) encoder.String(); + else if (type.Equals(PlatformTypes.Single)) encoder.Single(); + else if (type.Equals(PlatformTypes.Object)) encoder.Object(); + else if (type.Equals(PlatformTypes.IntPtr)) encoder.IntPtr(); + else if (type.Equals(PlatformTypes.UIntPtr)) encoder.UIntPtr(); + else + { + switch (type) + { + case IBasicType iBasicType: + { + var isValueType = type.TypeKind == TypeKind.ValueType; + if (iBasicType.IsGenericInstantiation()) + { + var genericInstantiation = encoder.GenericInstantiation( + GetOrAddTypeReference(iBasicType.GenericType), + iBasicType.GenericArguments.Count, + isValueType); + foreach (var genericArg in iBasicType.GenericArguments) + { + Encode(genericArg, genericInstantiation.AddArgument()); + } + } + else + { + encoder.Type(GetOrAddTypeReference(iBasicType), isValueType); + } + + break; + } + case ArrayType arrayType: + { + if (arrayType.IsVector) + { + Encode(arrayType.ElementsType, encoder.SZArray()); + } + else + { + encoder.Array( + elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), + arrayShapeEncoder => + { + // This assumes that all dimensions have 0 as lower bound and none declare sizes. + // Lower bounds and sizes are not modelled. + var lowerBounds = Repeat(0, (int) arrayType.Rank).ToImmutableArray(); + var sizes = ImmutableArray.Empty; + arrayShapeEncoder.Shape((int) arrayType.Rank, sizes, lowerBounds); + }); + } + + + break; + } + case PointerType pointerType: + { + var targetType = pointerType.TargetType; + if (targetType.Equals(PlatformTypes.Void)) + { + encoder.VoidPointer(); + } + else + { + Encode(targetType, encoder.Pointer()); + } + + break; + } + case FunctionPointerType _: + { + encoder.FunctionPointer(); + break; + } + case IGenericParameterReference genericParameter: + { + switch (genericParameter.Kind) + { + case GenericParameterKind.Type: + encoder.GenericTypeParameter(genericParameter.Index); + break; + case GenericParameterKind.Method: + encoder.GenericMethodTypeParameter(genericParameter.Index); + break; + default: + throw genericParameter.Kind.ToUnknownValueException(); + } + + break; + } + default: + throw new Exception($"Type {type} not supported"); + } + } + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generation/MetadataContainer.cs b/MetadataGenerator/Generation/MetadataContainer.cs index c2ec41ee..c72bf34d 100644 --- a/MetadataGenerator/Generation/MetadataContainer.cs +++ b/MetadataGenerator/Generation/MetadataContainer.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Model; using static MetadataGenerator.Generation.GenericParameterGenerator; using static MetadataGenerator.Generation.Types.InterfaceImplementationGenerator; @@ -12,40 +11,18 @@ namespace MetadataGenerator.Generation internal class MetadataContainer { public readonly ECMA335.MetadataBuilder MetadataBuilder; - public readonly MetadataResolver MetadataResolver; + public readonly HandleResolver HandleResolver; public readonly ECMA335.MethodBodyStreamEncoder MethodBodyStream; public readonly SRM.BlobBuilder MappedFieldData; public readonly ISet GenericParameterEntries; public readonly ISet InterfaceImplementationEntries; public readonly ISet NestedTypeEntries; - private SRM.MethodDefinitionHandle? mainMethodHandle; - private SRM.ModuleDefinitionHandle? moduleHandle; - - public SRM.MethodDefinitionHandle MainMethodHandle - { - get => mainMethodHandle ?? throw new Exception("Main method handle was not set"); - set - { - if (mainMethodHandle != null) throw new Exception("Main method was already set"); - mainMethodHandle = value; - } - } - - public SRM.ModuleDefinitionHandle ModuleHandle - { - get => moduleHandle ?? throw new Exception("Module handle was not set"); - set - { - if (moduleHandle != null) throw new Exception("Multiple modules not supported"); - moduleHandle = value; - } - } public MetadataContainer(Assembly assembly) { MetadataBuilder = new ECMA335.MetadataBuilder(); MethodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); - MetadataResolver = new MetadataResolver(this, assembly); + HandleResolver = new HandleResolver(this, assembly); MappedFieldData = new SRM.BlobBuilder(); GenericParameterEntries = new HashSet(); InterfaceImplementationEntries = new HashSet(); diff --git a/MetadataGenerator/Generation/MetadataResolver.cs b/MetadataGenerator/Generation/MetadataResolver.cs deleted file mode 100644 index 37200464..00000000 --- a/MetadataGenerator/Generation/MetadataResolver.cs +++ /dev/null @@ -1,339 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using MetadataGenerator.Generation.Fields; -using MetadataGenerator.Generation.Methods; -using Model; -using Model.Types; -using static System.Linq.Enumerable; -using static MetadataGenerator.Generation.Types.TypeGenerator; -using ECMA335 = System.Reflection.Metadata.Ecma335; -using SRM = System.Reflection.Metadata; - -namespace MetadataGenerator.Generation -{ - internal class MetadataResolver - { - private readonly Assembly assembly; - private readonly MetadataContainer metadataContainer; - private readonly IDictionary assemblyReferences = new Dictionary(); - private readonly IDictionary typeReferences = new Dictionary(); - - private readonly IDictionary, SRM.MemberReferenceHandle> memberReferences = - new Dictionary, SRM.MemberReferenceHandle>(); - - private readonly IDictionary, SRM.TypeSpecificationHandle> typeSpecificationReferences = - new Dictionary, SRM.TypeSpecificationHandle>(); - - private readonly IDictionary, SRM.MethodSpecificationHandle> methodSpecificationReferences = - new Dictionary, SRM.MethodSpecificationHandle>(); - - private readonly IDictionary standaloneSignatureReferences = - new Dictionary(); - - private readonly FieldSignatureEncoder fieldSignatureEncoder; - private readonly MethodSignatureEncoder methodSignatureEncoder; - - public MetadataResolver(MetadataContainer metadataContainer, Assembly assembly) - { - this.metadataContainer = metadataContainer; - this.assembly = assembly; - - foreach (var assemblyReference in assembly.References) - { - assemblyReferences.Add(assemblyReference.Name, metadataContainer.MetadataBuilder.AddAssemblyReference( - name: metadataContainer.MetadataBuilder.GetOrAddString(assemblyReference.Name), - version: assemblyReference.Version, - culture: metadataContainer.MetadataBuilder.GetOrAddString(assemblyReference.Culture), - publicKeyOrToken: metadataContainer.MetadataBuilder.GetOrAddBlob(assemblyReference.PublicKey), - flags: default, - hashValue: default) - ); - } - - fieldSignatureEncoder = new FieldSignatureEncoder(this); - methodSignatureEncoder = new MethodSignatureEncoder(this); - } - - public SRM.UserStringHandle UserStringHandleOf(string value) => metadataContainer.MetadataBuilder.GetOrAddUserString(value); - - public SRM.EntityHandle HandleOf(IMetadataReference metadataReference) - { - switch (metadataReference) - { - case IFieldReference field: - { - var signature = fieldSignatureEncoder.EncodeSignatureOf(field); - return GetOrAddFieldReference(field, signature); - } - case IMethodReference method: - { - var signature = methodSignatureEncoder.EncodeSignatureOf(method); - return GetOrAddMethodReference(method, signature); - } - case FunctionPointerType functionPointer: - { - var signature = methodSignatureEncoder.EncodeSignatureOf(functionPointer); - return GetOrAddStandaloneSignature(signature); - } - case IType type: - switch (type) - { - case IBasicType basicType: - return GetOrAddTypeReference(basicType); - case IType iType when iType is ArrayType || iType is PointerType || iType is IGenericParameterReference: - return GetOrAddTypeSpecificationFor(iType); - default: - throw new Exception($"type {type} not yet supported"); - } - default: - throw new Exception($"Metadata {metadataReference} reference not supported"); - } - } - - private SRM.EntityHandle GetOrAddTypeReference(IBasicType type) - { - if (type.IsGenericInstantiation()) return GetOrAddTypeSpecificationFor(type); - - var key = type.GetFullName(); - if (!typeReferences.TryGetValue(key, out var typeReference)) - { - SRM.EntityHandle resolutionScope; - if (type.ContainingType == null) // if defined in the namespace then search there - { - resolutionScope = type.ContainingAssembly.Name.Equals(assembly.Name) - ? metadataContainer.ModuleHandle - : (SRM.EntityHandle) assemblyReferences[type.ContainingAssembly.Name]; - } - else - { - // if not, recursively get a reference for the containing type and use that as the resolution scope - resolutionScope = GetOrAddTypeReference(type.ContainingType); - } - - typeReference = metadataContainer.MetadataBuilder.AddTypeReference( - resolutionScope: resolutionScope, - @namespace: metadataContainer.MetadataBuilder.GetOrAddString(type.ContainingNamespace), - name: metadataContainer.MetadataBuilder.GetOrAddString(TypeNameOf(type))); - typeReferences.Add(key, typeReference); - } - - return typeReference; - } - - private SRM.TypeSpecificationHandle GetOrAddTypeSpecificationFor(IType type) - { - var signature = new SRM.BlobBuilder(); - var encoder = new ECMA335.BlobEncoder(signature).TypeSpecificationSignature(); - Encode(type, encoder); - var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); - var key = new Tuple(type.GetFullName(), blobHandle); - if (!typeSpecificationReferences.TryGetValue(key, out var typeSpecification)) - { - typeSpecification = metadataContainer.MetadataBuilder.AddTypeSpecification(blobHandle); - typeSpecificationReferences.Add(key, typeSpecification); - } - - return typeSpecification; - } - - private SRM.MethodSpecificationHandle GetOrAddMethodSpecificationFor(IMethodReference method, SRM.BlobBuilder signature) - { - var genericMethodSignature = methodSignatureEncoder.EncodeSignatureOf(method.GenericMethod); - var key = new Tuple( - $"{method.GenericMethod.ContainingType.GetFullName()}.{method.GenericName}", - genericMethodSignature.ToArray() - ); - if (!methodSpecificationReferences.TryGetValue(key, out var methodSpecification)) - { - methodSpecification = metadataContainer.MetadataBuilder.AddMethodSpecification( - GetOrAddMethodReference(method.GenericMethod, genericMethodSignature), - metadataContainer.MetadataBuilder.GetOrAddBlob(signature) - ); - methodSpecificationReferences.Add(key, methodSpecification); - } - - return methodSpecification; - } - - public SRM.StandaloneSignatureHandle GetOrAddStandaloneSignature(SRM.BlobBuilder signature) - { - var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); - if (!standaloneSignatureReferences.TryGetValue(blobHandle, out var standaloneSignature)) - { - standaloneSignature = metadataContainer.MetadataBuilder.AddStandaloneSignature(blobHandle); - standaloneSignatureReferences.Add(blobHandle, standaloneSignature); - } - - return standaloneSignature; - } - - private SRM.EntityHandle GetOrAddMethodReference(IMethodReference method, SRM.BlobBuilder signature) - { - if (method.IsGenericInstantiation()) - { - return GetOrAddMethodSpecificationFor(method, signature); - } - else if (method.ContainingType is ArrayTypeWrapper arrayTypeWrapper) - { - var parentHandle = GetOrAddTypeSpecificationFor(arrayTypeWrapper.Type); - var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); - var key = new Tuple(parentHandle, signature.ToArray()); - if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) - { - methodReferenceHandle = metadataContainer.MetadataBuilder.AddMemberReference( - parent: parentHandle, - name: metadataContainer.MetadataBuilder.GetOrAddString(method.Name), - signature: blobHandle); - memberReferences.Add(key, methodReferenceHandle); - } - - return methodReferenceHandle; - } - else - { - var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); - var key = new Tuple( - $"{method.ContainingType.GetFullName()}.{method.GenericName}", - signature.ToArray() - ); - if (!memberReferences.TryGetValue(key, out var methodReferenceHandle)) - { - methodReferenceHandle = metadataContainer.MetadataBuilder.AddMemberReference( - parent: GetOrAddTypeReference(method.ContainingType), - name: metadataContainer.MetadataBuilder.GetOrAddString(method.Name), - signature: blobHandle); - memberReferences.Add(key, methodReferenceHandle); - } - - return methodReferenceHandle; - } - } - - private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field, SRM.BlobBuilder signature) - { - var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); - var key = new Tuple( - $"{field.ContainingType.GetFullName()}.{field.Name}", - signature.ToArray() - ); - if (!memberReferences.TryGetValue(key, out var memberReferenceHandle)) - { - memberReferenceHandle = metadataContainer.MetadataBuilder.AddMemberReference( - parent: GetOrAddTypeReference(field.ContainingType), - name: metadataContainer.MetadataBuilder.GetOrAddString(field.Name), - signature: blobHandle); - memberReferences.Add(key, memberReferenceHandle); - } - - return memberReferenceHandle; - } - - public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) - { - if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); - else if (type.Equals(PlatformTypes.Byte)) encoder.Byte(); - else if (type.Equals(PlatformTypes.SByte)) encoder.SByte(); - else if (type.Equals(PlatformTypes.Char)) encoder.Char(); - else if (type.Equals(PlatformTypes.Double)) encoder.Double(); - else if (type.Equals(PlatformTypes.Int16)) encoder.Int16(); - else if (type.Equals(PlatformTypes.UInt16)) encoder.UInt16(); - else if (type.Equals(PlatformTypes.Int32)) encoder.Int32(); - else if (type.Equals(PlatformTypes.UInt32)) encoder.UInt32(); - else if (type.Equals(PlatformTypes.Int64)) encoder.Int64(); - else if (type.Equals(PlatformTypes.UInt64)) encoder.UInt64(); - else if (type.Equals(PlatformTypes.String)) encoder.String(); - else if (type.Equals(PlatformTypes.Single)) encoder.Single(); - else if (type.Equals(PlatformTypes.Object)) encoder.Object(); - else if (type.Equals(PlatformTypes.IntPtr)) encoder.IntPtr(); - else if (type.Equals(PlatformTypes.UIntPtr)) encoder.UIntPtr(); - else - { - switch (type) - { - case IBasicType iBasicType: - { - var isValueType = type.TypeKind == TypeKind.ValueType; - if (iBasicType.IsGenericInstantiation()) - { - var genericInstantiation = encoder.GenericInstantiation( - GetOrAddTypeReference(iBasicType.GenericType), - iBasicType.GenericArguments.Count, - isValueType); - foreach (var genericArg in iBasicType.GenericArguments) - { - Encode(genericArg, genericInstantiation.AddArgument()); - } - } - else - { - encoder.Type(GetOrAddTypeReference(iBasicType), isValueType); - } - - break; - } - case ArrayType arrayType: - { - if (arrayType.IsVector) - { - Encode(arrayType.ElementsType, encoder.SZArray()); - } - else - { - encoder.Array( - elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), - arrayShapeEncoder => - { - // This assumes that all dimensions have 0 as lower bound and none declare sizes. - // Lower bounds and sizes are not modelled. - var lowerBounds = Repeat(0, (int) arrayType.Rank).ToImmutableArray(); - var sizes = ImmutableArray.Empty; - arrayShapeEncoder.Shape((int) arrayType.Rank, sizes, lowerBounds); - }); - } - - - break; - } - case PointerType pointerType: - { - var targetType = pointerType.TargetType; - if (targetType.Equals(PlatformTypes.Void)) - { - encoder.VoidPointer(); - } - else - { - Encode(targetType, encoder.Pointer()); - } - - break; - } - case FunctionPointerType _: - { - encoder.FunctionPointer(); - break; - } - case IGenericParameterReference genericParameter: - { - switch (genericParameter.Kind) - { - case GenericParameterKind.Type: - encoder.GenericTypeParameter(genericParameter.Index); - break; - case GenericParameterKind.Method: - encoder.GenericMethodTypeParameter(genericParameter.Index); - break; - default: - throw genericParameter.Kind.ToUnknownValueException(); - } - - break; - } - default: - throw new Exception($"Type {type} not supported"); - } - } - } - } -} \ No newline at end of file diff --git a/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs index 088fa064..1483a0f9 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs @@ -11,13 +11,13 @@ namespace MetadataGenerator.Generation.Methods.Body internal class MethodBodyControlFlow { private readonly ECMA335.InstructionEncoder instructionEncoder; - private readonly MetadataResolver metadataResolver; + private readonly HandleResolver _handleResolver; private readonly IDictionary labelHandles; - public MethodBodyControlFlow(ECMA335.InstructionEncoder instructionEncoder, MetadataResolver metadataResolver) + public MethodBodyControlFlow(ECMA335.InstructionEncoder instructionEncoder, HandleResolver handleResolver) { this.instructionEncoder = instructionEncoder; - this.metadataResolver = metadataResolver; + this._handleResolver = handleResolver; labelHandles = new Dictionary(); } @@ -79,7 +79,7 @@ public void ProcessExceptionInformation(IList exceptionInformati tryEnd, handlerStart, handlerEnd, - metadataResolver.HandleOf(handler.ExceptionType)); + _handleResolver.HandleOf(handler.ExceptionType)); break; } case ExceptionHandlerBlockKind.Fault: diff --git a/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs index 377d789a..9f3b6fc6 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs @@ -13,7 +13,7 @@ namespace MetadataGenerator.Generation.Methods.Body { internal class MethodBodyEncoder : IInstructionVisitor { - private readonly MetadataResolver metadataResolver; + private readonly HandleResolver _handleResolver; private readonly ECMA335.InstructionEncoder instructionEncoder; private readonly MethodBodyControlFlow methodBodyControlFlow; private readonly List switchInstructionsPlaceHolders; @@ -22,12 +22,12 @@ internal class MethodBodyEncoder : IInstructionVisitor private readonly StackSize stackSize; private int Index { get; set; } - public MethodBodyEncoder(MetadataResolver metadataResolver, MethodBody body) + public MethodBodyEncoder(HandleResolver handleResolver, MethodBody body) { - this.metadataResolver = metadataResolver; + this._handleResolver = handleResolver; this.body = body; instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), new ECMA335.ControlFlowBuilder()); - methodBodyControlFlow = new MethodBodyControlFlow(instructionEncoder, metadataResolver); + methodBodyControlFlow = new MethodBodyControlFlow(instructionEncoder, handleResolver); switchInstructionsPlaceHolders = new List(); skippedIndices = new HashSet(); stackSize = new StackSize(); @@ -79,7 +79,7 @@ public void Visit(Instruction instruction) public void Visit(InitObjInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Initobj); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.Type)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.Type)); stackSize.Decrement(); } @@ -225,7 +225,7 @@ public void Visit(BasicInstruction instruction) public void Visit(ConstrainedInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Constrained); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.ThisType)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.ThisType)); } public void Visit(LoadInstruction instruction) @@ -294,7 +294,7 @@ public void Visit(LoadInstruction instruction) break; case string value: - instructionEncoder.LoadString(metadataResolver.UserStringHandleOf(value)); + instructionEncoder.LoadString(_handleResolver.UserStringHandleOf(value)); stackSize.Increment(); break; case int value: @@ -377,7 +377,7 @@ public void Visit(LoadIndirectInstruction instruction) else { instructionEncoder.OpCode(SRM.ILOpCode.Ldobj); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.Type)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.Type)); } } @@ -396,7 +396,7 @@ public void Visit(LoadFieldInstruction instruction) throw instruction.Operation.ToUnknownValueException(); } - instructionEncoder.Token(metadataResolver.HandleOf(instruction.Field)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.Field)); if (isStatic) { stackSize.Increment(); @@ -407,7 +407,7 @@ public void Visit(LoadMethodAddressInstruction instruction) { var isVirtual = instruction.Method.IsVirtual; instructionEncoder.OpCode(isVirtual ? SRM.ILOpCode.Ldvirtftn : SRM.ILOpCode.Ldftn); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.Method)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.Method)); if (!isVirtual) { stackSize.Increment(); @@ -451,7 +451,7 @@ public void Visit(StoreIndirectInstruction instruction) else { instructionEncoder.OpCode(SRM.ILOpCode.Stobj); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.Type)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.Type)); } stackSize.Decrement(2); @@ -478,7 +478,7 @@ public void Visit(StoreFieldInstruction instruction) { var isStatic = instruction.Field.IsStatic; instructionEncoder.OpCode(isStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.Field)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.Field)); stackSize.Decrement(isStatic ? 1 : 2); } @@ -630,23 +630,23 @@ public void Visit(ConvertInstruction instruction) break; case ConvertOperation.Cast: instructionEncoder.OpCode(SRM.ILOpCode.Castclass); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.IsInst: instructionEncoder.OpCode(SRM.ILOpCode.Isinst); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.Box: instructionEncoder.OpCode(SRM.ILOpCode.Box); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.Unbox: instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.UnboxPtr: instructionEncoder.OpCode(SRM.ILOpCode.Unbox); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.ConversionType)); break; default: throw instruction.Operation.ToUnknownValueException(); @@ -729,14 +729,14 @@ public void Visit(SwitchInstruction instruction) public void Visit(SizeofInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.MeasuredType)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.MeasuredType)); stackSize.Increment(); } public void Visit(LoadTokenInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.Token)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.Token)); stackSize.Increment(); } @@ -746,12 +746,12 @@ public void Visit(MethodCallInstruction instruction) { case MethodCallOperation.Virtual: instructionEncoder.OpCode(SRM.ILOpCode.Callvirt); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.Method)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count + 1); break; case MethodCallOperation.Static: case MethodCallOperation.Jump: - instructionEncoder.Call(metadataResolver.HandleOf(instruction.Method)); + instructionEncoder.Call(_handleResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); break; default: @@ -766,7 +766,7 @@ public void Visit(MethodCallInstruction instruction) public void Visit(IndirectMethodCallInstruction instruction) { - var methodSignature = metadataResolver.HandleOf(instruction.Function); + var methodSignature = _handleResolver.HandleOf(instruction.Function); instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); stackSize.Decrement(instruction.Function.Parameters.Count + 1); if (!instruction.Function.ReturnType.Equals(PlatformTypes.Void)) @@ -777,7 +777,7 @@ public void Visit(IndirectMethodCallInstruction instruction) public void Visit(CreateObjectInstruction instruction) { - var method = metadataResolver.HandleOf(instruction.Constructor); + var method = _handleResolver.HandleOf(instruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); stackSize.Decrement(instruction.Constructor.Parameters.Count); @@ -789,11 +789,11 @@ public void Visit(CreateArrayInstruction instruction) if (instruction.Type.IsVector) { instructionEncoder.OpCode(SRM.ILOpCode.Newarr); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.Type.ElementsType)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.Type.ElementsType)); } else { - var method = metadataResolver.HandleOf(instruction.Constructor); + var method = _handleResolver.HandleOf(instruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); stackSize.Decrement(instruction.Constructor.Parameters.Count); @@ -805,7 +805,7 @@ public void Visit(LoadArrayElementInstruction instruction) { if (instruction.Method != null) { - instructionEncoder.Call(metadataResolver.HandleOf(instruction.Method)); + instructionEncoder.Call(_handleResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); stackSize.Increment(); } @@ -863,14 +863,14 @@ public void Visit(LoadArrayElementInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); instructionEncoder.Token( - metadataResolver.HandleOf(instruction.Array.ElementsType)); + _handleResolver.HandleOf(instruction.Array.ElementsType)); } break; case LoadArrayElementOperation.Address: instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); instructionEncoder.Token( - metadataResolver.HandleOf(instruction.Array.ElementsType)); + _handleResolver.HandleOf(instruction.Array.ElementsType)); break; default: @@ -885,7 +885,7 @@ public void Visit(StoreArrayElementInstruction instruction) { if (instruction.Method != null) { - instructionEncoder.Call(metadataResolver.HandleOf(instruction.Method)); + instructionEncoder.Call(_handleResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); } else @@ -925,7 +925,7 @@ public void Visit(StoreArrayElementInstruction instruction) else { instructionEncoder.OpCode(SRM.ILOpCode.Stelem); - instructionEncoder.Token(metadataResolver.HandleOf(instruction.Array.ElementsType)); + instructionEncoder.Token(_handleResolver.HandleOf(instruction.Array.ElementsType)); } stackSize.Decrement(3); diff --git a/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs b/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs index 6fc8228b..9af3b345 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs @@ -8,11 +8,11 @@ namespace MetadataGenerator.Generation.Methods.Body { internal class MethodLocalsSignatureEncoder { - private readonly MetadataResolver metadataResolver; + private readonly HandleResolver _handleResolver; - public MethodLocalsSignatureEncoder(MetadataResolver metadataResolver) + public MethodLocalsSignatureEncoder(HandleResolver handleResolver) { - this.metadataResolver = metadataResolver; + this._handleResolver = handleResolver; } public SRM.BlobBuilder EncodeSignatureOf(IList localVariables) @@ -23,7 +23,7 @@ public SRM.BlobBuilder EncodeSignatureOf(IList localVariables) var encoder = new ECMA335.BlobEncoder(signature).LocalVariableSignature(localVariables.Count); foreach (var localVariable in localVariables) { - metadataResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); + _handleResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); } return signature; diff --git a/MetadataGenerator/Generation/Methods/MethodGenerator.cs b/MetadataGenerator/Generation/Methods/MethodGenerator.cs index 9c8aeccc..7a24a92f 100644 --- a/MetadataGenerator/Generation/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodGenerator.cs @@ -20,8 +20,8 @@ internal class MethodGenerator public MethodGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; - methodSignatureEncoder = new MethodSignatureEncoder(metadataContainer.MetadataResolver); - methodLocalsSignatureEncoder = new MethodLocalsSignatureEncoder(metadataContainer.MetadataResolver); + methodSignatureEncoder = new MethodSignatureEncoder(metadataContainer.HandleResolver); + methodLocalsSignatureEncoder = new MethodLocalsSignatureEncoder(metadataContainer.HandleResolver); methodParameterGenerator = new MethodParameterGenerator(metadataContainer); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } @@ -36,17 +36,14 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var methodBodyOffset = -1; if (method.HasBody) { - SRM.StandaloneSignatureHandle localVariablesSignature = default; - if (method.Body.LocalVariables.Count > 0) - { - var signature = methodLocalsSignatureEncoder.EncodeSignatureOf(method.Body.LocalVariables); - localVariablesSignature = metadataContainer.MetadataResolver.GetOrAddStandaloneSignature(signature); - } + var localVariablesSignatureHandle = method.Body.LocalVariables.Count > 0 + ? metadataContainer.HandleResolver.HandleOf(method.Body.LocalVariables) + : default; - var instructionEncoder = new MethodBodyEncoder(metadataContainer.MetadataResolver, method.Body).Encode(out var maxStack); + var instructionEncoder = new MethodBodyEncoder(metadataContainer.HandleResolver, method.Body).Encode(out var maxStack); methodBodyOffset = metadataContainer.MethodBodyStream.AddMethodBody( instructionEncoder: instructionEncoder, - localVariablesSignature: localVariablesSignature, + localVariablesSignature: localVariablesSignatureHandle, maxStack: maxStack); } @@ -54,7 +51,8 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) SR.MethodImplAttributes.IL | (!method.HasBody && !method.IsAbstract ? SR.MethodImplAttributes.Runtime : SR.MethodImplAttributes.Managed); - var nextParameterHandle = ECMA335.MetadataTokens.ParameterHandle(metadataContainer.MetadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); + var nextParameterHandle = + ECMA335.MetadataTokens.ParameterHandle(metadataContainer.MetadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); // MethodDef Table (0x06) var methodDefinitionHandle = metadataContainer.MetadataBuilder.AddMethodDefinition( attributes: AttributesFor(method), @@ -71,7 +69,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) if (method.Name.Equals("Main")) { - metadataContainer.MainMethodHandle = methodDefinitionHandle; + metadataContainer.HandleResolver.MainMethodHandle = methodDefinitionHandle; } return methodDefinitionHandle; diff --git a/MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs b/MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs index 211fce1b..c7f292b8 100644 --- a/MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs +++ b/MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs @@ -7,11 +7,11 @@ namespace MetadataGenerator.Generation.Methods { internal class MethodSignatureEncoder { - private readonly MetadataResolver metadataResolver; + private readonly HandleResolver _handleResolver; - public MethodSignatureEncoder(MetadataResolver metadataResolver) + public MethodSignatureEncoder(HandleResolver handleResolver) { - this.metadataResolver = metadataResolver; + this._handleResolver = handleResolver; } public SRM.BlobBuilder EncodeSignatureOf(IMethodReference method) @@ -22,7 +22,7 @@ public SRM.BlobBuilder EncodeSignatureOf(IMethodReference method) var encoder = new ECMA335.BlobEncoder(signature).MethodSpecificationSignature(method.GenericArguments.Count); foreach (var genericArg in method.GenericArguments) { - metadataResolver.Encode(genericArg, encoder.AddArgument()); + _handleResolver.Encode(genericArg, encoder.AddArgument()); } return signature; @@ -57,7 +57,7 @@ private SRM.BlobBuilder EncodeSignature( else { var encoder = returnTypeEncoder.Type(); - metadataResolver.Encode(returnType, encoder); + _handleResolver.Encode(returnType, encoder); } }, parametersEncoder => @@ -73,7 +73,7 @@ private SRM.BlobBuilder EncodeSignature( } var encoder = parametersEncoder.AddParameter().Type(isByRef); - metadataResolver.Encode(type, encoder); + _handleResolver.Encode(type, encoder); } }); diff --git a/MetadataGenerator/Generation/ModuleGenerator.cs b/MetadataGenerator/Generation/ModuleGenerator.cs index 7d554a14..672aef30 100644 --- a/MetadataGenerator/Generation/ModuleGenerator.cs +++ b/MetadataGenerator/Generation/ModuleGenerator.cs @@ -19,7 +19,7 @@ public void GenerateModuleFor(Assembly assembly) var metadataBuilder = metadataContainer.MetadataBuilder; // Module Table (0x00) - metadataContainer.ModuleHandle = metadataBuilder.AddModule( + metadataContainer.HandleResolver.ModuleHandle = metadataBuilder.AddModule( generation: 0, moduleName: metadataBuilder.GetOrAddString(moduleName), mvid: metadataBuilder.GetOrAddGuid(Guid.NewGuid()), diff --git a/MetadataGenerator/Generation/Properties/PropertyGenerator.cs b/MetadataGenerator/Generation/Properties/PropertyGenerator.cs index a84bc3b9..fddecf87 100644 --- a/MetadataGenerator/Generation/Properties/PropertyGenerator.cs +++ b/MetadataGenerator/Generation/Properties/PropertyGenerator.cs @@ -16,7 +16,7 @@ internal class PropertyGenerator public PropertyGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; - propertySignatureEncoder = new PropertySignatureEncoder(metadataContainer.MetadataResolver); + propertySignatureEncoder = new PropertySignatureEncoder(metadataContainer.HandleResolver); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } diff --git a/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs b/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs index e185e83c..b473b4db 100644 --- a/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs +++ b/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs @@ -6,11 +6,11 @@ namespace MetadataGenerator.Generation.Properties { internal class PropertySignatureEncoder { - private readonly MetadataResolver metadataResolver; + private readonly HandleResolver _handleResolver; - public PropertySignatureEncoder(MetadataResolver metadataResolver) + public PropertySignatureEncoder(HandleResolver handleResolver) { - this.metadataResolver = metadataResolver; + this._handleResolver = handleResolver; } public SRM.BlobBuilder EncodeSignatureOf(PropertyDefinition property) @@ -20,7 +20,7 @@ public SRM.BlobBuilder EncodeSignatureOf(PropertyDefinition property) .PropertySignature(isInstanceProperty: !property.IsStatic) .Parameters( parameterCount: 0, - returnType: returnTypeEncoder => metadataResolver.Encode(property.PropertyType, returnTypeEncoder.Type()), + returnType: returnTypeEncoder => _handleResolver.Encode(property.PropertyType, returnTypeEncoder.Type()), parameters: parametersEncoder => { }); return signature; } diff --git a/MetadataGenerator/Generation/Types/TypeGenerator.cs b/MetadataGenerator/Generation/Types/TypeGenerator.cs index b92fc16a..f1a735ff 100644 --- a/MetadataGenerator/Generation/Types/TypeGenerator.cs +++ b/MetadataGenerator/Generation/Types/TypeGenerator.cs @@ -33,32 +33,23 @@ public TypeGenerator(MetadataContainer metadataContainer) public SRM.TypeDefinitionHandle Generate(TypeDefinition type) { - var methodDefinitionHandles = new List(); - var methodDefToHandle = new Dictionary(); - var methodOverrides = new List(); var metadataBuilder = metadataContainer.MetadataBuilder; - var metadataResolver = metadataContainer.MetadataResolver; + var metadataResolver = metadataContainer.HandleResolver; var fieldDefinitionHandles = type .Fields .Select(field => fieldGenerator.Generate(field)) .ToList(); - foreach (var method in type.Methods) - { - var methodDefinitionHandle = methodGenerator.Generate(method); - methodDefinitionHandles.Add(methodDefinitionHandle); - if (method.OverridenMethod != null) - { - methodOverrides.Add( - new MethodOverride(methodDefinitionHandle, metadataResolver.HandleOf(method.OverridenMethod))); - } + var methodToHandle = type + .Methods + .ToDictionary(method => method, method => methodGenerator.Generate(method)); - methodDefToHandle.Add(method, methodDefinitionHandle); - } + var nextFieldDefinitionHandle = + ECMA335.MetadataTokens.FieldDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.Field)); + var nextMethodDefinitionHandle = + ECMA335.MetadataTokens.MethodDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.MethodDef)); - var nextFieldDefinitionHandle = ECMA335.MetadataTokens.FieldDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.Field)); - var nextMethodDefinitionHandle = ECMA335.MetadataTokens.MethodDefinitionHandle(metadataBuilder.NextRowFor(ECMA335.TableIndex.MethodDef)); // TypeDef Table (0x02) var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( attributes: AttributesFor(type), @@ -66,10 +57,10 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) name: metadataBuilder.GetOrAddString(TypeNameOf(type)), baseType: type.Base != null ? metadataResolver.HandleOf(type.Base) : default, fieldList: fieldDefinitionHandles.FirstOr(nextFieldDefinitionHandle), - methodList: methodDefinitionHandles.FirstOr(nextMethodDefinitionHandle)); + methodList: methodToHandle.Values.FirstOr(nextMethodDefinitionHandle)); var propertyDefinitionHandles = type.PropertyDefinitions - .Select(property => propertyGenerator.Generate(property, methodDefToHandle)) + .Select(property => propertyGenerator.Generate(property, methodToHandle)) .ToList(); if (propertyDefinitionHandles.Count > 0) @@ -90,22 +81,24 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) metadataContainer.GenericParameterEntries.Add(new GenericParameterEntry(typeDefinitionHandle, genericParameter)); } - for (var i = 0; i < type.Methods.Count; i++) + foreach (var entry in methodToHandle) { - var method = type.Methods[i]; + var method = entry.Key; + var handle = entry.Value; + foreach (var genericParameter in method.GenericParameters) { - metadataContainer.GenericParameterEntries.Add(new GenericParameterEntry(methodDefinitionHandles[i], genericParameter)); + metadataContainer.GenericParameterEntries.Add(new GenericParameterEntry(handle, genericParameter)); } - } - foreach (var methodOverride in methodOverrides) - { - metadataBuilder.AddMethodImplementation( - typeDefinitionHandle, - methodOverride.methodImplementation, - methodOverride.overridenMethod - ); + if (method.OverridenMethod != null) + { + metadataBuilder.AddMethodImplementation( + typeDefinitionHandle, + handle, + metadataResolver.HandleOf(method.OverridenMethod) + ); + } } if (type.LayoutInformation.SpecifiesSizes()) @@ -167,16 +160,4 @@ IList GenericParametersNamesOf(IBasicType iBasicType) return typeName; } } - - internal class MethodOverride - { - public readonly SRM.MethodDefinitionHandle methodImplementation; - public readonly SRM.EntityHandle overridenMethod; - - public MethodOverride(SRM.MethodDefinitionHandle methodImplementation, SRM.EntityHandle overridenMethod) - { - this.methodImplementation = methodImplementation; - this.overridenMethod = overridenMethod; - } - } } \ No newline at end of file diff --git a/MetadataGenerator/Generation/Types/TypeSignatureEncoder.cs b/MetadataGenerator/Generation/Types/TypeSignatureEncoder.cs new file mode 100644 index 00000000..3b5dd2dd --- /dev/null +++ b/MetadataGenerator/Generation/Types/TypeSignatureEncoder.cs @@ -0,0 +1,23 @@ +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using SRM = System.Reflection.Metadata; + +namespace MetadataGenerator.Generation.Types +{ + internal class TypeSignatureEncoder + { + private readonly HandleResolver _handleResolver; + + public TypeSignatureEncoder(HandleResolver handleResolver) + { + this._handleResolver = handleResolver; + } + + public SRM.BlobBuilder EncodeSignatureOf(IType type) + { + var signature = new SRM.BlobBuilder(); + _handleResolver.Encode(type, new ECMA335.BlobEncoder(signature).TypeSpecificationSignature()); + return signature; + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index 427e8f4f..c6bef02c 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -28,7 +28,7 @@ public void Generate(Assembly assembly) metadataRootBuilder: new ECMA335.MetadataRootBuilder(metadataContainer.MetadataBuilder), ilStream: metadataContainer.MethodBodyStream.Builder, mappedFieldData: metadataContainer.MappedFieldData, - entryPoint: assembly.Kind == Exe ? metadataContainer.MainMethodHandle : default, + entryPoint: assembly.Kind == Exe ? metadataContainer.HandleResolver.MainMethodHandle : default, flags: SRPE.CorFlags.ILOnly | SRPE.CorFlags.StrongNameSigned ).Serialize(peBlob); peBlob.WriteContentTo(peStream); diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 29f51f60..8b4fabdb 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -31,12 +31,13 @@ - + + From 4ad8c9bbac7a1df6d4f48691ed55049b087b1b1e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 17 Oct 2020 21:23:08 -0300 Subject: [PATCH 249/256] encoders refactor --- .../Generation/Fields/FieldGenerator.cs | 4 +- .../Fields/FieldSignatureEncoder.cs | 11 +- .../Generation/HandleResolver.cs | 130 +----------------- .../Generation/MetadataContainer.cs | 16 +++ .../Methods/Body/MethodBodyControlFlow.cs | 6 +- .../Methods/Body/MethodBodyEncoder.cs | 56 ++++---- .../Body/MethodLocalsSignatureEncoder.cs | 9 +- .../Generation/Methods/MethodGenerator.cs | 6 +- .../Methods/MethodSignatureEncoder.cs | 13 +- .../Properties/PropertyGenerator.cs | 12 +- .../Properties/PropertySignatureEncoder.cs | 11 +- .../Generation/Types/TypeEncoder.cs | 126 +++++++++++++++++ .../Generation/Types/TypeSignatureEncoder.cs | 8 +- MetadataGenerator/MetadataGenerator.csproj | 1 + 14 files changed, 214 insertions(+), 195 deletions(-) create mode 100644 MetadataGenerator/Generation/Types/TypeEncoder.cs diff --git a/MetadataGenerator/Generation/Fields/FieldGenerator.cs b/MetadataGenerator/Generation/Fields/FieldGenerator.cs index baab1675..4dc06741 100644 --- a/MetadataGenerator/Generation/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generation/Fields/FieldGenerator.cs @@ -9,20 +9,18 @@ namespace MetadataGenerator.Generation.Fields internal class FieldGenerator { private readonly MetadataContainer metadataContainer; - private readonly FieldSignatureEncoder fieldSignatureEncoder; private readonly CustomAttributeGenerator customAttributeGenerator; public FieldGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; - fieldSignatureEncoder = new FieldSignatureEncoder(metadataContainer.HandleResolver); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } public SRM.FieldDefinitionHandle Generate(FieldDefinition field) { var metadataBuilder = metadataContainer.MetadataBuilder; - var fieldSignature = fieldSignatureEncoder.EncodeSignatureOf(field); + var fieldSignature = metadataContainer.FieldSignatureEncoder.EncodeSignatureOf(field); // Field Table (0x04) var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( diff --git a/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs b/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs index 9aa06ebc..38e7f183 100644 --- a/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs +++ b/MetadataGenerator/Generation/Fields/FieldSignatureEncoder.cs @@ -1,4 +1,5 @@ -using Model.Types; +using MetadataGenerator.Generation.Types; +using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -6,17 +7,17 @@ namespace MetadataGenerator.Generation.Fields { internal class FieldSignatureEncoder { - private readonly HandleResolver _handleResolver; + private readonly TypeEncoder typeEncoder; - public FieldSignatureEncoder(HandleResolver handleResolver) + public FieldSignatureEncoder(TypeEncoder typeEncoder) { - this._handleResolver = handleResolver; + this.typeEncoder = typeEncoder; } public SRM.BlobBuilder EncodeSignatureOf(IFieldReference field) { var fieldSignature = new SRM.BlobBuilder(); - _handleResolver.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); + typeEncoder.Encode(field.Type, new ECMA335.BlobEncoder(fieldSignature).FieldSignature()); return fieldSignature; } } diff --git a/MetadataGenerator/Generation/HandleResolver.cs b/MetadataGenerator/Generation/HandleResolver.cs index 09cd41a1..beda1151 100644 --- a/MetadataGenerator/Generation/HandleResolver.cs +++ b/MetadataGenerator/Generation/HandleResolver.cs @@ -1,11 +1,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Reflection; -using MetadataGenerator.Generation.Fields; -using MetadataGenerator.Generation.Methods; -using MetadataGenerator.Generation.Methods.Body; -using MetadataGenerator.Generation.Types; using Model; using Model.ThreeAddressCode.Values; using Model.Types; @@ -21,10 +16,6 @@ internal class HandleResolver { private readonly Assembly assembly; private readonly MetadataContainer metadataContainer; - private readonly FieldSignatureEncoder fieldSignatureEncoder; - private readonly MethodSignatureEncoder methodSignatureEncoder; - private readonly MethodLocalsSignatureEncoder methodLocalsSignatureEncoder; - private readonly TypeSignatureEncoder typeSignatureEncoder; #region handles @@ -96,7 +87,7 @@ public SRM.ModuleDefinitionHandle ModuleHandle private SRM.BlobHandle SpecKeyFor(IType type) { - var signature = typeSignatureEncoder.EncodeSignatureOf(type); + var signature = metadataContainer.TypeSignatureEncoder.EncodeSignatureOf(type); var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var key = blobHandle; return key; @@ -108,7 +99,7 @@ private SRM.BlobHandle SpecKeyFor(IType type) private Tuple RefKeyFor(IFieldReference field) { - var signature = fieldSignatureEncoder.EncodeSignatureOf(field); + var signature = metadataContainer.FieldSignatureEncoder.EncodeSignatureOf(field); var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var parent = HandleOf(field.ContainingType); var key = new Tuple( @@ -126,7 +117,7 @@ private SRM.BlobHandle SpecKeyFor(IType type) private Tuple RefKeyFor(IMethodReference method) { - var signature = methodSignatureEncoder.EncodeSignatureOf(method); + var signature = metadataContainer.MethodSignatureEncoder.EncodeSignatureOf(method); var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var parent = method.ContainingType is ArrayTypeWrapper arrayTypeWrapper @@ -145,7 +136,7 @@ method.ContainingType is ArrayTypeWrapper arrayTypeWrapper private Tuple SpecKeyFor(IMethodReference method) { - var signature = methodSignatureEncoder.EncodeSignatureOf(method); + var signature = metadataContainer.MethodSignatureEncoder.EncodeSignatureOf(method); var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var genericMethodHandle = HandleOf(method.GenericMethod); var key = new Tuple(genericMethodHandle, blobHandle); @@ -158,7 +149,7 @@ method.ContainingType is ArrayTypeWrapper arrayTypeWrapper private SRM.BlobHandle StandaloneSigKeyFor(IList localVariables) { - var signature = methodLocalsSignatureEncoder.EncodeSignatureOf(localVariables); + var signature = metadataContainer.MethodLocalsSignatureEncoder.EncodeSignatureOf(localVariables); var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var key = blobHandle; return key; @@ -194,10 +185,6 @@ public HandleResolver(MetadataContainer metadataContainer, Assembly assembly) fieldRefHandles = new Dictionary, SRM.MemberReferenceHandle>(); methodRefHandles = new Dictionary, SRM.MemberReferenceHandle>(); typeRefHandles = new Dictionary, SRM.TypeReferenceHandle>(); - fieldSignatureEncoder = new FieldSignatureEncoder(this); - methodSignatureEncoder = new MethodSignatureEncoder(this); - methodLocalsSignatureEncoder = new MethodLocalsSignatureEncoder(this); - typeSignatureEncoder = new TypeSignatureEncoder(this); } public SRM.UserStringHandle UserStringHandleOf(string value) => metadataContainer.MetadataBuilder.GetOrAddUserString(value); @@ -338,112 +325,5 @@ private SRM.MemberReferenceHandle GetOrAddFieldReference(IFieldReference field) return fieldRefHandle; } - - public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) - { - if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); - else if (type.Equals(PlatformTypes.Byte)) encoder.Byte(); - else if (type.Equals(PlatformTypes.SByte)) encoder.SByte(); - else if (type.Equals(PlatformTypes.Char)) encoder.Char(); - else if (type.Equals(PlatformTypes.Double)) encoder.Double(); - else if (type.Equals(PlatformTypes.Int16)) encoder.Int16(); - else if (type.Equals(PlatformTypes.UInt16)) encoder.UInt16(); - else if (type.Equals(PlatformTypes.Int32)) encoder.Int32(); - else if (type.Equals(PlatformTypes.UInt32)) encoder.UInt32(); - else if (type.Equals(PlatformTypes.Int64)) encoder.Int64(); - else if (type.Equals(PlatformTypes.UInt64)) encoder.UInt64(); - else if (type.Equals(PlatformTypes.String)) encoder.String(); - else if (type.Equals(PlatformTypes.Single)) encoder.Single(); - else if (type.Equals(PlatformTypes.Object)) encoder.Object(); - else if (type.Equals(PlatformTypes.IntPtr)) encoder.IntPtr(); - else if (type.Equals(PlatformTypes.UIntPtr)) encoder.UIntPtr(); - else - { - switch (type) - { - case IBasicType iBasicType: - { - var isValueType = type.TypeKind == TypeKind.ValueType; - if (iBasicType.IsGenericInstantiation()) - { - var genericInstantiation = encoder.GenericInstantiation( - GetOrAddTypeReference(iBasicType.GenericType), - iBasicType.GenericArguments.Count, - isValueType); - foreach (var genericArg in iBasicType.GenericArguments) - { - Encode(genericArg, genericInstantiation.AddArgument()); - } - } - else - { - encoder.Type(GetOrAddTypeReference(iBasicType), isValueType); - } - - break; - } - case ArrayType arrayType: - { - if (arrayType.IsVector) - { - Encode(arrayType.ElementsType, encoder.SZArray()); - } - else - { - encoder.Array( - elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), - arrayShapeEncoder => - { - // This assumes that all dimensions have 0 as lower bound and none declare sizes. - // Lower bounds and sizes are not modelled. - var lowerBounds = Repeat(0, (int) arrayType.Rank).ToImmutableArray(); - var sizes = ImmutableArray.Empty; - arrayShapeEncoder.Shape((int) arrayType.Rank, sizes, lowerBounds); - }); - } - - - break; - } - case PointerType pointerType: - { - var targetType = pointerType.TargetType; - if (targetType.Equals(PlatformTypes.Void)) - { - encoder.VoidPointer(); - } - else - { - Encode(targetType, encoder.Pointer()); - } - - break; - } - case FunctionPointerType _: - { - encoder.FunctionPointer(); - break; - } - case IGenericParameterReference genericParameter: - { - switch (genericParameter.Kind) - { - case GenericParameterKind.Type: - encoder.GenericTypeParameter(genericParameter.Index); - break; - case GenericParameterKind.Method: - encoder.GenericMethodTypeParameter(genericParameter.Index); - break; - default: - throw genericParameter.Kind.ToUnknownValueException(); - } - - break; - } - default: - throw new Exception($"Type {type} not supported"); - } - } - } } } \ No newline at end of file diff --git a/MetadataGenerator/Generation/MetadataContainer.cs b/MetadataGenerator/Generation/MetadataContainer.cs index c72bf34d..6cca20cd 100644 --- a/MetadataGenerator/Generation/MetadataContainer.cs +++ b/MetadataGenerator/Generation/MetadataContainer.cs @@ -1,4 +1,9 @@ using System.Collections.Generic; +using MetadataGenerator.Generation.Fields; +using MetadataGenerator.Generation.Methods; +using MetadataGenerator.Generation.Methods.Body; +using MetadataGenerator.Generation.Properties; +using MetadataGenerator.Generation.Types; using Model; using static MetadataGenerator.Generation.GenericParameterGenerator; using static MetadataGenerator.Generation.Types.InterfaceImplementationGenerator; @@ -12,6 +17,11 @@ internal class MetadataContainer { public readonly ECMA335.MetadataBuilder MetadataBuilder; public readonly HandleResolver HandleResolver; + public readonly FieldSignatureEncoder FieldSignatureEncoder; + public readonly MethodSignatureEncoder MethodSignatureEncoder; + public readonly MethodLocalsSignatureEncoder MethodLocalsSignatureEncoder; + public readonly TypeSignatureEncoder TypeSignatureEncoder; + public readonly PropertySignatureEncoder PropertySignatureEncoder; public readonly ECMA335.MethodBodyStreamEncoder MethodBodyStream; public readonly SRM.BlobBuilder MappedFieldData; public readonly ISet GenericParameterEntries; @@ -23,6 +33,12 @@ public MetadataContainer(Assembly assembly) MetadataBuilder = new ECMA335.MetadataBuilder(); MethodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); HandleResolver = new HandleResolver(this, assembly); + var typeEncoder = new TypeEncoder(HandleResolver); + FieldSignatureEncoder = new FieldSignatureEncoder(typeEncoder); + MethodSignatureEncoder = new MethodSignatureEncoder(typeEncoder); + MethodLocalsSignatureEncoder = new MethodLocalsSignatureEncoder(typeEncoder); + TypeSignatureEncoder = new TypeSignatureEncoder(typeEncoder); + PropertySignatureEncoder = new PropertySignatureEncoder(typeEncoder); MappedFieldData = new SRM.BlobBuilder(); GenericParameterEntries = new HashSet(); InterfaceImplementationEntries = new HashSet(); diff --git a/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs index 1483a0f9..28e87359 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs @@ -11,13 +11,13 @@ namespace MetadataGenerator.Generation.Methods.Body internal class MethodBodyControlFlow { private readonly ECMA335.InstructionEncoder instructionEncoder; - private readonly HandleResolver _handleResolver; + private readonly HandleResolver handleResolver; private readonly IDictionary labelHandles; public MethodBodyControlFlow(ECMA335.InstructionEncoder instructionEncoder, HandleResolver handleResolver) { this.instructionEncoder = instructionEncoder; - this._handleResolver = handleResolver; + this.handleResolver = handleResolver; labelHandles = new Dictionary(); } @@ -79,7 +79,7 @@ public void ProcessExceptionInformation(IList exceptionInformati tryEnd, handlerStart, handlerEnd, - _handleResolver.HandleOf(handler.ExceptionType)); + handleResolver.HandleOf(handler.ExceptionType)); break; } case ExceptionHandlerBlockKind.Fault: diff --git a/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs index 9f3b6fc6..57c0534b 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs @@ -13,7 +13,7 @@ namespace MetadataGenerator.Generation.Methods.Body { internal class MethodBodyEncoder : IInstructionVisitor { - private readonly HandleResolver _handleResolver; + private readonly HandleResolver handleResolver; private readonly ECMA335.InstructionEncoder instructionEncoder; private readonly MethodBodyControlFlow methodBodyControlFlow; private readonly List switchInstructionsPlaceHolders; @@ -24,7 +24,7 @@ internal class MethodBodyEncoder : IInstructionVisitor public MethodBodyEncoder(HandleResolver handleResolver, MethodBody body) { - this._handleResolver = handleResolver; + this.handleResolver = handleResolver; this.body = body; instructionEncoder = new ECMA335.InstructionEncoder(new SRM.BlobBuilder(), new ECMA335.ControlFlowBuilder()); methodBodyControlFlow = new MethodBodyControlFlow(instructionEncoder, handleResolver); @@ -79,7 +79,7 @@ public void Visit(Instruction instruction) public void Visit(InitObjInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Initobj); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.Type)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Type)); stackSize.Decrement(); } @@ -225,7 +225,7 @@ public void Visit(BasicInstruction instruction) public void Visit(ConstrainedInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Constrained); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.ThisType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.ThisType)); } public void Visit(LoadInstruction instruction) @@ -294,7 +294,7 @@ public void Visit(LoadInstruction instruction) break; case string value: - instructionEncoder.LoadString(_handleResolver.UserStringHandleOf(value)); + instructionEncoder.LoadString(handleResolver.UserStringHandleOf(value)); stackSize.Increment(); break; case int value: @@ -377,7 +377,7 @@ public void Visit(LoadIndirectInstruction instruction) else { instructionEncoder.OpCode(SRM.ILOpCode.Ldobj); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.Type)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Type)); } } @@ -396,7 +396,7 @@ public void Visit(LoadFieldInstruction instruction) throw instruction.Operation.ToUnknownValueException(); } - instructionEncoder.Token(_handleResolver.HandleOf(instruction.Field)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Field)); if (isStatic) { stackSize.Increment(); @@ -407,7 +407,7 @@ public void Visit(LoadMethodAddressInstruction instruction) { var isVirtual = instruction.Method.IsVirtual; instructionEncoder.OpCode(isVirtual ? SRM.ILOpCode.Ldvirtftn : SRM.ILOpCode.Ldftn); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.Method)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Method)); if (!isVirtual) { stackSize.Increment(); @@ -451,7 +451,7 @@ public void Visit(StoreIndirectInstruction instruction) else { instructionEncoder.OpCode(SRM.ILOpCode.Stobj); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.Type)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Type)); } stackSize.Decrement(2); @@ -478,7 +478,7 @@ public void Visit(StoreFieldInstruction instruction) { var isStatic = instruction.Field.IsStatic; instructionEncoder.OpCode(isStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.Field)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Field)); stackSize.Decrement(isStatic ? 1 : 2); } @@ -630,23 +630,23 @@ public void Visit(ConvertInstruction instruction) break; case ConvertOperation.Cast: instructionEncoder.OpCode(SRM.ILOpCode.Castclass); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.IsInst: instructionEncoder.OpCode(SRM.ILOpCode.Isinst); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.Box: instructionEncoder.OpCode(SRM.ILOpCode.Box); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.Unbox: instructionEncoder.OpCode(SRM.ILOpCode.Unbox_any); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.ConversionType)); break; case ConvertOperation.UnboxPtr: instructionEncoder.OpCode(SRM.ILOpCode.Unbox); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.ConversionType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.ConversionType)); break; default: throw instruction.Operation.ToUnknownValueException(); @@ -729,14 +729,14 @@ public void Visit(SwitchInstruction instruction) public void Visit(SizeofInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Sizeof); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.MeasuredType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.MeasuredType)); stackSize.Increment(); } public void Visit(LoadTokenInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Ldtoken); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.Token)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Token)); stackSize.Increment(); } @@ -746,12 +746,12 @@ public void Visit(MethodCallInstruction instruction) { case MethodCallOperation.Virtual: instructionEncoder.OpCode(SRM.ILOpCode.Callvirt); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.Method)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count + 1); break; case MethodCallOperation.Static: case MethodCallOperation.Jump: - instructionEncoder.Call(_handleResolver.HandleOf(instruction.Method)); + instructionEncoder.Call(handleResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); break; default: @@ -766,7 +766,7 @@ public void Visit(MethodCallInstruction instruction) public void Visit(IndirectMethodCallInstruction instruction) { - var methodSignature = _handleResolver.HandleOf(instruction.Function); + var methodSignature = handleResolver.HandleOf(instruction.Function); instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); stackSize.Decrement(instruction.Function.Parameters.Count + 1); if (!instruction.Function.ReturnType.Equals(PlatformTypes.Void)) @@ -777,7 +777,7 @@ public void Visit(IndirectMethodCallInstruction instruction) public void Visit(CreateObjectInstruction instruction) { - var method = _handleResolver.HandleOf(instruction.Constructor); + var method = handleResolver.HandleOf(instruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); stackSize.Decrement(instruction.Constructor.Parameters.Count); @@ -789,11 +789,11 @@ public void Visit(CreateArrayInstruction instruction) if (instruction.Type.IsVector) { instructionEncoder.OpCode(SRM.ILOpCode.Newarr); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.Type.ElementsType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Type.ElementsType)); } else { - var method = _handleResolver.HandleOf(instruction.Constructor); + var method = handleResolver.HandleOf(instruction.Constructor); instructionEncoder.OpCode(SRM.ILOpCode.Newobj); instructionEncoder.Token(method); stackSize.Decrement(instruction.Constructor.Parameters.Count); @@ -805,7 +805,7 @@ public void Visit(LoadArrayElementInstruction instruction) { if (instruction.Method != null) { - instructionEncoder.Call(_handleResolver.HandleOf(instruction.Method)); + instructionEncoder.Call(handleResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); stackSize.Increment(); } @@ -863,14 +863,14 @@ public void Visit(LoadArrayElementInstruction instruction) { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); instructionEncoder.Token( - _handleResolver.HandleOf(instruction.Array.ElementsType)); + handleResolver.HandleOf(instruction.Array.ElementsType)); } break; case LoadArrayElementOperation.Address: instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); instructionEncoder.Token( - _handleResolver.HandleOf(instruction.Array.ElementsType)); + handleResolver.HandleOf(instruction.Array.ElementsType)); break; default: @@ -885,7 +885,7 @@ public void Visit(StoreArrayElementInstruction instruction) { if (instruction.Method != null) { - instructionEncoder.Call(_handleResolver.HandleOf(instruction.Method)); + instructionEncoder.Call(handleResolver.HandleOf(instruction.Method)); stackSize.Decrement(instruction.Method.Parameters.Count); } else @@ -925,7 +925,7 @@ public void Visit(StoreArrayElementInstruction instruction) else { instructionEncoder.OpCode(SRM.ILOpCode.Stelem); - instructionEncoder.Token(_handleResolver.HandleOf(instruction.Array.ElementsType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Array.ElementsType)); } stackSize.Decrement(3); diff --git a/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs b/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs index 9af3b345..4354b755 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodLocalsSignatureEncoder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using MetadataGenerator.Generation.Types; using Model.ThreeAddressCode.Values; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -8,11 +9,11 @@ namespace MetadataGenerator.Generation.Methods.Body { internal class MethodLocalsSignatureEncoder { - private readonly HandleResolver _handleResolver; + private readonly TypeEncoder typeEncoder; - public MethodLocalsSignatureEncoder(HandleResolver handleResolver) + public MethodLocalsSignatureEncoder(TypeEncoder typeEncoder) { - this._handleResolver = handleResolver; + this.typeEncoder = typeEncoder; } public SRM.BlobBuilder EncodeSignatureOf(IList localVariables) @@ -23,7 +24,7 @@ public SRM.BlobBuilder EncodeSignatureOf(IList localVariables) var encoder = new ECMA335.BlobEncoder(signature).LocalVariableSignature(localVariables.Count); foreach (var localVariable in localVariables) { - _handleResolver.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); + typeEncoder.Encode(localVariable.Type, encoder.AddVariable().Type(isPinned: false)); } return signature; diff --git a/MetadataGenerator/Generation/Methods/MethodGenerator.cs b/MetadataGenerator/Generation/Methods/MethodGenerator.cs index 7a24a92f..d4f47e2e 100644 --- a/MetadataGenerator/Generation/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodGenerator.cs @@ -12,16 +12,12 @@ namespace MetadataGenerator.Generation.Methods internal class MethodGenerator { private readonly MetadataContainer metadataContainer; - private readonly MethodSignatureEncoder methodSignatureEncoder; - private readonly MethodLocalsSignatureEncoder methodLocalsSignatureEncoder; private readonly MethodParameterGenerator methodParameterGenerator; private readonly CustomAttributeGenerator customAttributeGenerator; public MethodGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; - methodSignatureEncoder = new MethodSignatureEncoder(metadataContainer.HandleResolver); - methodLocalsSignatureEncoder = new MethodLocalsSignatureEncoder(metadataContainer.HandleResolver); methodParameterGenerator = new MethodParameterGenerator(metadataContainer); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } @@ -32,7 +28,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) .Parameters .Select(parameter => methodParameterGenerator.Generate(parameter)) .ToList(); - var methodSignature = methodSignatureEncoder.EncodeSignatureOf(method); + var methodSignature = metadataContainer.MethodSignatureEncoder.EncodeSignatureOf(method); var methodBodyOffset = -1; if (method.HasBody) { diff --git a/MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs b/MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs index c7f292b8..31a9c82e 100644 --- a/MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs +++ b/MetadataGenerator/Generation/Methods/MethodSignatureEncoder.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using MetadataGenerator.Generation.Types; using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -7,11 +8,11 @@ namespace MetadataGenerator.Generation.Methods { internal class MethodSignatureEncoder { - private readonly HandleResolver _handleResolver; + private readonly TypeEncoder typeEncoder; - public MethodSignatureEncoder(HandleResolver handleResolver) + public MethodSignatureEncoder(TypeEncoder typeEncoder) { - this._handleResolver = handleResolver; + this.typeEncoder = typeEncoder; } public SRM.BlobBuilder EncodeSignatureOf(IMethodReference method) @@ -22,7 +23,7 @@ public SRM.BlobBuilder EncodeSignatureOf(IMethodReference method) var encoder = new ECMA335.BlobEncoder(signature).MethodSpecificationSignature(method.GenericArguments.Count); foreach (var genericArg in method.GenericArguments) { - _handleResolver.Encode(genericArg, encoder.AddArgument()); + typeEncoder.Encode(genericArg, encoder.AddArgument()); } return signature; @@ -57,7 +58,7 @@ private SRM.BlobBuilder EncodeSignature( else { var encoder = returnTypeEncoder.Type(); - _handleResolver.Encode(returnType, encoder); + typeEncoder.Encode(returnType, encoder); } }, parametersEncoder => @@ -73,7 +74,7 @@ private SRM.BlobBuilder EncodeSignature( } var encoder = parametersEncoder.AddParameter().Type(isByRef); - _handleResolver.Encode(type, encoder); + typeEncoder.Encode(type, encoder); } }); diff --git a/MetadataGenerator/Generation/Properties/PropertyGenerator.cs b/MetadataGenerator/Generation/Properties/PropertyGenerator.cs index fddecf87..6a879b26 100644 --- a/MetadataGenerator/Generation/Properties/PropertyGenerator.cs +++ b/MetadataGenerator/Generation/Properties/PropertyGenerator.cs @@ -10,23 +10,21 @@ namespace MetadataGenerator.Generation.Properties internal class PropertyGenerator { private readonly MetadataContainer metadataContainer; - private readonly PropertySignatureEncoder propertySignatureEncoder; private readonly CustomAttributeGenerator customAttributeGenerator; public PropertyGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; - propertySignatureEncoder = new PropertySignatureEncoder(metadataContainer.HandleResolver); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } // Properties can have getters or setters which are methods defined within the class. - // methodDefHandleOf is the association of methods to their handles. + // methodToHandle is the association of methods to their handles. public SRM.PropertyDefinitionHandle Generate( PropertyDefinition property, - IDictionary methodDefHandleOf) + IDictionary methodToHandle) { - var signature = propertySignatureEncoder.EncodeSignatureOf(property); + var signature = metadataContainer.PropertySignatureEncoder.EncodeSignatureOf(property); // Property Table (0x17) var propertyDefinitionHandle = metadataContainer.MetadataBuilder.AddProperty( attributes: SR.PropertyAttributes.None, @@ -39,7 +37,7 @@ public SRM.PropertyDefinitionHandle Generate( metadataContainer.MetadataBuilder.AddMethodSemantics( propertyDefinitionHandle, SR.MethodSemanticsAttributes.Getter, - methodDefHandleOf[property.Getter]); + methodToHandle[property.Getter]); } if (property.Setter != null) @@ -48,7 +46,7 @@ public SRM.PropertyDefinitionHandle Generate( metadataContainer.MetadataBuilder.AddMethodSemantics( propertyDefinitionHandle, SR.MethodSemanticsAttributes.Setter, - methodDefHandleOf[property.Setter]); + methodToHandle[property.Setter]); } foreach (var customAttribute in property.Attributes) diff --git a/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs b/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs index b473b4db..e5b51e2c 100644 --- a/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs +++ b/MetadataGenerator/Generation/Properties/PropertySignatureEncoder.cs @@ -1,4 +1,5 @@ -using Model.Types; +using MetadataGenerator.Generation.Types; +using Model.Types; using ECMA335 = System.Reflection.Metadata.Ecma335; using SRM = System.Reflection.Metadata; @@ -6,11 +7,11 @@ namespace MetadataGenerator.Generation.Properties { internal class PropertySignatureEncoder { - private readonly HandleResolver _handleResolver; + private readonly TypeEncoder typeEncoder; - public PropertySignatureEncoder(HandleResolver handleResolver) + public PropertySignatureEncoder(TypeEncoder typeEncoder) { - this._handleResolver = handleResolver; + this.typeEncoder = typeEncoder; } public SRM.BlobBuilder EncodeSignatureOf(PropertyDefinition property) @@ -20,7 +21,7 @@ public SRM.BlobBuilder EncodeSignatureOf(PropertyDefinition property) .PropertySignature(isInstanceProperty: !property.IsStatic) .Parameters( parameterCount: 0, - returnType: returnTypeEncoder => _handleResolver.Encode(property.PropertyType, returnTypeEncoder.Type()), + returnType: returnTypeEncoder => typeEncoder.Encode(property.PropertyType, returnTypeEncoder.Type()), parameters: parametersEncoder => { }); return signature; } diff --git a/MetadataGenerator/Generation/Types/TypeEncoder.cs b/MetadataGenerator/Generation/Types/TypeEncoder.cs new file mode 100644 index 00000000..0bea0ba3 --- /dev/null +++ b/MetadataGenerator/Generation/Types/TypeEncoder.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Immutable; +using Model; +using Model.Types; +using ECMA335 = System.Reflection.Metadata.Ecma335; +using static System.Linq.Enumerable; + +namespace MetadataGenerator.Generation.Types +{ + internal class TypeEncoder + { + private readonly HandleResolver handleResolver; + + public TypeEncoder(HandleResolver handleResolver) + { + this.handleResolver = handleResolver; + } + + public void Encode(IType type, ECMA335.SignatureTypeEncoder encoder) + { + if (type.Equals(PlatformTypes.Boolean)) encoder.Boolean(); + else if (type.Equals(PlatformTypes.Byte)) encoder.Byte(); + else if (type.Equals(PlatformTypes.SByte)) encoder.SByte(); + else if (type.Equals(PlatformTypes.Char)) encoder.Char(); + else if (type.Equals(PlatformTypes.Double)) encoder.Double(); + else if (type.Equals(PlatformTypes.Int16)) encoder.Int16(); + else if (type.Equals(PlatformTypes.UInt16)) encoder.UInt16(); + else if (type.Equals(PlatformTypes.Int32)) encoder.Int32(); + else if (type.Equals(PlatformTypes.UInt32)) encoder.UInt32(); + else if (type.Equals(PlatformTypes.Int64)) encoder.Int64(); + else if (type.Equals(PlatformTypes.UInt64)) encoder.UInt64(); + else if (type.Equals(PlatformTypes.String)) encoder.String(); + else if (type.Equals(PlatformTypes.Single)) encoder.Single(); + else if (type.Equals(PlatformTypes.Object)) encoder.Object(); + else if (type.Equals(PlatformTypes.IntPtr)) encoder.IntPtr(); + else if (type.Equals(PlatformTypes.UIntPtr)) encoder.UIntPtr(); + else + { + switch (type) + { + case IBasicType iBasicType: + { + var isValueType = type.TypeKind == TypeKind.ValueType; + if (iBasicType.IsGenericInstantiation()) + { + var genericInstantiation = encoder.GenericInstantiation( + handleResolver.HandleOf(iBasicType.GenericType), + iBasicType.GenericArguments.Count, + isValueType); + foreach (var genericArg in iBasicType.GenericArguments) + { + Encode(genericArg, genericInstantiation.AddArgument()); + } + } + else + { + encoder.Type(handleResolver.HandleOf(iBasicType), isValueType); + } + + break; + } + case ArrayType arrayType: + { + if (arrayType.IsVector) + { + Encode(arrayType.ElementsType, encoder.SZArray()); + } + else + { + encoder.Array( + elementTypeEncoder => Encode(arrayType.ElementsType, elementTypeEncoder), + arrayShapeEncoder => + { + // This assumes that all dimensions have 0 as lower bound and none declare sizes. + // Lower bounds and sizes are not modelled. + var lowerBounds = Repeat(0, (int) arrayType.Rank).ToImmutableArray(); + var sizes = ImmutableArray.Empty; + arrayShapeEncoder.Shape((int) arrayType.Rank, sizes, lowerBounds); + }); + } + + + break; + } + case PointerType pointerType: + { + var targetType = pointerType.TargetType; + if (targetType.Equals(PlatformTypes.Void)) + { + encoder.VoidPointer(); + } + else + { + Encode(targetType, encoder.Pointer()); + } + + break; + } + case FunctionPointerType _: + { + encoder.FunctionPointer(); + break; + } + case IGenericParameterReference genericParameter: + { + switch (genericParameter.Kind) + { + case GenericParameterKind.Type: + encoder.GenericTypeParameter(genericParameter.Index); + break; + case GenericParameterKind.Method: + encoder.GenericMethodTypeParameter(genericParameter.Index); + break; + default: + throw genericParameter.Kind.ToUnknownValueException(); + } + + break; + } + default: + throw new Exception($"Type {type} not supported"); + } + } + } + } +} \ No newline at end of file diff --git a/MetadataGenerator/Generation/Types/TypeSignatureEncoder.cs b/MetadataGenerator/Generation/Types/TypeSignatureEncoder.cs index 3b5dd2dd..3c997c44 100644 --- a/MetadataGenerator/Generation/Types/TypeSignatureEncoder.cs +++ b/MetadataGenerator/Generation/Types/TypeSignatureEncoder.cs @@ -6,17 +6,17 @@ namespace MetadataGenerator.Generation.Types { internal class TypeSignatureEncoder { - private readonly HandleResolver _handleResolver; + private readonly TypeEncoder typeEncoder; - public TypeSignatureEncoder(HandleResolver handleResolver) + public TypeSignatureEncoder(TypeEncoder typeEncoder) { - this._handleResolver = handleResolver; + this.typeEncoder = typeEncoder; } public SRM.BlobBuilder EncodeSignatureOf(IType type) { var signature = new SRM.BlobBuilder(); - _handleResolver.Encode(type, new ECMA335.BlobEncoder(signature).TypeSpecificationSignature()); + typeEncoder.Encode(type, new ECMA335.BlobEncoder(signature).TypeSpecificationSignature()); return signature; } } diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 8b4fabdb..609cceff 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -36,6 +36,7 @@ + From 703cf99a3e5c9fa942f64b81d60e08e144586b80 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 1 Nov 2020 18:28:43 -0300 Subject: [PATCH 250/256] finish refactor --- MetadataGenerator/Extensions.cs | 6 +- .../Generation/AssemblyGenerator.cs | 18 ++--- .../Generation/AttributesProvider.cs | 3 +- .../CustomAttributeGenerator.cs | 6 +- .../CustomAttributesSignatureEncoder.cs | 9 ++- .../Generation/Fields/FieldGenerator.cs | 10 ++- .../Generation/GenericParameterGenerator.cs | 12 ++- .../Generation/HandleResolver.cs | 67 ++++++++++++----- .../Generation/MetadataContainer.cs | 75 +++++++++++++++---- .../Methods/Body/MethodBodyControlFlow.cs | 2 +- .../Methods/Body/MethodBodyEncoder.cs | 10 ++- .../Generation/Methods/MethodGenerator.cs | 16 ++-- .../Methods/MethodParameterGenerator.cs | 2 + .../Generation/ModuleGenerator.cs | 2 +- .../Generation/NamespaceGenerator.cs | 5 +- .../Properties/PropertyGenerator.cs | 10 ++- .../Types/InterfaceImplementationGenerator.cs | 12 ++- .../Generation/Types/NestedTypeGenerator.cs | 12 ++- .../Generation/Types/TypeGenerator.cs | 32 +++++--- MetadataGenerator/Generator.cs | 4 +- 20 files changed, 226 insertions(+), 87 deletions(-) diff --git a/MetadataGenerator/Extensions.cs b/MetadataGenerator/Extensions.cs index f3894ceb..108d1c74 100644 --- a/MetadataGenerator/Extensions.cs +++ b/MetadataGenerator/Extensions.cs @@ -14,8 +14,10 @@ public static T FirstOr(this IEnumerable enumerable, T defaultValue) return first.Equals(default(T)) ? defaultValue : first; } - // The next available slot in the corresponding table. If nothing is defined in the module then use row number 1 for the corresponding table - public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => metadata.GetRowCount(tableIndex) + 1; + // The next available slot in the corresponding table. + // If nothing is defined in the module then use row number 1 for the that table + public static int NextRowFor(this ECMA335.MetadataBuilder metadata, ECMA335.TableIndex tableIndex) => + metadata.GetRowCount(tableIndex) + 1; public static bool IsGenericInstantiation(this IBasicType type) => type.GenericType != null; diff --git a/MetadataGenerator/Generation/AssemblyGenerator.cs b/MetadataGenerator/Generation/AssemblyGenerator.cs index 59645fd8..fbfaaad5 100644 --- a/MetadataGenerator/Generation/AssemblyGenerator.cs +++ b/MetadataGenerator/Generation/AssemblyGenerator.cs @@ -1,5 +1,5 @@ using MetadataGenerator.Generation.Types; -using Assembly = Model.Assembly; +using Model; using SR = System.Reflection; namespace MetadataGenerator.Generation @@ -9,8 +9,6 @@ internal static class AssemblyGenerator public static MetadataContainer Generate(Assembly assembly) { var metadataContainer = new MetadataContainer(assembly); - var namespaceGenerator = new NamespaceGenerator(metadataContainer); - var moduleGenerator = new ModuleGenerator(metadataContainer); var metadataBuilder = metadataContainer.MetadataBuilder; // Assembly Table (0x20) @@ -23,15 +21,15 @@ public static MetadataContainer Generate(Assembly assembly) hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1 ); - moduleGenerator.GenerateModuleFor(assembly); - namespaceGenerator.Generate(assembly.RootNamespace); + new ModuleGenerator(metadataContainer).Generate(assembly); + new NamespaceGenerator(metadataContainer).Generate(assembly.RootNamespace); // Some tables must be sorted by one or more of their columns. Since the dll's methods and types don't follow a - // particular order, the info needed to load this tables is stored during type/method generation but not added to the MetadataBuilder - // until now where they can be previously sorted - InterfaceImplementationGenerator.GenerateInterfaceImplementations(metadataContainer); - GenericParameterGenerator.GenerateGenericParameters(metadataContainer); - NestedTypeGenerator.GenerateNestedTypes(metadataContainer); + // particular order, the info needed to load this tables is stored during type/method generation but not added to the + // MetadataBuilder until now where they can be previously sorted. + new InterfaceImplementationGenerator(metadataContainer).Generate(); + new GenericParameterGenerator(metadataContainer).Generate(); + new NestedTypeGenerator(metadataContainer).Generate(); return metadataContainer; } diff --git a/MetadataGenerator/Generation/AttributesProvider.cs b/MetadataGenerator/Generation/AttributesProvider.cs index 84d6c1f1..02e5fb8d 100644 --- a/MetadataGenerator/Generation/AttributesProvider.cs +++ b/MetadataGenerator/Generation/AttributesProvider.cs @@ -49,7 +49,8 @@ private static TypeAttributes ClassTypeAttributes(TypeDefinition typeDefinition) LayoutAttributesFor(typeDefinition.LayoutInformation) | VisibilityAttributesFor(typeDefinition); - private static TypeAttributes InterfaceTypeAttributes() => TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; + private static TypeAttributes InterfaceTypeAttributes() => + TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract; public static FieldAttributes AttributesFor(FieldDefinition field) { diff --git a/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs b/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs index 8f356b37..0df7605b 100644 --- a/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs +++ b/MetadataGenerator/Generation/CustomAttributes/CustomAttributeGenerator.cs @@ -15,7 +15,11 @@ public CustomAttributeGenerator(MetadataContainer metadataContainer) public void Generate(SRM.EntityHandle owner, CustomAttribute customAttribute) { - var signature = CustomAttributesSignatureEncoder.EncodeSignatureOf(customAttribute); + var signature = metadataContainer + .Encoders + .CustomAttributesSignatureEncoder + .EncodeSignatureOf(customAttribute); + // CustomAttribute Table (0x0C) metadataContainer.MetadataBuilder.AddCustomAttribute( owner, diff --git a/MetadataGenerator/Generation/CustomAttributes/CustomAttributesSignatureEncoder.cs b/MetadataGenerator/Generation/CustomAttributes/CustomAttributesSignatureEncoder.cs index a380dee1..02f3ea93 100644 --- a/MetadataGenerator/Generation/CustomAttributes/CustomAttributesSignatureEncoder.cs +++ b/MetadataGenerator/Generation/CustomAttributes/CustomAttributesSignatureEncoder.cs @@ -8,9 +8,9 @@ namespace MetadataGenerator.Generation.CustomAttributes { - public static class CustomAttributesSignatureEncoder + public class CustomAttributesSignatureEncoder { - public static SRM.BlobBuilder EncodeSignatureOf(CustomAttribute customAttribute) + public SRM.BlobBuilder EncodeSignatureOf(CustomAttribute customAttribute) { var signature = new SRM.BlobBuilder(); new ECMA335.BlobEncoder(signature) @@ -119,8 +119,9 @@ private static void EncodeComplexValue(CustomAttribute customAttribute, Constant } } - // Simple values: bool (as byte), char, float32, float64, int8, int16, int32, int64, unsigned int8, unsigned int16, unsigned int32,unsigned int64, enums (integer value) - // If this parameter has type object in the customAttribute constructor, then its real type also needs to be encoded. + // Simple values: bool (as byte), char, float32, float64, int8, int16, int32, int64, unsigned int8, unsigned int16, unsigned int32, + // unsigned int64, enums (integer value). If this parameter has type object in the customAttribute constructor, then its real type + // also needs to be encoded. private static void EncodeSimpleValue(CustomAttribute customAttribute, Constant argument, ECMA335.LiteralEncoder encoder) { var type = argument.Type; diff --git a/MetadataGenerator/Generation/Fields/FieldGenerator.cs b/MetadataGenerator/Generation/Fields/FieldGenerator.cs index 4dc06741..226ff79e 100644 --- a/MetadataGenerator/Generation/Fields/FieldGenerator.cs +++ b/MetadataGenerator/Generation/Fields/FieldGenerator.cs @@ -11,16 +11,19 @@ internal class FieldGenerator private readonly MetadataContainer metadataContainer; private readonly CustomAttributeGenerator customAttributeGenerator; - public FieldGenerator(MetadataContainer metadataContainer) + public FieldGenerator(MetadataContainer metadataContainer, CustomAttributeGenerator customAttributeGenerator) { this.metadataContainer = metadataContainer; - customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); + this.customAttributeGenerator = customAttributeGenerator; } public SRM.FieldDefinitionHandle Generate(FieldDefinition field) { var metadataBuilder = metadataContainer.MetadataBuilder; - var fieldSignature = metadataContainer.FieldSignatureEncoder.EncodeSignatureOf(field); + var fieldSignature = metadataContainer + .Encoders + .FieldSignatureEncoder + .EncodeSignatureOf(field); // Field Table (0x04) var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( @@ -44,6 +47,7 @@ public SRM.FieldDefinitionHandle Generate(FieldDefinition field) } else if (field.Value != null) { + // Constant Table (0x0B) metadataBuilder.AddConstant(fieldDefinitionHandle, field.Value.Value); } diff --git a/MetadataGenerator/Generation/GenericParameterGenerator.cs b/MetadataGenerator/Generation/GenericParameterGenerator.cs index 896f734c..f450454b 100644 --- a/MetadataGenerator/Generation/GenericParameterGenerator.cs +++ b/MetadataGenerator/Generation/GenericParameterGenerator.cs @@ -9,11 +9,19 @@ namespace MetadataGenerator.Generation { - internal static class GenericParameterGenerator + internal class GenericParameterGenerator { + private readonly MetadataContainer metadataContainer; + + public GenericParameterGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + // GenericParam Table (0x2A) - public static void GenerateGenericParameters(MetadataContainer metadataContainer) => + public void Generate() => metadataContainer + .DelayedEntries .GenericParameterEntries .Select(entry => { diff --git a/MetadataGenerator/Generation/HandleResolver.cs b/MetadataGenerator/Generation/HandleResolver.cs index beda1151..13b553df 100644 --- a/MetadataGenerator/Generation/HandleResolver.cs +++ b/MetadataGenerator/Generation/HandleResolver.cs @@ -12,6 +12,19 @@ namespace MetadataGenerator.Generation { + // Responsible providing handles of items (types, methods, fields, etc) needed when adding metadata definitions or when + // encoding method body instructions. Since generation is done in a single pass, definitions might no have been added yet. So this + // module provides on demand handles in the form of references or specifications, which are added to the Metadata tables. + // + // This handles are stored for several reasons: + // - So they can be reused + // - To reduce generated metadata size + // - Because some tables do not allow duplicates + // They are stored with some key that relates to the key in the corresponding table (see ECMA). This is useful for when + // a new one needs to be added and also to guarantee the uniqueness of the key. + // + // Also stores some handles like the one of the module definition and main method that are needed in the last step of the + // generation. internal class HandleResolver { private readonly Assembly assembly; @@ -87,7 +100,11 @@ public SRM.ModuleDefinitionHandle ModuleHandle private SRM.BlobHandle SpecKeyFor(IType type) { - var signature = metadataContainer.TypeSignatureEncoder.EncodeSignatureOf(type); + var signature = metadataContainer + .Encoders + .TypeSignatureEncoder + .EncodeSignatureOf(type); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var key = blobHandle; return key; @@ -99,7 +116,11 @@ private SRM.BlobHandle SpecKeyFor(IType type) private Tuple RefKeyFor(IFieldReference field) { - var signature = metadataContainer.FieldSignatureEncoder.EncodeSignatureOf(field); + var signature = metadataContainer + .Encoders + .FieldSignatureEncoder + .EncodeSignatureOf(field); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var parent = HandleOf(field.ContainingType); var key = new Tuple( @@ -117,7 +138,11 @@ private SRM.BlobHandle SpecKeyFor(IType type) private Tuple RefKeyFor(IMethodReference method) { - var signature = metadataContainer.MethodSignatureEncoder.EncodeSignatureOf(method); + var signature = metadataContainer + .Encoders + .MethodSignatureEncoder + .EncodeSignatureOf(method); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var parent = method.ContainingType is ArrayTypeWrapper arrayTypeWrapper @@ -133,27 +158,18 @@ method.ContainingType is ArrayTypeWrapper arrayTypeWrapper private readonly IDictionary, SRM.MethodSpecificationHandle> methodSpecHandles; - private Tuple SpecKeyFor(IMethodReference method) { - var signature = metadataContainer.MethodSignatureEncoder.EncodeSignatureOf(method); + var signature = metadataContainer + .Encoders + .MethodSignatureEncoder + .EncodeSignatureOf(method); + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); var genericMethodHandle = HandleOf(method.GenericMethod); var key = new Tuple(genericMethodHandle, blobHandle); return key; } - // - - // other - private readonly IDictionary variablesSignatureHandles; - - private SRM.BlobHandle StandaloneSigKeyFor(IList localVariables) - { - var signature = metadataContainer.MethodLocalsSignatureEncoder.EncodeSignatureOf(localVariables); - var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); - var key = blobHandle; - return key; - } private SRM.MethodDefinitionHandle? mainMethodHandle; @@ -168,6 +184,23 @@ public SRM.MethodDefinitionHandle MainMethodHandle } // + // other + private readonly IDictionary variablesSignatureHandles; + + private SRM.BlobHandle StandaloneSigKeyFor(IList localVariables) + { + var signature = metadataContainer + .Encoders + .MethodLocalsSignatureEncoder + .EncodeSignatureOf(localVariables); + + var blobHandle = metadataContainer.MetadataBuilder.GetOrAddBlob(signature); + var key = blobHandle; + return key; + } + + // + #endregion diff --git a/MetadataGenerator/Generation/MetadataContainer.cs b/MetadataGenerator/Generation/MetadataContainer.cs index 6cca20cd..a84a4f3a 100644 --- a/MetadataGenerator/Generation/MetadataContainer.cs +++ b/MetadataGenerator/Generation/MetadataContainer.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using MetadataGenerator.Generation.CustomAttributes; using MetadataGenerator.Generation.Fields; using MetadataGenerator.Generation.Methods; using MetadataGenerator.Generation.Methods.Body; @@ -17,16 +18,10 @@ internal class MetadataContainer { public readonly ECMA335.MetadataBuilder MetadataBuilder; public readonly HandleResolver HandleResolver; - public readonly FieldSignatureEncoder FieldSignatureEncoder; - public readonly MethodSignatureEncoder MethodSignatureEncoder; - public readonly MethodLocalsSignatureEncoder MethodLocalsSignatureEncoder; - public readonly TypeSignatureEncoder TypeSignatureEncoder; - public readonly PropertySignatureEncoder PropertySignatureEncoder; public readonly ECMA335.MethodBodyStreamEncoder MethodBodyStream; public readonly SRM.BlobBuilder MappedFieldData; - public readonly ISet GenericParameterEntries; - public readonly ISet InterfaceImplementationEntries; - public readonly ISet NestedTypeEntries; + public readonly Encoders Encoders; + public readonly DelayedEntries DelayedEntries; public MetadataContainer(Assembly assembly) { @@ -34,15 +29,63 @@ public MetadataContainer(Assembly assembly) MethodBodyStream = new ECMA335.MethodBodyStreamEncoder(new SRM.BlobBuilder()); HandleResolver = new HandleResolver(this, assembly); var typeEncoder = new TypeEncoder(HandleResolver); - FieldSignatureEncoder = new FieldSignatureEncoder(typeEncoder); - MethodSignatureEncoder = new MethodSignatureEncoder(typeEncoder); - MethodLocalsSignatureEncoder = new MethodLocalsSignatureEncoder(typeEncoder); - TypeSignatureEncoder = new TypeSignatureEncoder(typeEncoder); - PropertySignatureEncoder = new PropertySignatureEncoder(typeEncoder); + Encoders = new Encoders( + new FieldSignatureEncoder(typeEncoder), + new MethodSignatureEncoder(typeEncoder), + new MethodLocalsSignatureEncoder(typeEncoder), + new TypeSignatureEncoder(typeEncoder), + new PropertySignatureEncoder(typeEncoder), + new CustomAttributesSignatureEncoder() + ); MappedFieldData = new SRM.BlobBuilder(); - GenericParameterEntries = new HashSet(); - InterfaceImplementationEntries = new HashSet(); - NestedTypeEntries = new HashSet(); + DelayedEntries = new DelayedEntries( + new HashSet(), + new HashSet(), + new HashSet() + ); + } + } + + internal class DelayedEntries + { + public readonly ISet GenericParameterEntries; + public readonly ISet InterfaceImplementationEntries; + public readonly ISet NestedTypeEntries; + + public DelayedEntries( + ISet genericParameterEntries, + ISet interfaceImplementationEntries, + ISet nestedTypeEntries) + { + GenericParameterEntries = genericParameterEntries; + InterfaceImplementationEntries = interfaceImplementationEntries; + NestedTypeEntries = nestedTypeEntries; + } + } + + internal class Encoders + { + public readonly FieldSignatureEncoder FieldSignatureEncoder; + public readonly MethodSignatureEncoder MethodSignatureEncoder; + public readonly MethodLocalsSignatureEncoder MethodLocalsSignatureEncoder; + public readonly TypeSignatureEncoder TypeSignatureEncoder; + public readonly PropertySignatureEncoder PropertySignatureEncoder; + public readonly CustomAttributesSignatureEncoder CustomAttributesSignatureEncoder; + + public Encoders( + FieldSignatureEncoder fieldSignatureEncoder, + MethodSignatureEncoder methodSignatureEncoder, + MethodLocalsSignatureEncoder methodLocalsSignatureEncoder, + TypeSignatureEncoder typeSignatureEncoder, + PropertySignatureEncoder propertySignatureEncoder, + CustomAttributesSignatureEncoder customAttributesSignatureEncoder) + { + FieldSignatureEncoder = fieldSignatureEncoder; + MethodSignatureEncoder = methodSignatureEncoder; + MethodLocalsSignatureEncoder = methodLocalsSignatureEncoder; + TypeSignatureEncoder = typeSignatureEncoder; + PropertySignatureEncoder = propertySignatureEncoder; + CustomAttributesSignatureEncoder = customAttributesSignatureEncoder; } } } \ No newline at end of file diff --git a/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs index 28e87359..e327ccf1 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyControlFlow.cs @@ -5,7 +5,7 @@ namespace MetadataGenerator.Generation.Methods.Body { // Control flow is tracked by using SRM.LabelHandle. This allows us to reference instructions in the method body that are targets of - // branch instructions or part of exception regions. This LabelHandles point a specific part of the InstructionEncoder which translates + // branch instructions or part of exception regions. This LabelHandles point to a specific part of the InstructionEncoder which translates // to the encoded instruction. Since we can target an instruction that is further away in the body, not encoded yet, LabelHandles are defined // with a placeholder target, and then marked when we actually process the target instruction. internal class MethodBodyControlFlow diff --git a/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs index 57c0534b..a4fef25c 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs @@ -33,11 +33,15 @@ public MethodBodyEncoder(HandleResolver handleResolver, MethodBody body) stackSize = new StackSize(); } - // Encodes instructions using SRM InstructionEncoder. Also calculates needed MaxStack since this value might not be present (programatically - // generated dll) or incorrect (if changes were made to the method body or if it was converted to TAC and back again). + // Encodes instructions using SRM InstructionEncoder. Also calculates needed MaxStack since this value might not be present + // (programatically generated dll) or incorrect (if changes were made to the method body or if it was converted to TAC and back again). public ECMA335.InstructionEncoder Encode(out int maxStack) { - var branchTargets = body.Instructions.OfType().Select(i => i.Target).ToList(); + var branchTargets = body + .Instructions + .OfType() + .Select(i => i.Target) + .ToList(); methodBodyControlFlow.ProcessExceptionInformation(body.ExceptionInformation); methodBodyControlFlow.ProcessBranchTargets(branchTargets); var labelToInstructionEncoderOffset = new Dictionary(); diff --git a/MetadataGenerator/Generation/Methods/MethodGenerator.cs b/MetadataGenerator/Generation/Methods/MethodGenerator.cs index d4f47e2e..0d8a2db3 100644 --- a/MetadataGenerator/Generation/Methods/MethodGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodGenerator.cs @@ -12,14 +12,14 @@ namespace MetadataGenerator.Generation.Methods internal class MethodGenerator { private readonly MetadataContainer metadataContainer; - private readonly MethodParameterGenerator methodParameterGenerator; private readonly CustomAttributeGenerator customAttributeGenerator; + private readonly MethodParameterGenerator methodParameterGenerator; - public MethodGenerator(MetadataContainer metadataContainer) + public MethodGenerator(MetadataContainer metadataContainer, CustomAttributeGenerator customAttributeGenerator) { this.metadataContainer = metadataContainer; + this.customAttributeGenerator = customAttributeGenerator; methodParameterGenerator = new MethodParameterGenerator(metadataContainer); - customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); } public SRM.MethodDefinitionHandle Generate(MethodDefinition method) @@ -28,8 +28,13 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) .Parameters .Select(parameter => methodParameterGenerator.Generate(parameter)) .ToList(); - var methodSignature = metadataContainer.MethodSignatureEncoder.EncodeSignatureOf(method); - var methodBodyOffset = -1; + + var methodSignature = metadataContainer + .Encoders + .MethodSignatureEncoder + .EncodeSignatureOf(method); + + var methodBodyOffset = -1; // no body if (method.HasBody) { var localVariablesSignatureHandle = method.Body.LocalVariables.Count > 0 @@ -49,6 +54,7 @@ public SRM.MethodDefinitionHandle Generate(MethodDefinition method) var nextParameterHandle = ECMA335.MetadataTokens.ParameterHandle(metadataContainer.MetadataBuilder.NextRowFor(ECMA335.TableIndex.Param)); + // MethodDef Table (0x06) var methodDefinitionHandle = metadataContainer.MetadataBuilder.AddMethodDefinition( attributes: AttributesFor(method), diff --git a/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs b/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs index a4736fd4..ba1bb145 100644 --- a/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs +++ b/MetadataGenerator/Generation/Methods/MethodParameterGenerator.cs @@ -20,8 +20,10 @@ public SRM.ParameterHandle Generate(MethodParameter methodParameter) attributes: AttributesFor(methodParameter), name: metadataContainer.MetadataBuilder.GetOrAddString(methodParameter.Name), sequenceNumber: methodParameter.Index); + if (methodParameter.HasDefaultValue) { + // Constant Table (0x0B) metadataContainer.MetadataBuilder.AddConstant(parameterHandle, methodParameter.DefaultValue.Value); } diff --git a/MetadataGenerator/Generation/ModuleGenerator.cs b/MetadataGenerator/Generation/ModuleGenerator.cs index 672aef30..ad27a6a0 100644 --- a/MetadataGenerator/Generation/ModuleGenerator.cs +++ b/MetadataGenerator/Generation/ModuleGenerator.cs @@ -12,7 +12,7 @@ public ModuleGenerator(MetadataContainer metadataContainer) this.metadataContainer = metadataContainer; } - public void GenerateModuleFor(Assembly assembly) + public void Generate(Assembly assembly) { var extension = assembly.Kind == AssemblyKind.Exe ? "exe" : "dll"; var moduleName = $"{assembly.Name}.{extension}"; diff --git a/MetadataGenerator/Generation/NamespaceGenerator.cs b/MetadataGenerator/Generation/NamespaceGenerator.cs index 836457aa..7a5be059 100644 --- a/MetadataGenerator/Generation/NamespaceGenerator.cs +++ b/MetadataGenerator/Generation/NamespaceGenerator.cs @@ -37,7 +37,10 @@ private SRM.TypeDefinitionHandle GenerateTypes(TypeDefinition type) var typeDefinitionHandle = typeGenerator.Generate(type); foreach (var nestedType in nestedTypes) { - metadataContainer.NestedTypeEntries.Add(new NestedTypeEntry(nestedType, typeDefinitionHandle)); + metadataContainer + .DelayedEntries + .NestedTypeEntries + .Add(new NestedTypeEntry(nestedType, typeDefinitionHandle)); } return typeDefinitionHandle; diff --git a/MetadataGenerator/Generation/Properties/PropertyGenerator.cs b/MetadataGenerator/Generation/Properties/PropertyGenerator.cs index 6a879b26..67ff877f 100644 --- a/MetadataGenerator/Generation/Properties/PropertyGenerator.cs +++ b/MetadataGenerator/Generation/Properties/PropertyGenerator.cs @@ -12,10 +12,10 @@ internal class PropertyGenerator private readonly MetadataContainer metadataContainer; private readonly CustomAttributeGenerator customAttributeGenerator; - public PropertyGenerator(MetadataContainer metadataContainer) + public PropertyGenerator(MetadataContainer metadataContainer, CustomAttributeGenerator customAttributeGenerator) { this.metadataContainer = metadataContainer; - customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); + this.customAttributeGenerator = customAttributeGenerator; } // Properties can have getters or setters which are methods defined within the class. @@ -24,7 +24,11 @@ public SRM.PropertyDefinitionHandle Generate( PropertyDefinition property, IDictionary methodToHandle) { - var signature = metadataContainer.PropertySignatureEncoder.EncodeSignatureOf(property); + var signature = metadataContainer + .Encoders + .PropertySignatureEncoder + .EncodeSignatureOf(property); + // Property Table (0x17) var propertyDefinitionHandle = metadataContainer.MetadataBuilder.AddProperty( attributes: SR.PropertyAttributes.None, diff --git a/MetadataGenerator/Generation/Types/InterfaceImplementationGenerator.cs b/MetadataGenerator/Generation/Types/InterfaceImplementationGenerator.cs index ba1c3285..42ea532d 100644 --- a/MetadataGenerator/Generation/Types/InterfaceImplementationGenerator.cs +++ b/MetadataGenerator/Generation/Types/InterfaceImplementationGenerator.cs @@ -4,11 +4,19 @@ namespace MetadataGenerator.Generation.Types { - internal static class InterfaceImplementationGenerator + internal class InterfaceImplementationGenerator { + private readonly MetadataContainer metadataContainer; + + public InterfaceImplementationGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + // InterfaceImpl Table (0x09) - public static void GenerateInterfaceImplementations(MetadataContainer metadataContainer) => + public void Generate() => metadataContainer + .DelayedEntries .InterfaceImplementationEntries .OrderBy(entry => ECMA335.CodedIndex.TypeDefOrRef(entry.Type)) .ThenBy(entry => ECMA335.CodedIndex.TypeDefOrRefOrSpec(entry.ImplementedInterface)) diff --git a/MetadataGenerator/Generation/Types/NestedTypeGenerator.cs b/MetadataGenerator/Generation/Types/NestedTypeGenerator.cs index 33520c36..ca1b1289 100644 --- a/MetadataGenerator/Generation/Types/NestedTypeGenerator.cs +++ b/MetadataGenerator/Generation/Types/NestedTypeGenerator.cs @@ -4,11 +4,19 @@ namespace MetadataGenerator.Generation.Types { - internal static class NestedTypeGenerator + internal class NestedTypeGenerator { + private readonly MetadataContainer metadataContainer; + + public NestedTypeGenerator(MetadataContainer metadataContainer) + { + this.metadataContainer = metadataContainer; + } + // NestedClass Table (0x29) - public static void GenerateNestedTypes(MetadataContainer metadataContainer) => + public void Generate() => metadataContainer + .DelayedEntries .NestedTypeEntries .OrderBy(entry => ECMA335.CodedIndex.TypeDefOrRef(entry.Type)) .ToList() diff --git a/MetadataGenerator/Generation/Types/TypeGenerator.cs b/MetadataGenerator/Generation/Types/TypeGenerator.cs index f1a735ff..1798fc33 100644 --- a/MetadataGenerator/Generation/Types/TypeGenerator.cs +++ b/MetadataGenerator/Generation/Types/TypeGenerator.cs @@ -17,18 +17,18 @@ namespace MetadataGenerator.Generation.Types internal class TypeGenerator { private readonly MetadataContainer metadataContainer; + private readonly CustomAttributeGenerator customAttributeGenerator; private readonly MethodGenerator methodGenerator; private readonly FieldGenerator fieldGenerator; private readonly PropertyGenerator propertyGenerator; - private readonly CustomAttributeGenerator customAttributeGenerator; public TypeGenerator(MetadataContainer metadataContainer) { this.metadataContainer = metadataContainer; - methodGenerator = new MethodGenerator(metadataContainer); - fieldGenerator = new FieldGenerator(metadataContainer); - propertyGenerator = new PropertyGenerator(metadataContainer); customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); + methodGenerator = new MethodGenerator(metadataContainer, customAttributeGenerator); + fieldGenerator = new FieldGenerator(metadataContainer, customAttributeGenerator); + propertyGenerator = new PropertyGenerator(metadataContainer, customAttributeGenerator); } public SRM.TypeDefinitionHandle Generate(TypeDefinition type) @@ -59,7 +59,8 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) fieldList: fieldDefinitionHandles.FirstOr(nextFieldDefinitionHandle), methodList: methodToHandle.Values.FirstOr(nextMethodDefinitionHandle)); - var propertyDefinitionHandles = type.PropertyDefinitions + var propertyDefinitionHandles = type + .PropertyDefinitions .Select(property => propertyGenerator.Generate(property, methodToHandle)) .ToList(); @@ -71,14 +72,18 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) foreach (var interfaze in type.Interfaces) { - metadataContainer.InterfaceImplementationEntries.Add(new InterfaceImplementationEntry( - typeDefinitionHandle, - metadataResolver.HandleOf(interfaze))); + metadataContainer + .DelayedEntries + .InterfaceImplementationEntries + .Add(new InterfaceImplementationEntry(typeDefinitionHandle, metadataResolver.HandleOf(interfaze))); } foreach (var genericParameter in type.GenericParameters) { - metadataContainer.GenericParameterEntries.Add(new GenericParameterEntry(typeDefinitionHandle, genericParameter)); + metadataContainer + .DelayedEntries + .GenericParameterEntries + .Add(new GenericParameterEntry(typeDefinitionHandle, genericParameter)); } foreach (var entry in methodToHandle) @@ -88,7 +93,10 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) foreach (var genericParameter in method.GenericParameters) { - metadataContainer.GenericParameterEntries.Add(new GenericParameterEntry(handle, genericParameter)); + metadataContainer + .DelayedEntries + .GenericParameterEntries + .Add(new GenericParameterEntry(handle, genericParameter)); } if (method.OverridenMethod != null) @@ -118,8 +126,8 @@ public SRM.TypeDefinitionHandle Generate(TypeDefinition type) return typeDefinitionHandle; } - // CLS-compliant generic type names are encoded using the format “name[`arity]”, where […] indicates that the grave accent character “`” and - // arity together are optional. The encoded name shall follow these rules: + // CLS-compliant generic type names are encoded using the format “name[`arity]”, where […] indicates that the grave accent character + // “`” and arity together are optional. The encoded name shall follow these rules: // - name shall be an ID that does not contain the “`” character. // - arity is specified as an unsigned decimal number without leading zeros or spaces. // - For a normal generic type, arity is the number of type parameters declared on the type. diff --git a/MetadataGenerator/Generator.cs b/MetadataGenerator/Generator.cs index c6bef02c..d84174cb 100644 --- a/MetadataGenerator/Generator.cs +++ b/MetadataGenerator/Generator.cs @@ -20,7 +20,9 @@ public void Generate(Assembly assembly) { var metadataContainer = AssemblyGenerator.Generate(assembly); var peHeaderBuilder = new SRPE.PEHeaderBuilder( - imageCharacteristics: assembly.Kind == Exe ? SRPE.Characteristics.ExecutableImage : SRPE.Characteristics.Dll + imageCharacteristics: assembly.Kind == Exe + ? SRPE.Characteristics.ExecutableImage + : SRPE.Characteristics.Dll ); var peBlob = new SRM.BlobBuilder(); new SRPE.ManagedPEBuilder( From 1c76aef2ea41d591654960dbb91d495ad4da52bb Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 1 Nov 2020 19:51:56 -0300 Subject: [PATCH 251/256] add comment --- .../Assembly/ExceptionInformation.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Backend/Transformations/Assembly/ExceptionInformation.cs b/Backend/Transformations/Assembly/ExceptionInformation.cs index 47baf598..911e196c 100644 --- a/Backend/Transformations/Assembly/ExceptionInformation.cs +++ b/Backend/Transformations/Assembly/ExceptionInformation.cs @@ -7,6 +7,15 @@ 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. + // + // A Stack is used to keep track of the ongoing protected regions, that is the try-handler in which the code is currently inside. + // Protected regions can be nested and each one exists onto the containing one so a stack is fitting. internal class ExceptionInformationBuilder { private readonly Stack protectedBlocks = new Stack(); @@ -46,8 +55,9 @@ public void AddFilterHandlerToCurrentProtectedBlock(string label, FilterInstruct { var protectedBlockBuilder = protectedBlocks.Peek(); - bool EndPreviousHandlerCondition() => protectedBlockBuilder.Handlers.Last().HandlerBlockKind != ExceptionHandlerBlockKind.Filter || - kind == FilterInstructionKind.FilterSection; + bool EndPreviousHandlerCondition() => + protectedBlockBuilder.Handlers.Last().HandlerBlockKind != ExceptionHandlerBlockKind.Filter || + kind == FilterInstructionKind.FilterSection; protectedBlockBuilder.EndPreviousRegionAt(label, EndPreviousHandlerCondition); @@ -86,7 +96,7 @@ public void EndCurrentProtectedBlockAt(string label) .HandlerEnd = label; result.AddRange(exceptionBlockBuilder.Build()); } - + private class ProtectedBlockBuilder { private string tryStart; From a1409294e5392c9e6776b6c4db5039c3a53055aa Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sun, 1 Nov 2020 20:24:30 -0300 Subject: [PATCH 252/256] comments + refactor file name --- Backend/Backend.csproj | 2 +- ...nformation.cs => ExceptionInformationBuilder.cs} | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) rename Backend/Transformations/Assembly/{ExceptionInformation.cs => ExceptionInformationBuilder.cs} (93%) diff --git a/Backend/Backend.csproj b/Backend/Backend.csproj index 5dd4062d..8fadd328 100644 --- a/Backend/Backend.csproj +++ b/Backend/Backend.csproj @@ -63,7 +63,7 @@ - + diff --git a/Backend/Transformations/Assembly/ExceptionInformation.cs b/Backend/Transformations/Assembly/ExceptionInformationBuilder.cs similarity index 93% rename from Backend/Transformations/Assembly/ExceptionInformation.cs rename to Backend/Transformations/Assembly/ExceptionInformationBuilder.cs index 911e196c..91098767 100644 --- a/Backend/Transformations/Assembly/ExceptionInformation.cs +++ b/Backend/Transformations/Assembly/ExceptionInformationBuilder.cs @@ -7,15 +7,22 @@ namespace Backend.Transformations.Assembly { - // helps with the translation of exception handling instructions from TAC to SIL. In SIL, exception information is stored + // 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. // - // A Stack is used to keep track of the ongoing protected regions, that is the try-handler in which the code is currently inside. - // Protected regions can be nested and each one exists onto the containing one so a stack is fitting. + // 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(); From 33185e8fb54d3a2f7fc7e683ccb9c2bbb9c63364 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Tue, 24 Nov 2020 08:39:36 -0300 Subject: [PATCH 253/256] correctly calculate max stack by using CFG --- Console/Program.cs | 30 ++- .../Methods/Body/MethodBodyEncoder.cs | 174 ++++++++++++------ MetadataGenerator/MetadataGenerator.csproj | 4 + 3 files changed, 147 insertions(+), 61 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index ba29552f..560f321e 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -441,7 +441,7 @@ private static void ProgramaticallyGeneratedAssembly() Instructions = { new Bytecode.LoadInstruction(0, Bytecode.LoadOperation.Content, thisVariable), - new Bytecode.MethodCallInstruction(1, Bytecode.MethodCallOperation.Jump, objectConstructorMethod), + new Bytecode.MethodCallInstruction(1, Bytecode.MethodCallOperation.Static, objectConstructorMethod), new Bytecode.BasicInstruction(2, Bytecode.BasicOperation.Nop), new Bytecode.BasicInstruction(3, Bytecode.BasicOperation.Return) } @@ -486,7 +486,7 @@ private static void ProgramaticallyGeneratedAssembly() Instructions = { new Bytecode.LoadInstruction(0, Bytecode.LoadOperation.Content, thisVariable), - new Bytecode.MethodCallInstruction(1, Bytecode.MethodCallOperation.Jump, objectConstructorMethod), + new Bytecode.MethodCallInstruction(1, Bytecode.MethodCallOperation.Static, objectConstructorMethod), new Bytecode.BasicInstruction(2, Bytecode.BasicOperation.Nop), new Bytecode.BasicInstruction(3, Bytecode.BasicOperation.Return) } @@ -519,11 +519,11 @@ private static void ProgramaticallyGeneratedAssembly() { new Bytecode.BasicInstruction(0, Bytecode.BasicOperation.Nop), new Bytecode.CreateObjectInstruction(1, englishTypeConstructor), - new Bytecode.MethodCallInstruction(2, Bytecode.MethodCallOperation.Jump, englishGreetMethod), + new Bytecode.MethodCallInstruction(2, Bytecode.MethodCallOperation.Static, englishGreetMethod), new Bytecode.MethodCallInstruction(3, Bytecode.MethodCallOperation.Static, ConsoleWriteLineMethodReference()), new Bytecode.BasicInstruction(4, Bytecode.BasicOperation.Nop), new Bytecode.CreateObjectInstruction(5, spanishTypeConstructor), - new Bytecode.MethodCallInstruction(6, Bytecode.MethodCallOperation.Jump, spanishGreetMethod), + new Bytecode.MethodCallInstruction(6, Bytecode.MethodCallOperation.Static, spanishGreetMethod), new Bytecode.MethodCallInstruction(7, Bytecode.MethodCallOperation.Static, ConsoleWriteLineMethodReference()), new Bytecode.BasicInstruction(8, Bytecode.BasicOperation.Nop), new Bytecode.BasicInstruction(9, Bytecode.BasicOperation.Return) @@ -559,7 +559,7 @@ where m.HasBody var tac = new Backend.Transformations.Disassembler(method).Execute(); method.Body = tac; - AddLogAtMethodEntry($"Entering method: {method.Name}", method.Body); + AddLogAtMethodEntry($"Entering method: {method.Name} of class: {method.ContainingType.Name}", method.Body); var cfanalysis = new ControlFlowAnalysis(method.Body); var cfg = cfanalysis.GenerateExceptionalControlFlow(); @@ -780,12 +780,24 @@ private static void DoWithLibs(Action operation) static void Main(string[] args) { - ReadAndGenerateDll(transformToTacAndBackToBytecode: false); - // ReadAndGenerateDll(transformToTacAndBackToBytecode: true); + // generation + ReadAndGenerateDll(transformToTacAndBackToBytecode: false); + // ReadAndGenerateDll(transformToTacAndBackToBytecode: true); + // + + // instrumentation // TacInstrumentation(); - // ProgramaticallyGeneratedAssembly(); - // RemoveUnusedMethodFromSimpleExecutable(); + // TODO instrument tests by printing the name of the test running. + // + + // programmatic generation + // ProgramaticallyGeneratedAssembly(); + // + // optimization + // RemoveUnusedMethodFromSimpleExecutable(); + // + System.Console.WriteLine("Done!"); } } diff --git a/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs index a4fef25c..89025d21 100644 --- a/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs +++ b/MetadataGenerator/Generation/Methods/Body/MethodBodyEncoder.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Backend.Analyses; +using Backend.Model; using Model; using Model.Bytecode; using Model.Bytecode.Visitor; @@ -20,7 +22,8 @@ internal class MethodBodyEncoder : IInstructionVisitor private readonly ISet skippedIndices; private readonly MethodBody body; private readonly StackSize stackSize; - private int Index { get; set; } + private CFGNode CurrentNode { get; set; } + private int NodeInstructionIndex { get; set; } public MethodBodyEncoder(HandleResolver handleResolver, MethodBody body) { @@ -33,8 +36,12 @@ public MethodBodyEncoder(HandleResolver handleResolver, MethodBody body) stackSize = new StackSize(); } - // Encodes instructions using SRM InstructionEncoder. Also calculates needed MaxStack since this value might not be present - // (programatically generated dll) or incorrect (if changes were made to the method body or if it was converted to TAC and back again). + // Encodes instructions using SRM InstructionEncoder. + // + // Also calculates needed MaxStack since this value might not be present (programatically generated dll) or incorrect + // (if changes were made to the method body or if it was converted to TAC and back again). + // While instructions are generated as they appear in the method body, the MaxStack cannot be calculated linearly. This is due + // to the fact that it needs to take into account flow of the execution. So we use the ControlFlowGraph for this. public ECMA335.InstructionEncoder Encode(out int maxStack) { var branchTargets = body @@ -46,20 +53,41 @@ public ECMA335.InstructionEncoder Encode(out int maxStack) methodBodyControlFlow.ProcessBranchTargets(branchTargets); var labelToInstructionEncoderOffset = new Dictionary(); - for (Index = 0; Index < body.Instructions.Count; Index++) + // build CFG and sort nodes to match the order of the instructions in the method body (CIL instructions must be + // generated in that order). + // stackSizeAtNodeEntry holds the number of elements in the stack when entering that node. This is necessary to + // correctly calculate MaxStack when branches occur (explore each branch path with the stack as it was before the branch) + var sortedNodes = PerformControlFlowAnalysis(out var stackSizeAtNodeEntry); + foreach (var node in sortedNodes) { - var instruction = (Instruction) body.Instructions[Index]; - labelToInstructionEncoderOffset[instruction.Label] = instructionEncoder.Offset; - methodBodyControlFlow.MarkLabelIfNeeded(instruction.Label); + CurrentNode = node; + stackSize.CurrentStackSize = stackSizeAtNodeEntry[node.Id]; - if (FilterOrCatchStartAt(instruction.Label)) + for (NodeInstructionIndex = 0; NodeInstructionIndex < node.Instructions.Count; NodeInstructionIndex++) { - stackSize.Increment(); + var instruction = (Instruction) node.Instructions[NodeInstructionIndex]; + labelToInstructionEncoderOffset[instruction.Label] = instructionEncoder.Offset; + methodBodyControlFlow.MarkLabelIfNeeded(instruction.Label); + + if (FilterOrCatchStartAt(instruction.Label)) + { + stackSize.Increment(); + } + + if (skippedIndices.Contains(NodeInstructionIndex)) + { + skippedIndices.Remove(NodeInstructionIndex); + } + else + { + instruction.Accept(this); + } } - if (!skippedIndices.Contains(Index)) + // prepare stack for successor nodes + foreach (var successor in node.Successors) { - instruction.Accept(this); + stackSizeAtNodeEntry[successor.Id] = stackSize.CurrentStackSize; } } @@ -72,6 +100,30 @@ public ECMA335.InstructionEncoder Encode(out int maxStack) return instructionEncoder; } + private IList PerformControlFlowAnalysis(out int[] stackSizeAtNodeEntry) + { + var controlFlowGraph = new ControlFlowAnalysis(body).GenerateExceptionalControlFlow(); + + var instructionToIndex = body.Instructions + .Select((instruction, index) => new KeyValuePair(instruction, index)) + .ToDictionary(pair => pair.Key, pair => pair.Value); + + // not used + controlFlowGraph.Nodes.Remove(controlFlowGraph.Entry); + controlFlowGraph.Nodes.Remove(controlFlowGraph.Exit); + + // sort nodes as they appear in the method body. Each node is represented with its first instruction and we sort by the + // index of that instruction in the method body. + var sortedNodes = controlFlowGraph.Nodes.ToList(); + sortedNodes.Sort((n1, n2) => + instructionToIndex[n1.Instructions.First()].CompareTo(instructionToIndex[n2.Instructions.First()])); + + // each node stack size at entry is initialized to 0. The +2 is for the Entry and Exit nodes. Although they are not processed, + // we use node.id to access the stackSizesAtNodeEntry, so it needs all CFG nodes count. + stackSizeAtNodeEntry = new int[controlFlowGraph.Nodes.Count + 2]; + return sortedNodes; + } + public void Visit(IInstructionContainer container) { } @@ -177,7 +229,6 @@ public void Visit(BasicInstruction instruction) break; case BasicOperation.Rethrow: instructionEncoder.OpCode(SRM.ILOpCode.Rethrow); - stackSize.Clear(); break; case BasicOperation.Not: instructionEncoder.OpCode(SRM.ILOpCode.Not); @@ -220,6 +271,7 @@ public void Visit(BasicInstruction instruction) break; case BasicOperation.Return: instructionEncoder.OpCode(SRM.ILOpCode.Ret); + if (stackSize.CurrentStackSize > 0) stackSize.Decrement(); // value to be returned (not always present) break; default: throw instruction.Operation.ToUnknownValueException(); @@ -281,9 +333,11 @@ public void Visit(LoadInstruction instruction) stackSize.Increment(); if ( - body.Instructions.Count > Index + 2 && - body.Instructions[Index + 1] is BasicInstruction i1 && i1.Operation == BasicOperation.Eq && - body.Instructions[Index + 2] is BasicInstruction i2 && i2.Operation == BasicOperation.Neg + CurrentNode.Instructions.Count > NodeInstructionIndex + 2 && + CurrentNode.Instructions[NodeInstructionIndex + 1] is BasicInstruction i1 && + i1.Operation == BasicOperation.Eq && + CurrentNode.Instructions[NodeInstructionIndex + 2] is BasicInstruction i2 && + i2.Operation == BasicOperation.Neg ) { // cgt_un is used as a compare-not-equal with null. @@ -292,8 +346,8 @@ public void Visit(LoadInstruction instruction) stackSize.Decrement(); // skip processing next 2 instructions - skippedIndices.Add(Index + 1); - skippedIndices.Add(Index + 2); + skippedIndices.Add(NodeInstructionIndex + 1); + skippedIndices.Add(NodeInstructionIndex + 2); } break; @@ -409,13 +463,20 @@ public void Visit(LoadFieldInstruction instruction) public void Visit(LoadMethodAddressInstruction instruction) { - var isVirtual = instruction.Method.IsVirtual; - instructionEncoder.OpCode(isVirtual ? SRM.ILOpCode.Ldvirtftn : SRM.ILOpCode.Ldftn); - instructionEncoder.Token(handleResolver.HandleOf(instruction.Method)); - if (!isVirtual) + switch (instruction.Operation) { - stackSize.Increment(); + case LoadMethodAddressOperation.Virtual: + instructionEncoder.OpCode(SRM.ILOpCode.Ldvirtftn); + break; + case LoadMethodAddressOperation.Static: + instructionEncoder.OpCode(SRM.ILOpCode.Ldftn); + stackSize.Increment(); + break; + default: + throw instruction.Operation.ToUnknownValueException(); } + + instructionEncoder.Token(handleResolver.HandleOf(instruction.Method)); } public void Visit(StoreIndirectInstruction instruction) @@ -480,10 +541,18 @@ public void Visit(StoreInstruction instruction) public void Visit(StoreFieldInstruction instruction) { - var isStatic = instruction.Field.IsStatic; - instructionEncoder.OpCode(isStatic ? SRM.ILOpCode.Stsfld : SRM.ILOpCode.Stfld); + if (instruction.Field.IsStatic) + { + instructionEncoder.OpCode(SRM.ILOpCode.Stsfld); + stackSize.Decrement(); + } + else + { + instructionEncoder.OpCode(SRM.ILOpCode.Stfld); + stackSize.Decrement(2); + } + instructionEncoder.Token(handleResolver.HandleOf(instruction.Field)); - stackSize.Decrement(isStatic ? 1 : 2); } public void Visit(ConvertInstruction instruction) @@ -669,9 +738,11 @@ public void Visit(BranchInstruction instruction) { case BranchOperation.False: opCode = SRM.ILOpCode.Brfalse; + stackSize.Decrement(); break; case BranchOperation.True: opCode = SRM.ILOpCode.Brtrue; + stackSize.Decrement(); break; case BranchOperation.Eq: opCode = SRM.ILOpCode.Beq; @@ -751,32 +822,28 @@ public void Visit(MethodCallInstruction instruction) case MethodCallOperation.Virtual: instructionEncoder.OpCode(SRM.ILOpCode.Callvirt); instructionEncoder.Token(handleResolver.HandleOf(instruction.Method)); - stackSize.Decrement(instruction.Method.Parameters.Count + 1); break; - case MethodCallOperation.Static: case MethodCallOperation.Jump: + instructionEncoder.OpCode(SRM.ILOpCode.Jmp); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Method)); + break; + case MethodCallOperation.Static: instructionEncoder.Call(handleResolver.HandleOf(instruction.Method)); - stackSize.Decrement(instruction.Method.Parameters.Count); break; default: throw instruction.Operation.ToUnknownValueException(); } - if (!instruction.Method.ReturnType.Equals(PlatformTypes.Void)) - { - stackSize.Increment(); - } + stackSize.Decrement(StackSize.MethodCallDecrement(instruction.Method)); + if (!instruction.Method.ReturnType.Equals(PlatformTypes.Void)) stackSize.Increment(); } public void Visit(IndirectMethodCallInstruction instruction) { var methodSignature = handleResolver.HandleOf(instruction.Function); instructionEncoder.CallIndirect((SRM.StandaloneSignatureHandle) methodSignature); - stackSize.Decrement(instruction.Function.Parameters.Count + 1); - if (!instruction.Function.ReturnType.Equals(PlatformTypes.Void)) - { - stackSize.Increment(); - } + stackSize.Decrement(StackSize.MethodCallDecrement(instruction.Function)); + if (!instruction.Function.ReturnType.Equals(PlatformTypes.Void)) stackSize.Increment(); } public void Visit(CreateObjectInstruction instruction) @@ -810,8 +877,8 @@ public void Visit(LoadArrayElementInstruction instruction) if (instruction.Method != null) { instructionEncoder.Call(handleResolver.HandleOf(instruction.Method)); - stackSize.Decrement(instruction.Method.Parameters.Count); - stackSize.Increment(); + stackSize.Decrement(StackSize.MethodCallDecrement(instruction.Method)); + stackSize.Increment(); // not void } else { @@ -866,15 +933,13 @@ public void Visit(LoadArrayElementInstruction instruction) else { instructionEncoder.OpCode(SRM.ILOpCode.Ldelem); - instructionEncoder.Token( - handleResolver.HandleOf(instruction.Array.ElementsType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Array.ElementsType)); } break; case LoadArrayElementOperation.Address: instructionEncoder.OpCode(SRM.ILOpCode.Ldelema); - instructionEncoder.Token( - handleResolver.HandleOf(instruction.Array.ElementsType)); + instructionEncoder.Token(handleResolver.HandleOf(instruction.Array.ElementsType)); break; default: @@ -890,7 +955,8 @@ public void Visit(StoreArrayElementInstruction instruction) if (instruction.Method != null) { instructionEncoder.Call(handleResolver.HandleOf(instruction.Method)); - stackSize.Decrement(instruction.Method.Parameters.Count); + stackSize.Decrement(StackSize.MethodCallDecrement(instruction.Method)); + // void, so no stack increment } else { @@ -977,34 +1043,38 @@ public void FillWithRealTargets(IDictionary labelToInstructionEncod private class StackSize { - private int currentStackSize; + public int CurrentStackSize { get; set; } public int MaxStackSize { get; private set; } public StackSize() { - currentStackSize = 0; + CurrentStackSize = 0; MaxStackSize = 0; } public void Increment() { - currentStackSize += 1; - if (currentStackSize > MaxStackSize) + CurrentStackSize += 1; + if (CurrentStackSize > MaxStackSize) { - MaxStackSize = currentStackSize; + MaxStackSize = CurrentStackSize; } } public void Decrement(int times = 1) { - if (currentStackSize < times) throw new Exception("Stack size cannot be less than 0"); - currentStackSize -= times; + if (CurrentStackSize < times) throw new Exception("Stack size cannot be less than 0"); + CurrentStackSize -= times; } public void Clear() { - currentStackSize = 0; + CurrentStackSize = 0; } + + // this (if any) + parameters + public static int MethodCallDecrement(IMethodReference method) => (method.IsStatic ? 0 : 1) + method.Parameters.Count; + public static int MethodCallDecrement(FunctionPointerType method) => (method.IsStatic ? 0 : 1) + method.Parameters.Count; } } } \ No newline at end of file diff --git a/MetadataGenerator/MetadataGenerator.csproj b/MetadataGenerator/MetadataGenerator.csproj index 609cceff..cde6a4a8 100644 --- a/MetadataGenerator/MetadataGenerator.csproj +++ b/MetadataGenerator/MetadataGenerator.csproj @@ -54,6 +54,10 @@ + + {45c7b613-e32d-43e8-8030-932d509602eb} + Backend + {F08216AD-E55C-44B1-A253-AB8B024B7597} Model From d125c1e0264c557aaca355d0872fc22eb5caa56e Mon Sep 17 00:00:00 2001 From: fcurdi Date: Sat, 28 Nov 2020 19:49:55 -0300 Subject: [PATCH 254/256] refactor example --- Console/Program.cs | 29 ++++++++++++++--------------- ExamplesEXE/ExamplesEXE.cs | 1 - 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Console/Program.cs b/Console/Program.cs index 560f321e..54749d77 100644 --- a/Console/Program.cs +++ b/Console/Program.cs @@ -672,7 +672,6 @@ where m.HasBody } }); - // TODO hacerlo generico y ver como darle sentido para los casos de estudio (ya que al ser libs van a tener metodos que no se usan). private static void RemoveUnusedMethodFromSimpleExecutable() { var input = "../../../ExamplesEXE/bin/Debug/ExamplesEXE.exe"; @@ -688,6 +687,7 @@ private static void RemoveUnusedMethodFromSimpleExecutable() var allDefinedMethods = (from a in host.Assemblies from t in a.RootNamespace.GetAllTypes() from m in t.Members.OfType() + where m.HasBody select m).ToList(); // convert bodies to typed tac @@ -714,6 +714,17 @@ from m in t.Members.OfType() var classHierarchyAnalysis = new ClassHierarchyAnalysis(classHierarchy); var roots = host.GetRootMethods(); var callGraph = classHierarchyAnalysis.Analyze(host, roots); + + // remove unused method + var unusedMethods = allDefinedMethods + .Except(callGraph.Methods.OfType()) + .ToList(); + foreach (var unusedMethod in unusedMethods) + { + unusedMethod.ContainingType.Methods.Remove(unusedMethod); + } + + System.Console.WriteLine($"File: {input} - Unused methods removed: {unusedMethods.Count}"); // convert back to bytecode for generation foreach (var method in allDefinedMethods) @@ -721,18 +732,6 @@ from m in t.Members.OfType() var bytecode = new Backend.Transformations.Assembly.Assembler(method).Execute(); method.Body = bytecode; } - - // remove unused method - var unusedPrivateMethods = allDefinedMethods - .Except(callGraph.Methods.Cast()) - .Where(method => method.Visibility == VisibilityKind.Private) - .ToList(); - foreach (var unusedMethods in unusedPrivateMethods) - { - unusedMethods.ContainingType.Methods.Remove(unusedMethods); - } - - System.Console.WriteLine($"File: {input} - Unused methods removed: {unusedPrivateMethods.Count}"); // generate var generator = new MetadataGenerator.Generator(); @@ -778,16 +777,16 @@ private static void DoWithLibs(Action operation) } + static void Main(string[] args) { // generation - ReadAndGenerateDll(transformToTacAndBackToBytecode: false); + ReadAndGenerateDll(transformToTacAndBackToBytecode: false); // ReadAndGenerateDll(transformToTacAndBackToBytecode: true); // // instrumentation // TacInstrumentation(); - // TODO instrument tests by printing the name of the test running. // // programmatic generation diff --git a/ExamplesEXE/ExamplesEXE.cs b/ExamplesEXE/ExamplesEXE.cs index 3db313a6..94b2e31f 100644 --- a/ExamplesEXE/ExamplesEXE.cs +++ b/ExamplesEXE/ExamplesEXE.cs @@ -4,7 +4,6 @@ public static class MainClass { public static void Main(string[] args) { - var x = 1; UsedMethod(); } From 377fb9a6ac64111a7e69f359269cf7c96ab99be9 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 16 Dec 2020 21:08:01 -0300 Subject: [PATCH 255/256] read assembly attributes --- MetadataProvider/AssemblyExtractor.cs | 2 ++ Model/Assembly.cs | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 394a8fe1..5c40ca80 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -129,6 +129,8 @@ public Assembly Extract() Culture = metadata.GetString(assemblydef.Culture), PublicKey = metadata.GetBlobBytes(assemblydef.PublicKey) }; + + ExtractAttributes(assembly, assemblydef.GetCustomAttributes()); foreach (var handle in metadata.AssemblyReferences) { diff --git a/Model/Assembly.cs b/Model/Assembly.cs index c3fc6b29..9a52ebae 100644 --- a/Model/Assembly.cs +++ b/Model/Assembly.cs @@ -9,7 +9,7 @@ namespace Model { - public interface IAssemblyReference + public interface IAssemblyReference : IMetadataReference { string Name { get; } Version Version { get; } @@ -23,10 +23,11 @@ public class AssemblyReference : IAssemblyReference public Version Version { get; set; } public string Culture { get; set; } public byte[] PublicKey { get; set; } - + public ISet Attributes { get; private set; } public AssemblyReference(string name) { this.Name = name; + this.Attributes = new HashSet(); } public override string ToString() @@ -58,10 +59,12 @@ public class Assembly : IAssemblyReference public Version Version { get; set; } public string Culture { get; set; } public byte[] PublicKey { get; set; } + public ISet Attributes { get; private set; } public Assembly(string name) { this.Name = name; this.References = new List(); + this.Attributes = new HashSet(); } public bool MatchReference(IAssemblyReference reference) From 08fec7c31ea2e31740b4ade07099cbfcfc303951 Mon Sep 17 00:00:00 2001 From: fcurdi Date: Wed, 16 Dec 2020 21:30:02 -0300 Subject: [PATCH 256/256] generate assembly attributes --- MetadataGenerator/Generation/AssemblyGenerator.cs | 13 ++++++++++--- MetadataGenerator/Generation/NamespaceGenerator.cs | 5 +++-- MetadataGenerator/Generation/Types/TypeGenerator.cs | 4 ++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/MetadataGenerator/Generation/AssemblyGenerator.cs b/MetadataGenerator/Generation/AssemblyGenerator.cs index fbfaaad5..2c04507b 100644 --- a/MetadataGenerator/Generation/AssemblyGenerator.cs +++ b/MetadataGenerator/Generation/AssemblyGenerator.cs @@ -1,4 +1,5 @@ -using MetadataGenerator.Generation.Types; +using MetadataGenerator.Generation.CustomAttributes; +using MetadataGenerator.Generation.Types; using Model; using SR = System.Reflection; @@ -10,9 +11,10 @@ public static MetadataContainer Generate(Assembly assembly) { var metadataContainer = new MetadataContainer(assembly); var metadataBuilder = metadataContainer.MetadataBuilder; + var customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); // Assembly Table (0x20) - metadataBuilder.AddAssembly( + var assemblyDefinitionHandle = metadataBuilder.AddAssembly( name: metadataBuilder.GetOrAddString(assembly.Name), version: assembly.Version, culture: metadataBuilder.GetOrAddString(assembly.Culture), @@ -21,8 +23,13 @@ public static MetadataContainer Generate(Assembly assembly) hashAlgorithm: SR.AssemblyHashAlgorithm.Sha1 ); + foreach (var customAttribute in assembly.Attributes) + { + customAttributeGenerator.Generate(assemblyDefinitionHandle, customAttribute); + } + new ModuleGenerator(metadataContainer).Generate(assembly); - new NamespaceGenerator(metadataContainer).Generate(assembly.RootNamespace); + new NamespaceGenerator(metadataContainer, customAttributeGenerator).Generate(assembly.RootNamespace); // Some tables must be sorted by one or more of their columns. Since the dll's methods and types don't follow a // particular order, the info needed to load this tables is stored during type/method generation but not added to the diff --git a/MetadataGenerator/Generation/NamespaceGenerator.cs b/MetadataGenerator/Generation/NamespaceGenerator.cs index 7a5be059..feea028f 100644 --- a/MetadataGenerator/Generation/NamespaceGenerator.cs +++ b/MetadataGenerator/Generation/NamespaceGenerator.cs @@ -1,4 +1,5 @@ using System.Linq; +using MetadataGenerator.Generation.CustomAttributes; using MetadataGenerator.Generation.Types; using Model; using Model.Types; @@ -12,10 +13,10 @@ internal class NamespaceGenerator private readonly MetadataContainer metadataContainer; private readonly TypeGenerator typeGenerator; - public NamespaceGenerator(MetadataContainer metadataContainer) + public NamespaceGenerator(MetadataContainer metadataContainer, CustomAttributeGenerator customAttributeGenerator) { this.metadataContainer = metadataContainer; - typeGenerator = new TypeGenerator(metadataContainer); + typeGenerator = new TypeGenerator(metadataContainer, customAttributeGenerator); } public void Generate(Namespace namezpace) diff --git a/MetadataGenerator/Generation/Types/TypeGenerator.cs b/MetadataGenerator/Generation/Types/TypeGenerator.cs index 1798fc33..058fafa5 100644 --- a/MetadataGenerator/Generation/Types/TypeGenerator.cs +++ b/MetadataGenerator/Generation/Types/TypeGenerator.cs @@ -22,10 +22,10 @@ internal class TypeGenerator private readonly FieldGenerator fieldGenerator; private readonly PropertyGenerator propertyGenerator; - public TypeGenerator(MetadataContainer metadataContainer) + public TypeGenerator(MetadataContainer metadataContainer, CustomAttributeGenerator customAttributeGenerator) { this.metadataContainer = metadataContainer; - customAttributeGenerator = new CustomAttributeGenerator(metadataContainer); + this.customAttributeGenerator = customAttributeGenerator; methodGenerator = new MethodGenerator(metadataContainer, customAttributeGenerator); fieldGenerator = new FieldGenerator(metadataContainer, customAttributeGenerator); propertyGenerator = new PropertyGenerator(metadataContainer, customAttributeGenerator);