-
-
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
Compiler: only have freeze_type in select AST nodes #12428
Conversation
Here's an extract output of
Here it is with this PR:
You can see ASTNode went from 72 bytes to 64 bytes, and that difference is also kept on (most) subclasses. |
module Freezable | ||
property freeze_type : Type? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if this even warrants a dedicated module. There's little benefit from that (at least for now, maybe you're already planning something else with it?) and we could just add the property directly to each class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. Especially if the definition of freeze_type
might change for some nodes (like Def
).
{% for name in %w(Block MetaVar MetaTypeVar Def) %} | ||
class {{name.id}} | ||
include Freezable | ||
end | ||
{% end %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's nice to have the binding-related things all defined here. But on the other hand, reopening a couple of classes just to include a module and define a property is also adding an extra code location you need to look at for understanding the properties of a AST type.
In semantics/ast.cr
we're already reopening all those ASTNode classes to add semantics functionality.
Perhaps it could be an option to just drop in property freeze_type : Type?
(or include Freezable
) there in the respective places?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
When you have code like this:
the way the compiler implements this is by setting the
freeze_type
property of aDef
toInt32
. Then before trying to set the method's type to String it will check if there's afreeze_type
set. If so, it will check String against Int32 and produce a compile-time error.This
freeze_type
concept was implemented generically in all AST nodes: any node can be "frozen", and whenever its type changes we check againstfreeze_type
.The thing is, there are only four AST nodes that need this
freeze_type
property: methods, blocks, and special nodes called "meta vars" or "meta type vars" that correspond to local vars and instance/class vars respectively.This PR makes it so that only those four nodes have a
freeze_type
instance var. All other nodes still respond tofreeze_type
by retuningnil
.With this, all AST nodes except those four will now take 8 bytes less in memory. The compiler creates a lot of AST nodes! And whenever a method is instantiated (its arguments get a concrete type) the entire method with all its AST nodes is cloned. So 8 bytes per nodes is a significant amount of memory.
It seems that compiling the compiler before this PR needed 2367.61MB. With this PR it goes down to 2240.64MB (and this is unrelated to the ZeroOneOrMany PR!)
Compilation times doesn't noticeably go down, at least not on my machine.
There are further optimizations to make here: instead of storing
freeze_type
for aDef
, we could actually makefreeze_type
return the return type AST node type's. But I'd like to make that change in a separate PR. I'm trying to make each change in the smallest way possible.