-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Symbols: share the set of Attachments #8718
Symbols: share the set of Attachments #8718
Conversation
In some profiles, we noticed that the call to `clone.updateAttachment` was generating up to 10 MiB of lambda objects. Since this seems to be reentrant, we can save those allocations by using a single Function1 object with a mutable state.
1975e40
to
8c0fc27
Compare
I'd prefer to take this in a slightly different direction which would avoid allocation of intermediate diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index ce0b975f7c..b834232eba 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -2025,7 +2025,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
setInfo (this.info cloneInfo clone)
setAnnotations this.annotations
)
- this.attachments.all.foreach(clone.updateAttachment)
+ assert(clone.attachments.isEmpty)
+ clone.setAttachments(this.attachments.cloneAttachments)
if (clone.thisSym != clone)
clone.typeOfThis = (clone.typeOfThis cloneInfo clone)
diff --git a/src/reflect/scala/reflect/macros/Attachments.scala b/src/reflect/scala/reflect/macros/Attachments.scala
index 157d142f2e..ce87107e89 100644
--- a/src/reflect/scala/reflect/macros/Attachments.scala
+++ b/src/reflect/scala/reflect/macros/Attachments.scala
@@ -76,6 +76,7 @@ abstract class Attachments { self =>
}
def isEmpty: Boolean = true
+ def cloneAttachments: Attachments { type Pos = self.Pos } = this
}
private object Attachments {
@@ -90,4 +91,5 @@ private final class NonemptyAttachments[P >: Null](override val pos: P, override
type Pos = P
def withPos(newPos: Pos) = new NonemptyAttachments(newPos, all)
override def isEmpty: Boolean = false
+ override def cloneAttachments: Attachments { type Pos = P } = new NonemptyAttachments[P](pos, all)
} |
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.
Consider alternative of reusing the underlying immutable.Set
when cloning a symbol with non-empty attachments.
Just for my information: are those Are those changes you mentioned complementary or opposite to extracting the |
The common case is that the attachment set is empty. In that case, the only allocation here is the Lambda. But for symbols with a non-empty set of attachments, the current means of cloning is inefficient -- it creates a copy of the the underlying set element by element (discarding the wrapper class But the underlying When we refactor the code to do this, we no longer call |
var theClone: TypeOfClonedSymbol = null | ||
def apply(x: Any): Unit = theClone.updateAttachment(x) | ||
} | ||
|
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.
For future reference, I realised that this was defined at the wrong level -- it should have been a member of Symbols
not of Symbol
.
/rebuild |
Needs a binary compatibility exception: |
81d58cb
to
31ba471
Compare
It turns out that we may be able to avoid the foreach and the lambda altogether, and instead use a cloneAttachments function.
31ba471
to
7ca7131
Compare
/synch |
/nothingtoseehere |
In some profiles, we noticed that the call to
![Screenshot 2020-02-15 at 15 10 32](https://user-images.githubusercontent.com/1764610/74590339-6eab4c80-5005-11ea-862e-74fe3cb17fb1.png)
clone.updateAttachment
was generating up to 10 MiB of lambda objects. Since this seems to be non-reentrant, we can save those allocations by using a singleFunction1
object with a mutable state.