Created
October 2, 2021 19:56
-
-
Save UplinkCoder/b8c2709f574417e43a5f0130356feea4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import core.reflect.reflect; | |
| import core.reflect.transitiveVisitor; | |
| import std_stdio = std.xml; | |
| struct PadDetctedTuple | |
| { | |
| string aggregateName; | |
| Location aggregateLocation; | |
| ulong number_of_pad_bytes; | |
| string msg; | |
| } | |
| struct S | |
| { | |
| ubyte a; // <--- is at offset 0 | |
| ubyte b; // <--- is at offset 1 | |
| uint d; // <--- is at offset 4 | |
| } | |
| static assert(S.init.a.offsetof == 0); | |
| static assert(S.init.b.offsetof == 1); | |
| static assert(S.init.d.offsetof == 4); | |
| static immutable sc = currentScope(); | |
| static immutable node = nodeFromName("S", ReflectFlags.Members | ReflectFlags.MemberRecursion, sc); | |
| static immutable stdio_n = nodeFromName("std_stdio", ReflectFlags.Members | ReflectFlags.MemberRecursion, sc); | |
| void main() | |
| { | |
| import std.stdio; | |
| foreach(p; detectPadding(stdio_n)) | |
| { | |
| writeln(p.aggregateName, " -- ", p.aggregateLocation.filename, ":", p.aggregateLocation.line, " ", p.msg); | |
| } | |
| /+ | |
| foreach(p; detectPadding(null)) | |
| { | |
| writeln(p.aggregateName, " -- ", p.aggregateLocation.filename, ":", p.aggregateLocation.line, p.msg); | |
| } | |
| +/ | |
| } | |
| PadDetctedTuple[] detectPadding(const Node n) | |
| { | |
| class PadDetectVisitor : TransitiveVisitor | |
| { | |
| import std.format; | |
| alias visit = TransitiveVisitor.visit; | |
| override void visit(StructDeclaration ad) | |
| { | |
| ulong lastOffset; | |
| ulong lastSize; | |
| ulong wastedBytes; | |
| string lastFieldName; | |
| string msg; | |
| foreach(f;ad.fields) | |
| { | |
| const waste = ((f.offset - lastOffset) - lastSize); | |
| wastedBytes += waste; | |
| if (waste) | |
| { | |
| msg ~= "\n\t%d bytes of waste between %s and %s".format(waste, lastFieldName, f.name); | |
| } | |
| lastOffset = f.offset; | |
| lastSize = f.type.size; | |
| if (cast(TypeDelegate)f.type) | |
| lastSize = size_t.sizeof + size_t.sizeof; | |
| lastFieldName = f.name; | |
| } | |
| if (wastedBytes) | |
| { | |
| pads ~= PadDetctedTuple(ad.name, ad.location, wastedBytes, msg); | |
| wastedBytes = 0; | |
| msg = ""; | |
| } | |
| } | |
| override void visit(ClassDeclaration cd) | |
| { | |
| ulong lastOffset = 16; // class metadata is 16 bytes | |
| ulong lastSize; | |
| ulong wastedBytes; | |
| string lastFieldName; | |
| string msg; | |
| // for classes we need to keep a stack of bases | |
| // let's go! | |
| ClassDeclaration[] baseStack = [cd]; | |
| for(auto base = cd.base; base; base = base.base) | |
| { | |
| baseStack ~= base; | |
| } | |
| foreach_reverse(base;baseStack) | |
| { | |
| foreach(f;base.fields) | |
| { | |
| assert(f.offset >= lastOffset); | |
| auto waste = ((f.offset - lastOffset) - lastSize); | |
| wastedBytes += waste; | |
| if (waste) | |
| { | |
| msg ~= "%d bytes of waste between %s and %s\n".format(waste, lastFieldName, f.name); | |
| } | |
| lastOffset = f.offset; | |
| lastSize = f.type.size; | |
| if (cast(TypeDelegate)f.type) | |
| lastSize = size_t.sizeof + size_t.sizeof; | |
| lastFieldName = f.name; | |
| } | |
| } | |
| if (wastedBytes) | |
| { | |
| pads ~= PadDetctedTuple(cd.name, cd.location, wastedBytes, msg); | |
| wastedBytes = 0; | |
| msg = ""; | |
| } | |
| } | |
| PadDetctedTuple[] pads; | |
| } | |
| scope padDetector = new PadDetectVisitor(); | |
| (cast()n).accept(padDetector); | |
| return padDetector.pads; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment