Skip to content

Unify TreeHash and Versioned into a single Version #4772

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
merged 1 commit into from
Dec 26, 2022
Merged

Conversation

gzm0
Copy link
Contributor

@gzm0 gzm0 commented Dec 23, 2022

No description provided.

@gzm0
Copy link
Contributor Author

gzm0 commented Dec 23, 2022

Only the last commit is part of this PR.

Copy link
Member

@sjrd sjrd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. I like it :)

val isHash = version.isHash
buffer.writeBoolean(isHash)
if (isHash)
version.writeHash(buffer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens/should happen if the version is Combined here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not write it. The idea (and yes I'll document this properly) is that we'll only ever serialize hashed versions. All the other versions are not serialization safe (as in: we cannot guarantee collision freedom across linker instances).

Comment on lines 34 to 36
private[linker] def fileTimeToVersion(time: FileTime): ir.Version =
ir.Version.fromBytes(time.toString().getBytes(StandardCharsets.US_ASCII))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems unnecessarily inefficient. Consider something like:

val instant = time.toInstant()
ir.Version.fromLongs(instant.getEpochSecond(), instant.getNano())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have. But that isn't lossless according to this: https://docs.oracle.com/javase/8/docs/api/java/nio/file/attribute/FileTime.html#toInstant--

toString is the only lossless serialization of FileTime I could find.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hum, OK. Probably worth a comment, then.

} { linkedInit =>
mergeVersions(linkedClass.version, linkedInit.version).map("2-" + _)
Version.combine(linkedClass.version, linkedInit.version)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit funny. We can distinguish those two Versions because Combine of different lengths are always different. That's a bit of an implementation detail, though, isn't it? Also, what if we wanted the same distinguishing feature but coming from two different single Versions?

Should we have a Version.tag(tag: Int, underlying: Version) constructor for that purpose?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have considered that. IMO that is subsumed by:

Version.combine(Version.fromInt(tag), underlying)

(arguably that is slighly less space efficient, but I'm not sure it matters).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, that makes sense.

@gzm0 gzm0 force-pushed the version branch 3 times, most recently from b41a68b to 88f6988 Compare December 23, 2022 11:04
@gzm0 gzm0 changed the title RFC: Use a unified version type for serialization and linking Unify TreeHash and Versioned into a single Version Dec 23, 2022
@@ -204,7 +204,7 @@ final class JavalibIRCleaner(baseDirectoryURI: URI) {
case m @ MethodDef(flags, name, originalName, args, resultType, body) =>
implicit val pos = m.pos
MethodDef(flags, transformMethodIdent(name), originalName, transformParamDefs(args),
transformType(resultType), body)(m.optimizerHints, m.hash)
transformType(resultType), body)(m.optimizerHints, Version.NoVersion)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: We're running the overall result through Hashers anyways (as we should). So this will just keep an old / wrong hash (in fact, it could lead to spurious diffs where there are non in the resulting tree).

@gzm0 gzm0 requested review from sjrd and removed request for sjrd December 23, 2022 15:21
@gzm0
Copy link
Contributor Author

gzm0 commented Dec 23, 2022

Not ready for review yet. Needs test adjustment (and tests).

@gzm0 gzm0 force-pushed the version branch 3 times, most recently from e130295 to ebe5066 Compare December 24, 2022 12:42
@gzm0 gzm0 requested a review from sjrd December 24, 2022 12:43
@gzm0
Copy link
Contributor Author

gzm0 commented Dec 24, 2022

Ready for review now.

Copy link
Member

@sjrd sjrd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comments only.

final class Version private (private val v: Array[Byte]) extends AnyVal {
import Version.Type

/** Whether this is a sentinel. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A sentinel is an implementation-detail concept. I wouldn't talk about it in the public API. Also this suggests that it returns true when it's the sentinel.

Consider instead "Whether this version is different than NoVersion." or something like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we weren't actually using this a public API, so I made it private and dropped the comment entirely.


testNe(v, fromHash(a))
testNe(v, fromBytes(a))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spurious new line.

exclude[DirectMissingMethodProblem]("org.scalajs.ir.Trees#JSPropertyDef.apply"),
exclude[MissingClassProblem]("org.scalajs.ir.Trees$DoWhile"),
exclude[MissingClassProblem]("org.scalajs.ir.Trees$DoWhile$"),
exclude[Problem]("org.scalajs.ir.*"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😅

@sjrd
Copy link
Member

sjrd commented Dec 24, 2022

Have you considered calling NoVersion instead Unknown? It might make it clearer why Unknown is not the same version as Unknown.

@gzm0 gzm0 marked this pull request as ready for review December 25, 2022 08:00
@gzm0
Copy link
Contributor Author

gzm0 commented Dec 25, 2022

Have you considered calling NoVersion instead Unknown? It might make it clearer why Unknown is not the same version as Unknown.

Good point. Unversioned also comes to mind (I feel this might almost be a bit better). I don't have a strong opinion on this, so any is fine by me.

@gzm0 gzm0 requested a review from sjrd December 25, 2022 08:02
@sjrd
Copy link
Member

sjrd commented Dec 25, 2022

No real preference between Unkown and Unversioned.

@gzm0
Copy link
Contributor Author

gzm0 commented Dec 25, 2022

Updated.

@gzm0 gzm0 force-pushed the version branch 3 times, most recently from eb5773c to 321e993 Compare December 26, 2022 11:19
@gzm0 gzm0 merged commit 205b6d7 into scala-js:main Dec 26, 2022
@gzm0 gzm0 deleted the version branch December 26, 2022 17:35
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.

2 participants