Skip to content
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

Consolidate Info Loading #4824

Merged
merged 2 commits into from Apr 11, 2023
Merged

Consolidate Info Loading #4824

merged 2 commits into from Apr 11, 2023

Conversation

gzm0
Copy link
Contributor

@gzm0 gzm0 commented Mar 5, 2023

Instead of individual loaders for BaseLinker and Refiner, we
consolidate into a single loader.

@gzm0
Copy link
Contributor Author

gzm0 commented Mar 5, 2023

Note that this currently fails org.scalajs.linker.BasicLinkerBackendTest.linkNoSecondAttemptInEmitter I wanted to get an opinion first, before debugging that.


private object ClassDefAndInfoCache {
final class Update(
val classDef: ClassDef,
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 we currently cache the entire ClassDef, even though the global IRCache already does that.

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.

That seems appropriate. It's overall a nice simplification, I think. The added caching probably won't do any good, but it also should not hurt. It might become beneficial with an incremental Analyzer?

@gzm0 gzm0 requested a review from sjrd March 12, 2023 16:21
@gzm0 gzm0 marked this pull request as ready for review March 12, 2023 16:21
@gzm0 gzm0 changed the title RFC: Consolidate Info Loading Consolidate Info Loading Mar 12, 2023
@@ -233,27 +233,16 @@ private[emitter] final class KnowledgeGuardian(config: Emitter.Config) {

private var isAlive: Boolean = true

private var isInterface = computeIsInterface(initClass)
private var linkedClass = initClass
Copy link
Member

Choose a reason for hiding this comment

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

Typo in the commit message? "Doesn't require use to compare"

superClassAskers += invalidatable
superClass
rawClassInfoAskers += invalidatable
linkedClass.superClass.fold[ClassName](null.asInstanceOf[ClassName])(_.name)
Copy link
Member

Choose a reason for hiding this comment

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

Is asInstanceOf necessary, here?

Suggested change
linkedClass.superClass.fold[ClassName](null.asInstanceOf[ClassName])(_.name)
linkedClass.superClass.fold[ClassName](null)(_.name)

Comment on lines 359 to 360
rawClassInfoAskers += invalidatable
linkedClass.fields
Copy link
Member

Choose a reason for hiding this comment

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

Is this valid? Can't fields evolve independently of linkedClass.version because of reachability analysis?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Uh, oh. Indeed :-/

val tree = ir.Serializers.deserialize(ByteBuffer.wrap(content))

new IRFileImpl(path, stableVersion) {
def entryPointsInfo(implicit ec: ExecutionContext): Future[ir.EntryPointsInfo] =
Copy link
Member

Choose a reason for hiding this comment

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

CI says: missing import for ExecutionContext and Future.

)
val path = "org/scalajs/linker/runtime/" + name
val content = Base64.getDecoder().decode(contentBase64)
val tree = ir.Serializers.deserialize(ByteBuffer.wrap(content))
Copy link
Member

Choose a reason for hiding this comment

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

Why don't we do the same thing in linker/jvm/.../PrivateLibHolder?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because I forgot :-/

case object InternalIRCheck extends IRCheckMode
}

private class ClassInfoCache(className: ClassName, irLoader: IRLoader, irCheckMode: InfoLoader.IRCheckMode) {
Copy link
Member

Choose a reason for hiding this comment

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

Consider putting all these private classes inside object InfoLoader. We usually do that.

Comment on lines 122 to 123
case FieldDef(flags, FieldIdent(name), _, ftpe) =>
if (!flags.namespace.isStatic)
builder.maybeAddReferencedFieldClass(name, ftpe)
Copy link
Member

Choose a reason for hiding this comment

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

Indentation issue.

private val methodSynthesizer = new MethodSynthesizer(irLoader)
private val infoLoader = new InfoLoader(irLoader,
Copy link
Member

Choose a reason for hiding this comment

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

Looks like this right hand side deserves a block.

@@ -107,11 +115,11 @@ final class BaseLinker(config: CommonPhaseConfig, checkIR: Boolean) {
private def assemble(moduleInitializers: Seq[ModuleInitializer],
analysis: Analysis)(implicit ec: ExecutionContext): Future[LinkingUnit] = {
def assembleClass(info: ClassInfo) = {
val classAndVersion = irLoader.loadClassDefAndVersion(info.className)
val version = irLoader.irFileVersion(info.className)
Copy link
Member

Choose a reason for hiding this comment

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

This split between the version and the tree does not seem warranted. It results in looking up the class name twice in a hash map instead of once. Why is this done?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To avoid triggering a load if the version stays the same (in other parts of the codebase):

Alternatives:

  • (re)-add an additional method loadClassDefAndVersion to IRLoader. Con: More complicated interface.
  • Return IRFiles from IRLoader (or Option[IRFile]). Con: Needs wrapping in the Refiner (OTOH, we could replace the tuples returned by the Optimizer by an IRFile subclass).

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, I see. I wouldn't go as far as returning IRFile from IRLoader. I think I would find that confusing. Either re-add loadClassDefAndVersion or leave it as is seem equally good.


/** Does a dead code elimination pass on a [[LinkingUnit]]. */
final class Refiner(config: CommonPhaseConfig, checkIR: Boolean) {
import Refiner._

private val inputProvider = new InputProvider(checkIR)
private val irLoader = new ClassDefIRLoader
private val infoLoader = new InfoLoader(irLoader,
Copy link
Member

Choose a reason for hiding this comment

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

Same as the other one. This deserves a block.

@gzm0
Copy link
Contributor Author

gzm0 commented Apr 9, 2023

Rebased onto main and addressed comments.

TBC: Not necessary for 1.13.1.

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.

LGTM module the suggested Squash.

Instead of individual loaders for BaseLinker and Refiner, we
consolidate into a single loader.
@gzm0 gzm0 merged commit 9781655 into scala-js:main Apr 11, 2023
3 checks passed
@gzm0 gzm0 deleted the info-loader branch April 16, 2023 15:29
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.

None yet

2 participants