Skip to content

Allocate fewer TypeMaps and TypeAccumulators #9618

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 5 commits into from
Aug 25, 2020

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Aug 21, 2020

Delay allocation of TypeMap and TypeAccumulators by handling common cases directly
before doing an allocation. The biggest win is handling AppliedTypes directly. This risks
creating more than one map instance, since function part and every argument might
in the end require a map. But looking at stats shows that the benefits largely outweigh
the costs.

@odersky
Copy link
Contributor Author

odersky commented Aug 21, 2020

test performance please

@dottybot
Copy link
Member

performance test scheduled: 17 job(s) in queue, 1 running.

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/9618/ to see the changes.

Benchmarks is based on merging with master (387c562)

Copy link
Contributor

@liufengyun liufengyun left a comment

Choose a reason for hiding this comment

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

LGTM

def foldArgs(x: T, args: List[Type]): T = args match
case arg :: rest => foldArgs(op(x, arg), rest)
case nil => x
foldArgs(op(x, tycon), args)
Copy link
Contributor

Choose a reason for hiding this comment

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

In map and fold, do we need to recurse on typcon? The semantics is quite different from TypeMap and TypeAccumulator, and is specific to Substituters. Maybe add a note here to avoid misuse?

}

final class SubstThisMap(from: ClassSymbol, to: Type)(using Context) extends DeepTypeMap {
def apply(tp: Type): Type = substThis(tp, from, to, this)
def apply(tp: Type): Type = substThis(tp, from, to, this)(using mapCtx)
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it mean all classes that inherit TypeMap (e.g. DeepTypeMap, ApproximatingTypeMap and AsSeenFromMap) have to write using mapCtx explicitly everywhere?

There's something problematic going on here. TypeMaps usually take a context as a
parameter, which becomes a private parameter acessor field. That parameter shadows
the mapCtx field inherited from TypeMap. `mapCtx` is a variable that is temporarily
mutated when mapping LazyRefs. But since it is shadowed, such mutations do not
affect code that is defined in the subclass of TypeMap.

One fix is to explicitly pass mapCtx to all code that is called from the maps.
That's what's done here for substituters. There might be other solutions as well,
which have to be tried out.
@odersky odersky merged commit c908b13 into scala:master Aug 25, 2020
@odersky odersky deleted the optimize-maps branch August 25, 2020 10:22
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