Skip to content

[SwiftSyntax] Make Syntax nodes structs instead of classes #14122

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

Merged

Conversation

harlanhaskins
Copy link
Contributor

@harlanhaskins harlanhaskins commented Jan 24, 2018

This patch, more in line with how I hoped we could structure the API, moves from a class-based model with Syntax as a superclass to a protocol-based model where each struct conforms to Syntax.

This has benefits and drawbacks:

Benefits

  • Syntax nodes, which are just thin wrappers around SyntaxData, no longer need to be ARC managed.
  • This moves it from a 4-word ARC box to a 2-word struct
  • Creating a Syntax node turns from a heap allocation into a retain on the root

(I noticed allocations of these things was a problem when I profiled a run of Silt's parser and noticed a huuuuge number of Syntax node allocations)

Drawbacks

  • Syntax/ExprSyntax/DeclSyntax, etc. nodes can no longer be created directly.
  • Syntax can no longer be Hashable because that precludes its use as an existential. Instead of comparing two Syntax nodes with an Equatable conformance, one must conditionally cast them down to the same type. There is an overload for ==, so most users won't feel the pain of this. But it does mean you can no longer make a Set<Syntax>, only Sets of concrete Syntax nodes.

I'm leaning towards the drawbacks outweighing the benefits, but I personally think it's unreasonable for each of these nodes to have to be an allocation.

@harlanhaskins harlanhaskins requested a review from rintaro January 24, 2018 07:26
@harlanhaskins
Copy link
Contributor Author

@swift-ci please smoke test

@rintaro
Copy link
Member

rintaro commented Jan 24, 2018

+1 I believe this is the right way to go!

@nkcsgexi
Copy link
Contributor

nkcsgexi commented Jan 24, 2018

This is an interesting experiment, @harlanhaskins . The second drawback is the one I'm not a big fan of. We do see our clients using Set/Dictionary to track Syntax nodes in multi-pass analysis (this patch may break their codebase). Can we reconcile the hashable convenience and the awesome memory efficiency?

@harlanhaskins
Copy link
Contributor Author

Well, hope is not completely lost. You can still have a set of, say, FunctionDeclSyntax, but a set of ExprSyntax or Syntax wouldn't work. I could add a .uniqueIdentifier property that you could use in a Set.

@harlanhaskins
Copy link
Contributor Author

@swift-ci please smoke test

@harlanhaskins
Copy link
Contributor Author

Another thing: I think Any<Kind>Syntax is actually much worse, as it really only fits in with a C++-style cast<>()-oriented Syntax tree, not one with structs and type metadata. Any<Kind>Syntax was really only necessary to appease the generic SyntaxCollection, because we couldn't say SyntaxCollection<ExprSyntax> if ExprSyntax is a protocol. Instead, the approach I've settled on is using gyb to generate all Syntax collections instead of generic typealiases. It'll lead to more generated code, but will expose a model where things like DeclListSyntax are a list of anything conforming to DeclSyntax.

@harlanhaskins harlanhaskins force-pushed the declassification-procedure branch from bfeb1d4 to e21878d Compare January 24, 2018 23:23
@harlanhaskins
Copy link
Contributor Author

@nkcsgexi So, this seems to be the best I can get the branch. All the existing CollectionSyntax nodes work the same way, and their Element type is still the upper bound of whatever type they wrap. Unfortunately, we lose the ability to directly compare Syntax nodes, requiring you to check
if they both have the same type. There is still an overload for ==, which helps when users are writing code, but doesn't allow e.g., [ExprSyntax] to conform to Equatable.

Also, we lose the ability to use Syntax and ExprSyntax nodes in Sets, directly, without making it a Set of some concrete Syntax type.

@harlanhaskins
Copy link
Contributor Author

@swift-ci please smoke test

@harlanhaskins harlanhaskins changed the title [Experiment][Syntax][Do Not Merge] Make Syntax nodes structs instead of classes [SwiftSyntax] Make Syntax nodes structs instead of classes Jan 25, 2018
@harlanhaskins
Copy link
Contributor Author

harlanhaskins commented Jan 25, 2018

To measure the performance impact of this change, I adjusted Silt's parser to use struct-based Syntax nodes and had it parse a 100,000-line file. Our AST, prior to this change, allocated 400MB, then kept allocating more memory as we dumped the AST until we reached 2.2GB while printing the 20,000th line. I killed the program after there because memory was climbing linearly.

After making this change, we got through all 100,000 lines allocating 1.75GB, which (though excessive) is a significant improvement.

@nkcsgexi
Copy link
Contributor

@harlanhaskins I think you're right. Judging from the experiment results, this is a great performance improvement that worths the dropping of hashability. Feel free to merge if when you feel ready. Thanks! 👍

@harlanhaskins
Copy link
Contributor Author

@swift-ci please smoke test

@harlanhaskins harlanhaskins merged commit a339c82 into swiftlang:master Jan 25, 2018
@harlanhaskins
Copy link
Contributor Author

Thanks for reviewing!

@harlanhaskins harlanhaskins deleted the declassification-procedure branch January 25, 2018 04:17
maldahleh pushed a commit to maldahleh/swift that referenced this pull request Oct 26, 2020
…#14122)

* [Experiment] Make Syntax nodes structs instead of classes

* [Experiment] Add Hashable conformance to concrete types

* Fix pep8 violation

* Remove AnySyntax, explicitly specialize SyntaxCollection nodes

* Refine the comment for SyntaxCollection nodes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants