Skip to content

Instantly share code, notes, and snippets.

@UplinkCoder
Created October 2, 2021 19:56
Show Gist options
  • Select an option

  • Save UplinkCoder/b8c2709f574417e43a5f0130356feea4 to your computer and use it in GitHub Desktop.

Select an option

Save UplinkCoder/b8c2709f574417e43a5f0130356feea4 to your computer and use it in GitHub Desktop.
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