コード例 #1
0
            /// <summary>
            /// Identity constructor -- converts an array of fields to a padded struct data,
            /// with no padding or alignment sorting being performed.
            /// </summary>
            /// <param name="fields">The fields to convert</param>
            public PaddedStructData(
                McgField[] fields)
            {
                AlignmentEntries = new AlignmentEntry[fields.Length];
                int i = 0;

                foreach (McgField field in fields)
                {
                    AlignmentEntry entry =
                        new AlignmentEntry(field, false, false);

                    entry.Offset = PaddedSize;

                    PaddedSize += field.Type.UnpaddedSize;

                    AlignmentEntries[i++] = entry;
                }
            }
コード例 #2
0
        /// <summary>
        /// SortStructForAlignment - returns an array of AlignmentEntry's which describe
        /// the correct, padded/aligned layout for this struct.
        /// </summary>
        /// <returns>
        /// PaddedStructData - this contains an array of AlignmentEntry's which dictate the fields
        /// in the sorted struct and the resultant struct size.
        /// </returns>
        /// <param name="fields"> The fields to sort. </param>
        /// <param name="doAnimations"> Whether or not to add extra handles for animations. </param>
        /// <param name="padFullStructure"> Whether or not to pad the entire structure to a multiple of 8 bytes. </param>
        internal static PaddedStructData SortStructForAlignment(
            McgField[] fields,
            bool doAnimations,
            bool padFullStructure)
        {
            Debug.Assert(DuceHandle.Size == 4 || DuceHandle.Size == 8,
                         "We assume UCE handles are 4 or 8 bytes.");

            bool alignHandles = DuceHandle.Size > 4;

            //
            //  The algorithm used to align the fields is to sort the fields into three buckets:
            //
            //    1) QWord aligned fields whose length happens to be evenly divisible by 8.
            //    2) QWord aligned fields whose length is evenly divisible by 4, but not 8.
            //    3) DWords
            //
            //  Fields in bucket 1 can be immediately emited because the following offset will
            //  always be QWord aligned.  Example:
            //
            //    +----------+
            //    |     8    |
            //    +----------+  <- Offset = 8   (QWord aligned)
            //    |          |
            //    |    24    |
            //    |          |
            //    +----------+  <- Offset = 32  (QWord aligned)
            //
            //  At the end of the sorting we will then use fields in bucket 3 as padding for fields
            //  in bucket 2.

            List <AlignmentEntry> sorted            = new List <AlignmentEntry>();
            List <AlignmentEntry> needsDwordPadding = new List <AlignmentEntry>();
            List <AlignmentEntry> dwords            = new List <AlignmentEntry>();

            foreach (McgField field in fields)
            {
                if (field.Type.ShouldBeQuadWordAligned)
                {
                    AlignmentEntry qwordEntry    = new AlignmentEntry(field, /* isAnimation = */ false, /* isPad = */ false);
                    int            paddingNeeded = field.Type.UnpaddedSize % 8;

                    if (paddingNeeded == 0)
                    {
                        sorted.Add(qwordEntry);
                    }
                    else if (paddingNeeded == 4)
                    {
                        needsDwordPadding.Add(qwordEntry);
                    }
                    else
                    {
                        Debug.Fail("We currently only support QWord/DWords aligment.");
                    }
                }
                else
                {
                    if (field.Type.UnpaddedSize == 4)
                    {
                        dwords.Add(new AlignmentEntry(field, /* isAnimation = */ false, /* isPad = */ false));
                    }
                    else
                    {
                        Debug.Fail("We currently do not support fields smaller than 4 bytes.");
                    }
                }

                if (doAnimations && field.IsAnimated)
                {
                    AlignmentEntry animationEntry = new AlignmentEntry(field, /* isAnimation = */ true, /* isPadding = */ false);

                    if (alignHandles)
                    {
                        sorted.Add(animationEntry);
                    }
                    else
                    {
                        dwords.Add(animationEntry);
                    }
                }
            }

            //
            //  Use our available DWord sized fields to pad any QWord aligned fields which
            //  have lengths not evenly divisible 8.  Example:
            //
            //    +----------+
            //    |          |
            //    |    12    |
            //    |          |
            //    +----------+  <- Offset = 12  (DWord aligned)
            //    |     4    |
            //    +----------+  <- Offset = 16  (QWord aligned)
            //
            //  If we have no DWords available we create padding.
            //

            foreach (AlignmentEntry qwordEntry in needsDwordPadding)
            {
                sorted.Add(qwordEntry);

                if (dwords.Count > 0)
                {
                    sorted.Add(dwords[0]);
                    dwords.RemoveAt(0);
                }
                else
                {
                    sorted.Add(new AlignmentEntry(/* field = */ null, /* isAnimation = */ false, /* isPad = */ true));
                }
            }

            //
            //  Emit any remaining DWords
            //

            foreach (AlignmentEntry dwordEntry in dwords)
            {
                sorted.Add(dwordEntry);
            }

            //
            //  Loop through the list of sorted entries and compute the size of the struct.
            //

            int structSize = 0;

            foreach (AlignmentEntry entry in sorted)
            {
                structSize += entry.Size;
            }

            //
            //  Pad the struct itself if necessary.
            //

            if (padFullStructure)
            {
                // Finally, the struct itself must be aligned
                if ((structSize % 8) != 0)
                {
                    // We're only handling DWORD -> QWORD padding at this point
                    Debug.Assert((structSize % 4) == 0);

                    sorted.Add(new AlignmentEntry(/* field = */ null, /* isAnimation = */ false, /* isPad = */ true));
                    structSize += 4;
                }
            }

            AlignmentEntry[] asArray = (AlignmentEntry[])sorted.ToArray();

            int offset = 0;

            // Now walk the list and add calculated offsets to each entry
            foreach (AlignmentEntry entry in asArray)
            {
                entry.Offset = offset;
                offset      += entry.Size;
            }

            return(new PaddedStructData(asArray, structSize));
        }