-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reordering instance variables to save space #13591
Comments
It makes a lot of sense. Great analysis, Quinton! 👏 |
One idea could be to repurpose There is some similarity to #7773 which proposes annotations for ivars regarding alignment and packing.
I noticed that as well while working on #12020 (which introduces an additional ivar): The memory layout of |
Given this is at the codegen level, macros would all be expanded already before the reordering happens yea? I.e. |
@Blacksmoke16 Yeah, this is all limited to codegen. |
But struct could be used for fast protocols: casting pointer to bytes into pointer to struct, and you're ready to read values. So, there should be not only Probably |
|
@HertzDevil by the effect (fixed field order and offsets, ie fixed layout) it is the same. But by meaning, it is not. |
Instance variables in a type are laid out in the order the compiler calls
Crystal::Type#declare_instance_var
on the type. Roughly speaking,TypeDeclaration
s andUninitializedVar
s go first, followed by other things like plain assignments. We can write this:We can also rearrange those instance variables to produce a smaller struct:
By reordering the instance variables, we have reduced the amount of padding between them and, therefore, the total byte size occupied by a
Foo
instance.I propose that the compiler should do this automatically for every type that isn't a primitive type or an extern type. All instance variables within a struct, not including its supertypes or subtypes, would be sorted in descending order by their alignments. For classes the situation is a bit different:
Because all reference types start with a type ID, which is an
Int32
with an alignment of 4 bytes, it would be more efficient if instance variables with an alignment of 4, 2, or 1 byte are placed first, followed by other variables with an alignment larger than 4. This applies to classes whose entire inheritance chain up toReference
does not define any instance variables, in particular classes inheriting directly fromReference
; subsequent subclasses are free to continue placing the most strictly aligned instance variables first.A consequence is that the same generic type may order its instance variables differently depending on the generic arguments:
The instance variables are never reordered across types; an instance variable in a subclass will never be moved before any instance variable in its superclasses. Thus, a pointer to a subclass is implicitly also a pointer to any of its superclasses. However, the same need not apply to included modules:
Here it is assumed that
Foo#@x
will always perform some kind of dynamic dispatch similar to union-typed variables.String
andLog::Metadata
are special since they do not have a fixed instance size. Instead,String#@c
andLog::Metadata#@first
are flexible array members that must be the last instance variable, although the rest of their instance variables can still be reordered. (ForString
this requires a bit of extra effort when defining its constants too.) There should be a special annotation for these special instance variables.The text was updated successfully, but these errors were encountered: