private void PerformStaticAllocationOf(Context allocation, Context assignment) { MosaType allocatedType = (allocation.InvokeMethod != null) ? allocation.InvokeMethod.DeclaringType : allocation.Result.Type; MosaField assignmentField = (assignment.Instruction is DupInstruction) ? FindStsfldForDup(assignment).MosaField : assignment.MosaField; // Get size of type int typeSize = TypeLayout.GetTypeSize(allocatedType); // If instruction is newarr then get the size of the element, multiply it by array size, and add array header size // Also need to align to a 4-byte boundry if (allocation.Instruction is NewarrInstruction) { typeSize = (TypeLayout.GetTypeSize(allocatedType.ElementType) * (int)allocation.Previous.Operand1.ConstantSignedLongInteger) + (TypeLayout.NativePointerSize * 3); } // Allocate a linker symbol to refer to this allocation. Use the destination field name as the linker symbol name. var symbolName = MethodCompiler.Linker.CreateSymbol(assignmentField.FullName + @"<<$cctor", SectionKind.ROData, Architecture.NativeAlignment, typeSize); // Try to get typeDefinitionSymbol if allocatedType isn't a value type string typeDefinitionSymbol = GetTypeDefinition(allocatedType); if (typeDefinitionSymbol != null) { MethodCompiler.Linker.Link(LinkType.AbsoluteAddress, BuiltInPatch.I4, symbolName, 0, 0, typeDefinitionSymbol, SectionKind.ROData, 0); } // Issue a load request before the newobj and before the assignment. Operand symbol1 = InsertLoadBeforeInstruction(assignment, symbolName.Name, assignmentField.FieldType); assignment.Operand1 = symbol1; // If the instruction is a newarr and the assignment instruction is a dup then we want to remove it if (allocation.Instruction is NewarrInstruction && assignment.Instruction is DupInstruction) { assignment.SetInstruction(CILInstruction.Get(OpCode.Ldc_i4), assignment.Result, assignment.Operand1); } // Change the newobj to a call and increase the operand count to include the this ptr. // If the instruction is a newarr, then just replace with a nop instead allocation.ResultCount = 0; if (allocation.Instruction is NewarrInstruction) { allocation.OperandCount = 0; allocation.SetInstruction(CILInstruction.Get(OpCode.Nop)); } else { Operand symbol2 = InsertLoadBeforeInstruction(allocation, symbolName.Name, assignmentField.FieldType); IEnumerable <Operand> ops = allocation.Operands; allocation.OperandCount++; allocation.Operand1 = symbol2; int i = 0; foreach (Operand op in ops) { i++; allocation.SetOperand(i, op); } allocation.ReplaceInstructionOnly(CILInstruction.Get(OpCode.Call)); } }
protected sealed override void GetPackSizeAndSize(out int packSize, out int size) { TypeLayout layout = TypeDefinition.GetLayout(); packSize = layout.PackingSize; size = layout.Size; }
private void CallVirtual(InstructionNode node) { var call = node.Operand1; var method = call.Method; if (TypeLayout.IsMethodOverridden(method)) { return; } if (!method.HasImplementation && method.IsAbstract) { return; } var symbol = Operand.CreateSymbolFromMethod(method, TypeSystem); var operands = node.GetOperands(); operands.RemoveAt(0); trace?.Log($"De-virtualize: {method}"); DevirtualizedCount++; node.SetInstruction(IRInstruction.CallStatic, node.Result, symbol, operands); MethodScanner.MethodInvoked(method, Method); }
private void CalculateMethodParameterSize() { // Check if already computed if (MethodData.ParameterStackSize != 0) { return; } int stacksize = 0; MethodData.ParameterSizes = new List <int>(Method.Signature.Parameters.Count); MethodData.ParameterOffsets = new List <int>(Method.Signature.Parameters.Count); if (Method.HasThis) { stacksize = TypeLayout.NativePointerSize; } foreach (var parameter in Method.Signature.Parameters) { var size = parameter.ParameterType.IsValueType ? TypeLayout.GetTypeSize(parameter.ParameterType) : TypeLayout.NativePointerAlignment; MethodData.ParameterSizes.Add(size); MethodData.ParameterOffsets.Add(stacksize); stacksize += Alignment.AlignUp(size, TypeLayout.NativePointerAlignment); } MethodData.ParameterStackSize = stacksize; }
protected override void RunPostCompile() { foreach (var type in TypeSystem.AllTypes) { foreach (var field in type.Fields) { if (!field.IsStatic) { continue; } if (!Compiler.MethodScanner.IsFieldAccessed(field)) { continue; } var section = field.Data != null ? SectionKind.ROData : SectionKind.BSS; int size = TypeLayout.GetFieldSize(field); var symbol = Compiler.Linker.DefineSymbol(field.FullName, section, Architecture.NativeAlignment, size); if (field.Data != null) { symbol.Stream.Write(field.Data, 0, size); } } } }
public void PrintStructMultipleByteWrappersLayout() { AssertNonRecursiveWithPadding <StructMultipleByteWrappers>(); // If the layout is sequential, then structs are aligned properly with no paddings TypeLayout.PrintLayout <StructMultipleByteWrappers>(); }
static void Main(string[] args) { TypeLayout.PrintLayout <Struct1>(); TypeLayout.PrintLayout <Struct2>(); TypeLayout.PrintLayout <Struct3>(); TypeLayout.PrintLayout <Struct4>(); }
private void ScheduleMethods(MosaType type) { var currentType = type; var slots = new bool[TypeLayout.GetMethodTable(type).Count]; while (currentType != null) { foreach (var method in currentType.Methods) { bool contains; lock (invokedMethods) { contains = invokedMethods.Contains(method); } if (contains) { int slot = TypeLayout.GetMethodSlot(method); if (slots[slot]) { continue; } slots[slot] = true; ScheduleMethod(method); } } currentType = currentType.BaseType; // EXPLORE: base types may not need to be considered } }
private void CallVirtual(InstructionNode node) { var call = node.Operand1; var method = call.Method; if (TypeLayout.IsMethodOverridden(method)) { return; } var symbol = Operand.CreateSymbolFromMethod(method, TypeSystem); var operands = node.GetOperands(); operands.RemoveAt(0); if (trace.Active) { trace.Log("De-virtualize: " + method); } DevirtualizedCount++; node.SetInstruction(IRInstruction.CallStatic, node.Result, symbol, operands); }
private void ScheduleInterfaces(MosaType type) { if (type.Interfaces.Count == 0) { return; } // find all interfaces methods for this type foreach (var itype in type.Interfaces) { if (!invokedInteraceTypes.Contains(itype)) { continue; } var imethods = TypeLayout.GetInterfaceTable(type, itype); var list = interfaceSlots.Get(itype); foreach (var slot in list) { var imethod = imethods[slot]; ScheduleMethod(imethod); } } }
public void UnsafeStructHasEmptyPaddings() { AssertNonRecursiveWithPadding <WithNestedUnsafeStruct>(); var typeLayout = TypeLayout.GetLayout <WithNestedUnsafeStruct>(includePaddings: true); Assert.That(typeLayout.Paddings, Is.EqualTo(0)); }
public void PrintClassMultipleByteWrappersLayout() { AssertNonRecursiveWithPadding <Slot <long> >(); // In this case every field aligned on the pointer boundaries TypeLayout.PrintLayout <Slot <long> >(); //Assert.That(TypeLayout.GetLayout<Slot>().Size, Is.EqualTo(24)); }
private void PerformStaticAllocation(InstructionNode node) { var allocatedType = node.MosaType; // node.Result.Type; //Debug.WriteLine($"Method: {Method} : {node}"); //Debug.WriteLine($" --> {allocatedType}"); MethodScanner.TypeAllocated(allocatedType, Method); int allocationSize; if (node.Instruction == IRInstruction.NewObject) { allocationSize = TypeLayout.GetTypeSize(allocatedType); } else { var elements = (int)GetConstant(node.Operand3); allocationSize = (TypeLayout.GetTypeSize(allocatedType.ElementType) * elements) + (TypeLayout.NativePointerSize * 3); } var symbolName = Linker.DefineSymbol(StaticSymbolPrefix + allocatedType.FullName, SectionKind.BSS, Architecture.NativeAlignment, allocationSize); string typeDefinitionSymbol = Metadata.TypeDefinition + allocatedType.FullName; Linker.Link(LinkType.AbsoluteAddress, Is32BitPlatform ? PatchType.I32 : PatchType.I64, symbolName, 0, typeDefinitionSymbol, 0); var staticAddress = Operand.CreateSymbol(allocatedType, symbolName.Name); var move = Is32BitPlatform ? (BaseInstruction)IRInstruction.Move32 : IRInstruction.Move64; node.SetInstruction(move, node.Result, staticAddress); }
//[Test] public void GetLayoutsForAllTypes() { //var xx = new SizeComputer<RSAOAEPKeyExchangeDeformatter>(); var cache = TypeLayoutCache.Create(); var layouts = GetAllLoadedTypes() //.Where(t => t.Assembly.FullName.Contains("mscorlib")) .Select(t => TypeLayout.TryGetLayout(t, cache)) .Where(t => t != null) .Select(t => t.Value) .ToList(); var top10BiggestInstances = layouts.OrderByDescending(l => l.Size).Take(20); var top10WithBiggestPaddings = layouts.OrderByDescending(l => l.Paddings).Take(20); Console.WriteLine("Top 10 biggest types:"); foreach (var t in top10BiggestInstances) { Console.WriteLine(t); } Console.WriteLine(); Console.WriteLine("Top 10 types with biggest paddings:"); foreach (var t in top10WithBiggestPaddings) { Console.WriteLine(t); } }
/// <summary> /// Lays out all parameters of the method. /// </summary> private void LayoutParameters() { var parameters = new List <Operand>(); int offset = 0; if (MethodCompiler.Method.HasThis || MethodCompiler.Method.HasExplicitThis) { ++offset; } for (int i = 0; i < MethodCompiler.Method.Signature.Parameters.Count + offset; ++i) { var parameter = MethodCompiler.GetParameterOperand(i); parameters.Add(parameter); } int returnSize = 0; if (TypeLayout.IsCompoundType(MethodCompiler.Method.Signature.ReturnType)) { returnSize = TypeLayout.GetTypeSize(MethodCompiler.Method.Signature.ReturnType); } int size = LayoutVariables(parameters, CallingConvention, CallingConvention.OffsetOfFirstParameter + returnSize, false); MethodCompiler.StackLayout.StackParameterSize = size; MethodCompiler.TypeLayout.SetMethodParameterStackSize(MethodCompiler.Method, size); }
/////////////////////////////////////////////////////////////////////// // Listings 13-79, 13-81 static void Main(string[] args) { Console.WriteLine(sizeof(Test1)); Console.WriteLine(sizeof(Test2)); //Console.WriteLine(sizeof(Test1o)); //Console.WriteLine(sizeof(Test2o)); Console.WriteLine(Unsafe.SizeOf <Test3>()); Console.WriteLine(Unsafe.SizeOf <Test4>()); TypeLayout.PrintLayout <SomeClass>(); TypeLayout layout = TypeLayout.GetLayout <AlignedDouble>(); Console.WriteLine($"Total size {layout.FullSize}B with {layout.Paddings}B padding."); foreach (var fieldBase in layout.Fields) { switch (fieldBase) { case FieldLayout field: Console.WriteLine($"{field.Offset} {field.Size} {field.FieldInfo.Name}"); break; case Padding padding: Console.WriteLine($"{padding.Offset} {padding.Size} Padding"); break; } } //TypeLayout.PrintLayout<UnalignedDoubleExplicit>(); //var o = new AlignedDouble(); //Console.ReadLine(); //GC.KeepAlive(o); Console.ReadLine(); }
public void Print_NotAlignedClass() { TypeLayout.PrintLayout <model>(); model u = new model(); u.FunC(); }
protected override void Setup() { foreach (var type in TypeSystem.AllTypes) { // If type has an interface - don't consider either type for de-virtualization // FUTURE: be more specific and check each method if (HasInterface(type)) { continue; } foreach (var method in type.Methods) { if (method.IsStatic || !method.IsVirtual) { continue; } if (!method.HasImplementation && method.IsAbstract) { continue; } if (TypeLayout.IsMethodOverridden(method)) { continue; } var methodData = Compiler.GetMethodData(method); methodData.IsDevirtualized = true; DevirtualizedMethodsCount++; } } }
private LinkerSymbol CreateInterfaceMethodTable(MosaType type, MosaType interfaceType) { // Emit interface method table var interfaceMethodTableSymbol = Linker.DefineSymbol(Metadata.InterfaceMethodTable + type.FullName + "$" + interfaceType.FullName, SectionKind.ROData, TypeLayout.NativePointerAlignment, 0); var writer = new EndianAwareBinaryWriter(interfaceMethodTableSymbol.Stream, Architecture.Endianness); var interfaceMethodTable = TypeLayout.GetInterfaceTable(type, interfaceType) ?? new MosaMethod[0]; // 1. Number of Interface Methods writer.Write((uint)interfaceMethodTable.Length, TypeLayout.NativePointerSize); // 2. Pointer to Interface Type Linker.Link(LinkType.AbsoluteAddress, NativePatchType, interfaceMethodTableSymbol, writer.Position, Metadata.TypeDefinition + interfaceType.FullName, 0); writer.WriteZeroBytes(TypeLayout.NativePointerSize); // 3. Pointers to Method Definitions foreach (var method in interfaceMethodTable) { // Create definition and get the symbol var methodDefinitionSymbol = CreateMethodDefinition(method); Linker.Link(LinkType.AbsoluteAddress, NativePatchType, interfaceMethodTableSymbol, writer.Position, methodDefinitionSymbol, 0); writer.WriteZeroBytes(TypeLayout.NativePointerSize); } return(interfaceMethodTableSymbol); }
private void EmitTypes() { writer.WriteLine("[Types]"); writer.WriteLine("TypeID\tTypeDef\tSize\tFullName\tBaseTypeID\tDeclaringTypeID\tElementTypeID"); foreach (var type in TypeSystem.AllTypes) { if (type.IsModule) { continue; } //if (!Linker.IsSymbolDefined(type.FullName)) // continue; writer.WriteLine( "{0}\t{1:x8}\t{2}\t{3}\t{4}\t{5}\t{6}", type.ID, Linker.GetSymbol(type.FullName).VirtualAddress, TypeLayout.GetTypeSize(type), type.FullName, (type.BaseType != null) ? type.BaseType.ID : 0, (type.DeclaringType != null) ? type.DeclaringType.ID : 0, (type.ElementType != null) ? type.ElementType.ID : 0 ); } }
public void Nullable() { TypeLayout.PrintLayout <Nullable <bool> >(); var typeLayout = TypeLayout.GetLayout <Nullable <bool> >(includePaddings: true); Assert.AreEqual(Unsafe.SizeOf <Nullable <bool> >(), typeLayout.Size); }
private void PerformStaticAllocationOf(InstructionNode allocation, InstructionNode assignment) { var allocatedType = (allocation.InvokeMethod != null) ? allocation.InvokeMethod.DeclaringType : allocation.Result.Type; var assignmentField = assignment.MosaField; // Get size of type int typeSize = TypeLayout.GetTypeSize(allocatedType); // If instruction is newarr then get the size of the element, multiply it by array size, and add array header size // Also need to align to a 4-byte boundary if (allocation.Instruction is CIL.NewarrInstruction) { int elements = GetConstant(allocation.Operand1); typeSize = (TypeLayout.GetTypeSize(allocatedType.ElementType) * elements) + (TypeLayout.NativePointerSize * 3); } // Allocate a linker symbol to refer to this allocation. Use the destination field name as the linker symbol name. var symbolName = MethodCompiler.Linker.CreateSymbol(assignmentField.FullName + "<<$cctor", SectionKind.ROData, Architecture.NativeAlignment, typeSize); // Try to get typeDefinitionSymbol if allocatedType isn't a value type string typeDefinitionSymbol = GetTypeDefinition(allocatedType); if (typeDefinitionSymbol != null) { MethodCompiler.Linker.Link(LinkType.AbsoluteAddress, PatchType.I4, symbolName, 0, SectionKind.ROData, typeDefinitionSymbol, 0); } var staticAddress = Operand.CreateSymbol(assignmentField.FieldType, symbolName.Name); var result1 = AllocateVirtualRegister(assignmentField.FieldType); //Operand result2 = AllocateVirtualRegister(assignmentField.FieldType); // Issue a load request before the newobj and before the assignment. new Context(allocation).InsertBefore().SetInstruction(CILInstruction.Get(OpCode.Ldc_i4), result1, staticAddress); assignment.Operand1 = result1; // If the instruction is a newarr if (allocation.Instruction is CIL.NewarrInstruction) { allocation.SetInstruction(CILInstruction.Get(OpCode.Ldc_i4), allocation.Result, result1); return; } //new Context(allocation).InsertBefore().SetInstruction(CILInstruction.Get(OpCode.Ldc_i4), result2, staticAddress); // Change the newobj to a call and increase the operand count to include the this ptr. // If the instruction is a newarr, then just replace with a nop instead allocation.Result = null; allocation.ResultCount = 0; allocation.OperandCount++; for (int i = allocation.OperandCount; i > 0; i--) { var op = allocation.GetOperand(i - 1); allocation.SetOperand(i, op); } allocation.Operand1 = result1; allocation.Instruction = CILInstruction.Get(OpCode.Call); }
public void PrivateMemoryLayout() { TypeLayout.PrintLayout <PrivateMemory <long> >(recursively: false); TypeLayout.PrintLayout <PrivateMemory <byte> >(recursively: false); TypeLayout.PrintLayout <PrivateMemory <object> >(recursively: false); var layout = TypeLayout.GetLayout <PrivateMemory <long> >(); }
void AssertSize <T>(int expectedSize) { Assert.Equal(expectedSize, Unsafe.SizeOf <T>()); Assert.Equal(expectedSize, Marshal.SizeOf <T>()); var layout = TypeLayout.GetLayout <T>(); // check that fields are aligned foreach (var field in layout.Fields) { if ($"{field}".Contains("padding")) { continue; } Assert.True(field.Offset % field.Size == 0, $"Field {field} is not aligned"); } // check that fields don't overlap var minOffset = 0; foreach (var field in layout.Fields) { Assert.True(field.Offset >= minOffset, $"Field {field.Offset} overlaps"); minOffset = field.Offset + field.Size; } // note that we aren't checking whether fields are efficiently arranged... // also not currently checking if the whole struct is correctly aligned, only the fields within. }
private void ScheduleDerivedMethods(MosaType type, int slot) { var children = TypeLayout.GetDerivedTypes(type); if (children == null) { return; } foreach (var derived in children) { bool contains; lock (allocatedTypes) { contains = allocatedTypes.Contains(derived); } if (contains) { var derivedMethod = TypeLayout.GetMethodBySlot(derived, slot); MarkMethodInvoked(derivedMethod); ScheduleMethod(derivedMethod); } ScheduleDerivedMethods(derived, slot); } }
private void CompoundLoad(Context context) { var type = context.Result.Type; int typeSize = TypeLayout.GetTypeSize(type); int alignedTypeSize = typeSize - (typeSize % NativeAlignment); int largeAlignedTypeSize = typeSize - (typeSize % LargeAlignment); Debug.Assert(typeSize > 0, context.Operand2.Name); int offset = 0; if (context.Operand2.IsConstant) { offset = (int)context.Operand2.ConstantSignedLongInteger; } var offsetop = context.Operand2; var src = context.Operand1; var dest = context.Result; Debug.Assert(dest.IsMemoryAddress, dest.Name); var srcReg = MethodCompiler.CreateVirtualRegister(dest.Type.TypeSystem.BuiltIn.I4); var dstReg = MethodCompiler.CreateVirtualRegister(dest.Type.TypeSystem.BuiltIn.I4); var tmp = MethodCompiler.CreateVirtualRegister(dest.Type.TypeSystem.BuiltIn.I4); var tmpLarge = Operand.CreateCPURegister(MethodCompiler.TypeSystem.BuiltIn.Void, SSE2Register.XMM1); context.SetInstruction(X86.Nop); context.AppendInstruction(X86.Mov, srcReg, src); context.AppendInstruction(X86.Lea, dstReg, dest); if (!offsetop.IsConstant) { context.AppendInstruction(X86.Add, srcReg, srcReg, offsetop); } for (int i = 0; i < largeAlignedTypeSize; i += LargeAlignment) { // Large Aligned moves allow 128bits to be copied at a time var index = Operand.CreateConstant(TypeSystem.BuiltIn.I4, i); var offset2 = Operand.CreateConstant(TypeSystem.BuiltIn.I4, i + offset); context.AppendInstruction(X86.MovupsLoad, tmpLarge, srcReg, index); context.AppendInstruction(X86.MovupsStore, null, dstReg, index, tmpLarge); } for (int i = largeAlignedTypeSize; i < alignedTypeSize; i += NativeAlignment) { var index = Operand.CreateConstant(TypeSystem.BuiltIn.I4, i); var offset2 = Operand.CreateConstant(TypeSystem.BuiltIn.I4, i + offset); context.AppendInstruction(X86.MovLoad, InstructionSize.Size32, tmp, srcReg, offset2); context.AppendInstruction(X86.MovStore, InstructionSize.Size32, null, dstReg, index, tmp); } for (int i = alignedTypeSize; i < typeSize; i++) { var index = Operand.CreateConstant(TypeSystem.BuiltIn.I4, i); var offset2 = Operand.CreateConstant(TypeSystem.BuiltIn.I4, i + offset); context.AppendInstruction(X86.MovzxLoad, InstructionSize.Size8, tmp, srcReg, offset2); context.AppendInstruction(X86.MovStore, InstructionSize.Size8, null, dstReg, index, tmp); } }
public void NullableLongByteStruct() { TypeLayout.PrintLayout <Nullable <LongByteStruct> >(); var typeLayout = TypeLayout.GetLayout <Nullable <LongByteStruct> >(includePaddings: true); var size = Unsafe.SizeOf <Nullable <LongByteStruct> >(); Assert.AreEqual(typeLayout.Size, size); }
public void LayoutForInstanceWithStringShouldNotCrash() { // I know, I know. This is bad to name tests like this. But this is life:) var layout = TypeLayout.GetLayout <WithString>(); Assert.That(layout.Fields.Length, Is.EqualTo(1)); Assert.That(layout.Paddings, Is.EqualTo(0)); }
public void CorePoolsLayout() { TypeLayout.PrintLayout <MPMCPoolCore <DummyPoolable> >(); TypeLayout.PrintLayout <ObjectPoolCore <DummyPoolable> >(); TypeLayout.PrintLayout <LockedObjectPoolCore <DummyPoolable> >(); TypeLayout.PrintLayout <ObjectPool <DummyPoolable> .RightPaddedObjectPoolCore>(); TypeLayout.PrintLayout <LockedObjectPool <DummyPoolable> .RightPaddedLockedObjectPoolCore>(); }
public void UnsafeStructRecursive() { TypeLayout.PrintLayout <WithNestedUnsafeStruct>(); var structLayout = UnsafeLayout.GetLayout <WithNestedUnsafeStruct>(); Assert.AreEqual(1, structLayout.Count()); Assert.AreEqual(0, structLayout[0].Offset); Assert.AreEqual(33, structLayout[0].Size); }
public CilTypeLayout(TypeLayout layout) { _layout = layout; }
// StructLayoutAttribute public void SetStructLayout(TypeLayout layout, CharSet charSet) { VerifySealed(expected: false); Debug.Assert(charSet == CharSet.Ansi || charSet == CharSet.Unicode || charSet == Cci.Constants.CharSet_Auto); _layout = layout; _charSet = charSet; SetDataStored(); }
public TypeInteropAnnotation(TypeLayout layout, StringFormat stringFormat, bool isSerializable) { Layout = layout; StringFormat = stringFormat; IsSerializable = isSerializable; }