Коммит
4135dc55b4
|
@ -48,6 +48,15 @@ namespace System.Collections.Generic
|
|||
_count += length;
|
||||
}
|
||||
|
||||
public void Append(ArrayBuilder<T> newItems)
|
||||
{
|
||||
if (newItems.Count == 0)
|
||||
return;
|
||||
EnsureCapacity(_count + newItems.Count);
|
||||
Array.Copy(newItems._items, 0, _items, _count, newItems.Count);
|
||||
_count += newItems.Count;
|
||||
}
|
||||
|
||||
public void ZeroExtend(int numItems)
|
||||
{
|
||||
Debug.Assert(numItems >= 0);
|
||||
|
|
|
@ -0,0 +1,778 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Internal.Text;
|
||||
|
||||
using BlobBuilder = System.Reflection.Metadata.BlobBuilder;
|
||||
using Blob = System.Reflection.Metadata.Blob;
|
||||
|
||||
namespace Internal.TypeSystem.TypesDebugInfo
|
||||
{
|
||||
class DebugInfoBlob
|
||||
{
|
||||
ArrayBuilder<byte> _data;
|
||||
|
||||
public byte[] ToArray() => _data.ToArray();
|
||||
|
||||
public uint Size() { return (uint)_data.Count; }
|
||||
|
||||
public uint DWORDAlignedSize(uint size)
|
||||
{
|
||||
checked
|
||||
{
|
||||
if ((size + Size()) % 4 != 0)
|
||||
{
|
||||
size = size + 4 - ((size + Size()) % 4);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void AlignToDWORD()
|
||||
{
|
||||
if ((Size() % 4) != 0)
|
||||
{
|
||||
uint pad = 4 - (Size() % 4);
|
||||
for (uint i = pad; i > 0; i--)
|
||||
{
|
||||
WriteBYTE((byte)(0xF0 | i)); // Insert LF_PADX entries.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetWORDAtBlobIndex(uint blobIndex, ushort src)
|
||||
{
|
||||
_data[(int)blobIndex] = (byte)src;
|
||||
_data[(int)blobIndex + 1] = (byte)(src >> 8);
|
||||
}
|
||||
|
||||
public void SetDWORDAtBlobIndex(uint blobIndex, uint src)
|
||||
{
|
||||
_data[(int)blobIndex] = (byte)src;
|
||||
_data[(int)blobIndex + 1] = (byte)(src >> 8);
|
||||
_data[(int)blobIndex + 2] = (byte)(src >> 16);
|
||||
_data[(int)blobIndex + 3] = (byte)(src >> 24);
|
||||
}
|
||||
|
||||
public void WriteBYTE(byte src)
|
||||
{
|
||||
_data.Add(src);
|
||||
}
|
||||
|
||||
public void WriteWORD(ushort src)
|
||||
{
|
||||
_data.Add((byte)src);
|
||||
_data.Add((byte)(src >> 8));
|
||||
}
|
||||
|
||||
public void WriteDWORD(uint src)
|
||||
{
|
||||
_data.Add((byte)src);
|
||||
_data.Add((byte)(src >> 8));
|
||||
_data.Add((byte)(src >> 16));
|
||||
_data.Add((byte)(src >> 24));
|
||||
}
|
||||
|
||||
public void WriteString(Utf8String utf8String)
|
||||
{
|
||||
_data.Append(utf8String.UnderlyingArray);
|
||||
_data.Add(0);
|
||||
}
|
||||
|
||||
public void WriteString(string str)
|
||||
{
|
||||
WriteString(new Utf8String(str));
|
||||
}
|
||||
|
||||
public void WriteBuffer(byte[] data)
|
||||
{
|
||||
_data.Append(data);
|
||||
}
|
||||
|
||||
public void WriteBuffer(DebugInfoBlob debugInfoBlob)
|
||||
{
|
||||
_data.Append(debugInfoBlob._data);
|
||||
}
|
||||
|
||||
public void WriteBuffer(BlobBuilder blobBuilder)
|
||||
{
|
||||
foreach (Blob blob in blobBuilder.GetBlobs())
|
||||
{
|
||||
ArraySegment<byte> byteChunk = blob.GetBytes();
|
||||
this.WriteBuffer(byteChunk.Array, byteChunk.Offset, byteChunk.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteBuffer(byte[] data, int index, int length)
|
||||
{
|
||||
_data.Append(data, index, length);
|
||||
}
|
||||
|
||||
public void WriteQWORD(ulong src)
|
||||
{
|
||||
_data.Add((byte)src);
|
||||
_data.Add((byte)(src >> 8));
|
||||
_data.Add((byte)(src >> 16));
|
||||
_data.Add((byte)(src >> 24));
|
||||
_data.Add((byte)(src >> 32));
|
||||
_data.Add((byte)(src >> 40));
|
||||
_data.Add((byte)(src >> 48));
|
||||
_data.Add((byte)(src >> 56));
|
||||
}
|
||||
|
||||
public static uint StringLengthEncoded(Utf8String str)
|
||||
{
|
||||
return checked((uint)str.Length + 1);
|
||||
}
|
||||
}
|
||||
class DebugInfoWriter
|
||||
{
|
||||
enum LeafKind : ushort
|
||||
{
|
||||
// values used for type records
|
||||
LF_VTSHAPE = 0x000a,
|
||||
LF_POINTER = 0x1002,
|
||||
LF_PROCEDURE = 0x1008,
|
||||
LF_MFUNCTION = 0x1009,
|
||||
LF_ARGLIST = 0x1201,
|
||||
LF_FIELDLIST = 0x1203,
|
||||
LF_BCLASS = 0x1400,
|
||||
LF_INDEX = 0x1404,
|
||||
LF_VFUNCTAB = 0x1409,
|
||||
LF_ENUMERATE = 0x1502,
|
||||
LF_ARRAY = 0x1503,
|
||||
LF_CLASS = 0x1504,
|
||||
LF_STRUCTURE = 0x1505,
|
||||
LF_ENUM = 0x1507,
|
||||
LF_MEMBER = 0x150d,
|
||||
LF_STATICMEMBER = 0x150e,
|
||||
LF_MFUNC_ID = 0x1602, // member func ID
|
||||
|
||||
// values used for numeric leafs
|
||||
LF_CHAR = 0x8000,
|
||||
LF_SHORT = 0x8001,
|
||||
LF_LONG = 0x8003,
|
||||
LF_ULONG = 0x8004,
|
||||
LF_QUADWORD = 0x8009
|
||||
};
|
||||
|
||||
enum LF_CLASS_Properties : ushort
|
||||
{
|
||||
None = 0x0000,
|
||||
ForwardReference = 0x0080
|
||||
}
|
||||
|
||||
enum CV_Visibility : ushort
|
||||
{
|
||||
Private = 0x1,
|
||||
Protected = 0x2,
|
||||
Public = 0x3
|
||||
}
|
||||
|
||||
class TypeRecordsBlob : DebugInfoBlob
|
||||
{
|
||||
uint _currentTypeIndex = 0x1000;
|
||||
|
||||
public uint GetNextTypeIndex()
|
||||
{
|
||||
Debug.Assert((Size() % 4) == 0);
|
||||
return _currentTypeIndex++;
|
||||
}
|
||||
|
||||
public void WriteCV_Visibility(CV_Visibility src)
|
||||
{
|
||||
WriteWORD((ushort)src);
|
||||
}
|
||||
|
||||
public void WriteLeafKind(LeafKind src)
|
||||
{
|
||||
WriteWORD((ushort)src);
|
||||
}
|
||||
|
||||
public void WriteLF_CLASS_Properties(LF_CLASS_Properties src)
|
||||
{
|
||||
WriteWORD((ushort)src);
|
||||
}
|
||||
|
||||
public void WriteNumericLeaf(ulong value)
|
||||
{
|
||||
long signedValue = (long)value;
|
||||
if (signedValue < 0)
|
||||
{
|
||||
if (signedValue >= -0x80)
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_CHAR);
|
||||
WriteBYTE((byte)value);
|
||||
}
|
||||
else if (signedValue >= -0x8000)
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_SHORT);
|
||||
WriteWORD((ushort)value);
|
||||
}
|
||||
else if (signedValue >= -0x80000000)
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_LONG);
|
||||
WriteDWORD((uint)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_QUADWORD);
|
||||
WriteQWORD(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value < 0x8000)
|
||||
{
|
||||
WriteWORD((ushort)value);
|
||||
}
|
||||
else if (value <= 0x7FFFFFFF)
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_LONG);
|
||||
WriteDWORD((uint)value);
|
||||
}
|
||||
else if (value <= 0xFFFFFFFF)
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_ULONG);
|
||||
WriteDWORD((uint)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_QUADWORD);
|
||||
WriteQWORD(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteNumericLeaf(long value)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
if (value >= -0x80)
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_CHAR);
|
||||
WriteBYTE((byte)value);
|
||||
}
|
||||
else if (value >= -0x8000)
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_SHORT);
|
||||
WriteWORD((ushort)value);
|
||||
}
|
||||
else if (value >= -0x80000000)
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_LONG);
|
||||
WriteDWORD((uint)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_QUADWORD);
|
||||
WriteQWORD((ulong)value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value < 0x8000)
|
||||
{
|
||||
WriteWORD((ushort)value);
|
||||
}
|
||||
else if (value <= 0x7FFFFFFF)
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_LONG);
|
||||
WriteDWORD((uint)value);
|
||||
}
|
||||
else if (value <= 0xFFFFFFFF)
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_ULONG);
|
||||
WriteDWORD((uint)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLeafKind(LeafKind.LF_QUADWORD);
|
||||
WriteQWORD((ulong)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static uint NumericLeafSize(long value)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
if (value >= -0x80)
|
||||
return 2 + 1;
|
||||
else if (value >= -0x8000)
|
||||
return 2 + 2;
|
||||
else if (value >= -0x80000000L)
|
||||
return 2 + 4;
|
||||
else
|
||||
return 2 + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value < 0x8000)
|
||||
return 2;
|
||||
else if (value <= 0x7FFFFFFF || value <= 0xFFFFFFFF)
|
||||
return 2 + 4;
|
||||
else
|
||||
return 2 + 8;
|
||||
}
|
||||
}
|
||||
|
||||
public static uint NumericLeafSize(ulong value)
|
||||
{
|
||||
long signedValue = (long)value;
|
||||
if (signedValue < 0)
|
||||
{
|
||||
if (signedValue >= -0x80)
|
||||
return 2 + 1;
|
||||
else if (signedValue >= -0x8000)
|
||||
return 2 + 2;
|
||||
else if (signedValue >= -0x80000000L)
|
||||
return 2 + 4;
|
||||
else
|
||||
return 2 + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value < 0x8000)
|
||||
return 2;
|
||||
else if (value <= 0x7FFFFFFF || value <= 0xFFFFFFFF)
|
||||
return 2 + 4;
|
||||
else
|
||||
return 2 + 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TypeRecordsBlob _blob = new TypeRecordsBlob();
|
||||
uint _tiVTShapePointer;
|
||||
|
||||
public DebugInfoWriter()
|
||||
{
|
||||
// Write header
|
||||
_blob.WriteBYTE(0x04);
|
||||
_blob.WriteBYTE(0x00);
|
||||
_blob.WriteBYTE(0x00);
|
||||
_blob.WriteBYTE(0x00);
|
||||
|
||||
// Write out vtable shape pointer. Various other contents of this file will refer to it.
|
||||
_tiVTShapePointer = EmitVFuncTableShapeDebugType();
|
||||
}
|
||||
|
||||
private struct FieldListInProgress
|
||||
{
|
||||
public uint TypeIndexOfFieldList;
|
||||
public uint BlobOffsetCurrentFieldListChunk;
|
||||
public ushort FieldsCount;
|
||||
}
|
||||
|
||||
public void VerifyBlobEligibleToBeBetweenRecords()
|
||||
{
|
||||
Debug.Assert((_blob.Size() % 4) == 0);
|
||||
}
|
||||
|
||||
private FieldListInProgress StartFieldList()
|
||||
{
|
||||
Debug.Assert((_blob.Size() % 4) == 0);
|
||||
FieldListInProgress fieldListInProgress = new FieldListInProgress();
|
||||
fieldListInProgress.BlobOffsetCurrentFieldListChunk = _blob.Size();
|
||||
fieldListInProgress.TypeIndexOfFieldList = _blob.GetNextTypeIndex();
|
||||
fieldListInProgress.FieldsCount = 0;
|
||||
_blob.WriteWORD(0);
|
||||
_blob.WriteLeafKind(LeafKind.LF_FIELDLIST);
|
||||
|
||||
return fieldListInProgress;
|
||||
}
|
||||
|
||||
private void FinalizeFieldList(FieldListInProgress fieldListInProgress)
|
||||
{
|
||||
ushort length = checked((ushort)(_blob.Size() - fieldListInProgress.BlobOffsetCurrentFieldListChunk - 2));
|
||||
_blob.SetWORDAtBlobIndex(fieldListInProgress.BlobOffsetCurrentFieldListChunk, length);
|
||||
}
|
||||
|
||||
private void ExtendFieldList(ref FieldListInProgress fieldListInProgress, uint newDataLength, out bool mustSkipEmission)
|
||||
{
|
||||
checked
|
||||
{
|
||||
if (fieldListInProgress.FieldsCount == 0xFFFF)
|
||||
{
|
||||
mustSkipEmission = true;
|
||||
return;
|
||||
}
|
||||
|
||||
mustSkipEmission = false;
|
||||
|
||||
fieldListInProgress.FieldsCount++;
|
||||
if ((_blob.Size() + newDataLength + 11/* size of LF_INDEX + maximum possible padding*/ - fieldListInProgress.BlobOffsetCurrentFieldListChunk) > 0xFF00)
|
||||
{
|
||||
Debug.Assert((_blob.Size() % 4) == 0);
|
||||
|
||||
// Add LF_INDEX record to push forward
|
||||
_blob.WriteLeafKind(LeafKind.LF_INDEX);
|
||||
_blob.WriteWORD(0); // pad0
|
||||
uint newFieldListTypeIndex = _blob.GetNextTypeIndex();
|
||||
_blob.WriteDWORD(newFieldListTypeIndex);
|
||||
FinalizeFieldList(fieldListInProgress);
|
||||
|
||||
Debug.Assert((_blob.Size() % 4) == 0);
|
||||
fieldListInProgress.BlobOffsetCurrentFieldListChunk = _blob.Size();
|
||||
_blob.WriteWORD(0);
|
||||
_blob.WriteLeafKind(LeafKind.LF_FIELDLIST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitBaseClass(ref FieldListInProgress fieldListInProgress, uint baseClassIndex)
|
||||
{
|
||||
Debug.Assert((_blob.Size() % 4) == 0);
|
||||
bool mustSkipEmission;
|
||||
ExtendFieldList(ref fieldListInProgress, 8 + TypeRecordsBlob.NumericLeafSize(0), out mustSkipEmission);
|
||||
if (mustSkipEmission)
|
||||
return;
|
||||
|
||||
_blob.WriteLeafKind(LeafKind.LF_BCLASS);
|
||||
_blob.WriteCV_Visibility(CV_Visibility.Public);
|
||||
_blob.WriteDWORD(baseClassIndex);
|
||||
_blob.WriteNumericLeaf(0);
|
||||
_blob.AlignToDWORD();
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
}
|
||||
|
||||
private void EmitDataMember(ref FieldListInProgress fieldListInProgress, uint type, int offset, Utf8String name)
|
||||
{
|
||||
Debug.Assert((_blob.Size() % 4) == 0);
|
||||
|
||||
bool isStaticField = (uint)offset == 0xFFFFFFFF;
|
||||
|
||||
bool mustSkipEmission;
|
||||
uint recordSize = 8 + (isStaticField ? 0 : TypeRecordsBlob.NumericLeafSize(offset)) + DebugInfoBlob.StringLengthEncoded(name);
|
||||
ExtendFieldList(ref fieldListInProgress, recordSize, out mustSkipEmission);
|
||||
if (mustSkipEmission)
|
||||
return;
|
||||
|
||||
_blob.WriteLeafKind(isStaticField ? LeafKind.LF_STATICMEMBER : LeafKind.LF_MEMBER);
|
||||
_blob.WriteCV_Visibility(CV_Visibility.Public);
|
||||
_blob.WriteDWORD(type);
|
||||
|
||||
if (!isStaticField)
|
||||
_blob.WriteNumericLeaf(offset);
|
||||
|
||||
_blob.WriteString(name);
|
||||
_blob.AlignToDWORD();
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
}
|
||||
|
||||
|
||||
private void EmitEnumerate(ref FieldListInProgress fieldListInProgress, ulong value, Utf8String name)
|
||||
{
|
||||
Debug.Assert((_blob.Size() % 4) == 0);
|
||||
bool mustSkipEmission;
|
||||
uint recordSize = 4 + TypeRecordsBlob.NumericLeafSize(value) + DebugInfoBlob.StringLengthEncoded(name);
|
||||
ExtendFieldList(ref fieldListInProgress, recordSize, out mustSkipEmission);
|
||||
if (mustSkipEmission)
|
||||
return;
|
||||
|
||||
_blob.WriteLeafKind(LeafKind.LF_ENUMERATE);
|
||||
_blob.WriteCV_Visibility(CV_Visibility.Public);
|
||||
_blob.WriteNumericLeaf(value);
|
||||
_blob.WriteString(name);
|
||||
_blob.AlignToDWORD();
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
}
|
||||
|
||||
private uint EmitVFuncTableShapeDebugType()
|
||||
{
|
||||
Debug.Assert((_blob.Size() % 4) == 0);
|
||||
uint vFuncTableShapeTypeIndex = _blob.GetNextTypeIndex();
|
||||
uint recordSize = 10;
|
||||
_blob.WriteWORD((ushort)(_blob.DWORDAlignedSize(recordSize) - 2));
|
||||
_blob.WriteLeafKind(LeafKind.LF_VTSHAPE);
|
||||
_blob.WriteWORD(0);
|
||||
_blob.WriteDWORD(0);
|
||||
_blob.AlignToDWORD();
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
return vFuncTableShapeTypeIndex;
|
||||
}
|
||||
|
||||
private void EmitVFuncTab(ref FieldListInProgress fieldListInProgress)
|
||||
{
|
||||
Debug.Assert((_blob.Size() % 4) == 0);
|
||||
bool mustSkipEmission;
|
||||
uint recordSize = 8;
|
||||
ExtendFieldList(ref fieldListInProgress, recordSize, out mustSkipEmission);
|
||||
if (mustSkipEmission)
|
||||
return;
|
||||
|
||||
_blob.WriteLeafKind(LeafKind.LF_VFUNCTAB);
|
||||
_blob.WriteWORD(0);
|
||||
_blob.WriteDWORD(_tiVTShapePointer);
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
}
|
||||
|
||||
public uint GetClassTypeIndex(ClassTypeDescriptor classTypeDescriptor)
|
||||
{
|
||||
FieldListInProgress fieldList = default(FieldListInProgress);
|
||||
if (classTypeDescriptor.BaseClassId != 0)
|
||||
{
|
||||
fieldList = StartFieldList();
|
||||
EmitBaseClass(ref fieldList, classTypeDescriptor.BaseClassId);
|
||||
FinalizeFieldList(fieldList);
|
||||
}
|
||||
|
||||
uint classTypeIndex = _blob.GetNextTypeIndex();
|
||||
Utf8String name = new Utf8String(classTypeDescriptor.Name);
|
||||
uint recordSize = 20 + DebugInfoBlob.StringLengthEncoded(name) + TypeRecordsBlob.NumericLeafSize(0) /*size of length */;
|
||||
_blob.WriteWORD(checked((ushort)(_blob.DWORDAlignedSize(recordSize) - 2))); // don't include size of 'length' in 'length'
|
||||
_blob.WriteLeafKind(classTypeDescriptor.IsStruct != 0 ? LeafKind.LF_STRUCTURE : LeafKind.LF_CLASS);
|
||||
_blob.WriteWORD(fieldList.FieldsCount);
|
||||
_blob.WriteLF_CLASS_Properties(LF_CLASS_Properties.ForwardReference);
|
||||
_blob.WriteDWORD(fieldList.TypeIndexOfFieldList);
|
||||
_blob.WriteDWORD(0); // Derivation list is not filled in here
|
||||
_blob.WriteDWORD(0); // No vtable shape
|
||||
_blob.WriteNumericLeaf(0);
|
||||
_blob.WriteString(name);
|
||||
_blob.AlignToDWORD();
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
|
||||
return classTypeIndex;
|
||||
}
|
||||
|
||||
public uint GetCompleteClassTypeIndex(ClassTypeDescriptor classTypeDescriptor, ClassFieldsTypeDescriptor classFieldsTypeDescriptior, DataFieldDescriptor[] fields)
|
||||
{
|
||||
FieldListInProgress fieldList = default(FieldListInProgress);
|
||||
if ((classTypeDescriptor.BaseClassId != 0) || (fields != null && fields.Length > 0) || (classTypeDescriptor.IsStruct == 0))
|
||||
{
|
||||
fieldList = StartFieldList();
|
||||
if (classTypeDescriptor.BaseClassId != 0)
|
||||
EmitBaseClass(ref fieldList, classTypeDescriptor.BaseClassId);
|
||||
|
||||
if (classTypeDescriptor.IsStruct == 0)
|
||||
EmitVFuncTab(ref fieldList);
|
||||
|
||||
if (fields != null)
|
||||
{
|
||||
foreach (DataFieldDescriptor field in fields)
|
||||
{
|
||||
EmitDataMember(ref fieldList, field.FieldTypeIndex, (int)field.Offset, new Utf8String(field.Name));
|
||||
}
|
||||
}
|
||||
FinalizeFieldList(fieldList);
|
||||
}
|
||||
|
||||
uint classTypeIndex = _blob.GetNextTypeIndex();
|
||||
Utf8String name = new Utf8String(classTypeDescriptor.Name);
|
||||
uint recordSize = 20 + DebugInfoBlob.StringLengthEncoded(name) + TypeRecordsBlob.NumericLeafSize(classFieldsTypeDescriptior.Size) /*size of length */;
|
||||
_blob.WriteWORD(checked((ushort)(_blob.DWORDAlignedSize(recordSize) - 2))); // don't include size of 'length' in 'length'
|
||||
_blob.WriteLeafKind(classTypeDescriptor.IsStruct != 0 ? LeafKind.LF_STRUCTURE : LeafKind.LF_CLASS);
|
||||
_blob.WriteWORD(fieldList.FieldsCount);
|
||||
_blob.WriteLF_CLASS_Properties(LF_CLASS_Properties.None);
|
||||
_blob.WriteDWORD(fieldList.TypeIndexOfFieldList);
|
||||
_blob.WriteDWORD(0); // Derivation list is not filled in here
|
||||
_blob.WriteDWORD(_tiVTShapePointer); // No vtable shape
|
||||
_blob.WriteNumericLeaf(classFieldsTypeDescriptior.Size);
|
||||
_blob.WriteString(name);
|
||||
_blob.AlignToDWORD();
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
return classTypeIndex;
|
||||
}
|
||||
|
||||
public uint GetEnumTypeIndex(EnumTypeDescriptor enumTypeDescriptor, EnumRecordTypeDescriptor[] enumerates)
|
||||
{
|
||||
checked
|
||||
{
|
||||
FieldListInProgress fieldList = default(FieldListInProgress);
|
||||
if ((enumerates != null && enumerates.Length > 0))
|
||||
{
|
||||
fieldList = StartFieldList();
|
||||
foreach (EnumRecordTypeDescriptor enumerate in enumerates)
|
||||
{
|
||||
EmitEnumerate(ref fieldList, enumerate.Value, new Utf8String(enumerate.Name));
|
||||
}
|
||||
FinalizeFieldList(fieldList);
|
||||
}
|
||||
|
||||
if (enumerates != null)
|
||||
Debug.Assert(checked((int)enumTypeDescriptor.ElementCount == enumerates.Length));
|
||||
if (enumerates == null)
|
||||
Debug.Assert(enumTypeDescriptor.ElementCount == 0);
|
||||
|
||||
uint enumTypeIndex = _blob.GetNextTypeIndex();
|
||||
Utf8String name = new Utf8String(enumTypeDescriptor.Name);
|
||||
uint recordSize = 16 + DebugInfoBlob.StringLengthEncoded(name);
|
||||
_blob.WriteWORD(checked((ushort)(_blob.DWORDAlignedSize(recordSize) - 2))); // don't include size of 'length' in 'length'
|
||||
_blob.WriteLeafKind(LeafKind.LF_ENUM);
|
||||
_blob.WriteWORD(fieldList.FieldsCount);
|
||||
_blob.WriteWORD(0);
|
||||
_blob.WriteDWORD((uint)enumTypeDescriptor.ElementType);
|
||||
_blob.WriteDWORD(fieldList.TypeIndexOfFieldList);
|
||||
_blob.WriteString(name);
|
||||
_blob.AlignToDWORD();
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
return enumTypeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetArgListTypeDescriptor(uint[] arguments)
|
||||
{
|
||||
uint argListTypeIndex = _blob.GetNextTypeIndex();
|
||||
ushort recordSizeEmit;
|
||||
uint argumentListEmit;
|
||||
|
||||
try
|
||||
{
|
||||
checked
|
||||
{
|
||||
uint recordSize = (ushort)(8 + (4 * arguments.Length));
|
||||
recordSizeEmit = checked((ushort)(_blob.DWORDAlignedSize(recordSize) - 2));
|
||||
argumentListEmit = (uint)arguments.Length;
|
||||
}
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
_blob.WriteWORD(recordSizeEmit); // don't include size of 'length' in 'length'
|
||||
_blob.WriteLeafKind(LeafKind.LF_ARGLIST);
|
||||
_blob.WriteDWORD(argumentListEmit);
|
||||
foreach (uint argType in arguments)
|
||||
{
|
||||
_blob.WriteDWORD(argType);
|
||||
}
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
return argListTypeIndex;
|
||||
}
|
||||
|
||||
public uint GetMemberFunctionTypeIndex(MemberFunctionTypeDescriptor memberDescriptor, uint[] arguments)
|
||||
{
|
||||
uint argumentList = GetArgListTypeDescriptor(arguments);
|
||||
if (argumentList == 0)
|
||||
return 0;
|
||||
|
||||
uint memberFunctionTypeIndex = _blob.GetNextTypeIndex();
|
||||
uint recordSize = 28;
|
||||
_blob.WriteWORD(checked((ushort)(_blob.DWORDAlignedSize(recordSize) - 2))); // don't include size of 'length' in 'length'
|
||||
_blob.WriteLeafKind(LeafKind.LF_MFUNCTION);
|
||||
_blob.WriteDWORD(memberDescriptor.ReturnType);
|
||||
_blob.WriteDWORD(memberDescriptor.ContainingClass);
|
||||
_blob.WriteDWORD(memberDescriptor.TypeIndexOfThisPointer);
|
||||
_blob.WriteBYTE(checked((byte)memberDescriptor.CallingConvention));
|
||||
_blob.WriteBYTE(0);
|
||||
_blob.WriteWORD(checked((ushort)arguments.Length));
|
||||
_blob.WriteDWORD(argumentList);
|
||||
_blob.WriteDWORD(memberDescriptor.ThisAdjust);
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
return memberFunctionTypeIndex;
|
||||
}
|
||||
|
||||
public uint GetMemberFunctionId(MemberFunctionIdTypeDescriptor memberIdDescriptor)
|
||||
{
|
||||
uint memberFunctionIdTypeIndex = _blob.GetNextTypeIndex();
|
||||
|
||||
Utf8String name = new Utf8String(memberIdDescriptor.Name);
|
||||
uint recordSize = 12 + DebugInfoBlob.StringLengthEncoded(name);
|
||||
_blob.WriteWORD(checked((ushort)(_blob.DWORDAlignedSize(recordSize) - 2))); // don't include size of 'length' in 'length'
|
||||
_blob.WriteLeafKind(LeafKind.LF_MFUNC_ID);
|
||||
_blob.WriteDWORD(memberIdDescriptor.MemberFunction);
|
||||
_blob.WriteDWORD(memberIdDescriptor.ParentClass);
|
||||
_blob.WriteString(name);
|
||||
_blob.AlignToDWORD();
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
return memberFunctionIdTypeIndex;
|
||||
}
|
||||
|
||||
public uint GetPointerTypeIndex(PointerTypeDescriptor pointerTypeDescriptor)
|
||||
{
|
||||
uint pointerTypeIndex = _blob.GetNextTypeIndex();
|
||||
uint recordSize = 12;
|
||||
uint attr = 0;
|
||||
if (pointerTypeDescriptor.IsReference != 0)
|
||||
attr |= 0x20;
|
||||
if (pointerTypeDescriptor.IsConst != 0)
|
||||
attr |= 0x400;
|
||||
if (pointerTypeDescriptor.Is64Bit != 0)
|
||||
attr |= 12;
|
||||
else
|
||||
attr |= 10;
|
||||
|
||||
_blob.WriteWORD(checked((ushort)(_blob.DWORDAlignedSize(recordSize) - 2))); // don't include size of 'length' in 'length'
|
||||
_blob.WriteLeafKind(LeafKind.LF_POINTER);
|
||||
_blob.WriteDWORD(pointerTypeDescriptor.ElementType);
|
||||
_blob.WriteDWORD(attr);
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
return pointerTypeIndex;
|
||||
}
|
||||
|
||||
public uint GetSimpleArrayTypeIndex(uint elementType, uint elementSize)
|
||||
{
|
||||
uint simpleArrayTypeIndex = _blob.GetNextTypeIndex();
|
||||
|
||||
TypeRecordsBlob simpleArrayDataBlob = new TypeRecordsBlob();
|
||||
simpleArrayDataBlob.WriteLeafKind(LeafKind.LF_ARRAY);
|
||||
simpleArrayDataBlob.WriteDWORD(elementType);
|
||||
simpleArrayDataBlob.WriteDWORD((uint)PrimitiveTypeDescriptor.TYPE_ENUM.T_INT4);
|
||||
simpleArrayDataBlob.WriteNumericLeaf(elementSize);
|
||||
simpleArrayDataBlob.WriteString("");
|
||||
|
||||
uint recordSize = simpleArrayDataBlob.Size() + 2;
|
||||
_blob.WriteWORD(checked((ushort)(_blob.DWORDAlignedSize(recordSize) - 2))); // don't include size of 'length' in 'length'
|
||||
_blob.WriteBuffer(simpleArrayDataBlob);
|
||||
_blob.AlignToDWORD();
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
return simpleArrayTypeIndex;
|
||||
}
|
||||
|
||||
public uint GetArrayTypeIndex(ClassTypeDescriptor classDescriptor, ArrayTypeDescriptor arrayTypeDescriptor, int targetPointerSize)
|
||||
{
|
||||
uint simpleArrayDebugType = GetSimpleArrayTypeIndex(arrayTypeDescriptor.ElementType, arrayTypeDescriptor.Size);
|
||||
|
||||
FieldListInProgress fieldList = default(FieldListInProgress);
|
||||
|
||||
fieldList = StartFieldList();
|
||||
EmitBaseClass(ref fieldList, classDescriptor.BaseClassId);
|
||||
EmitDataMember(ref fieldList, (uint)PrimitiveTypeDescriptor.TYPE_ENUM.T_INT4, targetPointerSize, new Utf8String("count"));
|
||||
int nextOffset = targetPointerSize * 2;
|
||||
if (arrayTypeDescriptor.IsMultiDimensional != 0)
|
||||
{
|
||||
for (uint i = 0; i < arrayTypeDescriptor.Rank; i++)
|
||||
{
|
||||
EmitDataMember(ref fieldList, (uint)PrimitiveTypeDescriptor.TYPE_ENUM.T_INT4, nextOffset, new Utf8String("length" + i.ToStringInvariant()));
|
||||
nextOffset += 4;
|
||||
}
|
||||
for (uint i = 0; i < arrayTypeDescriptor.Rank; i++)
|
||||
{
|
||||
EmitDataMember(ref fieldList, (uint)PrimitiveTypeDescriptor.TYPE_ENUM.T_INT4, nextOffset, new Utf8String("bounds" + i.ToStringInvariant()));
|
||||
nextOffset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
EmitDataMember(ref fieldList, simpleArrayDebugType, nextOffset, new Utf8String("values"));
|
||||
|
||||
FinalizeFieldList(fieldList);
|
||||
|
||||
uint classTypeIndex = _blob.GetNextTypeIndex();
|
||||
Utf8String name = new Utf8String(classDescriptor.Name);
|
||||
uint recordSize = 20 + DebugInfoBlob.StringLengthEncoded(name) + TypeRecordsBlob.NumericLeafSize(targetPointerSize) /*size of length */;
|
||||
_blob.WriteWORD(checked((ushort)(_blob.DWORDAlignedSize(recordSize) - 2))); // don't include size of 'length' in 'length'
|
||||
_blob.WriteLeafKind(classDescriptor.IsStruct != 0 ? LeafKind.LF_STRUCTURE : LeafKind.LF_CLASS);
|
||||
_blob.WriteWORD(fieldList.FieldsCount);
|
||||
_blob.WriteLF_CLASS_Properties(LF_CLASS_Properties.None);
|
||||
_blob.WriteDWORD(fieldList.TypeIndexOfFieldList);
|
||||
_blob.WriteDWORD(0); // Derivation list is not filled in here
|
||||
_blob.WriteDWORD(_tiVTShapePointer); // No vtable shape
|
||||
_blob.WriteNumericLeaf(targetPointerSize);
|
||||
_blob.WriteString(name);
|
||||
_blob.AlignToDWORD();
|
||||
VerifyBlobEligibleToBeBetweenRecords();
|
||||
return classTypeIndex;
|
||||
}
|
||||
|
||||
public DebugInfoBlob GetRawBlob()
|
||||
{
|
||||
return _blob;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
public interface IMethodBodyNodeWithFuncletSymbols : IMethodBodyNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Symbols of any funclets associated with this method.
|
||||
/// </summary>
|
||||
ISymbolNode[] FuncletSymbols { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using ILCompiler.DependencyAnalysisFramework;
|
||||
using Internal.Text;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a reference to a symbol attributed with a funclet id.
|
||||
/// </summary>
|
||||
public interface ISymbolNodeWithFuncletId : ISymbolNode
|
||||
{
|
||||
ISymbolNode AssociatedMethodSymbol { get; }
|
||||
int FuncletId { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using Internal.TypeSystem.TypesDebugInfo;
|
||||
using ILCompiler.DependencyAnalysisFramework;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
// Part of Node factory that deals with nodes describing windows debug data
|
||||
partial class NodeFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class that provides a level of grouping for all the windows debug data nodes
|
||||
/// </summary>
|
||||
public class WindowsDebugDataHelper
|
||||
{
|
||||
NodeFactory _nodeFactory;
|
||||
|
||||
public WindowsDebugDataHelper(NodeFactory nodeFactory)
|
||||
{
|
||||
_nodeFactory = nodeFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the WindowsDebugData emission pipeline.
|
||||
/// Cannot be called twice
|
||||
/// </summary>
|
||||
/// <param name="nonSectionBasedDebugInfoWriter">debug$T section generation interface. If null, use managed implementation that generates a object file section.</param>
|
||||
/// <param name="mergedAssemblyRecords">record of how assemblies are merged. If null, do not genearate extended debug information</param>
|
||||
/// <param name="graph">Graph to attach WindowsDebugData to</param>
|
||||
public void Init(ITypesDebugInfoWriter nonSectionBasedDebugInfoWriter, MergedAssemblyRecords mergedAssemblyRecords, DependencyAnalyzerBase<NodeFactory> graph)
|
||||
{
|
||||
Debug.Assert(_userDefinedTypeDescriptor == null); // Cannot be called twice
|
||||
Debug.Assert(graph != null);
|
||||
|
||||
_debugNeedTypeIndicesStore = new WindowsDebugNeedTypeIndicesStoreNode();
|
||||
|
||||
if (mergedAssemblyRecords != null)
|
||||
{
|
||||
_debugPseudoAssemblySection = new WindowsDebugPseudoAssemblySection(_nodeFactory.TypeSystemContext);
|
||||
_debugMergedAssembliesSection = new WindowsDebugMergedAssembliesSection(mergedAssemblyRecords);
|
||||
_debugILImagesSection = new WindowsDebugILImagesSection(mergedAssemblyRecords);
|
||||
_debugManagedNativeDictionaryInfoSection = new WindowsDebugManagedNativeDictionaryInfoSection();
|
||||
}
|
||||
|
||||
bool is64Bit = _nodeFactory.Target.PointerSize == 8 ? true : false;
|
||||
|
||||
if (nonSectionBasedDebugInfoWriter != null)
|
||||
{
|
||||
_userDefinedTypeDescriptor = new UserDefinedTypeDescriptor(nonSectionBasedDebugInfoWriter, is64Bit, _nodeFactory.Target.Abi);
|
||||
}
|
||||
else
|
||||
{
|
||||
_debugTypeRecordsSection = new WindowsDebugTypeRecordsSection(new DebugInfoWriter(), _nodeFactory);
|
||||
_userDefinedTypeDescriptor = new UserDefinedTypeDescriptor(_debugTypeRecordsSection, is64Bit, _nodeFactory.Target.Abi);
|
||||
}
|
||||
|
||||
if (mergedAssemblyRecords != null)
|
||||
{
|
||||
_debugTypeSignatureMapSection = new WindowsDebugTypeSignatureMapSection(_userDefinedTypeDescriptor);
|
||||
_debugMethodSignatureMapSection = new WindowsDebugMethodSignatureMapSection();
|
||||
}
|
||||
|
||||
graph.AddRoot(_debugNeedTypeIndicesStore, "Debug Force All EETypes to have type indices");
|
||||
|
||||
if (_debugManagedNativeDictionaryInfoSection != null)
|
||||
graph.AddRoot(_debugManagedNativeDictionaryInfoSection, "Debug Method MDToken map");
|
||||
if (_debugMethodSignatureMapSection != null)
|
||||
graph.AddRoot(_debugMethodSignatureMapSection, "Debug Method MDToken map");
|
||||
if (_debugTypeSignatureMapSection != null)
|
||||
graph.AddRoot(_debugTypeSignatureMapSection, "Debug Type MDToken map");
|
||||
if (_debugILImagesSection != null)
|
||||
graph.AddRoot(_debugILImagesSection, "Debug Merged ILImages");
|
||||
if (_debugMergedAssembliesSection != null)
|
||||
graph.AddRoot(_debugMergedAssembliesSection, "Debug MergedAssemblyRecords");
|
||||
if (_debugPseudoAssemblySection != null)
|
||||
graph.AddRoot(_debugPseudoAssemblySection, "Debug PseudoAssembly");
|
||||
if (_debugTypeRecordsSection != null)
|
||||
graph.AddRoot(_debugTypeRecordsSection, "Debug Type Records");
|
||||
}
|
||||
|
||||
private WindowsDebugILImagesSection _debugILImagesSection;
|
||||
private WindowsDebugTypeSignatureMapSection _debugTypeSignatureMapSection;
|
||||
private WindowsDebugTypeRecordsSection _debugTypeRecordsSection;
|
||||
private WindowsDebugManagedNativeDictionaryInfoSection _debugManagedNativeDictionaryInfoSection;
|
||||
private WindowsDebugMethodSignatureMapSection _debugMethodSignatureMapSection;
|
||||
private WindowsDebugMergedAssembliesSection _debugMergedAssembliesSection;
|
||||
private WindowsDebugPseudoAssemblySection _debugPseudoAssemblySection;
|
||||
private UserDefinedTypeDescriptor _userDefinedTypeDescriptor;
|
||||
private WindowsDebugNeedTypeIndicesStoreNode _debugNeedTypeIndicesStore;
|
||||
|
||||
internal WindowsDebugILImagesSection DebugILImagesSection => _debugILImagesSection;
|
||||
internal WindowsDebugTypeSignatureMapSection DebugTypeSignatureMapSection => _debugTypeSignatureMapSection;
|
||||
internal WindowsDebugMethodSignatureMapSection DebugMethodSignatureMapSection => _debugMethodSignatureMapSection;
|
||||
internal WindowsDebugTypeRecordsSection DebugTypeRecordsSection => _debugTypeRecordsSection;
|
||||
internal WindowsDebugMergedAssembliesSection DebugMergedAssembliesSection => _debugMergedAssembliesSection;
|
||||
internal WindowsDebugPseudoAssemblySection DebugPseudoAssemblySection => _debugPseudoAssemblySection;
|
||||
internal WindowsDebugManagedNativeDictionaryInfoSection DebugManagedNativeDictionaryInfoSection => _debugManagedNativeDictionaryInfoSection;
|
||||
internal WindowsDebugNeedTypeIndicesStoreNode DebugNeedTypeIndicesStore => _debugNeedTypeIndicesStore;
|
||||
|
||||
public UserDefinedTypeDescriptor UserDefinedTypeDescriptor => _userDefinedTypeDescriptor;
|
||||
}
|
||||
|
||||
public WindowsDebugDataHelper WindowsDebugData { get; private set; }
|
||||
}
|
||||
}
|
|
@ -479,6 +479,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
});
|
||||
|
||||
NativeLayout = new NativeLayoutHelper(this);
|
||||
WindowsDebugData = new WindowsDebugDataHelper(this);
|
||||
}
|
||||
|
||||
protected abstract IMethodNode CreateMethodEntrypointNode(MethodDesc method);
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
using ILCompiler.DependencyAnalysisFramework;
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
|
@ -15,10 +17,11 @@ namespace ILCompiler.DependencyAnalysis
|
|||
/// in the DependencyAnalysis infrastructure during compilation that is compiled
|
||||
/// in the current compilation process
|
||||
/// </summary>
|
||||
public class NonExternMethodSymbolNode : ExternSymbolNode, IMethodNode
|
||||
public class NonExternMethodSymbolNode : ExternSymbolNode, IMethodBodyNodeWithFuncletSymbols
|
||||
{
|
||||
private MethodDesc _method;
|
||||
private List<DependencyListEntry> _compilationDiscoveredDependencies;
|
||||
ISymbolNode[] _funcletSymbols = Array.Empty<ISymbolNode>();
|
||||
bool _dependenciesQueried;
|
||||
bool _hasCompiledBody;
|
||||
|
||||
|
@ -29,6 +32,8 @@ namespace ILCompiler.DependencyAnalysis
|
|||
_method = method;
|
||||
}
|
||||
|
||||
protected override string GetName(NodeFactory factory) => "Non" + base.GetName(factory);
|
||||
|
||||
public MethodDesc Method
|
||||
{
|
||||
get
|
||||
|
@ -45,6 +50,16 @@ namespace ILCompiler.DependencyAnalysis
|
|||
_hasCompiledBody = true;
|
||||
}
|
||||
|
||||
public void SetFuncletCount(int funcletCount)
|
||||
{
|
||||
Debug.Assert(funcletCount > 0);
|
||||
Debug.Assert(_funcletSymbols.Length == 0);
|
||||
ISymbolNode[] funclets = new ISymbolNode[funcletCount];
|
||||
for (int funcletId = 1; funcletId <= funcletCount; funcletId++)
|
||||
funclets[funcletId - 1] = new FuncletSymbol(this, funcletId);
|
||||
_funcletSymbols = funclets;
|
||||
}
|
||||
|
||||
public void AddCompilationDiscoveredDependency(IDependencyNode<NodeFactory> node, string reason)
|
||||
{
|
||||
Debug.Assert(!_dependenciesQueried);
|
||||
|
@ -64,6 +79,14 @@ namespace ILCompiler.DependencyAnalysis
|
|||
}
|
||||
}
|
||||
|
||||
ISymbolNode[] IMethodBodyNodeWithFuncletSymbols.FuncletSymbols
|
||||
{
|
||||
get
|
||||
{
|
||||
return _funcletSymbols;
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
|
||||
{
|
||||
_dependenciesQueried = true;
|
||||
|
@ -78,5 +101,49 @@ namespace ILCompiler.DependencyAnalysis
|
|||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
private class FuncletSymbol : ISymbolNodeWithFuncletId
|
||||
{
|
||||
public FuncletSymbol(NonExternMethodSymbolNode methodSymbol, int funcletId)
|
||||
{
|
||||
_funcletId = funcletId;
|
||||
_methodSymbol = methodSymbol;
|
||||
}
|
||||
|
||||
private int _funcletId;
|
||||
private NonExternMethodSymbolNode _methodSymbol;
|
||||
|
||||
public ISymbolNode AssociatedMethodSymbol => _methodSymbol;
|
||||
|
||||
public int FuncletId => _funcletId;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public bool RepresentsIndirectionCell => false;
|
||||
public bool InterestingForDynamicDependencyAnalysis => false;
|
||||
public bool HasDynamicDependencies => false;
|
||||
public bool HasConditionalStaticDependencies => false;
|
||||
public bool StaticDependenciesAreComputed => true;
|
||||
public bool Marked => _methodSymbol.Marked;
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
_methodSymbol.AppendMangledName(nameMangler, sb);
|
||||
}
|
||||
|
||||
public IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,14 @@ namespace ILCompiler.DependencyAnalysis
|
|||
EmitByte((byte)((emit >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
public void EmitUInt(uint emit)
|
||||
{
|
||||
EmitByte((byte)(emit & 0xFF));
|
||||
EmitByte((byte)((emit >> 8) & 0xFF));
|
||||
EmitByte((byte)((emit >> 16) & 0xFF));
|
||||
EmitByte((byte)((emit >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
public void EmitLong(long emit)
|
||||
{
|
||||
EmitByte((byte)(emit & 0xFF));
|
||||
|
@ -169,6 +177,11 @@ namespace ILCompiler.DependencyAnalysis
|
|||
_data.Append(bytes, offset, length);
|
||||
}
|
||||
|
||||
internal void EmitBytes(ArrayBuilder<byte> bytes)
|
||||
{
|
||||
_data.Append(bytes);
|
||||
}
|
||||
|
||||
public void EmitZeroPointer()
|
||||
{
|
||||
_data.ZeroExtend(_target.PointerSize);
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using Internal.Text;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
internal class WindowsDebugILImagesSection : ObjectNode, ISymbolDefinitionNode
|
||||
{
|
||||
private MergedAssemblyRecords _mergedAssemblies;
|
||||
|
||||
public WindowsDebugILImagesSection(MergedAssemblyRecords mergedAssemblies)
|
||||
{
|
||||
_mergedAssemblies = mergedAssemblies;
|
||||
}
|
||||
|
||||
private ObjectNodeSection _section = new ObjectNodeSection(".ilimges", SectionType.ReadOnly);
|
||||
public override ObjectNodeSection Section => _section;
|
||||
|
||||
public override bool IsShareable => false;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(GetName(null));
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
// This node does not trigger generation of other nodes.
|
||||
if (relocsOnly)
|
||||
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
BinaryWriter writer = new BinaryWriter(memoryStream, Encoding.Unicode, true);
|
||||
writer.Write(1); // magic format version number
|
||||
writer.Write(_mergedAssemblies.MergedAssemblies.Count); // number of il images that will follow
|
||||
|
||||
int totalSizeOfActualMergedAssemblies = 0;
|
||||
checked
|
||||
{
|
||||
const int ILIMAGES_HEADER_ELEMENTS = 2;
|
||||
const int ILIMAGES_PERMODULE_ELEMENTS = 3;
|
||||
int endOfILAssemblyListHeader = ((_mergedAssemblies.MergedAssemblies.Count * ILIMAGES_PERMODULE_ELEMENTS) + ILIMAGES_HEADER_ELEMENTS) * sizeof(int);
|
||||
|
||||
int offsetOfNextAssembly = endOfILAssemblyListHeader;
|
||||
|
||||
foreach (MergedAssemblyRecord mergedAssembly in _mergedAssemblies.MergedAssemblies)
|
||||
{
|
||||
int assemblyFileLen = mergedAssembly.Assembly.PEReader.GetEntireImage().Length;
|
||||
writer.Write(mergedAssembly.AssemblyIndex);
|
||||
writer.Write(offsetOfNextAssembly);
|
||||
writer.Write(assemblyFileLen);
|
||||
offsetOfNextAssembly += assemblyFileLen;
|
||||
totalSizeOfActualMergedAssemblies += assemblyFileLen;
|
||||
}
|
||||
|
||||
writer.Flush();
|
||||
writer.Dispose();
|
||||
|
||||
byte[] mergedAssemblyHeader = memoryStream.ToArray();
|
||||
Debug.Assert(mergedAssemblyHeader.Length == endOfILAssemblyListHeader);
|
||||
|
||||
byte[] mergedAssemblyBlob = new byte[mergedAssemblyHeader.Length + totalSizeOfActualMergedAssemblies];
|
||||
Array.Copy(mergedAssemblyHeader, mergedAssemblyBlob, mergedAssemblyHeader.Length);
|
||||
|
||||
offsetOfNextAssembly = endOfILAssemblyListHeader;
|
||||
foreach (MergedAssemblyRecord mergedAssembly in _mergedAssemblies.MergedAssemblies)
|
||||
{
|
||||
var memoryBlock = mergedAssembly.Assembly.PEReader.GetEntireImage();
|
||||
int assemblyFileLen = memoryBlock.Length;
|
||||
unsafe
|
||||
{
|
||||
Marshal.Copy(new IntPtr(memoryBlock.Pointer), mergedAssemblyBlob, offsetOfNextAssembly, assemblyFileLen);
|
||||
}
|
||||
offsetOfNextAssembly += assemblyFileLen;
|
||||
}
|
||||
|
||||
return new ObjectData(mergedAssemblyBlob, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
}
|
||||
}
|
||||
|
||||
protected override string GetName(NodeFactory context)
|
||||
{
|
||||
return "___DebugILImagesSection";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
using Internal.TypeSystem.TypesDebugInfo;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
internal class WindowsDebugManagedNativeDictionaryInfoSection : ObjectNode, ISymbolDefinitionNode
|
||||
{
|
||||
public WindowsDebugManagedNativeDictionaryInfoSection()
|
||||
{
|
||||
}
|
||||
|
||||
private ObjectNodeSection _section = new ObjectNodeSection(".dbgmanagednativedictionaryinfo", SectionType.ReadOnly);
|
||||
public override ObjectNodeSection Section => _section;
|
||||
|
||||
public override bool IsShareable => false;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(GetName(null));
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
// This node does not trigger generation of other nodes.
|
||||
if (relocsOnly)
|
||||
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
|
||||
ObjectDataBuilder objDataBuilder = new ObjectDataBuilder(factory, relocsOnly);
|
||||
|
||||
// Emit number of dictionaries in table
|
||||
objDataBuilder.AddSymbol(this);
|
||||
IReadOnlyCollection<GenericDictionaryNode> dictionariesEmitted = factory.MetadataManager.GetCompiledGenericDictionaries();
|
||||
objDataBuilder.EmitInt(dictionariesEmitted.Count);
|
||||
DebugInfoBlob signatureData = new DebugInfoBlob();
|
||||
|
||||
BlobBuilder signatureBlobBuilder = new BlobBuilder();
|
||||
BlobBuilder signatureLenBuilder = new BlobBuilder();
|
||||
ManagedBinaryEmitter pseudoAssembly = factory.WindowsDebugData.DebugPseudoAssemblySection.PseudoAssembly;
|
||||
|
||||
foreach (GenericDictionaryNode dictionary in dictionariesEmitted)
|
||||
{
|
||||
objDataBuilder.EmitReloc(dictionary, RelocType.IMAGE_REL_BASED_ADDR32NB);
|
||||
objDataBuilder.EmitUInt(signatureData.Size());
|
||||
|
||||
signatureBlobBuilder.Clear();
|
||||
|
||||
int typeDictLen = dictionary.TypeInstantiation.IsNull ? 0 : dictionary.TypeInstantiation.Length;
|
||||
int methodDictLen = dictionary.MethodInstantiation.IsNull ? 0 : dictionary.MethodInstantiation.Length;
|
||||
signatureBlobBuilder.WriteCompressedInteger(typeDictLen + methodDictLen);
|
||||
|
||||
if (typeDictLen != 0)
|
||||
{
|
||||
foreach (TypeDesc type in dictionary.TypeInstantiation)
|
||||
{
|
||||
pseudoAssembly.EncodeSignatureForType(type, signatureBlobBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
if (methodDictLen != 0)
|
||||
{
|
||||
foreach (TypeDesc type in dictionary.MethodInstantiation)
|
||||
{
|
||||
pseudoAssembly.EncodeSignatureForType(type, signatureBlobBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
int blobSize = signatureBlobBuilder.Count;
|
||||
|
||||
signatureLenBuilder.Clear();
|
||||
signatureLenBuilder.WriteCompressedInteger(blobSize);
|
||||
|
||||
// Prepend the signature data with a length
|
||||
signatureData.WriteBuffer(signatureLenBuilder);
|
||||
// And then attach the actual signature data
|
||||
signatureData.WriteBuffer(signatureBlobBuilder);
|
||||
}
|
||||
|
||||
// Attach signature information to end after all of the rva/offset pairs
|
||||
objDataBuilder.EmitBytes(signatureData.ToArray());
|
||||
|
||||
return objDataBuilder.ToObjectData();
|
||||
}
|
||||
|
||||
protected override string GetName(NodeFactory context)
|
||||
{
|
||||
return "___DebugManagedNativeDictionaryInfoSection";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem.TypesDebugInfo;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
internal class WindowsDebugMergedAssembliesSection : ObjectNode, ISymbolDefinitionNode
|
||||
{
|
||||
private MergedAssemblyRecords _mergedAssemblies;
|
||||
|
||||
public WindowsDebugMergedAssembliesSection(MergedAssemblyRecords mergedAssemblies)
|
||||
{
|
||||
_mergedAssemblies = mergedAssemblies;
|
||||
}
|
||||
|
||||
private ObjectNodeSection _section = new ObjectNodeSection(".dbgmergedassemblyrecords", SectionType.ReadOnly);
|
||||
public override ObjectNodeSection Section => _section;
|
||||
|
||||
public override bool IsShareable => false;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(GetName(null));
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
// This node does not trigger generation of other nodes.
|
||||
if (relocsOnly)
|
||||
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
|
||||
DebugInfoBlob debugBlob = new DebugInfoBlob();
|
||||
foreach (MergedAssemblyRecord record in _mergedAssemblies.MergedAssemblies)
|
||||
record.Encode(debugBlob);
|
||||
|
||||
byte [] _pdbBlob = debugBlob.ToArray();
|
||||
Debug.Assert(_pdbBlob.Length > 0);
|
||||
|
||||
return new ObjectData(_pdbBlob, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
}
|
||||
|
||||
protected override string GetName(NodeFactory context)
|
||||
{
|
||||
return "___DebugMergedAssemblyRecordsSection";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
using Internal.TypeSystem.TypesDebugInfo;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
internal class WindowsDebugMethodSignatureMapSection : ObjectNode, ISymbolDefinitionNode
|
||||
{
|
||||
public WindowsDebugMethodSignatureMapSection()
|
||||
{
|
||||
}
|
||||
|
||||
private ObjectNodeSection _section = new ObjectNodeSection(".dbgmethodsignaturemap", SectionType.ReadOnly);
|
||||
public override ObjectNodeSection Section => _section;
|
||||
|
||||
public override bool IsShareable => false;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(GetName(null));
|
||||
}
|
||||
|
||||
struct EmittedMethodWithILToken : IComparable<EmittedMethodWithILToken>
|
||||
{
|
||||
public EmittedMethodWithILToken(IMethodBodyNode emittedMethod, uint ilTokenRid)
|
||||
{
|
||||
EmittedMethod = emittedMethod;
|
||||
IlTokenRid = ilTokenRid;
|
||||
}
|
||||
|
||||
public IMethodBodyNode EmittedMethod;
|
||||
public uint IlTokenRid;
|
||||
|
||||
int IComparable<EmittedMethodWithILToken>.CompareTo(EmittedMethodWithILToken other)
|
||||
{
|
||||
if (other.IlTokenRid == IlTokenRid)
|
||||
return 0;
|
||||
if (other.IlTokenRid < IlTokenRid)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// returns the DEBUG_S_FUNC_MDTOKEN_MAP subsection as a byte array
|
||||
// DEBUG_S_FUNC_MDTOKEN_MAP subsection contains method RVA to mdToken mapping
|
||||
//
|
||||
// contents of subsection:
|
||||
// offset 0, 4 bytes: count of entries in the map
|
||||
// offset 4, 8*N bytes: 4 byte RVA + 4 byte 'offset' relative to the start of 'method data'
|
||||
// offset 4+8*N, * bytes: all method data packed sequentially with no padding. method data consists of
|
||||
// 1 byte 'count' of generic parameters, 3 bytes of method's rid and 'count'
|
||||
// variable sized ECMA formatted TypeSpec signatures for each generic parameter
|
||||
//
|
||||
// Compiler places the CTLToken (for a method) or the lexical funclet order (if a method has 1 or more funclets),
|
||||
// which binder uses to compute the RVA.
|
||||
//
|
||||
// all entries are sorted by 'offset' field.
|
||||
//
|
||||
// 'offset' optimization: if the method has no generic parameters, we don't need to pass in a signature
|
||||
// and can encode the mdToken of method in 'offset'
|
||||
// We do this by setting the high bit of 'offset' and then storing rid part of
|
||||
// token in last 3 bytes of 'offset'
|
||||
//
|
||||
internal DebugInfoBlob GetDebugMethodRVAToTokenMap(ManagedBinaryEmitter pseudoAssembly, IEnumerable<IMethodBodyNode> emittedMethods, out List<Relocation> debugRelocations)
|
||||
{
|
||||
DebugInfoBlob methodRVAToTokenMap = new DebugInfoBlob();
|
||||
DebugInfoBlob methodDataBlob = new DebugInfoBlob();
|
||||
debugRelocations = new List<Relocation>();
|
||||
BlobBuilder blobBuilder = new BlobBuilder();
|
||||
|
||||
uint entryCount = 0;
|
||||
methodRVAToTokenMap.WriteDWORD(0); // Placeholder for count of entries in map. Will be udpated later.
|
||||
|
||||
List<EmittedMethodWithILToken> tokenInOffsetEntries = new List<EmittedMethodWithILToken>();
|
||||
|
||||
foreach (IMethodBodyNode emitted in emittedMethods)
|
||||
{
|
||||
if (!(emitted.Method.GetMethodDefinition() is Internal.TypeSystem.Ecma.EcmaMethod))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityHandle methodHandle = pseudoAssembly.EmitMetadataHandleForTypeSystemEntity(emitted.Method.GetMethodDefinition());
|
||||
Debug.Assert(methodHandle.Kind == HandleKind.MemberReference);
|
||||
uint methodToken = (uint)MetadataTokens.GetToken(methodHandle);
|
||||
uint methodTokenRid = methodToken & 0xFFFFFF;
|
||||
|
||||
if (!(emitted.Method.HasInstantiation || emitted.Method.OwningType.HasInstantiation))
|
||||
{
|
||||
tokenInOffsetEntries.Add(new EmittedMethodWithILToken(emitted, methodTokenRid));
|
||||
continue;
|
||||
}
|
||||
|
||||
uint cGenericArguments = checked((uint)emitted.Method.Instantiation.Length + (uint)emitted.Method.OwningType.Instantiation.Length);
|
||||
|
||||
// Debugger format does not allow the debugging of methods that have more than 255 generic parameters (spread between the type and method instantiation)
|
||||
if (cGenericArguments > 0xFF)
|
||||
continue;
|
||||
|
||||
blobBuilder.Clear();
|
||||
|
||||
// write the signature for each generic parameter of class
|
||||
foreach (TypeDesc instantiationType in emitted.Method.OwningType.Instantiation)
|
||||
pseudoAssembly.EncodeSignatureForType(instantiationType, blobBuilder);
|
||||
|
||||
// write the signature for each generic parameter of the method
|
||||
foreach (TypeDesc instantiationType in emitted.Method.Instantiation)
|
||||
pseudoAssembly.EncodeSignatureForType(instantiationType, blobBuilder);
|
||||
|
||||
Add_DEBUG_S_FUNC_MDTOKEN_MAP_Entry(methodRVAToTokenMap, debugRelocations, emitted, methodDataBlob.Size(), ref entryCount);
|
||||
|
||||
methodDataBlob.WriteDWORD(cGenericArguments << 24 | methodTokenRid);
|
||||
methodDataBlob.WriteBuffer(blobBuilder);
|
||||
}
|
||||
|
||||
// sort tokenInOffsetEntries based on tokenInOffset
|
||||
tokenInOffsetEntries.Sort();
|
||||
|
||||
foreach (EmittedMethodWithILToken emitted in tokenInOffsetEntries)
|
||||
{
|
||||
Add_DEBUG_S_FUNC_MDTOKEN_MAP_Entry(methodRVAToTokenMap, debugRelocations, emitted.EmittedMethod, emitted.IlTokenRid | 0x80000000, ref entryCount);
|
||||
}
|
||||
|
||||
methodRVAToTokenMap.SetDWORDAtBlobIndex(0, entryCount); // // Update placeholder for count of entries in map
|
||||
methodRVAToTokenMap.WriteBuffer(methodDataBlob);
|
||||
|
||||
return methodRVAToTokenMap;
|
||||
}
|
||||
|
||||
private void Add_DEBUG_S_FUNC_MDTOKEN_MAP_Entry(DebugInfoBlob methodRVAToTokenMap, List<Relocation> debugRelocations, IMethodBodyNode method, uint methodDataOrOffsetToMethodData, ref uint entryCount)
|
||||
{
|
||||
debugRelocations.Add(new Relocation(RelocType.IMAGE_REL_BASED_ADDR32NB, checked((int)methodRVAToTokenMap.Size()), method));
|
||||
methodRVAToTokenMap.WriteDWORD(0);
|
||||
methodRVAToTokenMap.WriteDWORD(methodDataOrOffsetToMethodData);
|
||||
entryCount++;
|
||||
|
||||
IMethodBodyNodeWithFuncletSymbols funcletSymbolsNode = method as IMethodBodyNodeWithFuncletSymbols;
|
||||
|
||||
if (funcletSymbolsNode != null)
|
||||
{
|
||||
foreach (ISymbolNode funclet in funcletSymbolsNode.FuncletSymbols)
|
||||
{
|
||||
debugRelocations.Add(new Relocation(RelocType.IMAGE_REL_BASED_ADDR32NB, checked((int)methodRVAToTokenMap.Size()), funclet));
|
||||
methodRVAToTokenMap.WriteDWORD(0);
|
||||
methodRVAToTokenMap.WriteDWORD(methodDataOrOffsetToMethodData);
|
||||
entryCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
// This node does not trigger generation of other nodes.
|
||||
if (relocsOnly)
|
||||
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
|
||||
if (factory.WindowsDebugData.DebugTypeRecordsSection != null)
|
||||
factory.WindowsDebugData.DebugTypeRecordsSection.Neuter();
|
||||
|
||||
List<Relocation> relocations = new List<Relocation>();
|
||||
DebugInfoBlob debugData = GetDebugMethodRVAToTokenMap(factory.WindowsDebugData.DebugPseudoAssemblySection.PseudoAssembly, factory.MetadataManager.GetCompiledMethodBodies(), out relocations);
|
||||
|
||||
return new ObjectData(debugData.ToArray(), relocations.ToArray(), 1, new ISymbolDefinitionNode[] { this });
|
||||
}
|
||||
|
||||
protected override string GetName(NodeFactory context)
|
||||
{
|
||||
return "___DebugMethodSignatureMapSection";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
using Internal.TypeSystem.TypesDebugInfo;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
public class WindowsDebugNeedTypeIndicesStoreNode : ObjectNode, ISymbolDefinitionNode
|
||||
{
|
||||
public override ObjectNodeSection Section => ObjectNodeSection.DataSection;
|
||||
|
||||
public override bool IsShareable => true;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(GetName(null));
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
if (!relocsOnly)
|
||||
{
|
||||
UserDefinedTypeDescriptor userDefinedTypeDescriptor = factory.WindowsDebugData.UserDefinedTypeDescriptor;
|
||||
if (userDefinedTypeDescriptor != null)
|
||||
{
|
||||
List<TypeDesc> typesThatNeedIndices = new List<TypeDesc>();
|
||||
foreach (TypeDesc type in factory.MetadataManager.GetTypesWithEETypes())
|
||||
{
|
||||
if (!type.IsGenericDefinition)
|
||||
{
|
||||
typesThatNeedIndices.Add(type);
|
||||
}
|
||||
}
|
||||
|
||||
typesThatNeedIndices.Sort(new TypeSystemComparer().Compare);
|
||||
|
||||
foreach (TypeDesc type in typesThatNeedIndices)
|
||||
{
|
||||
// Force creation of type descriptors for _ALL_ EETypes
|
||||
userDefinedTypeDescriptor.GetVariableTypeIndex(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// There isn't actually any data in this node. Its simply an ObjectNode as that allows this
|
||||
// function to be executed in a defined time during object emission. This does imply embedding a bit of data
|
||||
// into the object file, but the linker should be able to strip it out of the final file, and even if its in the final file
|
||||
// it won't cost significant size.
|
||||
|
||||
return new ObjectData(new byte[1], Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
}
|
||||
|
||||
protected override string GetName(NodeFactory context)
|
||||
{
|
||||
return "___DebugNeedTypeIndicesStore";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
public class WindowsDebugPseudoAssemblySection : ObjectNode, ISymbolDefinitionNode
|
||||
{
|
||||
private ManagedBinaryEmitter _pseudoAssembly;
|
||||
|
||||
public WindowsDebugPseudoAssemblySection(TypeSystemContext typeSystemContext)
|
||||
{
|
||||
_pseudoAssembly = new ManagedBinaryEmitter(typeSystemContext, "PseudoAssembly");
|
||||
}
|
||||
|
||||
private ObjectNodeSection _section = new ObjectNodeSection(".psdo-il", SectionType.ReadOnly);
|
||||
public override ObjectNodeSection Section => _section;
|
||||
|
||||
public ManagedBinaryEmitter PseudoAssembly => _pseudoAssembly;
|
||||
public override bool IsShareable => false;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(GetName(null));
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
// This node does not trigger generation of other nodes.
|
||||
if (relocsOnly)
|
||||
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
|
||||
MemoryStream memoryStream = new MemoryStream(1000000);
|
||||
_pseudoAssembly.EmitToStream(memoryStream);
|
||||
_pseudoAssembly = null;
|
||||
return new ObjectData(memoryStream.ToArray(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
}
|
||||
|
||||
protected override string GetName(NodeFactory context)
|
||||
{
|
||||
return "___DebugPseudoAssemblySection";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
using Internal.TypeSystem.TypesDebugInfo;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
internal class WindowsDebugTypeRecordsSection : ObjectNode, ISymbolDefinitionNode, ITypesDebugInfoWriter
|
||||
{
|
||||
DebugInfoWriter _dbgInfo; // Pointer to DebugInfoWriter used to write data
|
||||
DebugInfoWriter _dbgInfoWriter; // Pointer to DebugInfoWriter used to generate new entries
|
||||
NodeFactory _nodeFactory;
|
||||
|
||||
public WindowsDebugTypeRecordsSection(DebugInfoWriter dbgInfo, NodeFactory factory)
|
||||
{
|
||||
_dbgInfoWriter = _dbgInfo = dbgInfo;
|
||||
_nodeFactory = factory;
|
||||
}
|
||||
|
||||
private ObjectNodeSection _section = new ObjectNodeSection(".debug$T", SectionType.ReadOnly);
|
||||
public override ObjectNodeSection Section => _section;
|
||||
|
||||
public override bool IsShareable => false;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(GetName(null));
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
// This node does not trigger generation of other nodes.
|
||||
if (relocsOnly)
|
||||
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
|
||||
Debug.Assert(_dbgInfoWriter == null); // Type records should all be written and writing shutdown before reaching this point
|
||||
|
||||
byte[] typeRecords = _dbgInfo.GetRawBlob().ToArray();
|
||||
_dbgInfo = null; // Neuter the section so that it cannot grow any larger
|
||||
|
||||
return new ObjectData(typeRecords, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
}
|
||||
|
||||
protected override string GetName(NodeFactory context)
|
||||
{
|
||||
return "___DebugTypeRecordsSection";
|
||||
}
|
||||
|
||||
public void Neuter()
|
||||
{
|
||||
_dbgInfoWriter = null;
|
||||
}
|
||||
|
||||
uint ITypesDebugInfoWriter.GetEnumTypeIndex(EnumTypeDescriptor enumTypeDescriptor, EnumRecordTypeDescriptor[] typeRecords)
|
||||
{
|
||||
return _dbgInfoWriter.GetEnumTypeIndex(enumTypeDescriptor, typeRecords);
|
||||
}
|
||||
|
||||
uint ITypesDebugInfoWriter.GetClassTypeIndex(ClassTypeDescriptor classTypeDescriptor)
|
||||
{
|
||||
return _dbgInfoWriter.GetClassTypeIndex(classTypeDescriptor);
|
||||
}
|
||||
|
||||
uint ITypesDebugInfoWriter.GetCompleteClassTypeIndex(ClassTypeDescriptor classTypeDescriptor, ClassFieldsTypeDescriptor classFieldsTypeDescriptior, DataFieldDescriptor[] fields)
|
||||
{
|
||||
return _dbgInfoWriter.GetCompleteClassTypeIndex(classTypeDescriptor, classFieldsTypeDescriptior, fields);
|
||||
}
|
||||
|
||||
uint ITypesDebugInfoWriter.GetArrayTypeIndex(ClassTypeDescriptor classDescriptor, ArrayTypeDescriptor arrayTypeDescriptor)
|
||||
{
|
||||
return _dbgInfoWriter.GetArrayTypeIndex(classDescriptor, arrayTypeDescriptor, _nodeFactory.Target.PointerSize);
|
||||
}
|
||||
|
||||
uint ITypesDebugInfoWriter.GetPointerTypeIndex(PointerTypeDescriptor pointerDescriptor)
|
||||
{
|
||||
return _dbgInfoWriter.GetPointerTypeIndex(pointerDescriptor);
|
||||
}
|
||||
|
||||
uint ITypesDebugInfoWriter.GetMemberFunctionTypeIndex(MemberFunctionTypeDescriptor memberDescriptor, uint[] argumentTypes)
|
||||
{
|
||||
return _dbgInfoWriter.GetMemberFunctionTypeIndex(memberDescriptor, argumentTypes);
|
||||
}
|
||||
|
||||
uint ITypesDebugInfoWriter.GetMemberFunctionId(MemberFunctionIdTypeDescriptor memberIdDescriptor)
|
||||
{
|
||||
return _dbgInfoWriter.GetMemberFunctionId(memberIdDescriptor);
|
||||
}
|
||||
|
||||
string ITypesDebugInfoWriter.GetMangledName(TypeDesc type)
|
||||
{
|
||||
return _nodeFactory.NameMangler.GetMangledTypeName(type);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
using Internal.Text;
|
||||
using Internal.TypeSystem;
|
||||
using Internal.TypeSystem.TypesDebugInfo;
|
||||
|
||||
namespace ILCompiler.DependencyAnalysis
|
||||
{
|
||||
internal class WindowsDebugTypeSignatureMapSection : ObjectNode, ISymbolDefinitionNode
|
||||
{
|
||||
UserDefinedTypeDescriptor _userDefinedTypeDescriptor;
|
||||
|
||||
public WindowsDebugTypeSignatureMapSection(UserDefinedTypeDescriptor userDefinedTypeDescriptor)
|
||||
{
|
||||
_userDefinedTypeDescriptor = userDefinedTypeDescriptor;
|
||||
}
|
||||
|
||||
private ObjectNodeSection _section = new ObjectNodeSection(".dbgtypesignaturemap", SectionType.ReadOnly);
|
||||
public override ObjectNodeSection Section => _section;
|
||||
|
||||
public override bool IsShareable => false;
|
||||
|
||||
public override bool StaticDependenciesAreComputed => true;
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append(GetName(null));
|
||||
}
|
||||
|
||||
|
||||
// returns the DEBUG_S_TYPE_MDTOKEN_MAP subsection as a byte array
|
||||
// DEBUG_S_TYPE_MDTOKEN_MAP subsection contains type-index to mdToken mapping
|
||||
//
|
||||
// contents of subsection:
|
||||
// offset 0, 4 bytes: count of entries in the map
|
||||
// offset 4, 8*N bytes: 4 byte type-index + 4 byte 'offset' relative to the start of 'type data'
|
||||
// offset 4+8*N, * bytes: ECMA formatted type signature packed sequentially with no padding
|
||||
//
|
||||
// 'offset' optimization: for type signatures with size<= 4-bytes
|
||||
// we can store the signature in offset field such that
|
||||
// offset = (1 << 31) | (sig[0] << 24 | sig[1] << 16 | sig[2] << 8 | sig[3])
|
||||
// We chose this bit encoding because sig[0] holds the CorElementType whose
|
||||
// highest bit is always 0 and the highest bit of offset can be used as a flag
|
||||
// to indicate that it is not an offset but the signature itself.
|
||||
//
|
||||
// all entries are sorted by 'offset' field and so offset-based entries are arranged before other
|
||||
// (raw-signature) entries (since raw-signature entries are of the form 0x80000000 | signature, and will always be
|
||||
// numerically bigger than the offset)
|
||||
//
|
||||
private DebugInfoBlob GetDebugTypeIndexToTokenMap(ManagedBinaryEmitter pseudoAssembly, ICollection<KeyValuePair<TypeDesc, uint>> completeKnownTypes)
|
||||
{
|
||||
DebugInfoBlob typeDataBlob = new DebugInfoBlob();
|
||||
DebugInfoBlob typeIndexToTokenMapBlob = new DebugInfoBlob();
|
||||
List<KeyValuePair<uint, uint>> sigInOffsetEntries = new List<KeyValuePair<uint, uint>>();
|
||||
|
||||
typeIndexToTokenMapBlob.WriteDWORD(checked((uint)completeKnownTypes.Count));
|
||||
BlobBuilder blobBuilder = new BlobBuilder();
|
||||
foreach (var entry in completeKnownTypes)
|
||||
{
|
||||
uint typeIndex = entry.Value;
|
||||
blobBuilder.Clear();
|
||||
pseudoAssembly.EncodeSignatureForType(entry.Key, blobBuilder);
|
||||
|
||||
// if signature fits in 4-bytes, store it in sigInOffsetEntries
|
||||
// otherwise store it in the type-data blob
|
||||
if (blobBuilder.Count <= 4)
|
||||
{
|
||||
uint sigInOffset = 0x80000000;
|
||||
int i = 0;
|
||||
|
||||
// This is a slightly confusing approach, but this is how one iterates through the bytes in a blobBuilder without flattening it to a byte[]
|
||||
foreach (Blob blob in blobBuilder.GetBlobs())
|
||||
{
|
||||
foreach (byte b in blob.GetBytes())
|
||||
{
|
||||
sigInOffset |= ((uint)b) << (8 * (3 - i));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// sigInOffsetEntries will be later sorted and appended to typeIndexToTokenMapBlob
|
||||
sigInOffsetEntries.Add(new KeyValuePair<uint, uint>(typeIndex, sigInOffset));
|
||||
}
|
||||
else
|
||||
{
|
||||
typeIndexToTokenMapBlob.WriteDWORD(typeIndex);
|
||||
typeIndexToTokenMapBlob.WriteDWORD(typeDataBlob.Size());
|
||||
typeDataBlob.WriteBuffer(blobBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
// sort sigInOffsetEntries based on sigInOffset
|
||||
sigInOffsetEntries.Sort((KeyValuePair<uint, uint> left, KeyValuePair<uint, uint> right) =>
|
||||
{
|
||||
if (left.Value < right.Value)
|
||||
return -1;
|
||||
if (left.Value == right.Value)
|
||||
return 0;
|
||||
return 1;
|
||||
});
|
||||
|
||||
// write the sorted sigInOffsetEntries
|
||||
foreach (KeyValuePair<uint, uint> sigInOffsetEntry in sigInOffsetEntries)
|
||||
{
|
||||
typeIndexToTokenMapBlob.WriteDWORD(sigInOffsetEntry.Key);
|
||||
typeIndexToTokenMapBlob.WriteDWORD(sigInOffsetEntry.Value);
|
||||
}
|
||||
|
||||
// add typeDataBlob to the end of m_typeIndexToTokenMapBlob
|
||||
typeIndexToTokenMapBlob.WriteBuffer(typeDataBlob.ToArray());
|
||||
|
||||
return typeIndexToTokenMapBlob;
|
||||
}
|
||||
|
||||
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
|
||||
{
|
||||
// This node does not trigger generation of other nodes.
|
||||
if (relocsOnly)
|
||||
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
|
||||
if (factory.WindowsDebugData.DebugTypeRecordsSection != null)
|
||||
factory.WindowsDebugData.DebugTypeRecordsSection.Neuter();
|
||||
|
||||
DebugInfoBlob debugData = GetDebugTypeIndexToTokenMap(factory.WindowsDebugData.DebugPseudoAssemblySection.PseudoAssembly, factory.WindowsDebugData.UserDefinedTypeDescriptor.CompleteKnownTypes);
|
||||
|
||||
return new ObjectData(debugData.ToArray(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
|
||||
}
|
||||
|
||||
protected override string GetName(NodeFactory context)
|
||||
{
|
||||
return "___DebugTypeSignatureMapSection";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,527 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Collections.Immutable;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Internal.TypeSystem;
|
||||
using Internal.TypeSystem.Ecma;
|
||||
using ILCompiler.DependencyAnalysis;
|
||||
|
||||
namespace ILCompiler
|
||||
{
|
||||
public class ManagedBinaryEmitter
|
||||
{
|
||||
public class EmittedTypeDefinition
|
||||
{
|
||||
private readonly ManagedBinaryEmitter _managedEmitter;
|
||||
private List<EmittedMethodDefinition> _methods = new List<EmittedMethodDefinition>();
|
||||
|
||||
public string Name { get; private set; }
|
||||
public bool IsValueType { get; private set; }
|
||||
public IReadOnlyList<EmittedMethodDefinition> Methods => _methods;
|
||||
|
||||
internal EmittedTypeDefinition(string name, bool isValueType, ManagedBinaryEmitter managedEmitter)
|
||||
{
|
||||
Name = name;
|
||||
IsValueType = isValueType;
|
||||
_managedEmitter = managedEmitter;
|
||||
}
|
||||
|
||||
public EmittedMethodDefinition EmitMethodDefinition(string name, MethodSignature signature)
|
||||
{
|
||||
var newMethodDef = new EmittedMethodDefinition(name, signature, _managedEmitter);
|
||||
_methods.Add(newMethodDef);
|
||||
return newMethodDef;
|
||||
}
|
||||
}
|
||||
public class EmittedMethodDefinition
|
||||
{
|
||||
private readonly ManagedBinaryEmitter _managedEmitter;
|
||||
|
||||
public string Name { get; private set; }
|
||||
public MethodSignature Signature { get; private set; }
|
||||
public InstructionEncoder Code { get; private set; }
|
||||
|
||||
internal EmittedMethodDefinition(string name, MethodSignature signature, ManagedBinaryEmitter managedEmitter)
|
||||
{
|
||||
Name = name;
|
||||
Signature = signature;
|
||||
_managedEmitter = managedEmitter;
|
||||
Code = new InstructionEncoder(new BlobBuilder());
|
||||
}
|
||||
}
|
||||
|
||||
private readonly TypeSystemContext _typeSystemContext;
|
||||
|
||||
private MetadataBuilder _metadataBuilder;
|
||||
private MethodBodyStreamEncoder _methodBodyStream;
|
||||
private List<EmittedTypeDefinition> _emittedTypes;
|
||||
|
||||
protected MetadataBuilder Builder => _metadataBuilder;
|
||||
|
||||
public ManagedBinaryEmitter(TypeSystemContext typeSystemContext, string assemblyName)
|
||||
{
|
||||
_typeSystemContext = typeSystemContext;
|
||||
|
||||
_metadataBuilder = new MetadataBuilder();
|
||||
_methodBodyStream = new MethodBodyStreamEncoder(new BlobBuilder());
|
||||
_emittedTypes = new List<EmittedTypeDefinition>();
|
||||
|
||||
_metadataBuilder.AddAssembly(
|
||||
_metadataBuilder.GetOrAddString(assemblyName),
|
||||
new Version(0, 0, 0, 0),
|
||||
culture: default(StringHandle),
|
||||
publicKey: default(BlobHandle),
|
||||
flags: default(AssemblyFlags),
|
||||
hashAlgorithm: AssemblyHashAlgorithm.None);
|
||||
|
||||
// Module type
|
||||
_metadataBuilder.AddTypeDefinition(
|
||||
default(TypeAttributes),
|
||||
default(StringHandle),
|
||||
_metadataBuilder.GetOrAddString("<Module>"),
|
||||
baseType: default(EntityHandle),
|
||||
fieldList: MetadataTokens.FieldDefinitionHandle(1),
|
||||
methodList: MetadataTokens.MethodDefinitionHandle(1));
|
||||
|
||||
}
|
||||
|
||||
public EmittedTypeDefinition EmitTypeDefinition(string typeName, bool isValueType)
|
||||
{
|
||||
EmittedTypeDefinition newTypeDef = new EmittedTypeDefinition(typeName, isValueType, this);
|
||||
_emittedTypes.Add(newTypeDef);
|
||||
return newTypeDef;
|
||||
}
|
||||
|
||||
public EntityHandle EmitMetadataHandleForTypeSystemEntity(TypeSystemEntity entity)
|
||||
{
|
||||
switch (entity)
|
||||
{
|
||||
case FieldDesc field: return MakeMemberReferenceHandle(field);
|
||||
case MethodDesc method: return MakeMemberReferenceHandle(method);
|
||||
case TypeDesc type: return MakeTypeRefOrSpecHandle(type);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public BlobHandle EmitSignatureBlobForMethodSignature(MethodSignature signature)
|
||||
{
|
||||
return MakeSignatureHandle(signature);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode a type signature into a specified blob.
|
||||
/// </summary>
|
||||
/// <param name="blobBuilder">Blob to encode type signature into. Must not be null</param>
|
||||
public void EncodeSignatureForType(TypeDesc type, BlobBuilder blobBuilder)
|
||||
{
|
||||
SignatureTypeEncoder sigEncoder = new SignatureTypeEncoder(blobBuilder);
|
||||
EncodeTypeSignature(sigEncoder, type);
|
||||
}
|
||||
|
||||
public void EmitOutputFile(string outputPath)
|
||||
{
|
||||
using (FileStream sw = new FileStream(outputPath, FileMode.Create, FileAccess.ReadWrite))
|
||||
{
|
||||
EmitToStream(sw);
|
||||
}
|
||||
}
|
||||
|
||||
public void EmitToStream(Stream stream)
|
||||
{
|
||||
foreach (var typeDef in _emittedTypes)
|
||||
{
|
||||
MethodDefinitionHandle? firstMethodHandle = null;
|
||||
|
||||
foreach (var methodDef in typeDef.Methods)
|
||||
{
|
||||
int bodyOffset = _methodBodyStream.AddMethodBody(methodDef.Code);
|
||||
|
||||
BlobHandle signature = MakeSignatureHandle(methodDef.Signature);
|
||||
|
||||
MethodDefinitionHandle methodHandle = _metadataBuilder.AddMethodDefinition(
|
||||
MethodAttributes.PrivateScope | MethodAttributes.Static,
|
||||
MethodImplAttributes.IL | MethodImplAttributes.Managed,
|
||||
_metadataBuilder.GetOrAddString(methodDef.Name),
|
||||
signature,
|
||||
bodyOffset,
|
||||
parameterList: default(ParameterHandle));
|
||||
|
||||
if (firstMethodHandle == null)
|
||||
firstMethodHandle = methodHandle;
|
||||
}
|
||||
|
||||
_metadataBuilder.AddTypeDefinition(
|
||||
default(TypeAttributes),
|
||||
default(StringHandle),
|
||||
_metadataBuilder.GetOrAddString(typeDef.Name),
|
||||
typeDef.IsValueType ?
|
||||
MakeTypeRefHandle(_typeSystemContext.GetWellKnownType(WellKnownType.ValueType)) :
|
||||
MakeTypeRefHandle(_typeSystemContext.GetWellKnownType(WellKnownType.Object)),
|
||||
fieldList: MetadataTokens.FieldDefinitionHandle(1),
|
||||
methodList: firstMethodHandle.Value);
|
||||
}
|
||||
|
||||
BlobBuilder peBlob = new BlobBuilder();
|
||||
new ManagedPEBuilder(PEHeaderBuilder.CreateLibraryHeader(), new MetadataRootBuilder(_metadataBuilder), _methodBodyStream.Builder).Serialize(peBlob);
|
||||
|
||||
peBlob.WriteContentTo(stream);
|
||||
|
||||
// Clear some variables to catch any caller trying to emit data after writing the output file
|
||||
_emittedTypes = null;
|
||||
_metadataBuilder = null;
|
||||
_methodBodyStream = default(MethodBodyStreamEncoder);
|
||||
}
|
||||
|
||||
#region TypeSystem Entities To Handle Encoders
|
||||
private Dictionary<EcmaAssembly, AssemblyReferenceHandle> _assemblyRefHandles = new Dictionary<EcmaAssembly, AssemblyReferenceHandle>();
|
||||
private Dictionary<TypeDesc, EntityHandle> _typeRefOrSpecHandles = new Dictionary<TypeDesc, EntityHandle>();
|
||||
private Dictionary<TypeSystemEntity, EntityHandle> _memberRefOrSpecHandles = new Dictionary<TypeSystemEntity, EntityHandle>();
|
||||
private Dictionary<MethodSignature, BlobHandle> _methodSignatureHandles = new Dictionary<MethodSignature, BlobHandle>();
|
||||
private Dictionary<FieldDesc, BlobHandle> _fieldSignatureHandles = new Dictionary<FieldDesc, BlobHandle>();
|
||||
|
||||
private void EncodeTypeSignature(SignatureTypeEncoder encoder, TypeDesc type)
|
||||
{
|
||||
if (type is RuntimeDeterminedType)
|
||||
{
|
||||
EncodeTypeSignature(encoder, ((RuntimeDeterminedType)type).RuntimeDeterminedDetailsType);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type.Category)
|
||||
{
|
||||
case TypeFlags.Boolean:
|
||||
encoder.Boolean(); break;
|
||||
case TypeFlags.Byte:
|
||||
encoder.Byte(); break;
|
||||
case TypeFlags.SByte:
|
||||
encoder.SByte(); break;
|
||||
case TypeFlags.Char:
|
||||
encoder.Char(); break;
|
||||
case TypeFlags.Int16:
|
||||
encoder.Int16(); break;
|
||||
case TypeFlags.UInt16:
|
||||
encoder.UInt16(); break;
|
||||
case TypeFlags.Int32:
|
||||
encoder.Int32(); break;
|
||||
case TypeFlags.UInt32:
|
||||
encoder.UInt32(); break;
|
||||
case TypeFlags.Int64:
|
||||
encoder.Int64(); break;
|
||||
case TypeFlags.UInt64:
|
||||
encoder.UInt64(); break;
|
||||
case TypeFlags.Single:
|
||||
encoder.Single(); break;
|
||||
case TypeFlags.Double:
|
||||
encoder.Double(); break;
|
||||
case TypeFlags.IntPtr:
|
||||
encoder.IntPtr(); break;
|
||||
case TypeFlags.UIntPtr:
|
||||
encoder.UIntPtr(); break;
|
||||
case TypeFlags.Void:
|
||||
encoder.Builder.WriteByte((byte)PrimitiveTypeCode.Void);
|
||||
break;
|
||||
|
||||
case TypeFlags.SignatureTypeVariable:
|
||||
encoder.GenericTypeParameter(((SignatureVariable)type).Index);
|
||||
break;
|
||||
|
||||
case TypeFlags.SignatureMethodVariable:
|
||||
encoder.GenericMethodTypeParameter(((SignatureMethodVariable)type).Index);
|
||||
break;
|
||||
|
||||
case TypeFlags.GenericParameter:
|
||||
{
|
||||
var genericTypeDesc = (GenericParameterDesc)type;
|
||||
if (genericTypeDesc.Kind == GenericParameterKind.Type)
|
||||
encoder.GenericTypeParameter(genericTypeDesc.Index);
|
||||
else
|
||||
encoder.GenericMethodTypeParameter(genericTypeDesc.Index);
|
||||
}
|
||||
break;
|
||||
|
||||
case TypeFlags.FunctionPointer:
|
||||
{
|
||||
FunctionPointerType fptrType = (FunctionPointerType)type;
|
||||
encoder.FunctionPointer(
|
||||
SignatureCallingConvention.Default,
|
||||
fptrType.Signature.IsStatic ? default(FunctionPointerAttributes) : FunctionPointerAttributes.HasThis,
|
||||
fptrType.Signature.GenericParameterCount);
|
||||
|
||||
// Return Type Sig
|
||||
EncodeTypeSignature(encoder, fptrType.Signature.ReturnType);
|
||||
|
||||
// Parameter Types Sig
|
||||
for (int i = 0; i < fptrType.Signature.Length; i++)
|
||||
EncodeTypeSignature(encoder, fptrType.Signature[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case TypeFlags.Array:
|
||||
{
|
||||
// Skip bounds and lobounds (TODO)
|
||||
ImmutableArray<int> bounds = ImmutableArray.Create<int>();
|
||||
ImmutableArray<int> lowerBounds = ImmutableArray.Create<int>();
|
||||
encoder.Array(
|
||||
elementType => EncodeTypeSignature(elementType, ((ArrayType)type).ElementType),
|
||||
arrayShape => arrayShape.Shape(((ArrayType)type).Rank, bounds, lowerBounds));
|
||||
}
|
||||
break;
|
||||
|
||||
case TypeFlags.SzArray:
|
||||
encoder.SZArray();
|
||||
EncodeTypeSignature(encoder, ((ParameterizedType)type).ParameterType);
|
||||
break;
|
||||
|
||||
case TypeFlags.ByRef:
|
||||
encoder.Builder.WriteByte((byte)SignatureTypeCode.ByReference);
|
||||
EncodeTypeSignature(encoder, ((ParameterizedType)type).ParameterType);
|
||||
break;
|
||||
|
||||
case TypeFlags.Pointer:
|
||||
encoder.Builder.WriteByte((byte)SignatureTypeCode.Pointer);
|
||||
EncodeTypeSignature(encoder, ((ParameterizedType)type).ParameterType);
|
||||
break;
|
||||
|
||||
case TypeFlags.Enum:
|
||||
case TypeFlags.Class:
|
||||
case TypeFlags.ValueType:
|
||||
case TypeFlags.Interface:
|
||||
case TypeFlags.Nullable:
|
||||
{
|
||||
if (type == _typeSystemContext.GetWellKnownType(WellKnownType.TypedReference))
|
||||
encoder.Builder.WriteByte((byte)PrimitiveTypeCode.TypedReference);
|
||||
else if (type == _typeSystemContext.GetWellKnownType(WellKnownType.Object))
|
||||
encoder.PrimitiveType(PrimitiveTypeCode.Object);
|
||||
else if (type == _typeSystemContext.GetWellKnownType(WellKnownType.String))
|
||||
encoder.PrimitiveType(PrimitiveTypeCode.String);
|
||||
else if (type.HasInstantiation && !type.IsGenericDefinition)
|
||||
{
|
||||
encoder.GenericInstantiation(MakeTypeRefOrSpecHandle(type.GetTypeDefinition()), type.Instantiation.Length, type.IsValueType);
|
||||
|
||||
for (int i = 0; i < type.Instantiation.Length; i++)
|
||||
EncodeTypeSignature(encoder, type.Instantiation[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder.Type(MakeTypeRefHandle(type), type.IsValueType);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Attempting to encode an invalid type signature.");
|
||||
}
|
||||
}
|
||||
|
||||
private BlobHandle MakeSignatureHandle(MethodSignature signature)
|
||||
{
|
||||
BlobHandle handle;
|
||||
|
||||
if (!_methodSignatureHandles.TryGetValue(signature, out handle))
|
||||
{
|
||||
BlobBuilder metadataSignature = new BlobBuilder();
|
||||
|
||||
MethodSignatureEncoder methodSigEncoder = new BlobEncoder(metadataSignature).MethodSignature(
|
||||
SignatureCallingConvention.Default, signature.GenericParameterCount, !signature.IsStatic);
|
||||
|
||||
ReturnTypeEncoder returnTypeEncoder;
|
||||
ParametersEncoder parametersEncoder;
|
||||
methodSigEncoder.Parameters(signature.Length, out returnTypeEncoder, out parametersEncoder);
|
||||
|
||||
// Return Type Sig
|
||||
EncodeTypeSignature(returnTypeEncoder.Type(), signature.ReturnType);
|
||||
|
||||
// Parameter Types Sig
|
||||
for (int i = 0; i < signature.Length; i++)
|
||||
EncodeTypeSignature(parametersEncoder.AddParameter().Type(), signature[i]);
|
||||
|
||||
_methodSignatureHandles[signature] = handle = _metadataBuilder.GetOrAddBlob(metadataSignature);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
private BlobHandle MakeSignatureHandle(TypeSystemEntity methodOrField)
|
||||
{
|
||||
if (methodOrField is MethodDesc)
|
||||
{
|
||||
return MakeSignatureHandle(((MethodDesc)methodOrField).Signature);
|
||||
}
|
||||
else
|
||||
{
|
||||
BlobHandle handle;
|
||||
FieldDesc field = (FieldDesc)methodOrField;
|
||||
|
||||
if (!_fieldSignatureHandles.TryGetValue(field, out handle))
|
||||
{
|
||||
BlobBuilder metadataSignature = new BlobBuilder();
|
||||
|
||||
SignatureTypeEncoder fieldSigEncoder = new BlobEncoder(metadataSignature).FieldSignature();
|
||||
EncodeTypeSignature(fieldSigEncoder, field.FieldType);
|
||||
|
||||
_fieldSignatureHandles[field] = handle = _metadataBuilder.GetOrAddBlob(metadataSignature);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
private AssemblyReferenceHandle MakeAssemblyReferenceHandle(EcmaAssembly assemblyRef)
|
||||
{
|
||||
AssemblyReferenceHandle handle;
|
||||
|
||||
if (!_assemblyRefHandles.TryGetValue(assemblyRef, out handle))
|
||||
{
|
||||
AssemblyName assemblyName = assemblyRef.GetName();
|
||||
|
||||
handle = _metadataBuilder.AddAssemblyReference(
|
||||
_metadataBuilder.GetOrAddString(assemblyName.Name),
|
||||
assemblyName.Version,
|
||||
default(StringHandle),
|
||||
_metadataBuilder.GetOrAddBlob(ImmutableArray.Create<byte>(assemblyName.GetPublicKeyToken())),
|
||||
default(AssemblyFlags),
|
||||
default(BlobHandle));
|
||||
|
||||
_assemblyRefHandles[assemblyRef] = handle;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
private AssemblyReferenceHandle MakeCorlibAssemblyReferenceHandle()
|
||||
{
|
||||
return MakeAssemblyReferenceHandle((EcmaAssembly)_typeSystemContext.SystemModule);
|
||||
}
|
||||
|
||||
private EntityHandle MakeTypeRefHandle(TypeDesc type)
|
||||
{
|
||||
Debug.Assert(type.IsTypeDefinition);
|
||||
Debug.Assert((type is EcmaType) || _typeSystemContext.IsCanonicalDefinitionType(type, CanonicalFormKind.Any));
|
||||
|
||||
EntityHandle handle;
|
||||
|
||||
if (!_typeRefOrSpecHandles.TryGetValue(type, out handle))
|
||||
{
|
||||
if (_typeSystemContext.IsCanonicalDefinitionType(type, CanonicalFormKind.Any))
|
||||
{
|
||||
CanonBaseType canonType = (CanonBaseType)type;
|
||||
|
||||
handle = _metadataBuilder.AddTypeReference(
|
||||
MakeCorlibAssemblyReferenceHandle(),
|
||||
_metadataBuilder.GetOrAddString(canonType.Namespace),
|
||||
_metadataBuilder.GetOrAddString(canonType.Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityHandle scope;
|
||||
EcmaType typeAsEcmaType = (EcmaType)type;
|
||||
|
||||
if (typeAsEcmaType.ContainingType != null)
|
||||
scope = MakeTypeRefHandle(typeAsEcmaType.ContainingType);
|
||||
else
|
||||
scope = MakeAssemblyReferenceHandle((EcmaAssembly)typeAsEcmaType.EcmaModule);
|
||||
|
||||
handle = _metadataBuilder.AddTypeReference(
|
||||
scope,
|
||||
_metadataBuilder.GetOrAddString(typeAsEcmaType.Namespace),
|
||||
_metadataBuilder.GetOrAddString(typeAsEcmaType.Name));
|
||||
}
|
||||
|
||||
_typeRefOrSpecHandles[type] = handle;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
private EntityHandle MakeTypeRefOrSpecHandle(TypeDesc type)
|
||||
{
|
||||
EntityHandle handle;
|
||||
|
||||
if (!_typeRefOrSpecHandles.TryGetValue(type, out handle))
|
||||
{
|
||||
if(!type.IsDefType || !type.IsTypeDefinition || type is RuntimeDeterminedType)
|
||||
{
|
||||
SignatureTypeEncoder sigEncoder = new SignatureTypeEncoder(new BlobBuilder());
|
||||
EncodeTypeSignature(sigEncoder, type);
|
||||
handle = _metadataBuilder.AddTypeSpecification(_metadataBuilder.GetOrAddBlob(sigEncoder.Builder));
|
||||
}
|
||||
else
|
||||
{
|
||||
handle = MakeTypeRefHandle(type);
|
||||
}
|
||||
|
||||
_typeRefOrSpecHandles[type] = handle;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
private EntityHandle MakeMemberReferenceHandle(TypeSystemEntity methodOrField)
|
||||
{
|
||||
EntityHandle handle;
|
||||
|
||||
if (!_memberRefOrSpecHandles.TryGetValue(methodOrField, out handle))
|
||||
{
|
||||
MethodDesc method = methodOrField as MethodDesc;
|
||||
FieldDesc field = methodOrField as FieldDesc;
|
||||
TypeDesc owningType = (method != null ? method.OwningType : field.OwningType);
|
||||
string name = (method != null ? method.Name : field.Name);
|
||||
|
||||
BlobHandle signature = method != null ?
|
||||
MakeSignatureHandle(method.GetTypicalMethodDefinition()) :
|
||||
MakeSignatureHandle(field);
|
||||
|
||||
handle = _metadataBuilder.AddMemberReference(
|
||||
MakeTypeRefOrSpecHandle(owningType),
|
||||
_metadataBuilder.GetOrAddString(name),
|
||||
signature);
|
||||
|
||||
if (method != null && method.HasInstantiation && !method.IsTypicalMethodDefinition)
|
||||
{
|
||||
BlobEncoder methodSpecEncoder = new BlobEncoder(new BlobBuilder());
|
||||
|
||||
GenericTypeArgumentsEncoder argEncoder = methodSpecEncoder.MethodSpecificationSignature(method.Instantiation.Length);
|
||||
for (int i = 0; i < method.Instantiation.Length; i++)
|
||||
{
|
||||
SignatureTypeEncoder argTypeEncoder = argEncoder.AddArgument();
|
||||
EncodeTypeSignature(argTypeEncoder, method.Instantiation[i]);
|
||||
}
|
||||
|
||||
handle = _metadataBuilder.AddMethodSpecification(handle, _metadataBuilder.GetOrAddBlob(methodSpecEncoder.Builder));
|
||||
}
|
||||
|
||||
_memberRefOrSpecHandles[methodOrField] = handle;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static class InstructionEncoderExtensions
|
||||
{
|
||||
public static void EmitLdToken(this InstructionEncoder code, TypeSystemEntity typeSystemEntity, ManagedBinaryEmitter emitter)
|
||||
{
|
||||
code.OpCode(ILOpCode.Ldtoken);
|
||||
code.Token(emitter.EmitMetadataHandleForTypeSystemEntity(typeSystemEntity));
|
||||
}
|
||||
public static void EmitI4Constant(this InstructionEncoder code, int value)
|
||||
{
|
||||
code.OpCode(ILOpCode.Ldc_i4);
|
||||
code.CodeBuilder.WriteInt32(value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
using Internal.TypeSystem.Ecma;
|
||||
using Internal.TypeSystem.TypesDebugInfo;
|
||||
|
||||
namespace ILCompiler
|
||||
{
|
||||
public class MergedAssemblyRecord
|
||||
{
|
||||
public EcmaAssembly Assembly { get; }
|
||||
public string Name { get; }
|
||||
public uint AssemblyIndex { get; }
|
||||
public uint Timestamp { get; }
|
||||
public bool HasPDB { get; }
|
||||
public byte[] PublicKey { get; }
|
||||
public byte[] VersionInfo { get; }
|
||||
public int VersionInfoLength
|
||||
{
|
||||
get
|
||||
{
|
||||
return BitConverter.ToUInt16(VersionInfo, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public MergedAssemblyRecord(EcmaAssembly assembly, string name, uint assemblyIndex, uint timestamp, bool hasPDB, byte[] publicKey, byte[] versionInfo)
|
||||
{
|
||||
Assembly = assembly;
|
||||
Name = name;
|
||||
AssemblyIndex = assemblyIndex;
|
||||
Timestamp = timestamp;
|
||||
HasPDB = hasPDB;
|
||||
PublicKey = publicKey;
|
||||
VersionInfo = versionInfo;
|
||||
|
||||
if (versionInfo.Length < sizeof(ushort))
|
||||
throw new ArgumentException("versionInfo");
|
||||
|
||||
int versionInfoLength = VersionInfoLength;
|
||||
if (versionInfoLength == 0)
|
||||
{
|
||||
VersionInfo = BitConverter.GetBytes((ushort)sizeof(ushort));
|
||||
Debug.Assert(VersionInfoLength == sizeof(ushort));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Validate that a non-empty version info contains a VS_VERSION_INFO structure
|
||||
string vsVersionInfoString = "VS_VERSION_INFO";
|
||||
|
||||
if (VersionInfoLength < (6 + vsVersionInfoString.Length * sizeof(char)))
|
||||
throw new ArgumentException("versionInfo");
|
||||
|
||||
string encodedString = Encoding.Unicode.GetString(versionInfo, 6, vsVersionInfoString.Length * sizeof(char));
|
||||
if (encodedString != vsVersionInfoString)
|
||||
throw new ArgumentException("versionInfo");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal void Encode(DebugInfoBlob blob)
|
||||
{
|
||||
blob.WriteDWORD(Timestamp);
|
||||
blob.WriteDWORD(AssemblyIndex & 0x7FFFFFFF | (HasPDB ? 0x80000000 : 0));
|
||||
blob.WriteBuffer(VersionInfo, 0, VersionInfoLength);
|
||||
|
||||
string nameWithPublicKey = Name;
|
||||
if (PublicKey != null && PublicKey.Length > 0)
|
||||
{
|
||||
nameWithPublicKey += ", PublicKey=";
|
||||
nameWithPublicKey += BitConverter.ToString(PublicKey).Replace("-", "");
|
||||
}
|
||||
blob.WriteString(nameWithPublicKey);
|
||||
blob.AlignToDWORD();
|
||||
}
|
||||
}
|
||||
|
||||
public class MergedAssemblyRecords
|
||||
{
|
||||
public IReadOnlyCollection<MergedAssemblyRecord> MergedAssemblies { get; }
|
||||
|
||||
public MergedAssemblyRecords(IReadOnlyCollection<MergedAssemblyRecord> mergedAssemblies)
|
||||
{
|
||||
MergedAssemblies = mergedAssemblies;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -42,6 +42,7 @@ namespace ILCompiler
|
|||
private HashSet<TypeDesc> _typesWithConstructedEETypesGenerated = new HashSet<TypeDesc>();
|
||||
private HashSet<MethodDesc> _methodsGenerated = new HashSet<MethodDesc>();
|
||||
private HashSet<GenericDictionaryNode> _genericDictionariesGenerated = new HashSet<GenericDictionaryNode>();
|
||||
private HashSet<IMethodBodyNode> _methodBodiesGenerated = new HashSet<IMethodBodyNode>();
|
||||
private List<ModuleDesc> _modulesWithMetadata = new List<ModuleDesc>();
|
||||
private List<TypeGVMEntriesNode> _typeGVMEntries = new List<TypeGVMEntriesNode>();
|
||||
|
||||
|
@ -155,6 +156,12 @@ namespace ILCompiler
|
|||
return;
|
||||
}
|
||||
|
||||
IMethodBodyNode methodBodyNode = obj as IMethodBodyNode;
|
||||
if (methodBodyNode != null)
|
||||
{
|
||||
_methodBodiesGenerated.Add(methodBodyNode);
|
||||
}
|
||||
|
||||
IMethodNode methodNode = obj as MethodCodeNode;
|
||||
if (methodNode == null)
|
||||
methodNode = obj as ShadowConcreteMethodNode;
|
||||
|
@ -548,7 +555,7 @@ namespace ILCompiler
|
|||
return _typeGVMEntries;
|
||||
}
|
||||
|
||||
internal IEnumerable<GenericDictionaryNode> GetCompiledGenericDictionaries()
|
||||
internal IReadOnlyCollection<GenericDictionaryNode> GetCompiledGenericDictionaries()
|
||||
{
|
||||
return _genericDictionariesGenerated;
|
||||
}
|
||||
|
@ -558,6 +565,11 @@ namespace ILCompiler
|
|||
return _methodsGenerated;
|
||||
}
|
||||
|
||||
internal IEnumerable<IMethodBodyNode> GetCompiledMethodBodies()
|
||||
{
|
||||
return _methodBodiesGenerated;
|
||||
}
|
||||
|
||||
internal bool TypeGeneratesEEType(TypeDesc type)
|
||||
{
|
||||
return _typesWithEETypesGenerated.Contains(type);
|
||||
|
|
|
@ -410,6 +410,17 @@ namespace ILCompiler
|
|||
return MetadataCategory.RuntimeMapping;
|
||||
}
|
||||
|
||||
private bool IsMethodSupportedInPrecomputedReflection(MethodDesc method)
|
||||
{
|
||||
if (!IsMethodSupportedInReflectionInvoke(method))
|
||||
return false;
|
||||
|
||||
MethodDesc typicalInvokeTarget = method.GetTypicalMethodDefinition();
|
||||
MethodDesc typicalDynamicInvokeStub;
|
||||
|
||||
return _dynamicInvokeStubs.Value.TryGetValue(typicalInvokeTarget, out typicalDynamicInvokeStub);
|
||||
}
|
||||
|
||||
void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider)
|
||||
{
|
||||
MetadataLoadedInfo loadedMetadata = _loadedMetadata.Value;
|
||||
|
@ -421,6 +432,9 @@ namespace ILCompiler
|
|||
if (method.HasInstantiation || method.OwningType.HasInstantiation)
|
||||
continue;
|
||||
|
||||
if (!IsMethodSupportedInPrecomputedReflection(method))
|
||||
continue;
|
||||
|
||||
if (method.IsVirtual)
|
||||
rootProvider.RootVirtualMethodForReflection(method, "Reflection root");
|
||||
else
|
||||
|
@ -438,6 +452,9 @@ namespace ILCompiler
|
|||
// Virtual methods need special handling (e.g. with dependency tracking) since they can be abstract.
|
||||
foreach (var method in loadedMetadata.RequiredGenericMethods)
|
||||
{
|
||||
if (!IsMethodSupportedInPrecomputedReflection(method))
|
||||
continue;
|
||||
|
||||
if (method.IsVirtual)
|
||||
rootProvider.RootVirtualMethodForReflection(method, "Required generic method");
|
||||
else
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" Condition="'$(IsProjectNLibrary)' != 'true'" />
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
|
@ -95,10 +95,20 @@
|
|||
<Compile Include="Compiler\CompilerTypeSystemContext.Mangling.cs" />
|
||||
<Compile Include="Compiler\CompilerTypeSystemContext.Sorting.cs" />
|
||||
<Compile Include="Compiler\CompilerGeneratedInteropStubManager .cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugILImagesSection.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugManagedNativeDictionaryInfoSection.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugMergedAssemblyRecordsSection.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugMethodMapSection.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugNeedTypeIndicesStoreNode.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugPseudoAssemblySection.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugTypeRecordsSection.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\WindowsDebugTypeSignatureMapSection.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\CustomAttributeBasedDependencyAlgorithm.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\FieldMetadataNode.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\ILScanNodeFactory.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\IMethodBodyNode.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\IMethodBodyNodeWithFuncletSymbols.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\ISymbolNodeWithFuncletId.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\LoopHijackFlagNode.cs" />
|
||||
<Compile Include="Compiler\DictionaryLayoutProvider.cs" />
|
||||
<Compile Include="Compiler\EmptyInteropStubManager.cs" />
|
||||
|
@ -222,6 +232,7 @@
|
|||
<Compile Include="Compiler\DependencyAnalysis\NodeFactory.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\NodeFactory.GenericLookups.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\NodeFactory.NativeLayout.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\NodeFactory.WindowsDebugData.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\NonGCStaticsNode.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\ObjectAndOffsetSymbolNode.cs" />
|
||||
<Compile Include="Compiler\DependencyAnalysis\ObjectDataBuilder.cs" />
|
||||
|
@ -269,8 +280,10 @@
|
|||
<Compile Include="Compiler\LazyGenericsPolicy.cs" />
|
||||
<Compile Include="Compiler\LibraryRootProvider.cs" />
|
||||
<Compile Include="Compiler\MainMethodRootProvider.cs" />
|
||||
<Compile Include="Compiler\ManagedBinaryEmitter.cs" />
|
||||
<Compile Include="Compiler\MemoryHelper.cs" />
|
||||
<Compile Include="Compiler\CompilerGeneratedMetadataManager.cs" />
|
||||
<Compile Include="Compiler\MergedAssemblyRecords.cs" />
|
||||
<Compile Include="Compiler\MetadataManager.cs" />
|
||||
<Compile Include="Compiler\InteropStubManager.cs" />
|
||||
<Compile Include="Compiler\MethodExtensions.cs" />
|
||||
|
@ -356,6 +369,9 @@
|
|||
<Compile Include="..\..\Common\src\TypeSystem\TypesDebugInfoWriter\TypesDebugInfoWriter.cs">
|
||||
<Link>TypeSystem\TypesDebugInfoWriter\TypesDebugInfoWriter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\Common\src\TypeSystem\TypesDebugInfoWriter\DebugInfoWriter.cs">
|
||||
<Link>TypeSystem\TypesDebugInfoWriter\DebugInfoWriter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\Common\src\TypeSystem\TypesDebugInfoWriter\UserDefinedTypeDescriptor.cs">
|
||||
<Link>TypeSystem\TypesDebugInfoWriter\UserDefinedTypeDescriptor.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -241,6 +241,15 @@ typedef DPTR(uint32_t) PTR_uint32_t;
|
|||
|
||||
enum CLRDataEnumMemoryFlags : int;
|
||||
|
||||
enum ThreadType
|
||||
{
|
||||
ThreadType_GC = 137,
|
||||
};
|
||||
|
||||
#undef ClrFlsSetThreadType
|
||||
#define ClrFlsSetThreadType(threadType) SetGCSpecialThread(threadType)
|
||||
void SetGCSpecialThread(ThreadType threadType);
|
||||
|
||||
#if defined(ENABLE_PERF_COUNTERS) || defined(FEATURE_EVENT_TRACE)
|
||||
// Note this is not updated in a thread safe way so the value may not be accurate. We get
|
||||
// it accurately in full GCs if the handle count is requested.
|
||||
|
|
|
@ -1259,11 +1259,13 @@ gc_alloc_context * Thread::GetAllocContext()
|
|||
return dac_cast<DPTR(gc_alloc_context)>(dac_cast<TADDR>(this) + offsetof(Thread, m_rgbAllocContextBuffer));
|
||||
}
|
||||
|
||||
#ifndef DACCESS_COMPILE
|
||||
bool IsGCSpecialThread()
|
||||
{
|
||||
// TODO: Implement for background GC
|
||||
return false;
|
||||
return ThreadStore::GetCurrentThread()->IsGCSpecial();
|
||||
}
|
||||
#endif // DACCESS_COMPILE
|
||||
|
||||
GPTR_IMPL(Thread, g_pFinalizerThread);
|
||||
GPTR_IMPL(Thread, g_pGcThread);
|
||||
|
@ -1280,15 +1282,23 @@ bool __SwitchToThread(uint32_t dwSleepMSec, uint32_t /*dwSwitchCount*/)
|
|||
return !!PalSwitchToThread();
|
||||
}
|
||||
|
||||
void SetGCSpecialThread(ThreadType threadType)
|
||||
{
|
||||
Thread *pThread = ThreadStore::RawGetCurrentThread();
|
||||
pThread->SetGCSpecial(threadType == ThreadType_GC);
|
||||
}
|
||||
|
||||
#endif // DACCESS_COMPILE
|
||||
|
||||
MethodTable * g_pFreeObjectMethodTable;
|
||||
int32_t g_TrapReturningThreads;
|
||||
|
||||
#ifndef DACCESS_COMPILE
|
||||
bool IsGCThread()
|
||||
{
|
||||
return false;
|
||||
return IsGCSpecialThread() || ThreadStore::GetSuspendingThread() == ThreadStore::GetCurrentThread();
|
||||
}
|
||||
#endif // DACCESS_COMPILE
|
||||
|
||||
void LogSpewAlways(const char * /*fmt*/, ...)
|
||||
{
|
||||
|
|
|
@ -334,6 +334,8 @@ bool Thread::IsInitialized()
|
|||
//
|
||||
void Thread::SetGCSpecial(bool isGCSpecial)
|
||||
{
|
||||
if (!IsInitialized())
|
||||
Construct();
|
||||
if (isGCSpecial)
|
||||
SetState(TSF_IsGcSpecialThread);
|
||||
else
|
||||
|
|
|
@ -209,9 +209,9 @@ namespace Internal.Runtime.Augments
|
|||
//
|
||||
// Helper to extract the artifact that uniquely identifies a method in the runtime mapping tables.
|
||||
//
|
||||
public static IntPtr GetDelegateLdFtnResult(Delegate d, out RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate, out bool isOpenResolver)
|
||||
public static IntPtr GetDelegateLdFtnResult(Delegate d, out RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate, out bool isOpenResolver, out bool isInterpreterEntrypoint)
|
||||
{
|
||||
return d.GetFunctionPointer(out typeOfFirstParameterIfInstanceDelegate, out isOpenResolver);
|
||||
return d.GetFunctionPointer(out typeOfFirstParameterIfInstanceDelegate, out isOpenResolver, out isInterpreterEntrypoint);
|
||||
}
|
||||
|
||||
public static void GetDelegateData(Delegate delegateObj, out object firstParameter, out object helperObject, out IntPtr extraFunctionPointerOrData, out IntPtr functionPointer)
|
||||
|
@ -277,6 +277,11 @@ namespace Internal.Runtime.Augments
|
|||
return RuntimeImports.RhBox(fieldType.ToEETypePtr(), *(void**)&address);
|
||||
}
|
||||
|
||||
public static unsafe object LoadPointerTypeField(IntPtr address, RuntimeTypeHandle fieldType)
|
||||
{
|
||||
return Pointer.Box(*(void**)address, Type.GetTypeFromHandle(fieldType));
|
||||
}
|
||||
|
||||
public static unsafe void StoreValueTypeField(ref byte address, Object fieldValue, RuntimeTypeHandle fieldType)
|
||||
{
|
||||
RuntimeImports.RhUnbox(fieldValue, ref address, fieldType.ToEETypePtr());
|
||||
|
@ -302,6 +307,16 @@ namespace Internal.Runtime.Augments
|
|||
}
|
||||
}
|
||||
|
||||
public static unsafe Object LoadPointerTypeField(Object obj, int fieldOffset, RuntimeTypeHandle fieldType)
|
||||
{
|
||||
fixed (IntPtr* pObj = &obj.m_pEEType)
|
||||
{
|
||||
IntPtr pData = (IntPtr)pObj;
|
||||
IntPtr pField = pData + fieldOffset;
|
||||
return LoadPointerTypeField(pField, fieldType);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void StoreReferenceTypeField(IntPtr address, Object fieldValue)
|
||||
{
|
||||
Volatile.Write<Object>(ref Unsafe.As<IntPtr, Object>(ref *(IntPtr*)address), fieldValue);
|
||||
|
@ -365,6 +380,19 @@ namespace Internal.Runtime.Augments
|
|||
return Unsafe.As<byte, object>(ref Unsafe.Add<byte>(ref typedReference.Value, fieldOffset));
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static object LoadPointerTypeFieldValueFromValueType(TypedReference typedReference, int fieldOffset, RuntimeTypeHandle fieldTypeHandle)
|
||||
{
|
||||
Debug.Assert(TypedReference.TargetTypeToken(typedReference).ToEETypePtr().IsValueType);
|
||||
Debug.Assert(fieldTypeHandle.ToEETypePtr().IsPointer);
|
||||
|
||||
IntPtr ptrValue = Unsafe.As<byte, IntPtr>(ref Unsafe.Add<byte>(ref typedReference.Value, fieldOffset));
|
||||
unsafe
|
||||
{
|
||||
return Pointer.Box((void*)ptrValue, Type.GetTypeFromHandle(fieldTypeHandle));
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe int ObjectHeaderSize => sizeof(EETypePtr);
|
||||
|
||||
[DebuggerGuidedStepThroughAttribute]
|
||||
|
@ -732,9 +760,7 @@ namespace Internal.Runtime.Augments
|
|||
public static String TryGetFullPathToMainApplication()
|
||||
{
|
||||
Func<String> delegateToAnythingInsideMergedApp = TryGetFullPathToMainApplication;
|
||||
RuntimeTypeHandle thDummy;
|
||||
bool boolDummy;
|
||||
IntPtr ipToAnywhereInsideMergedApp = delegateToAnythingInsideMergedApp.GetFunctionPointer(out thDummy, out boolDummy);
|
||||
IntPtr ipToAnywhereInsideMergedApp = delegateToAnythingInsideMergedApp.GetFunctionPointer(out RuntimeTypeHandle _, out bool __, out bool ___);
|
||||
IntPtr moduleBase = RuntimeImports.RhGetOSModuleFromPointer(ipToAnywhereInsideMergedApp);
|
||||
return TryGetFullPathToApplicationModule(moduleBase);
|
||||
}
|
||||
|
|
|
@ -109,16 +109,26 @@ namespace System
|
|||
/// <param name="isOpenResolver">
|
||||
/// This value indicates if the returned pointer is an open resolver structure.
|
||||
/// </param>
|
||||
/// <param name="isInterpreterEntrypoint">
|
||||
/// Delegate points to an object array thunk (the delegate wraps a Func<object[], object> delegate). This
|
||||
/// is typically a delegate pointing to the LINQ expression interpreter.
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
unsafe internal IntPtr GetFunctionPointer(out RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate, out bool isOpenResolver)
|
||||
unsafe internal IntPtr GetFunctionPointer(out RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate, out bool isOpenResolver, out bool isInterpreterEntrypoint)
|
||||
{
|
||||
typeOfFirstParameterIfInstanceDelegate = default(RuntimeTypeHandle);
|
||||
isOpenResolver = false;
|
||||
isInterpreterEntrypoint = false;
|
||||
|
||||
if (GetThunk(MulticastThunk) == m_functionPointer)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
else if (GetThunk(ObjectArrayThunk) == m_functionPointer)
|
||||
{
|
||||
isInterpreterEntrypoint = true;
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
else if (m_extraFunctionPointerOrData != IntPtr.Zero)
|
||||
{
|
||||
if (GetThunk(OpenInstanceThunk) == m_functionPointer)
|
||||
|
@ -899,8 +909,7 @@ namespace System
|
|||
else
|
||||
{
|
||||
RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate;
|
||||
bool isOpenThunk;
|
||||
IntPtr functionPointer = GetFunctionPointer(out typeOfFirstParameterIfInstanceDelegate, out isOpenThunk);
|
||||
IntPtr functionPointer = GetFunctionPointer(out typeOfFirstParameterIfInstanceDelegate, out bool __, out bool ___);
|
||||
if (!FunctionPointerOps.IsGenericMethodPointer(functionPointer))
|
||||
{
|
||||
return DebuggerFunctionPointerFormattingHook(functionPointer, typeOfFirstParameterIfInstanceDelegate);
|
||||
|
|
|
@ -97,8 +97,7 @@ namespace System.Runtime.InteropServices
|
|||
}
|
||||
public static IntPtr GetFunctionPointer(this Delegate del, out RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate)
|
||||
{
|
||||
bool dummyIsOpenInstanceFunction;
|
||||
return del.GetFunctionPointer(out typeOfFirstParameterIfInstanceDelegate, out dummyIsOpenInstanceFunction);
|
||||
return del.GetFunctionPointer(out typeOfFirstParameterIfInstanceDelegate, out bool _, out bool __);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -112,10 +111,9 @@ namespace System.Runtime.InteropServices
|
|||
if (!del.IsOpenStatic)
|
||||
return IntPtr.Zero;
|
||||
|
||||
bool dummyIsOpenInstanceFunction;
|
||||
RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate;
|
||||
|
||||
IntPtr funcPtr = del.GetFunctionPointer(out typeOfFirstParameterIfInstanceDelegate, out dummyIsOpenInstanceFunction);
|
||||
IntPtr funcPtr = del.GetFunctionPointer(out typeOfFirstParameterIfInstanceDelegate, out bool _, out bool __);
|
||||
|
||||
// if the function pointer points to a jump stub return the target
|
||||
return RuntimeImports.RhGetJmpStubCodeTarget(funcPtr);
|
||||
|
|
|
@ -17,6 +17,8 @@ using Internal.Runtime.TypeLoader;
|
|||
using Internal.TypeSystem;
|
||||
using Internal.Runtime.DebuggerSupport;
|
||||
|
||||
using IRC=Internal.Runtime.CallConverter;
|
||||
|
||||
namespace Internal.Runtime.DebuggerSupport
|
||||
{
|
||||
[McgIntrinsics]
|
||||
|
@ -31,6 +33,7 @@ namespace Internal.Runtime.DebuggerSupport
|
|||
private struct InvokeFunctionData
|
||||
{
|
||||
public object thisObj;
|
||||
public IRC.CallingConvention callingConvention;
|
||||
public RuntimeTypeHandle[] types;
|
||||
public byte[][] parameterValues;
|
||||
public FuncEvalResult result;
|
||||
|
@ -219,6 +222,7 @@ namespace Internal.Runtime.DebuggerSupport
|
|||
);
|
||||
|
||||
invokeFunctionData.types = new RuntimeTypeHandle[parameters.Length];
|
||||
invokeFunctionData.callingConvention = hasThis ? IRC.CallingConvention.ManagedInstance : IRC.CallingConvention.ManagedStatic;
|
||||
|
||||
for (int i = 0; i < invokeFunctionData.types.Length; i++)
|
||||
{
|
||||
|
@ -365,8 +369,7 @@ namespace Internal.Runtime.DebuggerSupport
|
|||
returnAndArgumentTypes[i] = new LocalVariableType(invokeFunctionData.types[i], false, false);
|
||||
}
|
||||
|
||||
// Hard coding static here
|
||||
DynamicCallSignature dynamicCallSignature = new DynamicCallSignature(Internal.Runtime.CallConverter.CallingConvention.ManagedStatic, returnAndArgumentTypes, returnAndArgumentTypes.Length);
|
||||
DynamicCallSignature dynamicCallSignature = new DynamicCallSignature(invokeFunctionData.callingConvention, returnAndArgumentTypes, returnAndArgumentTypes.Length);
|
||||
|
||||
// Invoke the target method
|
||||
Exception ex = null;
|
||||
|
|
|
@ -1315,8 +1315,11 @@ namespace Internal.Reflection.Execution
|
|||
return RuntimeAugments.IsValueType(fieldTypeHandle) ?
|
||||
(FieldAccessor)new ValueTypeFieldAccessorForInstanceFields(
|
||||
fieldAccessMetadata.Offset + fieldOffsetDelta, declaringTypeHandle, fieldTypeHandle) :
|
||||
(FieldAccessor)new ReferenceTypeFieldAccessorForInstanceFields(
|
||||
fieldAccessMetadata.Offset + fieldOffsetDelta, declaringTypeHandle, fieldTypeHandle);
|
||||
RuntimeAugments.IsUnmanagedPointerType(fieldTypeHandle) ?
|
||||
(FieldAccessor)new PointerTypeFieldAccessorForInstanceFields(
|
||||
fieldAccessMetadata.Offset + fieldOffsetDelta, declaringTypeHandle, fieldTypeHandle) :
|
||||
(FieldAccessor)new ReferenceTypeFieldAccessorForInstanceFields(
|
||||
fieldAccessMetadata.Offset + fieldOffsetDelta, declaringTypeHandle, fieldTypeHandle);
|
||||
}
|
||||
|
||||
case FieldTableFlags.Static:
|
||||
|
@ -1363,7 +1366,9 @@ namespace Internal.Reflection.Execution
|
|||
|
||||
return RuntimeAugments.IsValueType(fieldTypeHandle) ?
|
||||
(FieldAccessor)new ValueTypeFieldAccessorForStaticFields(cctorContext, staticsBase, fieldOffset, isGcStatic, fieldTypeHandle) :
|
||||
(FieldAccessor)new ReferenceTypeFieldAccessorForStaticFields(cctorContext, staticsBase, fieldOffset, isGcStatic, fieldTypeHandle);
|
||||
RuntimeAugments.IsUnmanagedPointerType(fieldTypeHandle) ?
|
||||
(FieldAccessor)new PointerTypeFieldAccessorForStaticFields(cctorContext, staticsBase, fieldOffset, isGcStatic, fieldTypeHandle) :
|
||||
(FieldAccessor)new ReferenceTypeFieldAccessorForStaticFields(cctorContext, staticsBase, fieldOffset, isGcStatic, fieldTypeHandle);
|
||||
}
|
||||
|
||||
case FieldTableFlags.ThreadStatic:
|
||||
|
@ -1375,12 +1380,19 @@ namespace Internal.Reflection.Execution
|
|||
(int)fieldAccessMetadata.Cookie,
|
||||
fieldAccessMetadata.Offset,
|
||||
fieldTypeHandle) :
|
||||
(FieldAccessor)new ReferenceTypeFieldAccessorForThreadStaticFields(
|
||||
TryGetStaticClassConstructionContext(declaringTypeHandle),
|
||||
declaringTypeHandle,
|
||||
(int)fieldAccessMetadata.Cookie,
|
||||
fieldAccessMetadata.Offset,
|
||||
fieldTypeHandle);
|
||||
RuntimeAugments.IsUnmanagedPointerType(fieldTypeHandle) ?
|
||||
(FieldAccessor)new PointerTypeFieldAccessorForThreadStaticFields(
|
||||
TryGetStaticClassConstructionContext(declaringTypeHandle),
|
||||
declaringTypeHandle,
|
||||
(int)fieldAccessMetadata.Cookie,
|
||||
fieldAccessMetadata.Offset,
|
||||
fieldTypeHandle) :
|
||||
(FieldAccessor)new ReferenceTypeFieldAccessorForThreadStaticFields(
|
||||
TryGetStaticClassConstructionContext(declaringTypeHandle),
|
||||
declaringTypeHandle,
|
||||
(int)fieldAccessMetadata.Cookie,
|
||||
fieldAccessMetadata.Offset,
|
||||
fieldTypeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,24 +2,21 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using global::System;
|
||||
using global::System.Threading;
|
||||
using global::System.Reflection;
|
||||
using global::System.Diagnostics;
|
||||
using global::System.Collections.Generic;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
using global::Internal.Runtime.Augments;
|
||||
using global::Internal.Reflection.Execution;
|
||||
using global::Internal.Reflection.Core.Execution;
|
||||
using Internal.Runtime.Augments;
|
||||
using Internal.Reflection.Core.Execution;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal abstract class InstanceFieldAccessor : FieldAccessor
|
||||
{
|
||||
public InstanceFieldAccessor(RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle fieldTypeHandle)
|
||||
public InstanceFieldAccessor(RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle fieldTypeHandle, int offsetPlusHeader)
|
||||
{
|
||||
this.DeclaringTypeHandle = declaringTypeHandle;
|
||||
this.FieldTypeHandle = fieldTypeHandle;
|
||||
this.OffsetPlusHeader = offsetPlusHeader;
|
||||
}
|
||||
|
||||
public abstract override int Offset { get; }
|
||||
|
@ -97,7 +94,8 @@ namespace Internal.Reflection.Execution.FieldAccessors
|
|||
protected abstract Object UncheckedGetField(Object obj);
|
||||
protected abstract void UncheckedSetField(Object obj, Object value);
|
||||
|
||||
protected RuntimeTypeHandle DeclaringTypeHandle { get; private set; }
|
||||
protected RuntimeTypeHandle FieldTypeHandle { get; private set; }
|
||||
protected int OffsetPlusHeader { get; }
|
||||
protected RuntimeTypeHandle DeclaringTypeHandle { get; }
|
||||
protected RuntimeTypeHandle FieldTypeHandle { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Internal.Runtime.Augments;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal sealed class PointerTypeFieldAccessorForInstanceFields : InstanceFieldAccessor
|
||||
{
|
||||
public PointerTypeFieldAccessorForInstanceFields(int offsetPlusHeader, RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(declaringTypeHandle, fieldTypeHandle, offsetPlusHeader)
|
||||
{
|
||||
}
|
||||
|
||||
public sealed override int Offset => OffsetPlusHeader - RuntimeAugments.ObjectHeaderSize;
|
||||
|
||||
protected sealed override Object UncheckedGetField(Object obj)
|
||||
{
|
||||
return RuntimeAugments.LoadPointerTypeField(obj, OffsetPlusHeader, this.FieldTypeHandle);
|
||||
}
|
||||
|
||||
protected sealed override object UncheckedGetFieldDirectFromValueType(TypedReference typedReference)
|
||||
{
|
||||
return RuntimeAugments.LoadPointerTypeFieldValueFromValueType(typedReference, this.Offset, this.FieldTypeHandle);
|
||||
}
|
||||
|
||||
protected sealed override void UncheckedSetField(Object obj, Object value)
|
||||
{
|
||||
RuntimeAugments.StoreValueTypeField(obj, OffsetPlusHeader, value, typeof(IntPtr).TypeHandle);
|
||||
}
|
||||
|
||||
protected sealed override void UncheckedSetFieldDirectIntoValueType(TypedReference typedReference, object value)
|
||||
{
|
||||
RuntimeAugments.StoreValueTypeFieldValueIntoValueType(typedReference, this.Offset, value, typeof(IntPtr).TypeHandle);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Internal.Runtime.Augments;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal sealed class PointerTypeFieldAccessorForStaticFields : RegularStaticFieldAccessor
|
||||
{
|
||||
public PointerTypeFieldAccessorForStaticFields(IntPtr cctorContext, IntPtr staticsBase, int fieldOffset, bool isGcStatic, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(cctorContext, staticsBase, fieldOffset, isGcStatic, fieldTypeHandle)
|
||||
{
|
||||
}
|
||||
|
||||
unsafe protected sealed override Object GetFieldBypassCctor()
|
||||
{
|
||||
#if CORERT
|
||||
if (IsGcStatic)
|
||||
{
|
||||
// The _staticsBase variable points to a GC handle, which points at the GC statics base of the type.
|
||||
// We need to perform a double indirection in a GC-safe manner.
|
||||
object gcStaticsRegion = RuntimeAugments.LoadReferenceTypeField(*(IntPtr*)StaticsBase);
|
||||
return RuntimeAugments.LoadPointerTypeField(gcStaticsRegion, FieldOffset, FieldTypeHandle);
|
||||
}
|
||||
#endif
|
||||
return RuntimeAugments.LoadPointerTypeField(StaticsBase + FieldOffset, FieldTypeHandle);
|
||||
}
|
||||
|
||||
unsafe protected sealed override void UncheckedSetFieldBypassCctor(Object value)
|
||||
{
|
||||
|
||||
#if CORERT
|
||||
if (IsGcStatic)
|
||||
{
|
||||
// The _staticsBase variable points to a GC handle, which points at the GC statics base of the type.
|
||||
// We need to perform a double indirection in a GC-safe manner.
|
||||
object gcStaticsRegion = RuntimeAugments.LoadReferenceTypeField(*(IntPtr*)StaticsBase);
|
||||
RuntimeAugments.StoreValueTypeField(gcStaticsRegion, FieldOffset, value, typeof(IntPtr).TypeHandle);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
RuntimeAugments.StoreValueTypeField(StaticsBase + FieldOffset, value, typeof(IntPtr).TypeHandle);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Internal.Runtime.Augments;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal sealed class PointerTypeFieldAccessorForThreadStaticFields : ThreadStaticFieldAccessor
|
||||
{
|
||||
public PointerTypeFieldAccessorForThreadStaticFields(IntPtr cctorContext, RuntimeTypeHandle declaringTypeHandle, int threadStaticsBlockOffset, int fieldOffset, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(cctorContext, declaringTypeHandle, threadStaticsBlockOffset, fieldOffset, fieldTypeHandle)
|
||||
{
|
||||
}
|
||||
|
||||
protected sealed override Object GetFieldBypassCctor()
|
||||
{
|
||||
IntPtr fieldAddress = RuntimeAugments.GetThreadStaticFieldAddress(DeclaringTypeHandle, ThreadStaticsBlockOffset, FieldOffset);
|
||||
return RuntimeAugments.LoadPointerTypeField(fieldAddress, FieldTypeHandle);
|
||||
}
|
||||
|
||||
protected sealed override void UncheckedSetFieldBypassCctor(Object value)
|
||||
{
|
||||
IntPtr fieldAddress = RuntimeAugments.GetThreadStaticFieldAddress(DeclaringTypeHandle, ThreadStaticsBlockOffset, FieldOffset);
|
||||
RuntimeAugments.StoreValueTypeField(fieldAddress, value, typeof(IntPtr).TypeHandle);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,33 +2,23 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using global::System;
|
||||
using global::System.Threading;
|
||||
using global::System.Reflection;
|
||||
using global::System.Diagnostics;
|
||||
using global::System.Collections.Generic;
|
||||
|
||||
using global::Internal.Runtime.Augments;
|
||||
using global::Internal.Reflection.Execution;
|
||||
using global::Internal.Reflection.Core.Execution;
|
||||
using System;
|
||||
using Internal.Runtime.Augments;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal sealed class ReferenceTypeFieldAccessorForInstanceFields : InstanceFieldAccessor
|
||||
{
|
||||
private int _offset;
|
||||
|
||||
public ReferenceTypeFieldAccessorForInstanceFields(int offset, RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(declaringTypeHandle, fieldTypeHandle)
|
||||
public ReferenceTypeFieldAccessorForInstanceFields(int offsetPlusHeader, RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(declaringTypeHandle, fieldTypeHandle, offsetPlusHeader)
|
||||
{
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
public sealed override int Offset => _offset - RuntimeAugments.ObjectHeaderSize;
|
||||
public sealed override int Offset => OffsetPlusHeader - RuntimeAugments.ObjectHeaderSize;
|
||||
|
||||
protected sealed override Object UncheckedGetField(Object obj)
|
||||
{
|
||||
return RuntimeAugments.LoadReferenceTypeField(obj, _offset);
|
||||
return RuntimeAugments.LoadReferenceTypeField(obj, OffsetPlusHeader);
|
||||
}
|
||||
|
||||
protected sealed override object UncheckedGetFieldDirectFromValueType(TypedReference typedReference)
|
||||
|
@ -38,7 +28,7 @@ namespace Internal.Reflection.Execution.FieldAccessors
|
|||
|
||||
protected sealed override void UncheckedSetField(Object obj, Object value)
|
||||
{
|
||||
RuntimeAugments.StoreReferenceTypeField(obj, _offset, value);
|
||||
RuntimeAugments.StoreReferenceTypeField(obj, OffsetPlusHeader, value);
|
||||
}
|
||||
|
||||
protected sealed override void UncheckedSetFieldDirectIntoValueType(TypedReference typedReference, object value)
|
||||
|
|
|
@ -2,57 +2,46 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using global::System;
|
||||
using global::System.Reflection;
|
||||
using global::System.Runtime.CompilerServices;
|
||||
using global::System.Runtime.InteropServices;
|
||||
|
||||
using global::Internal.Runtime.Augments;
|
||||
using System;
|
||||
using Internal.Runtime.Augments;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal sealed class ReferenceTypeFieldAccessorForStaticFields : WritableStaticFieldAccessor
|
||||
internal sealed class ReferenceTypeFieldAccessorForStaticFields : RegularStaticFieldAccessor
|
||||
{
|
||||
private IntPtr _staticsBase;
|
||||
private bool _isGcStaticsBase;
|
||||
private int _fieldOffset;
|
||||
|
||||
public ReferenceTypeFieldAccessorForStaticFields(IntPtr cctorContext, IntPtr staticsBase, int fieldOffset, bool isGcStatic, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(cctorContext, fieldTypeHandle)
|
||||
: base(cctorContext, staticsBase, fieldOffset, isGcStatic, fieldTypeHandle)
|
||||
{
|
||||
_staticsBase = staticsBase;
|
||||
_isGcStaticsBase = isGcStatic;
|
||||
_fieldOffset = fieldOffset;
|
||||
}
|
||||
|
||||
unsafe protected sealed override Object GetFieldBypassCctor()
|
||||
{
|
||||
#if CORERT
|
||||
if (_isGcStaticsBase)
|
||||
if (IsGcStatic)
|
||||
{
|
||||
// The _staticsBase variable points to a GC handle, which points at the GC statics base of the type.
|
||||
// We need to perform a double indirection in a GC-safe manner.
|
||||
object gcStaticsRegion = RuntimeAugments.LoadReferenceTypeField(*(IntPtr*)_staticsBase);
|
||||
return RuntimeAugments.LoadReferenceTypeField(gcStaticsRegion, _fieldOffset);
|
||||
object gcStaticsRegion = RuntimeAugments.LoadReferenceTypeField(*(IntPtr*)StaticsBase);
|
||||
return RuntimeAugments.LoadReferenceTypeField(gcStaticsRegion, FieldOffset);
|
||||
}
|
||||
#endif
|
||||
return RuntimeAugments.LoadReferenceTypeField(_staticsBase + _fieldOffset);
|
||||
return RuntimeAugments.LoadReferenceTypeField(StaticsBase + FieldOffset);
|
||||
}
|
||||
|
||||
unsafe protected sealed override void UncheckedSetFieldBypassCctor(Object value)
|
||||
{
|
||||
|
||||
#if CORERT
|
||||
if (_isGcStaticsBase)
|
||||
if (IsGcStatic)
|
||||
{
|
||||
// The _staticsBase variable points to a GC handle, which points at the GC statics base of the type.
|
||||
// We need to perform a double indirection in a GC-safe manner.
|
||||
object gcStaticsRegion = RuntimeAugments.LoadReferenceTypeField(*(IntPtr*)_staticsBase);
|
||||
RuntimeAugments.StoreReferenceTypeField(gcStaticsRegion, _fieldOffset, value);
|
||||
object gcStaticsRegion = RuntimeAugments.LoadReferenceTypeField(*(IntPtr*)StaticsBase);
|
||||
RuntimeAugments.StoreReferenceTypeField(gcStaticsRegion, FieldOffset, value);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
RuntimeAugments.StoreReferenceTypeField(_staticsBase + _fieldOffset, value);
|
||||
RuntimeAugments.StoreReferenceTypeField(StaticsBase + FieldOffset, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,41 +2,27 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using global::System;
|
||||
using global::System.Threading;
|
||||
using global::System.Reflection;
|
||||
using global::System.Diagnostics;
|
||||
using global::System.Collections.Generic;
|
||||
|
||||
using global::Internal.Runtime.Augments;
|
||||
using global::Internal.Reflection.Execution;
|
||||
using global::Internal.Reflection.Core.Execution;
|
||||
using System;
|
||||
using Internal.Runtime.Augments;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal sealed class ReferenceTypeFieldAccessorForThreadStaticFields : WritableStaticFieldAccessor
|
||||
internal sealed class ReferenceTypeFieldAccessorForThreadStaticFields : ThreadStaticFieldAccessor
|
||||
{
|
||||
private int _threadStaticsBlockOffset;
|
||||
private int _fieldOffset;
|
||||
private RuntimeTypeHandle _declaringTypeHandle;
|
||||
|
||||
public ReferenceTypeFieldAccessorForThreadStaticFields(IntPtr cctorContext, RuntimeTypeHandle declaringTypeHandle, int threadStaticsBlockOffset, int fieldOffset, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(cctorContext, fieldTypeHandle)
|
||||
: base(cctorContext, declaringTypeHandle, threadStaticsBlockOffset, fieldOffset, fieldTypeHandle)
|
||||
{
|
||||
_threadStaticsBlockOffset = threadStaticsBlockOffset;
|
||||
_fieldOffset = fieldOffset;
|
||||
_declaringTypeHandle = declaringTypeHandle;
|
||||
}
|
||||
|
||||
protected sealed override Object GetFieldBypassCctor()
|
||||
{
|
||||
IntPtr fieldAddress = RuntimeAugments.GetThreadStaticFieldAddress(_declaringTypeHandle, _threadStaticsBlockOffset, _fieldOffset);
|
||||
IntPtr fieldAddress = RuntimeAugments.GetThreadStaticFieldAddress(DeclaringTypeHandle, ThreadStaticsBlockOffset, FieldOffset);
|
||||
return RuntimeAugments.LoadReferenceTypeField(fieldAddress);
|
||||
}
|
||||
|
||||
protected sealed override void UncheckedSetFieldBypassCctor(Object value)
|
||||
{
|
||||
IntPtr fieldAddress = RuntimeAugments.GetThreadStaticFieldAddress(_declaringTypeHandle, _threadStaticsBlockOffset, _fieldOffset);
|
||||
IntPtr fieldAddress = RuntimeAugments.GetThreadStaticFieldAddress(DeclaringTypeHandle, ThreadStaticsBlockOffset, FieldOffset);
|
||||
RuntimeAugments.StoreReferenceTypeField(fieldAddress, value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal abstract class RegularStaticFieldAccessor : WritableStaticFieldAccessor
|
||||
{
|
||||
protected RegularStaticFieldAccessor(IntPtr cctorContext, IntPtr staticsBase, int fieldOffset, bool isGcStatic, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(cctorContext, fieldTypeHandle)
|
||||
{
|
||||
StaticsBase = staticsBase;
|
||||
IsGcStatic = isGcStatic;
|
||||
FieldOffset = fieldOffset;
|
||||
}
|
||||
|
||||
protected IntPtr StaticsBase { get; }
|
||||
protected bool IsGcStatic { get; }
|
||||
protected int FieldOffset { get; }
|
||||
}
|
||||
}
|
|
@ -2,21 +2,18 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using global::System;
|
||||
using global::System.Threading;
|
||||
using global::System.Reflection;
|
||||
using global::System.Diagnostics;
|
||||
using global::System.Collections.Generic;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
|
||||
using global::Internal.Runtime.Augments;
|
||||
using global::Internal.Reflection.Execution;
|
||||
using global::Internal.Reflection.Core.Execution;
|
||||
using Internal.Runtime.Augments;
|
||||
using Internal.Reflection.Core.Execution;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal abstract class StaticFieldAccessor : FieldAccessor
|
||||
{
|
||||
protected RuntimeTypeHandle FieldTypeHandle { get; private set; }
|
||||
protected RuntimeTypeHandle FieldTypeHandle { get; }
|
||||
|
||||
private IntPtr _cctorContext;
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal abstract class ThreadStaticFieldAccessor : WritableStaticFieldAccessor
|
||||
{
|
||||
protected ThreadStaticFieldAccessor(IntPtr cctorContext, RuntimeTypeHandle declaringTypeHandle, int threadStaticsBlockOffset, int fieldOffset, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(cctorContext, fieldTypeHandle)
|
||||
{
|
||||
ThreadStaticsBlockOffset = threadStaticsBlockOffset;
|
||||
FieldOffset = fieldOffset;
|
||||
DeclaringTypeHandle = declaringTypeHandle;
|
||||
}
|
||||
|
||||
protected int ThreadStaticsBlockOffset { get; }
|
||||
protected int FieldOffset { get; }
|
||||
protected RuntimeTypeHandle DeclaringTypeHandle { get; }
|
||||
}
|
||||
}
|
|
@ -2,33 +2,23 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using global::System;
|
||||
using global::System.Threading;
|
||||
using global::System.Reflection;
|
||||
using global::System.Diagnostics;
|
||||
using global::System.Collections.Generic;
|
||||
|
||||
using global::Internal.Runtime.Augments;
|
||||
using global::Internal.Reflection.Execution;
|
||||
using global::Internal.Reflection.Core.Execution;
|
||||
using System;
|
||||
using Internal.Runtime.Augments;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal sealed class ValueTypeFieldAccessorForInstanceFields : InstanceFieldAccessor
|
||||
{
|
||||
private int _offset;
|
||||
|
||||
public ValueTypeFieldAccessorForInstanceFields(int offset, RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(declaringTypeHandle, fieldTypeHandle)
|
||||
public ValueTypeFieldAccessorForInstanceFields(int offsetPlusHeader, RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(declaringTypeHandle, fieldTypeHandle, offsetPlusHeader)
|
||||
{
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
public sealed override int Offset => _offset - RuntimeAugments.ObjectHeaderSize;
|
||||
public sealed override int Offset => OffsetPlusHeader - RuntimeAugments.ObjectHeaderSize;
|
||||
|
||||
protected sealed override Object UncheckedGetField(Object obj)
|
||||
{
|
||||
return RuntimeAugments.LoadValueTypeField(obj, _offset, this.FieldTypeHandle);
|
||||
return RuntimeAugments.LoadValueTypeField(obj, OffsetPlusHeader, this.FieldTypeHandle);
|
||||
}
|
||||
|
||||
protected sealed override object UncheckedGetFieldDirectFromValueType(TypedReference typedReference)
|
||||
|
@ -38,7 +28,7 @@ namespace Internal.Reflection.Execution.FieldAccessors
|
|||
|
||||
protected sealed override void UncheckedSetField(Object obj, Object value)
|
||||
{
|
||||
RuntimeAugments.StoreValueTypeField(obj, _offset, value, this.FieldTypeHandle);
|
||||
RuntimeAugments.StoreValueTypeField(obj, OffsetPlusHeader, value, this.FieldTypeHandle);
|
||||
}
|
||||
|
||||
protected sealed override void UncheckedSetFieldDirectIntoValueType(TypedReference typedReference, object value)
|
||||
|
|
|
@ -2,56 +2,46 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using global::System;
|
||||
using global::System.Reflection;
|
||||
using global::System.Runtime.CompilerServices;
|
||||
|
||||
using global::Internal.Runtime.Augments;
|
||||
using System;
|
||||
using Internal.Runtime.Augments;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal sealed class ValueTypeFieldAccessorForStaticFields : WritableStaticFieldAccessor
|
||||
internal sealed class ValueTypeFieldAccessorForStaticFields : RegularStaticFieldAccessor
|
||||
{
|
||||
private IntPtr _staticsBase;
|
||||
private bool _isGcStaticsBase;
|
||||
private int _fieldOffset;
|
||||
|
||||
public ValueTypeFieldAccessorForStaticFields(IntPtr cctorContext, IntPtr staticsBase, int fieldOffset, bool isGcStatic, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(cctorContext, fieldTypeHandle)
|
||||
: base(cctorContext, staticsBase, fieldOffset, isGcStatic, fieldTypeHandle)
|
||||
{
|
||||
_staticsBase = staticsBase;
|
||||
_isGcStaticsBase = isGcStatic;
|
||||
_fieldOffset = fieldOffset;
|
||||
}
|
||||
|
||||
unsafe protected sealed override Object GetFieldBypassCctor()
|
||||
{
|
||||
#if CORERT
|
||||
if (_isGcStaticsBase)
|
||||
if (IsGcStatic)
|
||||
{
|
||||
// The _staticsBase variable points to a GC handle, which points at the GC statics base of the type.
|
||||
// We need to perform a double indirection in a GC-safe manner.
|
||||
object gcStaticsRegion = RuntimeAugments.LoadReferenceTypeField(*(IntPtr*)_staticsBase);
|
||||
return RuntimeAugments.LoadValueTypeField(gcStaticsRegion, _fieldOffset, FieldTypeHandle);
|
||||
object gcStaticsRegion = RuntimeAugments.LoadReferenceTypeField(*(IntPtr*)StaticsBase);
|
||||
return RuntimeAugments.LoadValueTypeField(gcStaticsRegion, FieldOffset, FieldTypeHandle);
|
||||
}
|
||||
#endif
|
||||
return RuntimeAugments.LoadValueTypeField(_staticsBase + _fieldOffset, FieldTypeHandle);
|
||||
return RuntimeAugments.LoadValueTypeField(StaticsBase + FieldOffset, FieldTypeHandle);
|
||||
}
|
||||
|
||||
unsafe protected sealed override void UncheckedSetFieldBypassCctor(Object value)
|
||||
{
|
||||
|
||||
#if CORERT
|
||||
if (_isGcStaticsBase)
|
||||
if (IsGcStatic)
|
||||
{
|
||||
// The _staticsBase variable points to a GC handle, which points at the GC statics base of the type.
|
||||
// We need to perform a double indirection in a GC-safe manner.
|
||||
object gcStaticsRegion = RuntimeAugments.LoadReferenceTypeField(*(IntPtr*)_staticsBase);
|
||||
RuntimeAugments.StoreValueTypeField(gcStaticsRegion, _fieldOffset, value, FieldTypeHandle);
|
||||
object gcStaticsRegion = RuntimeAugments.LoadReferenceTypeField(*(IntPtr*)StaticsBase);
|
||||
RuntimeAugments.StoreValueTypeField(gcStaticsRegion, FieldOffset, value, FieldTypeHandle);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
RuntimeAugments.StoreValueTypeField(_staticsBase + _fieldOffset, value, FieldTypeHandle);
|
||||
RuntimeAugments.StoreValueTypeField(StaticsBase + FieldOffset, value, FieldTypeHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,43 +2,27 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using global::System;
|
||||
using global::System.Threading;
|
||||
using global::System.Reflection;
|
||||
using global::System.Diagnostics;
|
||||
using global::System.Collections.Generic;
|
||||
|
||||
using global::Internal.Runtime.Augments;
|
||||
using global::Internal.Reflection.Execution;
|
||||
using global::Internal.Reflection.Core.Execution;
|
||||
|
||||
using global::Internal.Metadata.NativeFormat;
|
||||
using System;
|
||||
using Internal.Runtime.Augments;
|
||||
|
||||
namespace Internal.Reflection.Execution.FieldAccessors
|
||||
{
|
||||
internal sealed class ValueTypeFieldAccessorForThreadStaticFields : WritableStaticFieldAccessor
|
||||
internal sealed class ValueTypeFieldAccessorForThreadStaticFields : ThreadStaticFieldAccessor
|
||||
{
|
||||
private int _threadStaticsBlockOffset;
|
||||
private int _fieldOffset;
|
||||
private RuntimeTypeHandle _declaringTypeHandle;
|
||||
|
||||
public ValueTypeFieldAccessorForThreadStaticFields(IntPtr cctorContext, RuntimeTypeHandle declaringTypeHandle, int threadStaticsBlockOffset, int fieldOffset, RuntimeTypeHandle fieldTypeHandle)
|
||||
: base(cctorContext, fieldTypeHandle)
|
||||
: base(cctorContext, declaringTypeHandle, threadStaticsBlockOffset, fieldOffset, fieldTypeHandle)
|
||||
{
|
||||
_threadStaticsBlockOffset = threadStaticsBlockOffset;
|
||||
_fieldOffset = fieldOffset;
|
||||
_declaringTypeHandle = declaringTypeHandle;
|
||||
}
|
||||
|
||||
protected sealed override Object GetFieldBypassCctor()
|
||||
{
|
||||
IntPtr fieldAddress = RuntimeAugments.GetThreadStaticFieldAddress(_declaringTypeHandle, _threadStaticsBlockOffset, _fieldOffset);
|
||||
IntPtr fieldAddress = RuntimeAugments.GetThreadStaticFieldAddress(DeclaringTypeHandle, ThreadStaticsBlockOffset, FieldOffset);
|
||||
return RuntimeAugments.LoadValueTypeField(fieldAddress, FieldTypeHandle);
|
||||
}
|
||||
|
||||
protected sealed override void UncheckedSetFieldBypassCctor(Object value)
|
||||
{
|
||||
IntPtr fieldAddress = RuntimeAugments.GetThreadStaticFieldAddress(_declaringTypeHandle, _threadStaticsBlockOffset, _fieldOffset);
|
||||
IntPtr fieldAddress = RuntimeAugments.GetThreadStaticFieldAddress(DeclaringTypeHandle, ThreadStaticsBlockOffset, FieldOffset);
|
||||
RuntimeAugments.StoreValueTypeField(fieldAddress, value, FieldTypeHandle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,9 +24,16 @@ namespace Internal.Reflection.Extensions.NonPortable
|
|||
throw new ArgumentException();
|
||||
Delegate[] invokeList = del.GetInvocationList();
|
||||
del = invokeList[invokeList.Length - 1];
|
||||
RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate;
|
||||
bool isOpenResolver;
|
||||
IntPtr originalLdFtnResult = RuntimeAugments.GetDelegateLdFtnResult(del, out typeOfFirstParameterIfInstanceDelegate, out isOpenResolver);
|
||||
IntPtr originalLdFtnResult = RuntimeAugments.GetDelegateLdFtnResult(del, out RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate, out bool isOpenResolver, out bool isInterpreterEntrypoint);
|
||||
|
||||
if (isInterpreterEntrypoint)
|
||||
{
|
||||
// This is a special kind of delegate where the invoke method is "ObjectArrayThunk". Typically,
|
||||
// this will be a delegate that points the the LINQ Expression interpreter. We could manufacture
|
||||
// a MethodInfo based on the delegate's Invoke signature, but let's just throw for now.
|
||||
throw new PlatformNotSupportedException(SR.DelegateGetMethodInfo_ObjectArrayDelegate);
|
||||
}
|
||||
|
||||
if (originalLdFtnResult == (IntPtr)0)
|
||||
return null;
|
||||
|
||||
|
|
|
@ -237,4 +237,7 @@
|
|||
<data name="DelegateGetMethodInfo_NoInstantiation" xml:space="preserve">
|
||||
<value>Cannot retrieve a MethodInfo for this delegate because the necessary generic instantiation was not metadata-enabled. For more information, please visit http://go.microsoft.com/fwlink/?LinkID=616868</value>
|
||||
</data>
|
||||
<data name="DelegateGetMethodInfo_ObjectArrayDelegate" xml:space="preserve">
|
||||
<value>Cannot retrieve a MethodInfo for this delegate because the delegate target is an interpreted LINQ expression.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -71,10 +71,15 @@
|
|||
<Compile Include="Internal\Reflection\Execution\RuntimeHandlesExtensions.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\InstanceFieldAccessor.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\LiteralFieldAccessor.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\PointerTypeFieldAccessorForInstanceFields.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\PointerTypeFieldAccessorForStaticFields.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\PointerTypeFieldAccessorForThreadStaticFields.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\RegularStaticFieldAccessor.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\ReferenceTypeFieldAccessorForInstanceFields.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\ReferenceTypeFieldAccessorForStaticFields.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\ReferenceTypeFieldAccessorForThreadStaticFields.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\StaticFieldAccessor.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\ThreadStaticFieldAccessor.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\ValueTypeFieldAccessorForInstanceFields.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\ValueTypeFieldAccessorForStaticFields.cs" />
|
||||
<Compile Include="Internal\Reflection\Execution\FieldAccessors\ValueTypeFieldAccessorForThreadStaticFields.cs" />
|
||||
|
|
|
@ -263,11 +263,8 @@ namespace Internal.Runtime.TypeLoader
|
|||
if (thunkKind == ReversePinvokeThunk)
|
||||
{
|
||||
// Special unsupported thunk kind. Similar behavior to the thunks generated by the delegate ILTransform for this thunk kind
|
||||
|
||||
RuntimeTypeHandle thDummy;
|
||||
bool isOpenResolverDummy;
|
||||
Action throwNotSupportedException = () => { throw new NotSupportedException(); };
|
||||
return RuntimeAugments.GetDelegateLdFtnResult(throwNotSupportedException, out thDummy, out isOpenResolverDummy);
|
||||
return RuntimeAugments.GetDelegateLdFtnResult(throwNotSupportedException, out RuntimeTypeHandle _, out bool __, out bool ___);
|
||||
}
|
||||
|
||||
RuntimeTypeHandle delegateType = RuntimeAugments.GetRuntimeTypeHandleFromObjectReference(delegateObject);
|
||||
|
|
Загрузка…
Ссылка в новой задаче